Welcome to Foxite.COM Community Weblog Sign in | Join | Help

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
Published Monday, August 14, 2006 5:19 PM by stuartd
Filed Under:

Comments

Anonymous comments are disabled