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"
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

* 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.
* 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)


2 Responses to Determining Active Directory group membership

  • cesarchalom says:

    Hi Stuart,

    Great post !

    Maybe you should put your name in the top of your Blog… It becomes practically impossible to know who wrote these cool articles


    Cesar Chalom

  • stuartd says:

    Hi Cesar

    I have put my name in using custom CSS, it works in Firefox and IE anyway.

    Many thanks for your kind words.


Leave a Reply

Your email address will not be published. Required fields are marked *