ldap nested group membership - active-directory

My user is "SPR" and it is located under dc=aaaldap,dc=com
Now the filter i am trying to send is (IDEA: TO extract all groups to which user SPR belongs to)
Filter:
(&(objectclass=*)(memberof:1.2.840.113556.1.4.1941:=cn=SPR,dc=aaaldap,dc=com))
As part of this search result, i am getting response from AD server as ldapsearchresref (which to my understanding is an indication from ldap server that it is not able to find the entry in its server and thus giving a reference to a URL of another server which might help in resolving the entry).
My doubt is why it is not able to find any entry where in i am sure entry do exists?
Also, secondly i read somewhere that LDAP search filter doesn't work with commas. Can someone help me with this?

To fond all Groups a User is a member of including Nested groupsYou need to search the groups for the member attribute:
(member:1.2.840.113556.1.4.1941:=(cn=SPR,dc=aaaldap,dc=com))
-jim

If you need to find all the groups of that user belongs to you can user PrincipalContext.
Let me show you how
PrincipalContext pr = new PrincipalContext(ContextType.Domain, "aaaldap.com", "dc=aaaldap,dc=com", username, password);
List<string> lst = new List<string>();
UserPrincipal user = UserPrincipal.FindByIdentity(pr, DomainId);
if (user != null)
{
PrincipalSearchResult<Principal> results = user.GetGroups();
foreach (Principal p in results)
{
lst.Add(p.ToString());
}
lst.OrderBy(item => item.ToString());
}
pr.Dispose();
return lst;
I guess that is what you were looking for.
Cheers

When using LDAP and querying you can sometimes get a referring URL which means the account is known, but in a different domain. This happens when I query our global catalog, so I don't anymore. :)
This works on our domain here. Note I have commas in my filter.
private static void showMemberships()
{
// instantiate the DirectoryEntry instance with the FQDN of the domain to connect to
DirectoryEntry directoryObject = new DirectoryEntry("LDAP://CHILD.DOMAIN.ORG");
// create a DirectorySearcher object and pass the DirectoryEntry instance
DirectorySearcher ds = new DirectorySearcher(directoryObject);
// set search filter using LDAP query format
// this example fetches members for a group limiting to users only (not groups)
// and where the users are not in the stale objects ou
ds.Filter = "(&(objectCategory=User)(!ou=Stale Objects)(memberOf=CN=GROUPNAME,CN=Users,DC=CHILD,DC=DOMAIN,DC=ORG))";
// perform the search using the filter and store in a SearchResultsCollection
SearchResultCollection results = ds.FindAll();
// iterate through the results and do something with the info
foreach (SearchResult current in results)
{
string userId = current.Properties["cn"][0].ToString().Trim().ToUpper();
string userDn = current.Properties["distinguishedName"][0].ToString().Trim().ToUpper();
Console.Write(userId + " (" + userDn + ")\n");
}
// set the resource instances as released
directoryObject.Close();
directoryObject.Dispose();
}

Related

Why does "Microsoft.Graph.User.AdditionalData" property contain manager information?

Within the Microsoft.Graph.User object there is a field called "AdditionalData".
It seems this can hold many values, from telling if a record is a delta record to storing manager information.
In this instance, it holds information on a users manager.
It looks like it can hold multiple records however, so I am asking what is the best way to get data from this property, to ensure I get all values it might have.
I am also unsure why manager information is in the AdditionalData property and not in the Manager property.
Yes you are correct AdditionalData may hold multiple record,You can add additionalData to your user that can hold any information based on your customization.
you can add the multiple value to additionalData using Openxtension
Trick is to add the extensions like this
extension = new OpenTypeExtension
{
ExtensionName = AzureADExtensions.UserConstants.ExtensionName,
AdditionalData = new Dictionary<string, object>
{
{"OtherEmail", externalUser.Email},
{"OtherRole" , externalUser.Roles.FirstOrDefault()}
}
};
await _graphClient.Users[user.Id].Extensions.Request()
.AddAsync(extension);
And then retrieve them like this.
user = await _graphClient
.Users[userId]
.Request()
.GetAsync();
// Note : you should be able to expand this on original request, but fails for me.
var extensions = await _graphClient.Users[user.Id].Extensions.Request().GetAsync();
user.Extensions = extensions;
Reference : Azure AD GraphServiceClient can't set AdditionalData against User
The "Additional Data" property only holds manager info if we do a delta query, if we do a regular query, we have to use extended properties to get the manager.
We are avoiding delta query for the moment in the interests of time but might come back to it at another point.
Thanks all.

Active directory check if user belongs to a group

I am using the below code to pull active directory groups. How can I find out if a user belongs to xyz group or not?
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for a GroupPrincipal
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
You can get the list of groups a user is a member of by querying the memberOf navigation property on the user object.
Read about it here.
https://graph.windows.net/myorganization/users/{user_id}/$links/memberOf?api-version
Note that you can remove the $links part of the query to return the whole group object, rather than the link to the object. However, for simply validating a user is a member of a certain group, you can use the links, and compare the object id of the groups that are returned to the one you are looking for.

Find Group size in active directory

I have the following code. I get a directory entry for a user (strpath).
And then I get the groups where the user is listed.
How can I get the number of users in each group?
DirectoryEntry myDE = new System.DirectoryServices.DirectoryEntry(strpath);
object obGroups = myDE.Invoke("Groups");
foreach (object ob in (IEnumerable)obGroups)
{
DirectoryEntry obGpEntry = new DirectoryEntry(ob);
GroupsListBox.Items.Add(obGpEntry.Name );
}
If you're on .NET 3.5 (or can upgrade to it), there's a massively extended System.DirectoryServices.AccountManagement namespace that makes these jobs of managing user, groups and their memberships a whole lot easier.
Check out the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 for an introduction to S.DS.AM.
You can get a user principal like this:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");
UserPrincipal user = UserPrincipal.FindByIdentity("some user name");
PrincipalSearchResult<Principal> userGroups = user.GetGroups();
foreach (Principal p in myGroups)
{
GroupPrincipal gp = (p as GroupPrincipal);
if (gp != null)
{
int memberCount = gp.Members.Count;
}
}
This way, you can enumerate all groups a given user has, and enumerating those groups, you can find out how many members (users and other groups) each group has.

Get machine name from Active Directory

I have performed an "LDAP://" query to get a list of computers within a specified OU, my issue is not being able to collect just the computer "name" or even "cn".
DirectoryEntry toShutdown = new DirectoryEntry("LDAP://" + comboBox1.Text.ToString());
DirectorySearcher machineSearch = new DirectorySearcher(toShutdown);
//machineSearch.Filter = "(objectCatergory=computer)";
machineSearch.Filter = "(objectClass=computer)";
machineSearch.SearchScope = SearchScope.Subtree;
machineSearch.PropertiesToLoad.Add("name");
SearchResultCollection allMachinesCollected = machineSearch.FindAll();
Methods myMethods = new Methods();
string pcName;
foreach (SearchResult oneMachine in allMachinesCollected)
{
//pcName = oneMachine.Properties.PropertyNames.ToString();
pcName = oneMachine.Properties["name"].ToString();
MessageBox.Show(pcName);
}
Help much appreciated.
If you can upgrade to .NET 3.5, I would definitely recommend doing so.
With .NET 3.5, you get a new System.DirectoryServices.AccountManagement namespace which makes a lot of these takes much easier.
To find all computers and enumerate them, you'd do something like this:
// define a domain context - use your NetBIOS domain name
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");
// set up the principal searcher and give it a "prototype" of what you want to
// search for (Query by Example) - here: a ComputerPrincipal
PrincipalSearcher srch = new PrincipalSearcher();
srch.QueryFilter = new ComputerPrincipal(ctx);;
// do the search
PrincipalSearchResult<Principal> results = srch.FindAll();
// enumerate over results
foreach(ComputerPrincipal cp in results)
{
string computerName = cp.Name;
}
Check out the Managing Directory Security Principals in the .NET Framework 3.5 on MSDN Magazine for more information on the new S.DS.AM namespace and what it offers.
If you can't move up to .NET 3.5 - you just need to keep in mind that the .Properties["name"] that you get from the search result is a collection of values - so in order to grab the actual pc name, use this:
pcName = oneMachine.Properties["name"][0].ToString();
You need to index the .Properties["name"] collection with a [0] to get the first entry (typically also the only entry - hardly any computer has more than one name).

Best way to quickly determine whether a user account is a member of an AD group?

I currently have some code that pulls down a list of users in a group and then iterates through that group to determine if a given account exists, but it seems like there ought to be a more concise (and perhaps faster) way to accomplish this.
This code (VB.NET) attempts to use the member property of the group object, but it is returning false even when the user is a member of that group. Can anyone see what I am doing wrong here?
Dim group As DirectoryEntry = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName)
Dim user As DirectoryEntry =GetNetworkObject(UserDomainName, NetworkObjectType.NetworkUser, Login)
Return group.Properties("member").Contains(user.Path)
FYI: The GetNetworkObject calls just return a directoryEntry object, I have confirmed that the correct object is being returned for both the group and user object.
If you are on .NET 3.5 stack, System.DirectoryServices.AccountManagement.dll assembly has a nice API on top of AD. The following method can be implemented to solve your issue:
static bool IsUserMemberOf(string userName, string groupName)
{
using (var ctx = new PrincipalContext(ContextType.Domain))
using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, groupName))
using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, userName))
{
return userPrincipal.IsMemberOf(groupPrincipal);
}
}
// Usage:
bool result = IsUserMemberOf("CONTOSO\\john.doe", "CONTOSO\\Administrators");
I don't know how this method performs but it is a clean solution.
Here is what I've used in the past in a VBS Script that worked very well:
Set wshNet = CreateObject("WScript.Network") 'Setup connection to the Network
Set fso = CreateObject("Scripting.FileSystemObject") 'Create File System Object for any file manipulations
Set ADSysInfo = CreateObject("ADSystemInfo") 'Setup connection to Active Directory
Set CurrentUser = GetObject("LDAP://" & ADSysInfo.UserName) 'Setup current user to look for in Active Directory
strGroups = LCase(Join(CurrentUser.MemberOf)) 'Grabs all the groups the current user is a member of
I then use an InStr to see if the user is part of that group:
If InStr(strGroups, "MyGroup") Then MyGroupSub
You might be able to adapt the above in your project.
By the way, I noticed that in your code you have groupdoman as your last parameter for 'group' Not sure if you wanted that to be groupdomain or not:
Dim group As DirectoryEntry = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName, groupdoman)
vs
Dim group As DirectoryEntry = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName, groupdomain)
Let me know if this helps! JFV
I found an answer that seems to work in NET 2.0, is relatively quick and overcomes the possible issue of groups containing more than 100 items (which require range searching)
Here is the code that I wound up with:
Dim DSearcher As New DirectorySearcher(group, "(&(objectClass=user)(cn=" + Login + "))", New String() {"member;Range=0-5000"}, SearchScope.OneLevel)
group = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName)
user = GetNetworkObject(UserDomainName, NetworkObjectType.NetworkUser, Login)
DSearcher.AttributeScopeQuery = "member"
Return (DSearcher.FindOne() IsNot Nothing)
Here's another way using the directory searcher and memberOf. This is using the current users objectSID but you could change that to some other identifier.
dSearch.Filter = String.Format("(&(memberOf={0})(objectSid={1}))", groupDN, WindowsIdentity.GetCurrent.User)
Return dSearch.FindOne() IsNot Nothing
if your going to use user input which might contain invalid characters, you should always escape them...
searchName = searchName.Replace("\", "\5c"). _
Replace("/", "\2f"). _
Replace("*", "\2a"). _
Replace("(", "\28"). _
Replace(")", "\29")

Resources