因為工作需求近期做過一個從客戶AD域獲取數據實現單點登錄的功能,在此整理分享。
前提:用戶可能有很多系統的情況下,為了方便賬號的統一管理使用AD域驗證登錄,所以不需要我們的系統登錄,就需要獲取用戶的AD域組織和用戶信息,實現域認證和單點登錄。
LDAP: LDAP是輕量目錄訪問協議
AD域:微軟基於域模式的集中化管理
1.常規的AD域登陸驗證
LdapContext dc = null;
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://ld.123.com:389");//AD域路徑和端口號
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.REFERRAL, "throw");
env.put("java.naming.ldap.attributes.binary", "objectGUID");// objectGUID也可以指定為其它屬性
try {
DirContext ctx = new InitialDirContext(env);
System.out.println("認證成功");
ctx.close();
} catch (Exception e) {
System.out.println("認證失敗");
}
2.獲取AD域用戶組織及屬性信息
獲取AD域連接:
private static void entryActiveDirectory() throws NamingException {
LdapContext dc = null;
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://ld.123.com:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, " ld\\admin");
env.put(Context.SECURITY_CREDENTIALS, passwprd);
env.put(Context.REFERRAL, "throw");
dc = new InitialLdapContext(env, null);
String dn="OU=集團總部,OU=Greenland,DC=ld,DC=Greenland,DC=com";
processOrganize(dc,dn);
}
數據處理
//要獲取的對象屬性
private static String[] attributeNames = { "memberOf", "name", "userPrincipalName", "objectClass", "objectGUID","sAMAccountName","description" };
NamingEnumeration<?> contentsEnum = dc.list(dn);
while (contentsEnum.hasMore()) {
NameClassPair ncp = (NameClassPair) contentsEnum.next();
String ncpName = ncp.getName();
// 對特殊字符的DN跳過
if ((ncpName + "," + dn).indexOf("\"") != -1 || (ncpName + "," + dn).indexOf("/") != -1) {continue;}
Attributes atts = dc.getAttributes(ncpName + "," + dn, attributeNames);
//獲取對象屬性
Attribute objectClassAuttribute = atts.get("objectClass");
if (objectClassAuttribute.toString().indexOf("user") != -1) {//獲取用戶是user,部門組織是organizationalUnit
System.out.println(atts+ncpName + "," + dn); }
}
3.GUID的處理方式
objectguid是AD域組織和用戶的唯一標識,當用戶或組織修改名字后也不會發生變化,但是其他屬性通過上面的方式都可以獲取到正常值,包括中文。
但是objectguid是個例外,正常情況下都會出現亂碼,而且一般的轉碼方式都是無效的(本人已經嘗試了許多種),通過網上多種方式搜尋的答案許多都不靠譜,
最后在國外的一個論壇上找到了這個方法,首先聲明下,這個方法獲取的guid和AD域中看到的還是不一樣的,但是,也是可以保證唯一性的,而且修改名字后,
再次獲取也不會發生變化,所以可用,以下的處理代碼:
Object oo= atts.get("objectguid").get();
byte[] GUID = toByteArray(oo);
String 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);
System.out.println("GUID (String format): " + strGUID);