Active Directory Integration

Topics: Developer Forum
Jul 28, 2009 at 4:43 PM
Edited Jul 28, 2009 at 4:44 PM

We just started looking into N2 CMS this week and so far I am very impressed with the implementation. One of the things that we're interested in would be some sort of Active Directory integration where we could do the following:

  • Use network name and password to log in to the editor interface
  • Allow users to edit only certain sections of the site based on AD groups
  • Possibly have some sort of workflow notification so editors know when something should be approved to publish

Do you have any suggestions for how to go about implementing this? If I do end up writing code to make this work I would be interested in contributing it back to the source code.

Thanks!

Jul 28, 2009 at 5:28 PM
N2 uses the standard .NET Membership API to authenticate users & manage groups, so you should just be able to wire in the built-in AD providers using the web.config file & the security stuff should work as normal.

There's an N2Contrib project on googlecode (http://code.google.com/p/n2contrib/) that includes a Workflow component. It might help you but I've never looked into it beyond reading the site..

Steve

2009/7/28 sddaniels <notifications@codeplex.com>

From: sddaniels

We just started looking into N2 CMS this week and so far I am very impressed with the implementation. One of the things that we're interested in would be some sort of Active Directory integration where we could do the following:

  • Use network name and password to log in to the editor interface
  • Restrict users to certain sections of the site based on AD groups
  • Possibly have some sort of workflow notification so editors know when something should be approved to publish

Do you have any suggestions for how to go about implementing this? If I do end up writing code to make this work I would be interested in contributing it back to the source code.

Thanks!

Read the full discussion online.

To add a post to this discussion, reply to this email (n2cms@discussions.codeplex.com)

To start a new discussion for this project, email n2cms@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Jul 31, 2009 at 3:41 PM

Thanks for the help, Steve. I was able to use the built in MembershipADProvider, and I wrote a custom role provider that interfaced with the AD groups I wanted to use. The other options for role provider seemed like to much trouble (required an AzMan store).

I do have another question though: When the signed in person has permission as a Writer, they're not supposed to be able to publish articles, right? This seems to be the case for the edit page, but when I went to the previous versions page I was able to publish any version as a Writer. Is this something that I can fix somehow or is this a bug?

Jul 31, 2009 at 9:30 PM

Hi, 

 

perhaps you can share your code on the custom role provider?

A userfull piece of code I think...

 

Thanks!
Martijn

Jul 31, 2009 at 9:45 PM
Edited Jul 31, 2009 at 9:51 PM

No guarantees, of course, but here you go:

Config Section

 

		<roleManager enabled="true" defaultProvider="CustomActiveDirectoryProvider">
			<providers>
				<clear/>
				<add name="CustomActiveDirectoryProvider"
					 type="CustomRoleProvider"
					 groups="Writers=Group 1;Editors=Group 2;Administrators=Group 3"
					 activeDirectoryPath="LDAP://yourserver.com/DC=YOURSERVER,DC=COM"/>
			</providers>
		</roleManager>

Code

 

 

Imports System.Collections.Generic
Imports System.DirectoryServices

Public Class CustomRoleProvider
    Inherits RoleProvider
    
    Private groupsByRole As Dictionary(Of String, String) ' key = role name,     value = AD group name
    Private rolesByGroup As Dictionary(Of String, String) ' key = AD group name, value = role name
    Private adPath As String

    Public Overrides Sub Initialize(ByVal name As String, ByVal config As System.Collections.Specialized.NameValueCollection)

        If config Is Nothing Then
            Throw New ArgumentNullException("config")
        End If

        MyBase.Initialize(name, config)

        adPath = config("activeDirectoryPath")

        ' store all roles and their corresponding active directory groups
        Dim rolesArr() As String = config("groups").Split(";"c)

        groupsByRole = New Dictionary(Of String, String)
        rolesByGroup = New Dictionary(Of String, String)
        For Each roleEntry As String In rolesArr

            Dim roleEntryArr() As String = roleEntry.Split("="c)
            groupsByRole.Add(roleEntryArr(0), roleEntryArr(1))
            rolesByGroup.Add(roleEntryArr(1), roleEntryArr(0))

        Next

    End Sub
    
    Public Overrides Sub AddUsersToRoles(ByVal usernames() As String, ByVal roleNames() As String)
        Throw New NotSupportedException()
    End Sub

    Public Overrides Property ApplicationName() As String
        Get
            Throw New NotSupportedException()
        End Get
        Set
            Throw new NotSupportedException()
        End Set
    End Property

    Public Overrides Sub CreateRole(ByVal roleName As String)
        Throw New NotSupportedException()
    End Sub

    Public Overrides Function DeleteRole(ByVal roleName As String, ByVal throwOnPopulatedRole As Boolean) As Boolean
        Throw New NotSupportedException()
    End Function

    Public Overrides Function FindUsersInRole(ByVal roleName As String, ByVal usernameToMatch As String) As String()
        Throw New NotSupportedException()
    End Function

    Public Overrides Function GetAllRoles() As String()
        
        Dim allRoles(groupsByRole.Count) As String
        Dim i As Integer = 0

        For Each pair As KeyValuePair(Of String, String) In groupsByRole
            allRoles(i) = pair.Key
            i += 1
        Next

        Return allRoles

    End Function

    Public Overrides Function GetRolesForUser(ByVal username As String) As String()

        Dim userRoles As New List(Of String)
        Dim domain As New DirectoryEntry(Me.adPath)
        Dim searcher As New DirectorySearcher(domain)

        ' find user in AD
        searcher.Filter = "sAMAccountName=" & username
        Dim result As SearchResult = searcher.FindOne()

        For Each groupDN As String In result.Properties("memberOf")

            ' strip the group name out of the distinguished name
            Dim groupArr() As String = groupDN.Split(","c)
            Dim groupName As New StringBuilder(groupArr(0))
            groupName.Replace("CN=", "")

            ' look up group name in our list of roles
            Dim roleToAdd As String = ""
            rolesByGroup.TryGetValue(groupName.ToString(), roleToAdd)

            If Not roleToAdd = String.Empty Then
                userRoles.Add(roleToAdd)
            End If

        Next

        Return userRoles.ToArray()

    End Function

    Public Overrides Function GetUsersInRole(ByVal roleName As String) As String()

        Dim users As New List(Of String)
        Dim domain As New DirectoryEntry(Me.adPath)
        Dim searcher As New DirectorySearcher(domain)

        ' find group in AD
        searcher.Filter = "cn=" & groupsByRole(roleName)
        Dim result As SearchResult = searcher.FindOne()

        ' build search filter to get AD nodes of all users found in previous query
        Dim filter As New StringBuilder("(!")
        For Each userDN As String In result.Properties("member")
            filter.Append("(distinguishedName=" & userDN & ")")
        Next
        filter.Append(")")

        ' get all users for role
        searcher.Filter = filter.ToString()
        Dim results As SearchResultCollection = searcher.FindAll()

        For Each result In results
            users.Add(getValue(result, "sAMAccountName"))
        Next

        Return users.ToArray()

    End Function

    Public Overrides Function IsUserInRole(ByVal username As String, ByVal roleName As String) As Boolean

        Dim domain As New DirectoryEntry(Me.adPath)
        Dim searcher As New DirectorySearcher(domain)

        ' find user in AD
        searcher.Filter = "sAMAccountName=" & username
        Dim result As SearchResult = searcher.FindOne()

        For Each groupDN As String In result.Properties("memberOf")

            ' strip the group name out of the distinguished name
            Dim groupArr() As String = groupDN.Split(","c)
            Dim groupName As New StringBuilder(groupArr(0))
            groupName.Replace("CN=", "")

            ' look up group name in our list of roles
            Dim role As String = ""
            rolesByGroup.TryGetValue(groupName.ToString(), role)

            If Not role = String.Empty Then
                If role.Equals(roleName) Then
                    Return True
                End If
            End If

        Next

        ' still here, so we didn't find the role
        Return False

    End Function

    Public Overrides Sub RemoveUsersFromRoles(ByVal usernames() As String, ByVal roleNames() As String)
        Throw New NotSupportedException()
    End Sub

    Public Overrides Function RoleExists(ByVal roleName As String) As Boolean

        If roleName Is Nothing Then
            Throw New ArgumentNullException()
        Else If rolename = String.Empty Then
            Throw New ArgumentException()
        End If

        Return groupsByRole.ContainsKey(roleName)

    End Function

    Private Function getValue(result As SearchResult, propertyName As String) As String

        Dim vColl As ResultPropertyValueCollection = result.Properties(propertyname)

        If vColl.Count > 0 Then
            Return vColl(0).ToString()
        Else
            Return ""
        End If

    End Function

End Class

 

Aug 3, 2009 at 6:26 PM
Hmm, sounds like a bug.  I don't think I have permission to turn this case into a work item, but if you're able to dig into the source and fix the issue then I'll be happy to apply a patch to the source if you post it up here.

I'm looking at a busy couple of weeks so wont be able to look at this myself for a while (maybe Libardo will re-appear from his holidays at some point and be able to take a look)

S

2009/7/31 sddaniels <notifications@codeplex.com>

From: sddaniels

Thanks for the help, Steve. I was able to use the built in MembershipADProvider, and I wrote a custom role provider that interfaced with the AD groups I wanted to use. The other options for role provider seemed like to much trouble (required an AzMan store).

I do have another question though: When the signed in person has permission as a Writer, they're not supposed to be able to publish articles, right? This seems to be the case for the edit page, but when I went to the previous versions page I was able to publish any version as a Writer. Is this something that I can fix somehow or is this a bug?

Read the full discussion online.

To add a post to this discussion, reply to this email (n2cms@discussions.codeplex.com)

To start a new discussion for this project, email n2cms@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Coordinator
Aug 5, 2009 at 9:45 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Aug 5, 2009 at 3:40 PM

Thanks Libardo! Judging by the work item it looks like you've already fixed the bug. Any idea when this will come out in a release? Unfortunately we're still using VS 2005 at work so I don't think I can compile it myself from source.

Apr 21, 2011 at 3:20 PM

I am also trying to get AD working with my N2CMS site...... with no luck. Should I be able to log into /N2/login.aspx with my domain name by following the above method?? Thanks.

Coordinator
Apr 21, 2011 at 8:48 PM

Have you tried the msdn documentation? http://technet.microsoft.com/en-us/library/cc733010(WS.10).aspx

I could log in using basic authentication.