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>
'''<remarks></remarks>
'''<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>
'''<returns>Boolean</returns>
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
Else
'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
Else
'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
Next
End If
'if we are here, the user is not found
Return False
End Function
'''<summary>Finds all subgroups of a group</summary>
'''<remarks></remarks>
'''<param name="spGroupDistinguishName">Distinguished name of the parent group</param>
'''<param name="spDomain">Domain name</param>
'''<returns>Collections.Specialized.StringCollection</returns>
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
oRet.Add(oResult.Properties("distinguishedname")(0).ToString)
Next
Return oRet
End Function
'''<summary>According to the filter specified, searches LDAP</summary>
'''<remarks></remarks>
'''<param name="spFilter">what to search for</param>
'''<param name="spDomain">The domain to search</param>
'''<returns>DirectoryServices.SearchResultCollection</returns>
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
Try
'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
Try
'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")
Else
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>
'''<returns>Boolean</returns>
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
Else
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?”
Comments are closed.