Stuff I've learned along the way
This is the first article in a series about programming with Active Directory.
Some of the most common tasks is determining:
I’ll go into how to handle those tasks in other articles, but it’s important first to understand just how a user comes to be considered a member of a group.
It turns out that there are 3 ways:
member
attributeThis is the most obvious and 99% of the time the only one you will need to care about.
The distinguishedName
of an object is added to the member
attribute of a group. That object (whatever kind it may be) is now a member of that group. Makes sense?
But wait, there’s more.
This one is easy to forget (or never learn), but fortunately it will likely rarely matter to you. Every user object must have a Primary Group, which is indicated by the primaryGroupId
attribute on the user object. That attribute is set to the primaryGroupToken
attribute of a group on the same domain. That makes the user a member of that group.
The
primaryGroupToken
attribute of a group is equivalent to the group’s Relative Identifier (RID), which is the portion of the Security Identifier (SID) that comes after the domain portion of the SID. When reading a SID string, the RID is the numbers after the last hyphen.
In most cases, the primaryGroupId
will be 513
, which is always the RID for the Domain Users
group. However the primaryGroupId
can be changed.
You may or may not care what a user’s primary group is. You probably won’t care unless maybe you’re working in a domain where the primary group is changed as a matter of practice.
If you are working with a domain that trusts other domains outside of the same AD forest, then this one can be very important to you.
A group can have members from external, trusted domains. This is done by updating the member
attribute of the group, but not with the distinguishedName
of the user.
When a user from an external domain is added to a group, a Foreign Security Principal (FSP) object is created. Every domain has a ForeignSecurityPrincipals
container at the root of the domain, and that’s where these are stored.
Fun fact: a “container” is different from an “organizational unit” (OU). One has an
objectClass
ofcontainer
, the other,organizationalUnit
. They function much the same: you can put all the same objects inside. The only difference is that group policies can only be applied to OUs.
That FSP is named after the SID of the user on the external domain. The distinguishedName
of the FSP object is then be added to the member
attribute of the group, which makes the external user a member of that group.
This can only be done with groups with a scope of Domain Local.
memberOf
When checking group membership, you may be tempted to just use the memberOf
attribute of the user. That’s what it’s for, right? It has all the groups the user is a member of…
Well, maybe. Groups only get added to memberOf
if they have a Group Scope of:
Groups do not get added to memberOf
if they have a Group Scope of Global and are on another domain (even if in the same forest).
On top of that, memberOf
will only include Domain Local groups from the same domain of the server you are retrieving results from. (if you are working in a multi-domain environment and reading from a Global Catalog, this may not be the same domain the user is from)
It will also not report the user’s primary group (usually Domain Users
), if that’s important to you, nor will it include groups on external trusted domains.
Does this mean you can never rely on memberOf
? No. It’s perfectly appropriate if:
If memberOf
is good enough for you, then use it! It will be the quickest way.
The next important question is:
This knowledge is valuable for performance in your code. If you can make assumptions about the groups and users you are working with, then you may be able to ignore Primary Groups or Foreign Security Principals, and thus save time.
For exmaple,
primaryGroupId
.My other articles in this series will cover how you can do this.
2 comments