8 Replies Latest reply on Jan 23, 2009 10:45 AM by 843793

    JNDI, Active Directory and SID's (Security Identifiers)

    800477
      Security Identifiers (SID's) are used to uniquely identify security pricipals (users, groups, computers) in Windows.

      For information on SID's refer to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/sid_components.asp

      In the Active Directory, evey security principal has its SID stored in the attribute objectSID.

      Like any other attribute, it value can be retrieved and it can be also be used in a LDAP search filter.

      There are two ways of using the SID in a search filter;
      1. The string representation
      S-1-5-21-1169329820-375589439-2226611983-3280
      or
      2. the binary represenation
      \01\05\00\00\00\00\00\05\15\00\00\00\00\00.......\f4\01\00

      The trick is to be able to derive either form from an LDAP query.

      For the string representation, you simply need to decode the binary data, which is of the form:
      byte[0] - revision level
      byte[1-7] - 48 bit authority
      byte[8]- count of sub authorities
      and then count x 32 bit sub authorities

      You then need to format it into the string form:
      S-Revision-Authority-SubAuths....

      For the binary representation, it is just the sequence of bytes.

      The following sample illustrates retrieving a SID from the directory.
      (Note that as I'm not a Java programmer this is not necessarily the correct nor most elegant way of doing this)
      /**
       * sid.java
       * January 2005 (Based on old retrieve.java, circa 2001)
       * Sample JNDI application to retrieve a single object from the Active Directory
       * and display the object's Security Identifier (SID) in string & binary formats
       */
      
      import java.util.Hashtable;
      import javax.naming.*;
      import javax.naming.ldap.*;
      import javax.naming.directory.*;
      
      public class sid     {
           public static void main (String[] args)     {
           
                Hashtable env = new Hashtable();
                String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
                String adminPassword = "XXXXXX";
                String objectName = "CN=Albert Einstein,OU=Research,DC=antipodes,DC=com";
                String ldapURL = "ldap://mydc.antipodes.com:389";
                     
                env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
           
                //set security credentials, note using simple cleartext authentication
                env.put(Context.SECURITY_AUTHENTICATION,"simple");
                env.put(Context.SECURITY_PRINCIPAL,adminName);
                env.put(Context.SECURITY_CREDENTIALS,adminPassword);
                          
                //specify attributes to be returned in binary format
                env.put("java.naming.ldap.attributes.binary","objectSID");
      
                //connect to my domain controller
                env.put(Context.PROVIDER_URL, ldapURL);
      
                try {
      
                     // Create the initial directory context
                     LdapContext ctx = new InitialLdapContext(env,null);
               
                     // Retrieve all attributes of the requested object 
                     Attributes attrs = ctx.getAttributes(objectName);
      
                     // Print out some of the attributes
                     System.out.println("DN: " + attrs.get("distinguishedName").get());
                     System.out.println("logon: " + attrs.get("samAccountName").get());
                     System.out.println("phone: " + attrs.get("telephoneNumber").get());
                     System.out.println("email: " + attrs.get("mail").get());
      
                     // Get the SID
                     byte[] SID = (byte[])attrs.get("objectSID").get();
                     String strSID = "";
                     String byteSID = "";
                     int j;
                     //Convert the SID into string using the byte format
                     for (int i=0;i<SID.length;i++) {
                          j = (int)SID[i] & 0xFF;
                          if (j<0xF) {
                               //add a leading zero, add two leading \\ to make it easy 
                               //to paste into subsequent searches
                               byteSID = byteSID + "\\0" + Integer.toHexString(j);
                          }
                          else {
                               byteSID = byteSID + "\\" + Integer.toHexString(j);
                          }
                     }
                     //convert the SID into string format S-V-A-R-R...-R
                     //This is probably not entirely correct nor elegant
                     int version;
                     long authority;
                     int count;
                     String rid;
                     //Add the 'S' prefix
                     strSID = "S";
                     //first byte is the version
                     version = SID[0];
                     strSID = strSID + "-" + Integer.toString(version);
                     //48 bit Authority 
                     rid = Integer.toHexString((int)SID[6]&0xFF) + Integer.toHexString((int)SID[5]&0xFF) + Integer.toHexString((int)SID[4]&0xFF) + Integer.toHexString((int)SID[3]&0xFF) + Integer.toHexString((int)SID[2]&0xFF) + Integer.toHexString((int)SID[1]&0xFF);
                     authority = Long.parseLong(rid);
                     strSID = strSID + "-" + Long.toString(authority);
                     //next byte is the count of sub-authorities
                     count = SID[7];
                     //iterate all the sub-auths
                     for (int i=0;i<count;i++) {
                          rid = Integer.toHexString((int)SID[11+(i*4)]&0xFF) + Integer.toHexString((int)SID[10+(i*4)]&0xFF) + Integer.toHexString((int)SID[9+(i*4)]&0xFF) + Integer.toHexString((int)SID[8+(i*4)]&0xFF);
                          strSID = strSID + "-" + Long.parseLong(rid,16);
                     }
                     System.out.println("SID (String format): " + strSID);
                     System.out.println("SID (Byte format): " + byteSID);
                     ctx.close();
      
                }
                catch (NamingException e) {
                     System.err.println("Problem retrieving object: " + e);
                }
           }
      }
      When using the SID in a search filter, for the string representation, it is used directly in the search filter, whereas for the binary representation in the search filter just delimit each byte with the "\" character.

      The following code illustrates a search using objectSID
      /**
       * searchbysid.java
       * 5 July 2001, updated January 2005
       * Sample JNDI application to perform a search against the Active Directory
       * using the objectSID
       */
      
      import java.util.Hashtable;
      import javax.naming.ldap.*;
      import javax.naming.directory.*;
      import javax.naming.*;
      
      
      public class searchbysid     {
           public static void main (String[] args)     {
           
                Hashtable env = new Hashtable();
                String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM";
                String adminPassword = "XXXXXXXX";
                String ldapURL = "ldap://mydc.antipodes.com:389";
                
                env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
      
                //set security credentials, note using simple cleartext authentication
                env.put(Context.SECURITY_AUTHENTICATION,"simple");
                env.put(Context.SECURITY_PRINCIPAL,adminName);
                env.put(Context.SECURITY_CREDENTIALS,adminPassword);
                          
                //connect to my domain controller
                env.put(Context.PROVIDER_URL,ldapURL);
                try {
      
                     //Create the initial directory context
                     LdapContext ctx = new InitialLdapContext(env,null);
                
                     //Create the search controls           
                     SearchControls searchCtls = new SearchControls();
                
                     //Specify the attributes to return
                     String returnedAtts[]={"sn","givenName","mail"};
                     searchCtls.setReturningAttributes(returnedAtts);
                
                     //Specify the search scope
                     searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
      
                     //specify the LDAP search filter, can use either binary or string forms.
                     //This is the binary format of the SID
                     //String searchFilter = "(objectSID=\\01\\05\\00\\00\\00\\00\\00\\05\\15\\00\\00\\00\\9c\\8e\\b2\\45\\3f\\bf\\d9\\df\\5f\\2a\\b8\\84\\D0\\0C\\00\\00)";
                     //This is the string format of the SID
                     String searchFilter = "(objectSID=S-1-5-21-1169329820-3755589439-2226661983-3280)";
      
                     //Specify the Base for the search
                     String searchBase = "DC=antipodes,DC=com";
      
                     //initialize counter to total the results
                     int totalResults = 0;
      
      
                     //Search for objects using the filter
                     NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
      
                     //Loop through the search results
                     while (answer.hasMoreElements()) {
                          SearchResult sr = (SearchResult)answer.next();
      
                          totalResults++;
      
                          System.out.println(">>>" + sr.getName());
      
                          // Print out some of the attributes, catch the exception if the attributes have no values
                          Attributes attrs = sr.getAttributes();
                          if (attrs != null) {
                               try {
                                    System.out.println("   name: " + attrs.get("givenName").get() + " " + attrs.get("sn").get());
                                    System.out.println("   mail: " + attrs.get("mail").get());
                               }
                               catch (NullPointerException e)     {
                                    System.err.println("Problem listing attributes: " + e);
                               }
                          
                          }
      
                     }
      
                      System.out.println("Total results: " + totalResults);
                     ctx.close();
      
                } 
                catch (NamingException e) {
                     System.err.println("Problem searching directory: " + e);
                }
           }
      }
        • 1. Re: JNDI, Active Directory and SID's (Security Identifiers)
          843793
          I've tried this example and found out that there is a little bug converting the byte to hex representation. For small values (<0x10) the leading zero is missing.

          Here is my solution for getting the objectSID, based on the previous solution.
          I think that should work fine now:
          import java.util.Hashtable;
          import javax.naming.*;
          import javax.naming.ldap.*;
          import javax.naming.directory.*;
           
          public class sid     {
               public static void main (String[] args)     {
                    
                    Hashtable env = new Hashtable();
                    String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
                    String adminPassword = "XXXXXX";
                    String objectName = "CN=Albert Einstein,OU=Research,DC=antipodes,DC=com";
                    String ldapURL = "ldap://mydc.antipodes.com:389";
                         
                    env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
               
                    //set security credentials, note using simple cleartext authentication
                    env.put(Context.SECURITY_AUTHENTICATION,"simple");
                    env.put(Context.SECURITY_PRINCIPAL,adminName);
                    env.put(Context.SECURITY_CREDENTIALS,adminPassword);
                              
                    //specify attributes to be returned in binary format
                    env.put("java.naming.ldap.attributes.binary","objectSID");
           
                    //connect to my domain controller
                    env.put(Context.PROVIDER_URL, ldapURL);
           
                    try {
           
                         // Create the initial directory context
                         LdapContext ctx = new InitialLdapContext(env,null);
                   
                         // Retrieve all attributes of the requested object 
                         Attributes attrs = ctx.getAttributes(objectName);
           
                         // Print out some of the attributes
                         System.out.println("DN: " + attrs.get("distinguishedName").get());
                         System.out.println("logon: " + attrs.get("samAccountName").get());
                         System.out.println("phone: " + attrs.get("telephoneNumber").get());
                         System.out.println("email: " + attrs.get("mail").get());
           
                         // Get the SID
                         byte[] SID = (byte[])attrs.get("objectSID").get();
          
                         String strSID = getSIDasStringOfBytes(SID);
                         String byteSID = getSIDasBytestringOfBytes(SID);
                         
                         
                         System.out.println("SID (String format): " + strSID);
                         System.out.println("SID (Byte format): " + byteSID);
                         ctx.close();
           
                    }
                    catch (NamingException e) {
                         System.err.println("Problem retrieving object: " + e);
                    }
               }
          
               public static String getSIDasBytestringOfBytes(byte[] sid) {
                    String byteSID = "";
                    int j;
                    //Convert the SID into string using the byte format
                    for (int i=0;i<sid.length;i++) {
                         j = (int)sid[i] & 0xFF;
                         if (j<0xF) {
                         //add a leading zero, add two leading \\ to make it easy 
                         //to paste into subsequent searches
                                 byteSID = byteSID + "\\0" + Integer.toHexString(j);
                         }
                         else {
                              byteSID = byteSID + "\\" + Integer.toHexString(j);
                         }
                    }  
                    return byteSID;
               }
          
               public static String getSIDasStringOfBytes(byte[] sid) {
                    String strSID = "";
                    int version;
                    long authority;
                    int count;
                    String rid = "";
                    strSID = "S";
              
                     // get version
                    version = sid[0];
                    strSID = strSID + "-" + Integer.toString(version);
                    for (int i=6; i>0; i--) {
                         rid += byte2hex(sid);
                    }

                    // get authority
                    authority = Long.parseLong(rid);
                    strSID = strSID + "-" + Long.toString(authority);

                    //next byte is the count of sub-authorities
                    count = sid[7]&0xFF;

                    //iterate all the sub-auths
                    for (int i=0;i<count;i++) {
                         rid = "";
                         for (int j=11; j>7; j--) {
                              rid += byte2hex(sid[j+(i*4)]);
                         }
                         strSID = strSID + "-" + Long.parseLong(rid,16);
                    }
                    return strSID;
               }

               public static String byte2hex(byte b) {
                    String ret = Integer.toHexString((int)b&0xFF);
                    if (ret.length()<2) ret = "0"+ret;
                    return ret;
               }

          }
          • 2. Re: JNDI, Active Directory and SID's (Security Identifiers)
            843793
            Hello Steven,

            Thank you for postings these terrific bits of LDAP query code!

            I am a complete Java newbie so I have a question that may seem obvious.

            I would like to somehow perform the data type conversion of objectSID values of the objects that I query in the Deleted Objects container.

            The problem I run into is that when I get the enumerated results of the Deleted Objects container, I cannot use the method of "Convert the SID into string using the byte format" as outlined in the code above.

            Any suggestions or help would be appreciated.

            Thanks,

            Ben
            • 3. Re: JNDI, Active Directory and SID's (Security Identifiers)
              800477
              Firstly you can find some sample code demonstrating how to search for deleted objects somewhere in the thread http://forum.java.sun.com/thread.jspa?threadID=449782&tstart=225

              Secondly when an object is deleted in Active Directory, most of the attribute values are discarded. I should really clarify this. When you delete an object in AD, you are really marking an object for deletion. The original object is moved into a container and most of the attribute values are stripped. This tombstone object is replicated amongst all of the other domain controllers and once the tombstone period has elapsed, the tombstone object is deleted.

              This made it difficult to undelete an object and to restore the original values unless you were using a provisioning tool that maintained a separate history of the attribute values.

              Anyway, I think it was in Windows Server 2003 SP1 that administrators could define which attributes to retain on the tombstone, making it easier to "reanimate" deleted objects.

              In your case, it could be that the objectSID value is no longer present on the deleted object.. Without actually testing this myself, I can't tell you the exact answer. You may just want to retrieve all the attributes on your deleted object and see whether a value for objectSID is present or not.

              Good luck.
              • 4. Re: JNDI, Active Directory and SID's (Security Identifiers)
                843793
                Thank you for your reply Steven!

                I have read up on the deleted objects container and attributes and tombstone lifespans etc. I apologize as I was not clear in my last post. I can see that the deleted objects have the ObjectSID still associated with them. In fact there are a fair number of attributes that are still associated with tombstone objects. Here is the link where it shows the attributes for the tombstone objects: http://msdn2.microsoft.com/en-us/library/aa772216.aspx

                Here is what i have so far (full code at the bottom). It fails on
                byte[] SID2 = (byte[])e.next();
                I'm not sure why I cannot convert the e.next() into byte[] and store in SID2 so that I can perform the steps that you have provided to convert into string format. Any tips that you can give me would be greatly appreciated.

                Again, thank you for all your help!

                Ben
                               String strSID = "";
                               String byteSID = "";
                               int j;
                               //Convert the SID into string using the byte format
                               for (int i=0;i<SID.length;i++) {
                                    j = (int)SID[i] & 0xFF;
                                    if (j>0xF) {
                                         //add a leading zero, add two leading \\ to make it easy 
                                         //to paste into subsequent searches
                                         //byteSID = byteSID + "\\0" + Integer.toHexString(j);
                                         byteSID = byteSID + Integer.toHexString(j);
                                    }
                                    else {
                                         byteSID = byteSID + "0" + Integer.toHexString(j);
                                         //byteSID = byteSID + "\\" + Integer.toHexString(j);
                                    }
                               }
                Here is the full code that I have:
                import java.util.Hashtable;
                import javax.naming.*;
                import javax.naming.ldap.*;
                import javax.naming.directory.*;
                //import com.sun.jndi.ldap.ctl.*;
                
                
                class DeletedControlSid implements Control {
                     /**
                      * 
                      */
                     private static final long serialVersionUID = 1L;
                     public byte[] getEncodedValue() {
                          return new byte[] {};
                     }
                     public String getID() {
                          return "1.2.840.113556.1.4.417";
                     }
                     public boolean isCritical() {
                          return true;
                     }
                }
                
                
                
                public class DeletedSid     {
                     public static void main (String[] args)     {
                     
                          Hashtable env = new Hashtable();
                          String adminName = "CN=Administrator,CN=Users,DC=DOMAIN,DC=COM";
                          String adminPassword = "PASSWORD";
                          String ldapURL = "ldap://DC:389";
                          String sUserList = "";
                          //my declarations
                          String objectName = "CN=Joe Watt,CN=Users,DC=domain,DC=com";
                          //byte[] SID = null;
                          
                          env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
                 
                          //set security credentials, note using simple cleartext authentication
                          env.put(Context.SECURITY_AUTHENTICATION,"simple");
                          env.put(Context.SECURITY_PRINCIPAL,adminName);
                          env.put(Context.SECURITY_CREDENTIALS,adminPassword);
                
                          //specify attributes to be returned in binary format
                          env.put("java.naming.ldap.attributes.binary","objectSID");
                          
                          //connect to my domain controller
                          env.put(Context.PROVIDER_URL,ldapURL);
                          
                          try {
                 
                               //Create the initial directory context
                               LdapContext ctx = new InitialLdapContext(env,null);
                          
                               /*+++++++++++++ My testing out the byte object manipulation ++++++++++++++ */
                               Attributes attrs2 = ctx.getAttributes(objectName);
                               // Get the SID
                               System.out.println("before byte " + attrs2.get("objectSID").get());
                               String sAccountName = attrs2.get("objectSID").toString();
                               System.out.println(sAccountName);
                               byte[] SID = (byte[])attrs2.get("objectSID").get();
                               String strSID = "";
                               String byteSID = "";
                               int j;
                               //Convert the SID into string using the byte format
                               for (int i=0;i<SID.length;i++) {
                                    j = (int)SID[i] & 0xFF;
                                    if (j>0xF) {
                                         //add a leading zero, add two leading \\ to make it easy 
                                         //to paste into subsequent searches
                                         //byteSID = byteSID + "\\0" + Integer.toHexString(j);
                                         byteSID = byteSID + Integer.toHexString(j);
                                    }
                                    else {
                                         byteSID = byteSID + "0" + Integer.toHexString(j);
                                         //byteSID = byteSID + "\\" + Integer.toHexString(j);
                                    }
                               }
                               System.out.println("SID (String format): " + byteSID);
                               
                               //System.out.println("SID--" + SID +"--"+attrs2.get("objectSID").get());
                               
                               
                               
                               //Create the search controls           
                               SearchControls searchCtls = new SearchControls();
                          
                               //Specify the attributes to return
                               String returnedAtts[]={"distinguishedName","lastKnownParent","objectsid","sAMAccountName"};
                               searchCtls.setReturningAttributes(returnedAtts);
                          
                               //Specify the search scope
                               searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
                 
                               //specify the LDAP search filter
                               String searchFilter = "(&(|(objectClass=User)(objectClass=Group))(isDeleted=TRUE))";
                 
                               //Specify the Base for the search
                               String searchBase = "DC=domain,DC=com";
                 
                               //initialize counter to total the results
                               int totalResults = 0;
                 
                               //specify the Deleted control
                               Control[] rqstCtls = new Control[] {new DeletedControlSid()};
                               ctx.setRequestControls(rqstCtls);
                 
                               //Search for objects using the filter
                               NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
                 
                
                               
                               //Loop through the search results
                               while (answer.hasMoreElements()) {
                                    SearchResult sr = (SearchResult)answer.next();
                 
                                    totalResults++;
                 
                                    //System.out.println(totalResults + ". " + sr.getName().toString());
                 
                                    // Print out some of the attributes, catch the exception if the attributes have no values
                                    
                 
                                    Attributes attrs = sr.getAttributes();
                                    System.out.println("attrs is: " + attrs + "****");
                                    if (attrs != null) {
                                         try {
                 
                                              for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) {
                                                   System.out.println("attrs.getAll()" + attrs.getAll().next());
                                                   Attribute attr = (Attribute)ae.next();
                                                        System.out.println("attr is: " + attr + "-----");
                                                        if (attr.getID().compareTo("objectSid")==0){
                                                             System.out.println("honk!: " + attr.getID());
                                                             
                                                             for (NamingEnumeration e = attr.getAll();e.hasMore();
                                                             System.out.println("objectSID   " + e.next()));{
                                                                  
                                                                  NamingEnumeration e = attr.getAll();e.hasMore();
                                                                  System.out.println("newline " + e.next());
                                                                  
                                                                  //This is where it all errors!!
                                                                  byte[] SID2 = (byte[])e.next();
                                                                  //System.out.println("SID " + SID);
                                                             }
                                                             //sUserList = sUserList + e.next().toString() + ",");
                                                             /*byte[] SID = (byte[])e.next();
                                                             String strSID = "";
                                                             String byteSID = "";
                                                             System.out.println("strSID");*/
                                                        }
                                                        else{
                                                             for (NamingEnumeration e = attr.getAll();e.hasMore();/*System.out.println("   " + e.next().toString())*/);
                                                             //sUserList = sUserList + e.next().toString() + ",");
                                                             }
                                                        }
                                                        
                                                        /*else{
                                                             System.out.println(attr.getID()+ "Attribute: " + attr.getID());
                                                        }*/
                                                   }
                                         catch (NullPointerException e)     {
                                         System.err.println("Problem listing attributes: " + e);
                                         }
                                    }
                 
                               }
                 
                                System.out.println("Deleted objects: " + totalResults);
                                System.out.println("Full list of users:" + sUserList);
                               ctx.close();
                 
                          } 
                          catch (NamingException e) {
                          System.err.println("Problem searching directory: " + e);
                          }
                     }
                }
                • 5. Re: JNDI, Active Directory and SID's (Security Identifiers)
                  843793
                  Hi Stephen,

                  I'm an idiot :)

                  I was causing an infinite loop in my previous code example.

                  I got it working now.

                  Here is the final code:
                  package ldapsync;
                  /**
                   * deleted.java
                   * 5 July 2001
                   * Sample JNDI application to search for deleted objects
                   * Modified December 2004 to add Win2K3 lastKnownParent
                   * Modified August 2007 to bring back ObjectSID values in string format
                   * 
                   */
                   
                  import java.util.Hashtable;
                  import javax.naming.*;
                  import javax.naming.ldap.*;
                  import javax.naming.directory.*;
                  
                  class DeletedControlSidExample implements Control {
                       /**
                        * 
                        */
                       private static final long serialVersionUID = 1L;
                       public byte[] getEncodedValue() {
                            return new byte[] {};
                       }
                       public String getID() {
                            return "1.2.840.113556.1.4.417";
                       }
                       public boolean isCritical() {
                            return true;
                       }
                  }
                  
                  
                  
                  public class DeletedSidExample     {
                       public static void main (String[] args)     {
                       
                            Hashtable env = new Hashtable();
                            String adminName = "CN=administrator,CN=Users,DC=domain,DC=COM";
                            String adminPassword = "password";
                            String ldapURL = "ldap://domaincontroller:389";
                            String sUserList = "";
                            
                            env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
                   
                            //set security credentials, note using simple cleartext authentication
                            env.put(Context.SECURITY_AUTHENTICATION,"simple");
                            env.put(Context.SECURITY_PRINCIPAL,adminName);
                            env.put(Context.SECURITY_CREDENTIALS,adminPassword);
                  
                            //specify attributes to be returned in binary format
                            env.put("java.naming.ldap.attributes.binary","objectSID");
                            
                            //connect to my domain controller
                            env.put(Context.PROVIDER_URL,ldapURL);
                            
                            try {
                   
                                 //Create the initial directory context
                                 LdapContext ctx = new InitialLdapContext(env,null);
                            
                                 //Create the search controls           
                                 SearchControls searchCtls = new SearchControls();
                            
                                 //Specify the attributes to return
                                 String returnedAtts[]={"distinguishedName","lastKnownParent","objectsid","sAMAccountName"};
                                 searchCtls.setReturningAttributes(returnedAtts);
                            
                                 //Specify the search scope
                                 searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
                   
                                 //specify the LDAP search filter
                                 String searchFilter = "(&(|(objectClass=User)(objectClass=Group))(isDeleted=TRUE))";
                   
                                 //Specify the Base for the search
                                 String searchBase = "DC=domain,DC=com";
                   
                                 //initialize counter to total the results
                                 int totalResults = 0;
                   
                                 //specify the Deleted control
                                 Control[] rqstCtls = new Control[] {new DeletedControlSid()};
                                 ctx.setRequestControls(rqstCtls);
                   
                                 //Search for objects using the filter
                                 NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
                   
                  
                                 
                                 //Loop through the search results
                                 while (answer.hasMoreElements()) {
                                      SearchResult sr = (SearchResult)answer.next();
                   
                                      totalResults++;
                   
                                      // Print out some of the attributes, catch the exception if the attributes have no values
                   
                                      Attributes attrs = sr.getAttributes();
                  
                                      if (attrs != null) {
                                           try {
                   
                                                for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) {
                  
                                                     Attribute attr = (Attribute)ae.next();
                  
                                                          if (attr.getID().compareTo("objectSid")==0){
                  
                                                               
                                                               for (NamingEnumeration e = attr.getAll();e.hasMore();){
                                                                    
                                                                    byte[] SID = (byte[])e.next();
                                                                    System.out.println("SID " + SID);
                                                                    String byteSID = "";
                                                                    int j;
                                                                    //Convert the SID into string using the byte format
                                                                    for (int i=0;i<SID.length;i++) {
                                                                         j = (int)SID[i] & 0xFF;
                                                                         if (j>0xF) {
                                                                              byteSID = byteSID + Integer.toHexString(j);
                                                                         }
                                                                         else {
                                                                              byteSID = byteSID + "0" + Integer.toHexString(j);
                                                                              
                                                                         }
                                                                    }
                                                                    System.out.println("byteSID " + byteSID);
                                                               }
                                                          }
                                                     }
                                                }
                                           catch (NullPointerException e)     {
                                           System.err.println("Problem listing attributes: " + e);
                                           }
                                      }
                   
                                 }
                   
                                  System.out.println("Deleted objects: " + totalResults);
                                  System.out.println("Full list of users:" + sUserList);
                                 ctx.close();
                   
                            } 
                            catch (NamingException e) {
                            System.err.println("Problem searching directory: " + e);
                            }
                       }
                  }
                  Thank you! Thank you!

                  Cheers,

                  Ben

                  Message was edited by:
                  hoodwinkle
                  • 6. Re: JNDI, Active Directory and SID's (Security Identifiers)
                    843793
                    Hi Steven,

                    I tried using byte representation of objectSID in my search filter against ActiveDirectory as told by you but could not retrieve any value. Is there any thing else we have to do?
                    Also I was trying to get sid from bytes by doing some manual computation but it seems to me that the bytes that I am getting are incorrect.

                    byte b[] = getobjectSid().getBytes();

                    Regards,
                    Sumedh
                    • 7. Re: JNDI, Active Directory and SID's (Security Identifiers)
                      800477
                      If you are sure that you have a valid SID (perhaps verify with another tool such as LDP), then make sure that you are escapaing the "\" character correctly when retrieving an object using the byte format of the SID
                      String searchFilter = "(objectSID=\\01\\05\\00\\00\\00\\00\\00\\05\\15\\00\\00\\00\\9c\\8e\\b2\\45\\3f\\bf\\d9\\df\\5f\\2a\\b8\\84\\D0\\0C\\00\\00)";
                      If you are attemtping to construct a string representation of the SID, then make sure you are retrieving the attribute in a binary format
                      //specify attributes to be returned in binary format
                      env.put("java.naming.ldap.attributes.binary","objectSID");
                      • 8. Re: JNDI, Active Directory and SID's (Security Identifiers)
                        843793
                        According to Microsoft specification:
                        [http://msdn.microsoft.com/en-us/library/cc230371(PROT.10).aspx]

                        The binary data is in 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)

                        So, none of the code above has been working for me. But after small changes I got the working version:
                        public static String getSIDasStringOfBytes(byte[] sid) {
                                  String strSID = "";
                                  int version;
                                  long authority;
                                  int count;
                                  String rid = "";
                                  strSID = "S";
                            
                                   // get version
                                  version = sid[0];
                                  strSID = strSID + "-" + Integer.toString(version);
                                  for (int i=2; i<=7; i++) {
                                       rid += byte2hex(sid);
                                  }

                                  // get authority
                                  authority = Long.parseLong(rid);
                                  strSID = strSID + "-" + Long.toString(authority);

                                  //next byte is the count of sub-authorities
                                  count = sid[1]&0xFF;

                                  //iterate all the sub-auths
                                  for (int i=0;i<count;i++) {
                                       rid = "";
                                       for (int j=11; j>7; j--) {
                                            rid += byte2hex(sid[j+(i*4)]);
                                       }
                                       strSID = strSID + "-" + Long.parseLong(rid,16);
                                  }
                                  return strSID;
                             }
                        Edited by: VadimKa on Jan 23, 2009 2:44 AM