<blog:entry xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:blog="http://www.adamretter.org.uk/blog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.adamretter.org.uk/blog http://www.adamretter.org.uk/blog/entry.xsd" status="published" id="918b3704-2bc9-4447-b53b-e33753ef5f49">
    <blog:article timestamp="2011-07-01T22:57:00.000+02:00" author="Adam Retter" last-updated="2011-07-01T22:57:00.000+02:00">
        <blog:title>LDAP query for Active Directory User's Primary Group</blog:title>
        <blog:sub-title>Java LDAP code for Active Directory</blog:sub-title>
        <blog:article-content>
            <xh:p>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.</xh:p>
            <xh:p>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.</xh:p>
            <xh:p>PS. If you need to find a good LDAP querying and browse tool for examining the objects in AD LDAP, then I found <xh:a href="http://directory.apache.org/studio" title="Apache Directory Studio">Apache Directory Studio</xh:a> to be absolutely fantastic.</xh:p>
            <xh:p>Basically, every object class in AD LDAP has an 'objectSID' identifier. This SID (Security Identifier) is a binary identifier provided as a byte array.</xh:p>
            <blog:mini-title>The binary expression of a SID has the following format:</blog:mini-title>
            <xh:pre>
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]                
            </xh:pre>
            <xh:p>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.</xh:p>
            <xh:p>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 <xh:a href="http://msdn.microsoft.com/en-us/library/cc230371(PROT.10).aspx" title="SID String Format Syntax">here</xh:a>.</xh:p>
            <blog:mini-title>The string expression of a SID has the following format:</blog:mini-title>
            <xh:pre>
“S-{Revision}-{Authority}-{SubAuthority1}-{SubAuthority2}...-{SubAuthorityN}”

e.g. -
“S-1-5-21-977923109-2952828257-175163757-387119”
            </xh:pre>
            <xh:p>I based my code for decoding a binary expression of a SID into a string expression on the code found <xh:a href="http://forums.oracle.com/forums/thread.jspa?threadID=1155740&amp;tstart=0" title="Oracle Forums">here</xh:a> but I have tried to simplify and improve on the approach.</xh:p>
            <blog:mini-title>Java Code for decoding Binary a SID into a String SID:</blog:mini-title>
            <xh:pre>
/**
* 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&amp;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] &amp; 0xFF;
    
    //get the authority
    long authority = 0;
    //String rid = "";
    for(int i = 2; i &lt;= 7; i++) {
        authority |= ((long)sid[i]) &lt;&lt; (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 &lt; countSubAuths; j++) {
        long subAuthority = 0;
        for(int k = 0; k &lt; size; k++) {
            subAuthority |= (long)(sid[offset + k] &amp; 0xFF) &lt;&lt; (8 * k);
        }
        
        strSid.append("-");
        strSid.append(subAuthority);
        
        offset += size;
    }
        
    return strSid.toString();    
}
</xh:pre>
            <xh:p>
                <xh:a href="blog/entries/LDAPTest.java" title="Java code for LDAPTest.java">A complete Java example complete with LDAP query code is available here LDAPTest.java</xh:a>.</xh:p>
        </blog:article-content>
    </blog:article>
    <blog:tags>
        <blog:tag>Active Directory</blog:tag>
        <blog:tag>LDAP</blog:tag>
        <blog:tag>Java</blog:tag>
        <blog:tag>Primary Group</blog:tag>
        <blog:tag>SID</blog:tag>
    </blog:tags>
</blog:entry>