LDAP_MATCHING_RULE_IN_CHAIN not working with default AD groups - Domain Users
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
In my program, I need to fetch all the AD groups for a user.
The current version of my program uses System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups.
This works good until we had a new customer with a much largeer AD. There it is really slow. (Up to 60 seconds)
Now I've been looking around, and saw the posts that the AccountManagement is easy to use, but slow.
I also found that LDAP_MATCHING_RULE_IN_CHAIN should also fetch all the nested groups that a user is member of. And is more performant.
From this link.
But I'm having an issue with the default groups that in AD exists.
For example the group "Domain Users" is not returned by the function.
They also have a group "BDOC" that as member have "Domain Users". That group is also not returned.
Trough the GetAuthorizationGroups it is returned correct.
I'm using following code to fetch the groups by user.
VB.NET:
Dim strFilter As String = String.Format("(member:1.2.840.113556.1.4.1941:={0})", oUserPrincipal.DistinguishedName)
Dim objSearcher As New DirectoryServices.DirectorySearcher("LDAP://" & oLDAPAuthenticationDetail.Domain & If(Not String.IsNullOrWhiteSpace(oLDAPAuthenticationDetail.Container), oLDAPAuthenticationDetail.Container, String.Empty))
objSearcher.PageSize = 1000
objSearcher.Filter = strFilter
objSearcher.SearchScope = DirectoryServices.SearchScope.Subtree
objSearcher.PropertiesToLoad.Add(sPropGuid)
objSearcher.PropertiesToLoad.Add(sPropDisplayName)
Dim colResults As DirectoryServices.SearchResultCollection = objSearcher.FindAll()
Afterwards I was testing with the script from the link, if it was possible to fetch all the users from the Domain Users group, by changing the "member" to "memberOf" in the filter.
When I put the Domain Admins group in the filter, it shows the admins correct.
When I put the Domain Users group in the filter, it returns nothing.
Powershell:
$userdn = 'CN=Domain Users,CN=Users,DC=acbenelux,DC=local'
$strFilter = "(memberOf:1.2.840.113556.1.4.1941:=$userdn)"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://rootDSE")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://$($objDomain.rootDomainNamingContext)"
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Base"
$colProplist = "name"
foreach ($i in $colPropList)
{
$objSearcher.PropertiesToLoad.Add($i) > $nul
}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
$objItem = $objResult.Properties
$objItem.name
}
I don't know what I'm doing wrong. Or is it maybe just not possible to fetch the "default groups" with that filter?
What is a good alternative then?
vb.net powershell active-directory ldap
add a comment |
In my program, I need to fetch all the AD groups for a user.
The current version of my program uses System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups.
This works good until we had a new customer with a much largeer AD. There it is really slow. (Up to 60 seconds)
Now I've been looking around, and saw the posts that the AccountManagement is easy to use, but slow.
I also found that LDAP_MATCHING_RULE_IN_CHAIN should also fetch all the nested groups that a user is member of. And is more performant.
From this link.
But I'm having an issue with the default groups that in AD exists.
For example the group "Domain Users" is not returned by the function.
They also have a group "BDOC" that as member have "Domain Users". That group is also not returned.
Trough the GetAuthorizationGroups it is returned correct.
I'm using following code to fetch the groups by user.
VB.NET:
Dim strFilter As String = String.Format("(member:1.2.840.113556.1.4.1941:={0})", oUserPrincipal.DistinguishedName)
Dim objSearcher As New DirectoryServices.DirectorySearcher("LDAP://" & oLDAPAuthenticationDetail.Domain & If(Not String.IsNullOrWhiteSpace(oLDAPAuthenticationDetail.Container), oLDAPAuthenticationDetail.Container, String.Empty))
objSearcher.PageSize = 1000
objSearcher.Filter = strFilter
objSearcher.SearchScope = DirectoryServices.SearchScope.Subtree
objSearcher.PropertiesToLoad.Add(sPropGuid)
objSearcher.PropertiesToLoad.Add(sPropDisplayName)
Dim colResults As DirectoryServices.SearchResultCollection = objSearcher.FindAll()
Afterwards I was testing with the script from the link, if it was possible to fetch all the users from the Domain Users group, by changing the "member" to "memberOf" in the filter.
When I put the Domain Admins group in the filter, it shows the admins correct.
When I put the Domain Users group in the filter, it returns nothing.
Powershell:
$userdn = 'CN=Domain Users,CN=Users,DC=acbenelux,DC=local'
$strFilter = "(memberOf:1.2.840.113556.1.4.1941:=$userdn)"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://rootDSE")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://$($objDomain.rootDomainNamingContext)"
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Base"
$colProplist = "name"
foreach ($i in $colPropList)
{
$objSearcher.PropertiesToLoad.Add($i) > $nul
}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
$objItem = $objResult.Properties
$objItem.name
}
I don't know what I'm doing wrong. Or is it maybe just not possible to fetch the "default groups" with that filter?
What is a good alternative then?
vb.net powershell active-directory ldap
add a comment |
In my program, I need to fetch all the AD groups for a user.
The current version of my program uses System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups.
This works good until we had a new customer with a much largeer AD. There it is really slow. (Up to 60 seconds)
Now I've been looking around, and saw the posts that the AccountManagement is easy to use, but slow.
I also found that LDAP_MATCHING_RULE_IN_CHAIN should also fetch all the nested groups that a user is member of. And is more performant.
From this link.
But I'm having an issue with the default groups that in AD exists.
For example the group "Domain Users" is not returned by the function.
They also have a group "BDOC" that as member have "Domain Users". That group is also not returned.
Trough the GetAuthorizationGroups it is returned correct.
I'm using following code to fetch the groups by user.
VB.NET:
Dim strFilter As String = String.Format("(member:1.2.840.113556.1.4.1941:={0})", oUserPrincipal.DistinguishedName)
Dim objSearcher As New DirectoryServices.DirectorySearcher("LDAP://" & oLDAPAuthenticationDetail.Domain & If(Not String.IsNullOrWhiteSpace(oLDAPAuthenticationDetail.Container), oLDAPAuthenticationDetail.Container, String.Empty))
objSearcher.PageSize = 1000
objSearcher.Filter = strFilter
objSearcher.SearchScope = DirectoryServices.SearchScope.Subtree
objSearcher.PropertiesToLoad.Add(sPropGuid)
objSearcher.PropertiesToLoad.Add(sPropDisplayName)
Dim colResults As DirectoryServices.SearchResultCollection = objSearcher.FindAll()
Afterwards I was testing with the script from the link, if it was possible to fetch all the users from the Domain Users group, by changing the "member" to "memberOf" in the filter.
When I put the Domain Admins group in the filter, it shows the admins correct.
When I put the Domain Users group in the filter, it returns nothing.
Powershell:
$userdn = 'CN=Domain Users,CN=Users,DC=acbenelux,DC=local'
$strFilter = "(memberOf:1.2.840.113556.1.4.1941:=$userdn)"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://rootDSE")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://$($objDomain.rootDomainNamingContext)"
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Base"
$colProplist = "name"
foreach ($i in $colPropList)
{
$objSearcher.PropertiesToLoad.Add($i) > $nul
}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
$objItem = $objResult.Properties
$objItem.name
}
I don't know what I'm doing wrong. Or is it maybe just not possible to fetch the "default groups" with that filter?
What is a good alternative then?
vb.net powershell active-directory ldap
In my program, I need to fetch all the AD groups for a user.
The current version of my program uses System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups.
This works good until we had a new customer with a much largeer AD. There it is really slow. (Up to 60 seconds)
Now I've been looking around, and saw the posts that the AccountManagement is easy to use, but slow.
I also found that LDAP_MATCHING_RULE_IN_CHAIN should also fetch all the nested groups that a user is member of. And is more performant.
From this link.
But I'm having an issue with the default groups that in AD exists.
For example the group "Domain Users" is not returned by the function.
They also have a group "BDOC" that as member have "Domain Users". That group is also not returned.
Trough the GetAuthorizationGroups it is returned correct.
I'm using following code to fetch the groups by user.
VB.NET:
Dim strFilter As String = String.Format("(member:1.2.840.113556.1.4.1941:={0})", oUserPrincipal.DistinguishedName)
Dim objSearcher As New DirectoryServices.DirectorySearcher("LDAP://" & oLDAPAuthenticationDetail.Domain & If(Not String.IsNullOrWhiteSpace(oLDAPAuthenticationDetail.Container), oLDAPAuthenticationDetail.Container, String.Empty))
objSearcher.PageSize = 1000
objSearcher.Filter = strFilter
objSearcher.SearchScope = DirectoryServices.SearchScope.Subtree
objSearcher.PropertiesToLoad.Add(sPropGuid)
objSearcher.PropertiesToLoad.Add(sPropDisplayName)
Dim colResults As DirectoryServices.SearchResultCollection = objSearcher.FindAll()
Afterwards I was testing with the script from the link, if it was possible to fetch all the users from the Domain Users group, by changing the "member" to "memberOf" in the filter.
When I put the Domain Admins group in the filter, it shows the admins correct.
When I put the Domain Users group in the filter, it returns nothing.
Powershell:
$userdn = 'CN=Domain Users,CN=Users,DC=acbenelux,DC=local'
$strFilter = "(memberOf:1.2.840.113556.1.4.1941:=$userdn)"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://rootDSE")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://$($objDomain.rootDomainNamingContext)"
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Base"
$colProplist = "name"
foreach ($i in $colPropList)
{
$objSearcher.PropertiesToLoad.Add($i) > $nul
}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
$objItem = $objResult.Properties
$objItem.name
}
I don't know what I'm doing wrong. Or is it maybe just not possible to fetch the "default groups" with that filter?
What is a good alternative then?
vb.net powershell active-directory ldap
vb.net powershell active-directory ldap
asked Nov 23 '18 at 18:52
StinusStinus
761213
761213
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
The default group is odd. It is not stored in memberOf
, or even in the member
attribute of the group. That's why your search won't find it. The default group is determined by the primaryGroupId
of the user. That attribute stores the RID (the last part of the SID) of the group. It's kind of dumb, I know :)
I actually wrote an article about the 3 (yes 3) different ways someone can be a member of a group: What makes a member a member?
I also wrote an article about getting all of the groups a single user belongs to, and how to account for all 3 ways: Finding all of a user’s groups
For example, here is the C# code I put in that article about how to find the name of the primary group for a user (given a DirectoryEntry
). It shouldn't be too hard to translate that to VB.NET:
private static string GetUserPrimaryGroup(DirectoryEntry de) {
de.RefreshCache(new {"primaryGroupID", "objectSid"});
//Get the user's SID as a string
var sid = new SecurityIdentifier((byte)de.Properties["objectSid"].Value, 0).ToString();
//Replace the RID portion of the user's SID with the primaryGroupId
//so we're left with the group's SID
sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
sid = sid + de.Properties["primaryGroupId"].Value;
//Find the group by its SID
var group = new DirectoryEntry($"LDAP://<SID={sid}>");
group.RefreshCache(new {"cn"});
return group.Properties["cn"].Value as string;
}
You are right that the AccountManagement
namespace makes things easy, but it really does have terrible performance sometimes. I never use it anymore. I find that DirectoryEntry
/DirectorySearcher
gives you much more control of how often your code makes calls out to AD.
I have been meaning to write an article about writing high performance code with DirectoryEntry
, but I haven't gotten around to it yet.
Update: So if you need the nested groups for the user, including membership through the primary group, then you can find the primary group first, then do an LDAP_MATCHING_RULE_IN_CHAIN search for groups that have both the user and the primary group as members:
(|(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}))
Update: If you want to include Authenticated Users
in your search (edit the DC
portion of the distinguishedName
):
(|(member:1.2.840.113556.1.4.1941:=CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=domain,DC=com)(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN})
Note that you can also use the tokenGroups
attribute of a user to find out all of the authentication groups for a user. The tokenGroups
attribute is a constructed attribute, so you only get it if you specifically ask for it (with DirectoryEntry.RefreshCache()
or, in a search, add it to DirectorySearcher.PropertiesToLoad
.
The caveat is that tokenGroups
is a list of SIDs, not distinguishedName
, but you can bind directly to an object using the SID with the LDAP://<SID={sid}>
syntax.
Thanks for the great post. I've tested the functions, and in my company we only have 1 domain. So I can't test the trusted domains part. But I still have an issue with "A nested group who has the primary group as member". From the example I can find what the primary group is for a user. But take following example: user sgielen has as primairy group Domain Users. Domain Users is member of Group A, and Group A is member of Group B. How to get Domain Users+Group A+Group B?
– Stinus
Nov 24 '18 at 13:07
There is no way to do that in one search. But after you find the primary group, you can use that in your search. I updated my answer with an example.
– Gabriel Luci
Nov 24 '18 at 17:57
Thanks, that was exactly what I needed. In my company AD (30,32 sec -> 1,02 sec) But I have 1 wierd thing in my company's AD. From the GetAuthorizationGroups I get that my User is in the following groups. But my user is not in them. CN=Administrators,CN=Builtin,DC=acbenelux,DC=local CN=Users,CN=Builtin,DC=acbenelux,DC=local Any idea how that would happen?
– Stinus
Nov 26 '18 at 6:46
TheUsers
group likely hasAuthenticated Users
in it, which is one of the "well-known SIDs" that have special meaning. I can't say why theAdminstrators
group is showing up, but check it in AD and see what its members are. It's possible there is a similar thing going on there.
– Gabriel Luci
Nov 26 '18 at 13:28
I made an update to my answer with some more information.
– Gabriel Luci
Nov 26 '18 at 13:38
|
show 4 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53451706%2fldap-matching-rule-in-chain-not-working-with-default-ad-groups-domain-users%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The default group is odd. It is not stored in memberOf
, or even in the member
attribute of the group. That's why your search won't find it. The default group is determined by the primaryGroupId
of the user. That attribute stores the RID (the last part of the SID) of the group. It's kind of dumb, I know :)
I actually wrote an article about the 3 (yes 3) different ways someone can be a member of a group: What makes a member a member?
I also wrote an article about getting all of the groups a single user belongs to, and how to account for all 3 ways: Finding all of a user’s groups
For example, here is the C# code I put in that article about how to find the name of the primary group for a user (given a DirectoryEntry
). It shouldn't be too hard to translate that to VB.NET:
private static string GetUserPrimaryGroup(DirectoryEntry de) {
de.RefreshCache(new {"primaryGroupID", "objectSid"});
//Get the user's SID as a string
var sid = new SecurityIdentifier((byte)de.Properties["objectSid"].Value, 0).ToString();
//Replace the RID portion of the user's SID with the primaryGroupId
//so we're left with the group's SID
sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
sid = sid + de.Properties["primaryGroupId"].Value;
//Find the group by its SID
var group = new DirectoryEntry($"LDAP://<SID={sid}>");
group.RefreshCache(new {"cn"});
return group.Properties["cn"].Value as string;
}
You are right that the AccountManagement
namespace makes things easy, but it really does have terrible performance sometimes. I never use it anymore. I find that DirectoryEntry
/DirectorySearcher
gives you much more control of how often your code makes calls out to AD.
I have been meaning to write an article about writing high performance code with DirectoryEntry
, but I haven't gotten around to it yet.
Update: So if you need the nested groups for the user, including membership through the primary group, then you can find the primary group first, then do an LDAP_MATCHING_RULE_IN_CHAIN search for groups that have both the user and the primary group as members:
(|(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}))
Update: If you want to include Authenticated Users
in your search (edit the DC
portion of the distinguishedName
):
(|(member:1.2.840.113556.1.4.1941:=CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=domain,DC=com)(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN})
Note that you can also use the tokenGroups
attribute of a user to find out all of the authentication groups for a user. The tokenGroups
attribute is a constructed attribute, so you only get it if you specifically ask for it (with DirectoryEntry.RefreshCache()
or, in a search, add it to DirectorySearcher.PropertiesToLoad
.
The caveat is that tokenGroups
is a list of SIDs, not distinguishedName
, but you can bind directly to an object using the SID with the LDAP://<SID={sid}>
syntax.
Thanks for the great post. I've tested the functions, and in my company we only have 1 domain. So I can't test the trusted domains part. But I still have an issue with "A nested group who has the primary group as member". From the example I can find what the primary group is for a user. But take following example: user sgielen has as primairy group Domain Users. Domain Users is member of Group A, and Group A is member of Group B. How to get Domain Users+Group A+Group B?
– Stinus
Nov 24 '18 at 13:07
There is no way to do that in one search. But after you find the primary group, you can use that in your search. I updated my answer with an example.
– Gabriel Luci
Nov 24 '18 at 17:57
Thanks, that was exactly what I needed. In my company AD (30,32 sec -> 1,02 sec) But I have 1 wierd thing in my company's AD. From the GetAuthorizationGroups I get that my User is in the following groups. But my user is not in them. CN=Administrators,CN=Builtin,DC=acbenelux,DC=local CN=Users,CN=Builtin,DC=acbenelux,DC=local Any idea how that would happen?
– Stinus
Nov 26 '18 at 6:46
TheUsers
group likely hasAuthenticated Users
in it, which is one of the "well-known SIDs" that have special meaning. I can't say why theAdminstrators
group is showing up, but check it in AD and see what its members are. It's possible there is a similar thing going on there.
– Gabriel Luci
Nov 26 '18 at 13:28
I made an update to my answer with some more information.
– Gabriel Luci
Nov 26 '18 at 13:38
|
show 4 more comments
The default group is odd. It is not stored in memberOf
, or even in the member
attribute of the group. That's why your search won't find it. The default group is determined by the primaryGroupId
of the user. That attribute stores the RID (the last part of the SID) of the group. It's kind of dumb, I know :)
I actually wrote an article about the 3 (yes 3) different ways someone can be a member of a group: What makes a member a member?
I also wrote an article about getting all of the groups a single user belongs to, and how to account for all 3 ways: Finding all of a user’s groups
For example, here is the C# code I put in that article about how to find the name of the primary group for a user (given a DirectoryEntry
). It shouldn't be too hard to translate that to VB.NET:
private static string GetUserPrimaryGroup(DirectoryEntry de) {
de.RefreshCache(new {"primaryGroupID", "objectSid"});
//Get the user's SID as a string
var sid = new SecurityIdentifier((byte)de.Properties["objectSid"].Value, 0).ToString();
//Replace the RID portion of the user's SID with the primaryGroupId
//so we're left with the group's SID
sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
sid = sid + de.Properties["primaryGroupId"].Value;
//Find the group by its SID
var group = new DirectoryEntry($"LDAP://<SID={sid}>");
group.RefreshCache(new {"cn"});
return group.Properties["cn"].Value as string;
}
You are right that the AccountManagement
namespace makes things easy, but it really does have terrible performance sometimes. I never use it anymore. I find that DirectoryEntry
/DirectorySearcher
gives you much more control of how often your code makes calls out to AD.
I have been meaning to write an article about writing high performance code with DirectoryEntry
, but I haven't gotten around to it yet.
Update: So if you need the nested groups for the user, including membership through the primary group, then you can find the primary group first, then do an LDAP_MATCHING_RULE_IN_CHAIN search for groups that have both the user and the primary group as members:
(|(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}))
Update: If you want to include Authenticated Users
in your search (edit the DC
portion of the distinguishedName
):
(|(member:1.2.840.113556.1.4.1941:=CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=domain,DC=com)(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN})
Note that you can also use the tokenGroups
attribute of a user to find out all of the authentication groups for a user. The tokenGroups
attribute is a constructed attribute, so you only get it if you specifically ask for it (with DirectoryEntry.RefreshCache()
or, in a search, add it to DirectorySearcher.PropertiesToLoad
.
The caveat is that tokenGroups
is a list of SIDs, not distinguishedName
, but you can bind directly to an object using the SID with the LDAP://<SID={sid}>
syntax.
Thanks for the great post. I've tested the functions, and in my company we only have 1 domain. So I can't test the trusted domains part. But I still have an issue with "A nested group who has the primary group as member". From the example I can find what the primary group is for a user. But take following example: user sgielen has as primairy group Domain Users. Domain Users is member of Group A, and Group A is member of Group B. How to get Domain Users+Group A+Group B?
– Stinus
Nov 24 '18 at 13:07
There is no way to do that in one search. But after you find the primary group, you can use that in your search. I updated my answer with an example.
– Gabriel Luci
Nov 24 '18 at 17:57
Thanks, that was exactly what I needed. In my company AD (30,32 sec -> 1,02 sec) But I have 1 wierd thing in my company's AD. From the GetAuthorizationGroups I get that my User is in the following groups. But my user is not in them. CN=Administrators,CN=Builtin,DC=acbenelux,DC=local CN=Users,CN=Builtin,DC=acbenelux,DC=local Any idea how that would happen?
– Stinus
Nov 26 '18 at 6:46
TheUsers
group likely hasAuthenticated Users
in it, which is one of the "well-known SIDs" that have special meaning. I can't say why theAdminstrators
group is showing up, but check it in AD and see what its members are. It's possible there is a similar thing going on there.
– Gabriel Luci
Nov 26 '18 at 13:28
I made an update to my answer with some more information.
– Gabriel Luci
Nov 26 '18 at 13:38
|
show 4 more comments
The default group is odd. It is not stored in memberOf
, or even in the member
attribute of the group. That's why your search won't find it. The default group is determined by the primaryGroupId
of the user. That attribute stores the RID (the last part of the SID) of the group. It's kind of dumb, I know :)
I actually wrote an article about the 3 (yes 3) different ways someone can be a member of a group: What makes a member a member?
I also wrote an article about getting all of the groups a single user belongs to, and how to account for all 3 ways: Finding all of a user’s groups
For example, here is the C# code I put in that article about how to find the name of the primary group for a user (given a DirectoryEntry
). It shouldn't be too hard to translate that to VB.NET:
private static string GetUserPrimaryGroup(DirectoryEntry de) {
de.RefreshCache(new {"primaryGroupID", "objectSid"});
//Get the user's SID as a string
var sid = new SecurityIdentifier((byte)de.Properties["objectSid"].Value, 0).ToString();
//Replace the RID portion of the user's SID with the primaryGroupId
//so we're left with the group's SID
sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
sid = sid + de.Properties["primaryGroupId"].Value;
//Find the group by its SID
var group = new DirectoryEntry($"LDAP://<SID={sid}>");
group.RefreshCache(new {"cn"});
return group.Properties["cn"].Value as string;
}
You are right that the AccountManagement
namespace makes things easy, but it really does have terrible performance sometimes. I never use it anymore. I find that DirectoryEntry
/DirectorySearcher
gives you much more control of how often your code makes calls out to AD.
I have been meaning to write an article about writing high performance code with DirectoryEntry
, but I haven't gotten around to it yet.
Update: So if you need the nested groups for the user, including membership through the primary group, then you can find the primary group first, then do an LDAP_MATCHING_RULE_IN_CHAIN search for groups that have both the user and the primary group as members:
(|(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}))
Update: If you want to include Authenticated Users
in your search (edit the DC
portion of the distinguishedName
):
(|(member:1.2.840.113556.1.4.1941:=CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=domain,DC=com)(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN})
Note that you can also use the tokenGroups
attribute of a user to find out all of the authentication groups for a user. The tokenGroups
attribute is a constructed attribute, so you only get it if you specifically ask for it (with DirectoryEntry.RefreshCache()
or, in a search, add it to DirectorySearcher.PropertiesToLoad
.
The caveat is that tokenGroups
is a list of SIDs, not distinguishedName
, but you can bind directly to an object using the SID with the LDAP://<SID={sid}>
syntax.
The default group is odd. It is not stored in memberOf
, or even in the member
attribute of the group. That's why your search won't find it. The default group is determined by the primaryGroupId
of the user. That attribute stores the RID (the last part of the SID) of the group. It's kind of dumb, I know :)
I actually wrote an article about the 3 (yes 3) different ways someone can be a member of a group: What makes a member a member?
I also wrote an article about getting all of the groups a single user belongs to, and how to account for all 3 ways: Finding all of a user’s groups
For example, here is the C# code I put in that article about how to find the name of the primary group for a user (given a DirectoryEntry
). It shouldn't be too hard to translate that to VB.NET:
private static string GetUserPrimaryGroup(DirectoryEntry de) {
de.RefreshCache(new {"primaryGroupID", "objectSid"});
//Get the user's SID as a string
var sid = new SecurityIdentifier((byte)de.Properties["objectSid"].Value, 0).ToString();
//Replace the RID portion of the user's SID with the primaryGroupId
//so we're left with the group's SID
sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
sid = sid + de.Properties["primaryGroupId"].Value;
//Find the group by its SID
var group = new DirectoryEntry($"LDAP://<SID={sid}>");
group.RefreshCache(new {"cn"});
return group.Properties["cn"].Value as string;
}
You are right that the AccountManagement
namespace makes things easy, but it really does have terrible performance sometimes. I never use it anymore. I find that DirectoryEntry
/DirectorySearcher
gives you much more control of how often your code makes calls out to AD.
I have been meaning to write an article about writing high performance code with DirectoryEntry
, but I haven't gotten around to it yet.
Update: So if you need the nested groups for the user, including membership through the primary group, then you can find the primary group first, then do an LDAP_MATCHING_RULE_IN_CHAIN search for groups that have both the user and the primary group as members:
(|(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}))
Update: If you want to include Authenticated Users
in your search (edit the DC
portion of the distinguishedName
):
(|(member:1.2.840.113556.1.4.1941:=CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=domain,DC=com)(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN})
Note that you can also use the tokenGroups
attribute of a user to find out all of the authentication groups for a user. The tokenGroups
attribute is a constructed attribute, so you only get it if you specifically ask for it (with DirectoryEntry.RefreshCache()
or, in a search, add it to DirectorySearcher.PropertiesToLoad
.
The caveat is that tokenGroups
is a list of SIDs, not distinguishedName
, but you can bind directly to an object using the SID with the LDAP://<SID={sid}>
syntax.
edited Nov 26 '18 at 13:37
answered Nov 24 '18 at 0:02
Gabriel LuciGabriel Luci
11.6k11525
11.6k11525
Thanks for the great post. I've tested the functions, and in my company we only have 1 domain. So I can't test the trusted domains part. But I still have an issue with "A nested group who has the primary group as member". From the example I can find what the primary group is for a user. But take following example: user sgielen has as primairy group Domain Users. Domain Users is member of Group A, and Group A is member of Group B. How to get Domain Users+Group A+Group B?
– Stinus
Nov 24 '18 at 13:07
There is no way to do that in one search. But after you find the primary group, you can use that in your search. I updated my answer with an example.
– Gabriel Luci
Nov 24 '18 at 17:57
Thanks, that was exactly what I needed. In my company AD (30,32 sec -> 1,02 sec) But I have 1 wierd thing in my company's AD. From the GetAuthorizationGroups I get that my User is in the following groups. But my user is not in them. CN=Administrators,CN=Builtin,DC=acbenelux,DC=local CN=Users,CN=Builtin,DC=acbenelux,DC=local Any idea how that would happen?
– Stinus
Nov 26 '18 at 6:46
TheUsers
group likely hasAuthenticated Users
in it, which is one of the "well-known SIDs" that have special meaning. I can't say why theAdminstrators
group is showing up, but check it in AD and see what its members are. It's possible there is a similar thing going on there.
– Gabriel Luci
Nov 26 '18 at 13:28
I made an update to my answer with some more information.
– Gabriel Luci
Nov 26 '18 at 13:38
|
show 4 more comments
Thanks for the great post. I've tested the functions, and in my company we only have 1 domain. So I can't test the trusted domains part. But I still have an issue with "A nested group who has the primary group as member". From the example I can find what the primary group is for a user. But take following example: user sgielen has as primairy group Domain Users. Domain Users is member of Group A, and Group A is member of Group B. How to get Domain Users+Group A+Group B?
– Stinus
Nov 24 '18 at 13:07
There is no way to do that in one search. But after you find the primary group, you can use that in your search. I updated my answer with an example.
– Gabriel Luci
Nov 24 '18 at 17:57
Thanks, that was exactly what I needed. In my company AD (30,32 sec -> 1,02 sec) But I have 1 wierd thing in my company's AD. From the GetAuthorizationGroups I get that my User is in the following groups. But my user is not in them. CN=Administrators,CN=Builtin,DC=acbenelux,DC=local CN=Users,CN=Builtin,DC=acbenelux,DC=local Any idea how that would happen?
– Stinus
Nov 26 '18 at 6:46
TheUsers
group likely hasAuthenticated Users
in it, which is one of the "well-known SIDs" that have special meaning. I can't say why theAdminstrators
group is showing up, but check it in AD and see what its members are. It's possible there is a similar thing going on there.
– Gabriel Luci
Nov 26 '18 at 13:28
I made an update to my answer with some more information.
– Gabriel Luci
Nov 26 '18 at 13:38
Thanks for the great post. I've tested the functions, and in my company we only have 1 domain. So I can't test the trusted domains part. But I still have an issue with "A nested group who has the primary group as member". From the example I can find what the primary group is for a user. But take following example: user sgielen has as primairy group Domain Users. Domain Users is member of Group A, and Group A is member of Group B. How to get Domain Users+Group A+Group B?
– Stinus
Nov 24 '18 at 13:07
Thanks for the great post. I've tested the functions, and in my company we only have 1 domain. So I can't test the trusted domains part. But I still have an issue with "A nested group who has the primary group as member". From the example I can find what the primary group is for a user. But take following example: user sgielen has as primairy group Domain Users. Domain Users is member of Group A, and Group A is member of Group B. How to get Domain Users+Group A+Group B?
– Stinus
Nov 24 '18 at 13:07
There is no way to do that in one search. But after you find the primary group, you can use that in your search. I updated my answer with an example.
– Gabriel Luci
Nov 24 '18 at 17:57
There is no way to do that in one search. But after you find the primary group, you can use that in your search. I updated my answer with an example.
– Gabriel Luci
Nov 24 '18 at 17:57
Thanks, that was exactly what I needed. In my company AD (30,32 sec -> 1,02 sec) But I have 1 wierd thing in my company's AD. From the GetAuthorizationGroups I get that my User is in the following groups. But my user is not in them. CN=Administrators,CN=Builtin,DC=acbenelux,DC=local CN=Users,CN=Builtin,DC=acbenelux,DC=local Any idea how that would happen?
– Stinus
Nov 26 '18 at 6:46
Thanks, that was exactly what I needed. In my company AD (30,32 sec -> 1,02 sec) But I have 1 wierd thing in my company's AD. From the GetAuthorizationGroups I get that my User is in the following groups. But my user is not in them. CN=Administrators,CN=Builtin,DC=acbenelux,DC=local CN=Users,CN=Builtin,DC=acbenelux,DC=local Any idea how that would happen?
– Stinus
Nov 26 '18 at 6:46
The
Users
group likely has Authenticated Users
in it, which is one of the "well-known SIDs" that have special meaning. I can't say why the Adminstrators
group is showing up, but check it in AD and see what its members are. It's possible there is a similar thing going on there.– Gabriel Luci
Nov 26 '18 at 13:28
The
Users
group likely has Authenticated Users
in it, which is one of the "well-known SIDs" that have special meaning. I can't say why the Adminstrators
group is showing up, but check it in AD and see what its members are. It's possible there is a similar thing going on there.– Gabriel Luci
Nov 26 '18 at 13:28
I made an update to my answer with some more information.
– Gabriel Luci
Nov 26 '18 at 13:38
I made an update to my answer with some more information.
– Gabriel Luci
Nov 26 '18 at 13:38
|
show 4 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53451706%2fldap-matching-rule-in-chain-not-working-with-default-ad-groups-domain-users%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown