Does this user belong to that domain group?

UPD: This works only on LDAP groups and LDAP:// provider, not WinNT groups!

If we know two things – a login name of a user for instance northwind\JohnDoe and a domain group northwind\board. We want to check if John Doe belongs to the “board” group or not.

This is how you find it: IsUserMember( "northwind\JohnDoe", "northwind\board")

Here is the VB.Net code you need :

'''<summary>Checks if a user belongs to the domain group</summary>
'''<param name="spLogin">Full  login name domain\user</param>
'''<param name="spGroupLogin">Group full login name domain\group</param>
'''<returns>True if belongs, False if not</returns>
Public Function IsUserMember(ByVal spLogin As String, _
                             ByVal spGroupLogin As String) As Boolean
    Dim sUserDistinguish, sGroupDistinguish As String
    Dim sFilter As String
    Dim sAccount, sGroupAccount, sDomain As String

    If Not Me.SplitLogin(spLogin, sDomain, sAccount) Then
        'if username is not formed as domain\user, return false
        Return False
    End If

    If Not Me.SplitLogin(spGroupLogin, sDomain, sGroupAccount) Then
        'if group name is not formed as domain\group, return false
        Return False
    End If

    'get the distinguishedName of both user and group
    sUserDistinguish = DistingishedNameFromLogin(spLogin)
    sGroupDistinguish = DistingishedNameFromLogin(spGroupLogin)

    'check in a recursive manner if user belongs to group (or its subgroups)
    Return Me.IsUserInGroupRecursive(sUserDistinguish, sGroupDistinguish, sDomain, New Specialized.StringDictionary)
End Function

'''<summary>Recursively (in subgroups, too) finds a user in a group</summary>
'''<param name="spUserDistinguish">DistinguishedName of a user</param>
'''<param name="spGroupDistinguish">DistinguishedName of a group</param>
'''<param name="spDomain">domain name</param>
'''<param name="opCheckedGroups">Groups already sought</param>
Public Function IsUserInGroupRecursive(ByVal spUserDistinguish As String, _
                                       ByVal spGroupDistinguish As String, _
                                       ByVal spDomain As String, _
                                       ByRef opCheckedGroups As Collections.Specialized.StringDictionary) As Boolean

    If opCheckedGroups(spGroupDistinguish) = "DONE" Then
        'there may be occasions when a group is somehow a subgroup of itself 
        'so we have to remember if the group is already sought or not
        'if thr group is already sought, there is NO such user
        Return False
        'mark the group as sought otherwise
        opCheckedGroups(spGroupDistinguish) = "DONE"
    End If

    If Me.IsUserDirectlyInGroup(spUserDistinguish, spGroupDistinguish, spDomain) Then
        'if the user is can be found in the group directly
        Return True
        'if not in the group directly, get all the subgroups
        For Each sSubGroup As String In Me.GetSubGroups(spGroupDistinguish, spDomain)
            'check subgroup recursively 
            If IsUserInGroupRecursive(spUserDistinguish, sSubGroup, spDomain, opCheckedGroups) Then
                'if user is found in a subgroup, return true
                Return True
                'otherwise check the next subgroup
            End If
    End If

    'if we are here, the user is not found
    Return False
End Function

'''<summary>Finds all subgroups of a group</summary>
'''<param name="spGroupDistinguishName">Distinguished name of the parent group</param>
'''<param name="spDomain">Domain name</param>
Public Function GetSubGroups( _
        ByVal spGroupDistinguishName As String, _
        ByVal spDomain As String) As Collections.Specialized.StringCollection

    Dim sFilter As String
    Dim oResults As SearchResultCollection
    Dim oRet As Collections.Specialized.StringCollection

    'searches for subgroups that are members of this group
    sFilter = "(&(objectCategory=group)(memberof=" & spGroupDistinguishName & "))"

    oResults = Me.FindByFilter(sFilter, spDomain)

    oRet = New Collections.Specialized.StringCollection
    For Each oResult As SearchResult In oResults
    Return oRet
End Function

'''<summary>According to the filter specified, searches LDAP</summary>
'''<param name="spFilter">what to search for</param>
'''<param name="spDomain">The domain to search</param>
Private Function FindByFilter(ByVal spFilter As String, ByVal spDomain As String) As SearchResultCollection
    Dim dsEntryObj As DirectoryEntry
    Dim dsSearcher As DirectorySearcher
    Dim dsResult As SearchResultCollection
        'search LDAP://domain
        dsEntryObj = New DirectoryEntry("LDAP://" & spDomain)
    Catch e As Exception
        Throw New System.Exception(String.Format("Error creating LDAP directory object {0}!", "LDAP://" & spDomain))
    End Try

    'create the searcher object
    dsSearcher = New DirectorySearcher(dsEntryObj)
    dsSearcher.Filter = spFilter
        'search in the directory
        dsResult = dsSearcher.FindAll()
    Catch e As Exception
        Throw New Exception(String.Format("Error searching in directory. Filter {0}", dsSearcher.Filter))
    End Try

    Return dsResult
End Function

'''<summary>Does user belong to the group directly?(i.e. not in subgroups)</summary>
'''<param name="spUserDistinguishName">Distinguished name of the user</param>
'''<param name="spGroupDistinguishName">distinguished name of the group</param>
'''<param name="spDomain">domain name</param>
Public Function IsUserDirectlyInGroup(ByVal spUserDistinguishName As String, _
                                      ByVal spGroupDistinguishName As String, _
                                      ByVal spDomain As String) As Boolean
    Dim sFilter As String
    sFilter = "(&(&(objectCategory=group)" & _
                  "(distinguishedname=" & spGroupDistinguishName & ")" & _
                 ")" & _
                "(member=" & spUserDistinguishName & "))"

    Return (Me.FindByFilter(sFilter, spDomain).Count > 0)
End Function

'''<summary>Gets the distinguished name from user name</summary>
'''<param name="spLogin">Full login name domain\user</param>
Public Function DistingishedNameFromLogin(ByVal spLogin As String) As String
    'empty input results in empty output
    If Trim(spLogin) = "" Then Return ""
    Dim sLogin, sDomain As String
    Dim sFilter As String
    Dim oResult As SearchResultCollection

    'separate the login name into parts
    If Not (SplitLogin(spLogin, sDomain, sLogin)) Then
        Return ""
    End If

    'search by sam account, only groups and users
    sFilter = "(&(sAMAccountName=" & sLogin & ")(|(objectCategory=group)(objectCategory=person)))"

    oResult = Me.FindByFilter(sFilter, sDomain)

    If oResult.Count = 0 Then
        Return ""
    ElseIf oResult.Count > 1 Then
        Throw New ArgumentException("More than one entry for this sAMAccountName")
        Return oResult(0).Properties("distinguishedname")(0).ToString
    End If
End Function

'''<summary>Splits the login name into parts - domain and account</summary>
'''<param name="spLogin">Full login name:  domain\account</param>
'''<param name="spDomain">OUT: Domain name</param>
'''<param name="spAccount">OUT: Account</param>
Public Function SplitLogin(ByVal spLogin As String, ByRef spDomain As String, ByRef spAccount As String) As Boolean
    Dim iSlashPos As Integer
    spLogin = spLogin.Replace("/"c, "\"c)
    iSlashPos = spLogin.IndexOf("\"c)
    If iSlashPos > -1 Then
        With spLogin.Split("\"c)
            spAccount = .GetValue(1).ToString
            spDomain = .GetValue(0).ToString
        End With
        Return True
        Return False
    End If
End Function

Note: Add system.directoryservices.dll to project references, import System.DirectoryServices namespace!

One thought on “Does this user belong to that domain group?”

  1. Pingback: ProgTips

Comments are closed.