Determining Active Directory group membership
In order to determine whether a user is a member of an Active Directory group (or a member of a group which is a member of the group) in a large directory, iteration through the members collection is too slow as each group can contain thousands of members: we need to be able to tell what groups are members of each group and recursively query those until we find a group the user is a member of.
There are various means of querying the Active Directory: the recommended way for clients like VFP is to use ADO. The ADO AD provider supports two types of query: LDAP filters and SQL. SQL has to be used as VFP doesn't understand the multi-valued adVariant objects returned by LDAP filter queries and can't parse the individual values (using WMI to access the AD returns the same kind of variant arrays, although single-value properties can be accessed)
This example code will determine if the current user is a member of a specified Active Directory group:
lparameters cGroup
* Determine if the current user is a member of this group.
* As group memberships can be nested - user is a member of a group
* which is a member of a group which is a member of the target group -
* use recursive queries to look into the contained groups. Because some of the
* groups have thousands of user members, use querying not iteration.
local oConnection, oCommand, oADSysInfo, cUser, oUser, cUserName, ;
oRoot, cRootDomain, lMember
* Pass the ADSPath to the target group
* cGroup = "CN=TestGroup,OU=Security Groups,DC=foxite,DC=com"
oConnection = createobject("ADODB.Connection")
oCommand = createobject("ADODB.Command")
oConnection.Provider = "ADsDSOObject"
oConnection.open()
oCommand.ActiveConnection = oConnection
oADSysInfo = createobject("ADSystemInfo")
cUser = oADSysInfo.UserName
oUser = getobject("LDAP://" + cUser)
cUserName = oUser.SamAccountName
oRoot = getobject("LDAP://RootDSE")
cRootDomain = oRoot.get("DefaultNamingContext")
lMember = .f.
IsGroupMember_Recurse(cGroup, cUserName, oCommand, cRootDomain, @lMember)
return lMember
procedure IsGroupMember_Recurse(cGroup, cUserName, oCommand, cRootDomain, lMember)
if lMember
* We are already a member: speed through the rest of the recursion stack
return
endif
* Need a different oRS for each iteration
local oRS, cSQL, cGroupPath
* Is user a member of group?
cSQL = [SELECT name from 'LDAP://] + cRootDomain + ;
[' WHERE memberOf='] + cGroup + ;
[' AND objectClass='user' AND SAMAccountName = '] + cUserName + [']
oCommand.CommandText = cSQL
oRS = oCommand.Execute
if oRS.RecordCount > 0
* ? cUserName + " is a member of " + cGroup
lMember = .t.
else
* Get the groups which are a member of this group
cSQL = [select distinguishedname from 'LDAP://] + cRootDomain + ;
[' where memberof='] + cGroup + [' and objectclass = 'group']
oCommand.CommandText = cSQL
oRS = oCommand.Execute
* Recurse
do while not oRS.eof
cGroupPath = oRS.fields(0).value
IsGroupMember_Recurse(cGroupPath, cUserName, oCommand, cRootDomain, @lMember)
oRS.MoveNext
enddo
endif
endproc