ldap AD域 objectGUID objectSID

來源:互聯網
上載者:User
package org.jd.test;import java.io.UnsupportedEncodingException;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.util.Hashtable;import java.util.Vector;import javax.naming.Context;import javax.naming.NamingEnumeration;import javax.naming.NamingException;import javax.naming.directory.Attribute;import javax.naming.directory.Attributes;import javax.naming.directory.SearchControls;import javax.naming.directory.SearchResult;import javax.naming.ldap.InitialLdapContext;import javax.naming.ldap.LdapContext;/** * 非ssl方式擷取域的組織成員資訊 * @author ganjh * */public class AdTest {/** * 域:test.jd.com * user:hhx * password:12345678 * 域控伺服器ip:10.0.6.151 * @param name * @return * @throws UnsupportedEncodingException  */public String GetADInfo(String name) throws UnsupportedEncodingException {String userName = name; // 使用者名稱稱if (userName == null) {userName = "";}Object company = "";String host = "10.0.6.151"; // AD伺服器String port = "389"; // 連接埠String url = new String("ldap://" + host + ":" + port);Hashtable HashEnv = new Hashtable();// String adminName ="CN=oyxiaoyuanxy,CN=Users,DC=Hebmc,DC=com";//AD的使用者名稱String adminName = "test\\hhx"; // 注意使用者名稱的寫法:domain\UserString adminPassword = "12345678"; // 密碼HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); // LDAP訪問安全層級HashEnv.put(Context.SECURITY_PRINCIPAL, adminName); // AD UserHashEnv.put(Context.SECURITY_CREDENTIALS, adminPassword); // AD PasswordHashEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); // LDAP工廠類HashEnv.put(Context.PROVIDER_URL, url);try {LdapContext ctx = new InitialLdapContext(HashEnv, null);// 域節點String searchBase = "OU=金地集團,DC=test,DC=jd,DC=com";// LDAP搜尋過濾器類String searchFilter = "objectClass=User";// 搜尋控制器SearchControls searchCtls = new SearchControls(); // Create the// search// controls// 建立搜尋控制器searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); // Specify// the// search// scope// 設定搜尋範圍// searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE); //// Specify the search scope 設定搜尋範圍// String returnedAtts[] = { "memberOf", "distinguishedName",// "Pwd-Last-Set", "User-Password", "cn" };// 定製返回屬性String returnedAtts[] = { "company","User-Password","cn","objectSID","objectGUID","description" };// 定製返回屬性// String returnedAtts[] = { "url", "whenChanged", "employeeID",// "name", "userPrincipalName", "physicalDeliveryOfficeName",// "departmentNumber", "telephoneNumber", "homePhone",// "mobile", "department", "sAMAccountName", "whenChanged",// "mail" }; // 定製返回屬性searchCtls.setReturningAttributes(returnedAtts); // 設定返回屬性集// 根據設定的域節點、過濾器類和搜尋控制器搜尋LDAP得到結果NamingEnumeration answer = ctx.search(searchBase, searchFilter,searchCtls);// Search for objects using the filter// 初始化搜尋結果數為0int totalResults = 0;// Specify the attributes to returnint rows = 0;while (answer.hasMoreElements()) {// 遍曆結果集SearchResult sr = (SearchResult) answer.next();// 得到符合搜尋條件的DNSystem.out.println(++rows+ "************************************************");String dn = sr.getName();System.out.println(dn);String match = dn.split("CN=")[1].split(",")[0];// 返回格式一般是CN=ptyh,OU=專賣System.out.println(match);//if (userName.equals(match)) {Attributes Attrs = sr.getAttributes();// 得到合格屬性集if (Attrs != null) {try {for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {Attribute Attr = (Attribute) ne.next();// 得到下一個屬性System.out.println(" AttributeID=屬性名稱:"+ Attr.getID().toString());if("objectGUID".equals(Attr.getID())){String st = getGUID(Attr.get().toString().getBytes());// 讀取屬性值for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) {//Vector c = (Vector)e.next();//System.out.println(c.get(0));company = new String(e.next().toString().getBytes("GB2312"),"utf-8");System.out.println("    AttributeValues=屬性值:"+ new String(company.toString().getBytes("GB2312"),"utf-8"));}}System.out.println("    ---------------");}} catch (NamingException e) {System.err.println("Throw Exception : " + e);}//}// if}}// whileSystem.out.println("************************************************");System.out.println("Number: " + totalResults);ctx.close();} catch (NamingException e) {e.printStackTrace();System.err.println("Throw Exception : " + e);}return company.toString();}private static String getGUID(byte[] inArr) {StringBuffer guid = new StringBuffer();for (int i = 0; i < inArr.length; i++) {StringBuffer dblByte = new StringBuffer(Integer.toHexString(inArr[i] & 0xff));if (dblByte.length() == 1) {guid.append("0");}guid.append(dblByte);}return guid.toString();}public static void main(String args[]) throws Exception {// 執行個體化AdTest ad = new AdTest();String company = ad.GetADInfo("huanghx");//Class.forName("oracle.jdbc.driver.OracleDriver"); //Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","eas","kingdee"); //String sql = "insert into ct_cos_test(fid,objectguid) values('11111','"+company+"')";//PreparedStatement ps = conn.prepareStatement(sql);////System.out.println(ps.executeUpdate());//////rs.close();//ps.close();//conn.close();//}}

 

補充:

網上通過ldap操作AD的例子很多,我也是通過網路搜尋然後成功的搜尋了公司未知結構的AD,中間經曆了一些波折,下面總結一下過程,我相信對需要操作AD的碼工碼農們多多少少是有些協助。

1 擷取DirContext要注意的地方。

以下是構造DirContext的基本代碼:

Java代碼
  1. DirContext ctx = null; 
  2. String ldapURL = "ldap://10.0.15.1:389"; 
  3. String user = "test@xxx.com"; 
  4. String password = "restart#123"; 
  5. Hashtable env = new Hashtable(); 
  6. env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
  7. env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
  8. env.put(Context.PROVIDER_URL, ldapURL); 
  9. env.put(Context.SECURITY_PRINCIPAL, user); 
  10. env.put(Context.SECURITY_CREDENTIALS, password); 
  11. ctx = new InitialDirContext(env);
 DirContext ctx = null;  String ldapURL = "ldap://10.0.15.1:389";  String user = "test@xxx.com";  String password = "restart#123";  Hashtable env = new Hashtable();  env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");  env.put(Context.SECURITY_AUTHENTICATION, "simple");  env.put(Context.PROVIDER_URL, ldapURL);  env.put(Context.SECURITY_PRINCIPAL, user);  env.put(Context.SECURITY_CREDENTIALS, password);  ctx = new InitialDirContext(env);

 

(1) 對AD結構是未知的情況下,ldapURL的寫法保守一點比較好,所以不在連接埠後加DN。

(2) 為什麼不用網域名稱,而用IP,因為有時候通過網域名稱訪問不到AD,存在不穩定情況,擷取域地址方法,通過cmd輸入ipconfig -all找到win server既是所需ip,可能會存在多個,一般大點的公司會有多個網域控制站。

(3)使用者名稱的寫法,不能直接用使用者名稱,而要加上域資訊,如userid@domain address或domain address\userid方式,如test@xxx.com,test是域帳號,xxx.com為AD網域名稱,否則會報異常。

2 查詢要注意的地方。

因為AD結構未知,所以查詢仍然要保守點。

Java代碼
  1. DirContext cnt = null; 
  2.   try 
  3.   { 
  4.    cnt = this.getContext(); 
  5.    String base = "dc=xxx,dc=com"; 
  6.    String filter = "(&(objectClass=user)(sAMAccountName=*test*))"; 
  7.    int limitsize = 1; 
  8.    SearchControls searchCons = new SearchControls(); 
  9.    NamingEnumeration namingEnum = null; 
  10.    searchCons.setSearchScope(2); 
  11.    searchCons.setCountLimit(limitsize); 
  12.    searchCons.setTimeLimit(0); 
  13.    namingEnum = cnt.search(base, filter, searchCons); 
  14.    print(namingEnum, base, limitsize); 
  15.   } 
  16.   catch (Exception e) 
  17.   { 
  18.    e.printStackTrace(); 
  19.   } 
  20.   finally 
  21.   { 
  22.    if (cnt != null) 
  23.    { 
  24.     cnt.close(); 
  25.    } 
  26.   } 
DirContext cnt = null;  try  {   cnt = this.getContext();   String base = "dc=xxx,dc=com";   String filter = "(&(objectClass=user)(sAMAccountName=*test*))";   int limitsize = 1;   SearchControls searchCons = new SearchControls();   NamingEnumeration namingEnum = null;   searchCons.setSearchScope(2);   searchCons.setCountLimit(limitsize);   searchCons.setTimeLimit(0);   namingEnum = cnt.search(base, filter, searchCons);   print(namingEnum, base, limitsize);  }  catch (Exception e)  {   e.printStackTrace();  }  finally  {   if (cnt != null)   {    cnt.close();   }  }

 

(1) 未知AD情況下base開始唯寫出dc,因為域帳號通常不會直接建立在user節點下,一般會自己建立組織。

(2) 過濾器條件越少越好,而且最好用模糊比對,如String filter = sAMAccountName=*test*",其中test為登入帳號名。
(3)searchCons.setSearchScope(2),設為2會查詢子節點。

(4) searchCons.setTimeLimit(0),設逾時時間為0標識沒有逾時限制。

(5)因為過濾條件比較簡單而且是模糊條件,此時基本上能查出想要的資料,但節點數量很大的話查詢會比較慢,此時可以根據查詢的結果資訊來補充DN和filter,如在DN中加入OU根,在filter加上多個條件,filter加多個條件的方法(&(條件1)(條件2))。

(6)searchCons.setCountLimit(limitsize)問題,有時查詢時會報limitsize的異常,這是在遍曆查詢結果時出現的問題,下面是遍曆的部分代碼:

while (namingEnum != null && namingEnum.hasMore())

可以手工設定一個limitsize,當while迴圈次數到達limitsize時跳出while迴圈。

(7)注意關閉DirContext

3 遍曆結果要注意的問題。

(1) 時間的處理

Java代碼
  1. private String getConvertTime(Object time) 
  2.   SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
  3.   if (time == null ||
    "".equalsIgnoreCase(time.toString().trim())) 
  4.   { 
  5.    return ""; 
  6.   } 
  7.   String strTime = time.toString().trim(); 
  8.  
  9.   if (strTime.indexOf(".") != -1) 
  10.   { 
  11.    strTime = strTime.substring(0, strTime.indexOf(".")); 
  12.   } 
  13.   long longTime = Long.valueOf(strTime); 
  14.  
  15.   GregorianCalendar Win32Epoch = new GregorianCalendar(1601, Calendar.JANUARY,
    1); 
  16.   Win32Epoch.setTimeZone(TimeZone.getTimeZone("China")); 
  17.   Date Win32EpochDate = Win32Epoch.getTime(); 
  18.   long TimeSinceWin32Epoch = longTime /
    10000 + Win32EpochDate.getTime();  
  19.   Date lastLogon = new Date(TimeSinceWin32Epoch); 
  20.   return sf.format(lastLogon); 
  21.  
private String getConvertTime(Object time) {  SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  if (time == null || "".equalsIgnoreCase(time.toString().trim()))  {   return "";  }  String strTime = time.toString().trim();  if (strTime.indexOf(".") != -1)  {   strTime = strTime.substring(0, strTime.indexOf("."));  }  long longTime = Long.valueOf(strTime);  GregorianCalendar Win32Epoch = new GregorianCalendar(1601, Calendar.JANUARY, 1);  Win32Epoch.setTimeZone(TimeZone.getTimeZone("China"));  Date Win32EpochDate = Win32Epoch.getTime();  long TimeSinceWin32Epoch = longTime / 10000 + Win32EpochDate.getTime();   Date lastLogon = new Date(TimeSinceWin32Epoch);  return sf.format(lastLogon); }

這個時間是基于格林威治1601年1月1日的,這要處理兩個問題,a:加上1601年1月1日這個基礎時間-Win32EpochDate.getTime(),b:格林威治時間與你所在時區有位移量(Win32Epoch.setTimeZone(TimeZone.getTimeZone("China"));
),所以要加減位移量才是真正的時間。

(2) lastLogon與lastLogonTimestamp,其中lastLogon至少在一台AD上是即時更新的,而lastLogonTimestamp則不是通常半個月才會更新,lastLogon因為存在在不同AD上的同步問題,所以需要在所有AD上都找到lastLogon,並找出最大值才是最後的登入時間。

(3)id類的處理,id屬性值是一串位元據,需要進行轉換字串。

  1. private static String getGUID(byte[] inArr) 
  2.   StringBuffer guid = new StringBuffer(); 
  3.   for (int i =
    0; i < inArr.length; i++) 
  4.   { 
  5.    StringBuffer dblByte = new StringBuffer(Integer.toHexString(inArr[i] &
    0xff)); 
  6.    if (dblByte.length() == 1) 
  7.    { 
  8.     guid.append("0"); 
  9.    } 
  10.    guid.append(dblByte); 
  11.   } 
  12.   return guid.toString(); 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.