JNDI, Active Directory and objectGUID's

转自:https://community.oracle.com/thread/1157698


JNDI, Active Directory and objectGUID's 


For some reason my original post on this topic was dropped from the forum.


Active Directory and for that matter Active Directory Application Mode (ADAM) allow most objects to be renamed or moved. There are internal mechanisms to ensure the integrity of 


the directory which make objects rename safe. 


For example assume there is a user object cn=Jenny Smith ,ou=Finance,dc=antipodes,dc=com and she is a member of the group cn=Tennis Players,ou=Social Club,dc=antipodes,dc=com


If Jenny gets married, and changes jobs, her distinguished name becomes cn=Jenny Smith-Jones,ou=Sales,dc=antipodes,dc=com.


Because AD is rename safe, her group memberships are maintained.


However how does an application keep track of directory objects as they are renamed or moved? For every directory object there is one attribute called objectGUID which is unique 


and invariant. objectGUID's are created by the system and are guaranteed to be globally unique.


The following sample code demonstrates retrieving the objectGUID attribute and displaying it in both the binary and string form.
/**
 * searchforguid.java
 * 5 July 2001
 * Sample JNDI application to perform a search against the Active Directory
 * and also return the objectGUID in both binary and string formats
 * 
 */


import java.util.Hashtable;
import javax.naming.ldap.*;
import javax.naming.directory.*;
import javax.naming.*;


public class searchforguid     {
     public static void main (String[] args)     {
     
          Hashtable env = new Hashtable();
          //Can use either DN, NTLM or UPN style credentials
          String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM";
          //String adminName = "Administrator@ANTIPODES.COM";
          //String adminName = "ANTIPODES\\Administrator";
          String adminPassword = "XXXXXX";
          String ldapURL = "ldap://myddc.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","objectGUID");


          //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","objectGUID"};
               searchCtls.setReturningAttributes(returnedAtts);
          
               //Specify the search scope
               searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);


               //specify the LDAP search filter
               String searchFilter = "(&(objectClass=user)(cn=Albert Einstein))";


               //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());
                              byte[] GUID = (byte[])attrs.get("objectGUID").get();
                              String strGUID = "";
                              String byteGUID = "";
                              //Convert the GUID into string using the byte format
                              for (int c=0;c<GUID.length;c++) {
                                   byteGUID = byteGUID + "\\" + AddLeadingZero((int)GUID[c] & 0xFF);
                              }
                              //convert the GUID into string format
                              strGUID = "{";
                              strGUID = strGUID + AddLeadingZero((int)GUID[3] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[2] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[1] & 0xFF); 
                              strGUID = strGUID + AddLeadingZero((int)GUID[0] & 0xFF);
                              strGUID = strGUID + "-";
                              strGUID = strGUID + AddLeadingZero((int)GUID[5] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[4] & 0xFF);
                              strGUID = strGUID + "-";
                              strGUID = strGUID + AddLeadingZero((int)GUID[7] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[6] & 0xFF);
                              strGUID = strGUID + "-";
                              strGUID = strGUID + AddLeadingZero((int)GUID[8] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[9] & 0xFF);
                              strGUID = strGUID + "-";
                              strGUID = strGUID + AddLeadingZero((int)GUID[10] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[11] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[12] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[13] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[14] & 0xFF);
                              strGUID = strGUID + AddLeadingZero((int)GUID[15] & 0xFF);
                              strGUID = strGUID + "}";
                              System.out.println("GUID (String format): " + strGUID);
                              System.out.println("GUID (Byte format): " + byteGUID);


                         }
                         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);
          }
     }


     static String AddLeadingZero(int k) {
          return (k<=0xF)?"0" + Integer.toHexString(k):Integer.toHexString(k);
     }
}




Now there are two ways to retrieve an object using its objectGUID.


The first is to simply perform a search using the objectGUID in it's binary format. (Remember that the backslash character is an LDAP special character and must be escaped).


In this case just modify your application to use a search filter that includes the binary form of the objectGUID
//specify the LDAP search filter
//This is the binary format of the objectGUID
//Note that I've escaped the '\' character
String searchFilter = "(objectGUID=\\67\\8a\\44\\7c\\3b\\92\\ee\\48\\b2\\1a\\34\\51\\f2\\f7\\58\\ca)";
To use the string form of the search filter, in older versions of JNDI before they screwed up the LDAP name parsing :-( 
all you needed to do was issue a base level search using the objectGUID as the searchbase, and objectClass=* as the search filter.
//Specify the search scope
//Note for GUID=xxxx must use base level search
searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE);




//specify the LDAP search filter
//Note for GUID=xxxx must use objectClass filter
String searchFilter = "(objectClass=*)";




//Specify the Base for the search
//This is the string form of the GUID without the braces
String searchBase = "<GUID=7c448a67-923b-48ee-b21a-3451f2f758ca>";
Unfortunately in current Java releases, this results in a InvalidNamingException because it appears that the NamingEnumeration cannot parse a dn that contains LDAP special 


characters, in this case the <> characters that enclose the GUID.
Fortunately you can just simply retrieve the object by binding directly to it, as this sample illustrates.


/**
 * retrievebyguid.java
 * 5 July 2001
 * Sample JNDI application to retrieve an Active Directory 
 * object using the string form of its objectGUID
 */




import java.util.Hashtable;
import javax.naming.ldap.*;
import javax.naming.directory.*;
import javax.naming.*;


public class retrievebyguid     {
     public static void main (String[] args)     {
     
          Hashtable env = new Hashtable();
          String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM";
          String adminPassword = "XXXXXX";
          String ldapURL = "ldap://myddc.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);
          
               //Bind directly using the string form of the GUID
               String strGUID = "<GUID=7c448a67-923b-48ee-b21a-3451f2f758ca>";


               //Specify the attributes to return
               String returnedAtts[]={"distinguishedName","sn","givenName","mail"};


               Attributes attr = ctx.getAttributes(strGUID,returnedAtts);


               //print out the retrieved attributes
               System.out.println("DN: " + attr.get("distinguishedName").get());
               System.out.println("Name: " + attr.get("givenName").get() + " " + attr.get("sn").get());
               System.out.println("Mail: " + attr.get("mail").get());
               
               ctx.close();


          }
          catch (NamingException e) {
               System.err.println("Problem searching directory: " + e);
          }
     }
}












1. Re: JNDI, Active Directory and objectGUID's
 


843793 2005-9-27 上午9:28 (回复 800477)
Hi Steven,
From the above code, I manage to get the objectGUID and gets it string form and save it to the database. I tried various ways to query it using the examples you had provided to 


get back to the object
It always gave me an exception.


I had my objectGUID to be returned in the binary form even while comparing once I had that stuff in the String form. 


It did not work. Now this string in maintained in the database, is there any way to sort of reverse engineer it and obtain the same binary string as it orginally was, then I could 


use a searchfilter and obtain that object.


One more query in your AddLeadingZero method


return (k><0xF)?"0" + Integer.toHexString(k):Integer.toHexString(k);


there is no expression in java as k>< did you mean k> or k< or k!= please specify that too...




Please help, 


Thanks




2. Re: JNDI, Active Directory and objectGUID's
 


800477 2005-9-30 上午3:41 (回复 843793)
Looks like either a typo in my code, or something in the web page formatting that screwed things up.


The AddLeading Zero function is simply:
static String AddLeadingZero(int k) {
    return (k<0xF)?"0" + Integer.toHexString(k):Integer.toHexString(k);
}
If retrieving an object by the string form of its guid,because the LDAP name parser doesn't like <> characters, you must retrieve the object directly. For example:
LdapContext ctx = new InitialLdapContext(env,null);
String strGUID = "<GUID=7c448a67-923b-48ee-b21a-3451f2f758ca>";
Attributes attr = ctx.getAttributes(strGUID);
If retrieving the GUID using the binary form then you can issue an LDAP search with the binary form of the GUID (remember to escape correctly).
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String returnedAtts[] = {"sn","givenName","mail"};
searchCtls.setReturningAttributes(returnedAtts);
String searchFilter = "(objectGUID=\\67\\8a\\44\\7c\\3b\\92\\ee\\48\\b2\\1a\\34\\51\\f2\\f7\\58\\ca)";
String searchBase = "dc=antipodes,dc=com";
Naming Enumeration answer = ctx.search(searchBase,searchFilter,searchCtls);
 (0)
3. Re: JNDI, Active Directory and objectGUID's
 


843793 2005-9-30 上午11:48 (回复 800477)
Thats great it finally worked.:). I am attaching a peice of code for those who want to get the Escaped form the string. The input String is of the form


"6448d4ff-813f-432b-a0be-e2504173f0b6" and output will be the escaped string that can be used in the search filters.
i.e \ff\d4\48\64\3f\81\2b\43\a0\be\e2\50\41\73\f0\b6
     public static String objectGUID(String s){
          StringBuffer sb = new StringBuffer();
          StringTokenizer st = new StringTokenizer(s,"-");
          String temp,s1,s2,s3,s4,s5;
          temp=s1=s2=s3=s4=s5=null;
          int i=1;
          while(st.hasMoreTokens()){
              temp = st.nextToken();
              switch  (i){ 
                   case 1 :
                        s1= temp;
                        break;
                   case 2 :     
                        s2= temp;
                        break;
                   case 3 :
                        s3= temp;
                        break;
                   case 4 :
                        s4= temp;
                        break;
                   case 5 :
                        s5= temp;
                        break;
                   default :
                        break;
              }
               i++;
          }
          
          sb.append("\\" + s1.substring(6,8));
          sb.append("\\" + s1.substring(4,6));
          sb.append("\\" + s1.substring(2,4));
          sb.append("\\" + s1.substring(0,2));
          
          sb.append("\\" + s2.substring(2,4));
          sb.append("\\" + s2.substring(0,2));
          
          sb.append("\\" + s3.substring(2,4));
          sb.append("\\" + s3.substring(0,2));
          
          sb.append("\\" + s4.substring(0,2));
          sb.append("\\" + s4.substring(2,4));
          
          
          sb.append("\\" + s5.substring(0,2));
          sb.append("\\" + s5.substring(2,4));
          sb.append("\\" + s5.substring(4,6));
          sb.append("\\" + s5.substring(6,8));
          sb.append("\\" + s5.substring(8,10));
          sb.append("\\" + s5.substring(10,12));
          
          return sb.toString();
     }
Thanks Steven.


4. Re: JNDI, Active Directory and objectGUID's
 


843793 2005-10-3 上午11:56 (回复 800477)
In your example you call indexes 14 and 15 of the byteArray in order to build out the entires GUID string. When i tried this against my environment, I only have 13 14 items in the 


byte array so I had to comment out those last lines. 


I also had to change how you built the byteArray becuase I was getting class cast exceptions from your example.


Here is how i am building the byteArray.
String guid = (String)attrs.get("objectGUID").get();
                              byte[] GUID = guid.getBytes();
I had to go this route becuase the .get("objectGUID") calls returns a string in my case, so the initial example of casting it as a byte[] was blowing up. 




With this in place, I was able to get a string and byte version of the GUID. When I turn around and try to query by the GUID (either as a String or a Byte version) I get no 


results. What I am thinking is that I am not converting the GUID into a valid string. Is there a way to check this, or can I send you some more examples and have you look at it? 


I feel like I am finally really close here, but am just missing a little detail.


5. Re: JNDI, Active Directory and objectGUID's
 


800477 2005-10-5 上午12:36 (回复 843793)
There must be a problem in your code as the GUID is always a fixed length. 
Don't forget to request that the objectGUID attribute is to be returned as binary data rather than a string by specifiying
env.put("java.naming.ldap.attributes.binary","objectGUID");
When performing a search using a string format of the GUID, don't forget to escape the \ characters.


6. Re: JNDI, Active Directory and objectGUID's
 


843793 2006-2-7 下午5:23 (回复 800477)
small bug here:


replace:
return (k<0xF)?"0" + Integer.toHexString(k):Integer.toHexString(k);


with:


return (k <= 0xF)?"0" + Integer.toHexString(k):Integer.toHexString(k);




7. Re: JNDI, Active Directory and objectGUID's
 


843793 2007-2-8 上午9:26 (回复 800477)
failing to specify the attribute type as binary by the following code


env.put("java.naming.ldap.attributes.binary","objectGUID");


would result in java.lang.ClassCastException if you try to typecaste it into a byte[].


To bypass this if you typecast it into String this would corrupt the 
the binary content of the objectGUID.








8. Re: JNDI, Active Directory and objectGUID's
 


843793 2007-9-14 上午8:39 (回复 843793)
in steven's code... he converts the byte array to both a string hex format (strGUID) and string byte format (byteGUID).


How do I go about converting the string hex format to the byte format or byte array?


strGUID --> byteGUID
strGUID --> GUID




9. Re: JNDI, Active Directory and objectGUID's
 


843793 2007-9-14 上午8:56 (回复 843793)
never mind....
http://forum.java.sun.com/thread.jspa?threadID=546486&messageID=2661501
10. Re: JNDI, Active Directory and objectGUID's
 


843793 2008-2-7 上午8:04 (回复 800477)
>
If retrieving an object by the string form of its guid,because the LDAP name parser doesn't like <> characters, you must retrieve the object directly. For example:
LdapContext ctx = new InitialLdapContext(env,null);
String strGUID = "<GUID=7c448a67-923b-48ee-b21a-3451f2f758ca>";
Attributes attr = ctx.getAttributes(strGUID);
Would this work if I use along with DirSync for each object obtained from Active Directory? would I have to specify any special search control?






11. Re: JNDI, Active Directory and objectGUID's
 


800479 2009-3-13 上午5:14 (回复 800477)
Thanks guys.

This was too appreciate to me!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值