Mega Code Archive

 
Categories / Delphi / Files
 

Enumerate a users Active Directory Security group membership

Title: Enumerate a user's Active Directory Security group membership Question: How can i get all group memberships of an Active Directory user account? Answer: This Article based on my Articles in this Community. -Group Policy Attributes in the Active Directory -Query against the Active Directory by LDAP ************************************************************************************* The PrimaryGroupToken and TokenGroups attribute of a user object in the active directory is an constructed attribute, which means that the property is constructed on the client by the Active Directory Service Interface(ADSI) provider and not stored as data in the AD. The PrimayGroupToken attribute does not enumerate the nested groups! To list all of the security groups that a user object is a member of you must query the TokenGroups attribute. The SID for the group is stored in its binary form in the TokenGroups attribute, is not human-readable and cannot used to bind to the group object in the AD. The SID must be converted to bind to an object. You have to register the ADsSecurity.dll on the Client that runs the program(run at the command prompt -REGSVR32.EXE ADsSecurity.DLL-) and import this dll into Delphis IDE too. The IADsSID object that is exported by ADsSecurity.dll can be used to convert the binary SID into a Security Account Manager (SAM) account name or a LDAP DN. AdsSecurity.dll is available as part of ADSI Software Development Kit by Microsoft. ****************************************************************************************** procedure Tfm_main.Button1Click(Sender: TObject); var SQL,DOMAIN,USER,DN,DOM_ID,SPACE:string; t:_recordset; n,x:byte; obj:iadsuser; grp:array of olevariant ; SID:IADsSID; pgrp:IADS; list:Tstringlist; begin DOMAIN:='''LDAP://dc=yourdomain,dc=domainextension'''; listbox2.Clear; try //************************************************************************** // some information of the current logged in user //*************************************************************************** USER:=''''+username+''''; // current user SQL:='select displayname,createtimestamp,distinguishedname from '+DOMAIN+' where objectclass='+'''user'''+' and cn='+USER; cmd.CommandText:=SQL; t:=cmd.Execute; // normally the resultset is filled in order of the query // arguments and starts with 0 the filling of the resultset by // the DomainController starts with the last search argument of // the SQL Select order in this example the argument displayname // is not resultset[0] but resultset[2] listbox2.Items.Add('Account: '+USER); listbox2.Items.Add(' -Created at: '+datetostr(t.Fields[1].value)+' '+timetostr(t.Fields[1].value)); listbox2.Items.Add(' -Displayname: '+t.Fields[2].value); DN:=t.Fields[0].value; listbox2.Items.Add(' -Distinguishedname: '+DN); //************************************************************************** // get primary group membership // (not confuse to PrimayGroupToken attribute!) //*************************************************************************** obj:=MKGetObject('LDAP://'+DN) as IAdsuser; SID:=coADsSID.create; SID.SetAs(ADS_SID_ACTIVE_DIRECTORY_PATH, 'LDAP://'+DN); DOM_ID:=SID.GetAs(ADS_SID_SDDL); // get domain RID + user RID x:=0; for n:=length(DOM_ID) downto 0 do if copy(DOM_ID,n,1) '-' then inc(x) else break; DOM_ID:=copy(DOM_ID,1,length(DOM_ID)-x); //only domain RID is needed DOM_ID:=DOM_ID+inttostr(obj.Get('primarygroupid')); SID.SetAs(ADS_SID_SDDL ,DOM_ID); pgrp:=MKGetObject('LDAP://') as IADS; listbox2.Items.Add(''); listbox2.Items.Add(' -Primary Group Membership:'+pgrp.Get('cn')); //****************************************************************** // get security group memberships //******************************************************************** setlength(grp,1); grp[0]:='TokenGroups'; //the TokenGroups attribute is by default not in the local cache obj.GetInfoEx(grp,0); // first load grp[0] into local cache grp:=obj.get(grp[0]); // get binary code of all groups list:=tstringlist.Create; // only for alphabetic reading list.Sorted:=true; SPACE:=' '; for n:=0 to high(grp) do begin // convert binary code and bind it to group object try SID.SetAs(ADS_SID_RAW,grp[n]); DOM_ID:=SID.GetAs(ADS_SID_SDDL); SID.SetAs(ADS_SID_SDDL ,DOM_ID); DOM_ID:=SID.GetAs(ADS_SID_HEXSTRING); pgrp:=MKGetObject('LDAP://') as IADS; list.add(pgrp.Get('cn')); except on exception do // maybe group is always deleted list.add(' ID='+SID.GetAs(ADS_SID_SDDL)+' is missing !!'); end; end; listbox2.Items.Add(''); listbox2.Items.Add(' -Member of '+inttostr(list.Count)+' Groups,lines without -(Member)- are nested groups'); for n:=0 to list.Count - 1 do listbox2.Items.Add(SPACE+list.Strings[n]); grp:=obj.get('memberof'); for n:=0 to high(grp) do begin dn:=SPACE+copy(grp[n],4,pos(',',grp[n])-4); if listbox2.items.IndexOf(dn) -1 then listbox2.Items.Strings[listbox2.Items.IndexOf(dn)]:=dn+SPACE+SPACE+SPACE+'(Member)'; end; adoconnection1.Connected:=false; list.Free; except on exception do showmessage('Error'); end; end; function Tfm_main.username:string; var userName: array[1..100] of Char ; arrSize: DWord; begin arrSize := SizeOf(UserName); GetUserName(@UserName, arrSize); result:=copy(username,1,arrsize-1); end; function Tfm_main.mkGetObject(const Name : String): IDispatch; var Moniker : IMoniker; Eaten : Integer; BindContext : IBindCtx; Dispatch : IDispatch; begin OleCheck(CreateBindCtx(0, BindContext)); OleCheck(MkParseDisplayName(BindContext, PWideChar(WideString(Name)), Eaten, Moniker)); OleCheck(Moniker.BindToObject(BindContext, NIL, IDispatch, Dispatch)); Result := Dispatch; end; end.