Blog

Ponderings of a kind

This is my own personal blog, each article is an XML document and the code powering it is hand cranked in XQuery and XSLT. It is fairly simple and has evolved only as I have needed additional functionality. I plan to Open Source the code once it is a bit more mature, however if you would like a copy in the meantime drop me a line.

Atom Feed

LDAP query for Active Directory User's Primary Group

Java LDAP code for Active Directory

When querying AD (Active Directory) with LDAP (Light-weight Directory Access Protocol), it is possible to easily retrieve a lot of attribute information about a user. However, it is not obvious or straight-forward to understand how to find out the Primary Group that a user belongs to. Whilst you can get a list of groups from the 'memberOf' attribute on the 'user' object class, or even find groups by their members through the 'member' attribute of the 'group' object class, these lists do not include information about the User's Primary Group.

The 'user' Class, does provide a 'primaryGroupID' attribute, however the 'group' class does not contain a matching attribute that you can directly search against. However there is a trick! After quite some Googling and pulling information together from various sources, I have managed to achieve this, and to make it easier for everyone else, I am publishing a complete example.

PS. If you need to find a good LDAP querying and browse tool for examining the objects in AD LDAP, then I found Apache Directory Studio to be absolutely fantastic.

Basically, every object class in AD LDAP has an 'objectSID' identifier. This SID (Security Identifier) is a binary identifier provided as a byte array.

The binary expression of a SID has the following format:
byte[0] - Revision Level
byte[1] - count of Sub-Authorities
byte[2-7] - 48 bit Authority (big-endian)
...and then n Sub-Authorities, 32 bits each (little-endian)

e.g. -
[1,5,0,0,0,0,0,5,21,0,0,0,37,-20,73,58,97,-107,0,-80,109,-55,112,10,47,-24,5,0]                
            

The last sub-authority of a SID is known as the RID (Relative Identifier), and it is this RID that differentiates objects from within the same domain. This basically means that by replacing the RID in an SID you can generate the SID for a different object. The 'primaryGroupID' attribute from the 'user' class is a RID. So, we can take the SID of the user, and replace the RID part with the primary group id, we can then lookup the group in LDAP using this SID as the key.

A binary SID can be decoded into a string, which is both easier to understand and can also be used for subsequent queries within AD LDAP. The specifics of the SID string format can be found here.

The string expression of a SID has the following format:
“S-{Revision}-{Authority}-{SubAuthority1}-{SubAuthority2}...-{SubAuthorityN}”

e.g. -
“S-1-5-21-977923109-2952828257-175163757-387119”
            

I based my code for decoding a binary expression of a SID into a string expression on the code found here but I have tried to simplify and improve on the approach.

Java Code for decoding Binary a SID into a String SID:
/**
* The binary data is in the form:
* byte[0] - revision level
* byte[1] - count of sub-authorities
* byte[2-7] - 48 bit authority (big-endian)
* and then count x 32 bit sub authorities (little-endian)
* 
* The String value is: S-Revision-Authority-SubAuthority[n]...
* 
* Based on code from here - http://forums.oracle.com/forums/thread.jspa?threadID=1155740&tstart=0
*/
public static String decodeSID(byte[] sid) {

    final StringBuilder strSid = new StringBuilder("S-");
    
    // get version
    final int revision = sid[0];
    strSid.append(Integer.toString(revision));
    
    //next byte is the count of sub-authorities
    final int countSubAuths = sid[1] & 0xFF;
    
    //get the authority
    long authority = 0;
    //String rid = "";
    for(int i = 2; i <= 7; i++) {
        authority |= ((long)sid[i]) << (8 * (5 - (i - 2)));
    }
    strSid.append("-");
    strSid.append(Long.toHexString(authority));
    
    //iterate all the sub-auths
    int offset = 8;
    int size = 4; //4 bytes for each sub auth
    for(int j = 0; j < countSubAuths; j++) {
        long subAuthority = 0;
        for(int k = 0; k < size; k++) {
            subAuthority |= (long)(sid[offset + k] & 0xFF) << (8 * k);
        }
        
        strSid.append("-");
        strSid.append(subAuthority);
        
        offset += size;
    }
        
    return strSid.toString();    
}

A complete Java example complete with LDAP query code is available here LDAPTest.java.

Adam Retter posted on Friday, 1st July 2011 at 22.57 (GMT+02:00)
Updated: Friday, 1st 2011 at July 22.57 (GMT+02:00)

tags: Active DirectoryLDAPJavaPrimary GroupSID

Comments (1)


Thanks for the sample code. Wanted to add couple of findings from my searches for this;

1) When using spring LDAP, you can use the following code snippet to get the user objectSid

<code>
<!-- In beans.xml make sure you have the following defined for the ldapContext definition -->

<property name="baseEnvironmentProperties">
<map>
<entry key="java.naming.ldap.attributes.binary">
	<value>objectSid</value>
</entry>
</map>
</property>

<!-- Now in your code you can get the sid by -->
byte[] userSid = (byte[]) userContext.getAttributes().get("objectSid").get(); 
String userSidValue = LdapUtils.convertBinarySidToString(userSid);



</code>


Add Comment



(will not be shown)






Tag Cloud