標籤:enum inf prope des actor 整合 serve 覆蓋 min
項目上遇到的需要在整合 操作域使用者的資訊的功能,第一次接觸ad域,因為不瞭解而且網上其他介紹不明確,比較費時,這裡記錄下。
說明:
(1). 特別注意:Java操作查詢域使用者資訊擷取到的資料和網域系統管理員在電腦上操作查詢的資料可能會存在差異(同一個意思的表示欄位,兩者可能不同)。
(2). 串連ad域有兩個地址: ldap://XXXXX.com:389 和 ldap://XXXXX.com:636(SSL)。
(3). 連接埠389用於一般的串連,例如登入,查詢等非密碼操作,連接埠636安全性較高,使用者密碼相關操作,例如修改密碼等。
(4). 域控可能有多台伺服器,之間資料同步不及時,可能會導致已經修改的資料被覆蓋掉,這個要麼域控縮短同步的時間差,要麼同時修改每一台伺服器的資料。
1. 389登入
// 只要不拋出異常就是驗證通過
public LdapContext adLogin(JSONObject json) { String username = json.getString("username"); String password = json.getString("password"); String server = "ldap://XXXXXXX.com:389"; try { Hashtable<String, String> env = new Hashtable<String, String>(); //使用者名稱稱,cn,ou,dc 分別:使用者,組,域 env.put(Context.SECURITY_PRINCIPAL, username); //使用者密碼 cn 的密碼 env.put(Context.SECURITY_CREDENTIALS, password); //url 格式:協議://ip:連接埠/組,域 ,直接連接到域或者組上面 env.put(Context.PROVIDER_URL, server); //LDAP 工廠 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); //驗證的類型 "none", "simple", "strong" env.put(Context.SECURITY_AUTHENTICATION, "simple"); LdapContext ldapContext = new InitialLdapContext(env, null); log.info("ldapContext:" + ldapContext); log.info("使用者" + username + "登入驗證成功"); return ldapContext; } catch (NamingException e) { log.info("使用者" + username + "登入驗證失敗"); log.info("錯誤資訊:"+e.getExplanation()); return null; } }
2. 636登入驗證(需要匯入認證)
//認證提前倒入的Java庫中// 參考:https://www.cnblogs.com/moonson/p/4454159.htmlLdapContext adLoginSSL(JSONObject json) {String username = json.getString("username");String password = json.getString("password");Hashtable env = new Hashtable();String javaHome = System.getProperty("java.home"); String keystore = javaHome+"/lib/security/cacerts"; log.info("java.home,{}",keystore); // 載入匯入jdk的域認證 System.setProperty("javax.net.ssl.trustStore", keystore); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); String LDAP_URL = "ldap://XXXXXX.com:636"; // LDAP訪問地址 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.SECURITY_PROTOCOL, "ssl");//連結證明伺服器 env.put(Context.PROVIDER_URL, LDAP_URL); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, username); env.put(Context.SECURITY_CREDENTIALS, password); try { LdapContext ldapContext = new InitialLdapContext(env, null); log.info("認證成功");// 這裡可以改成異常拋出。 return ldapContext; } catch (javax.naming.AuthenticationException e) { log.info("認證失敗:{}",e.getMessage()); } catch (Exception e) { log.info("認證出錯:{}",e.getMessage()); } return null; }
3. 查詢域使用者資訊
public List getUserKey(JSONObject json){ JSONObject admin = new JSONObject(); admin.put("username","Aaaaa"); admin.put("password", "bbbbbbbb"); String name = json.getString("name"); log.info("需要查詢的ad資訊:{}",name); List<JSONObject> resultList = new JSONArray(); LdapContext ldapContext = adLogin(admin); //串連到域控 if (ldapContext!=null){ String company = ""; String result = ""; try { // 域節點 String searchBase = "DC=XXXXXXX,DC=com"; // LDAP搜尋過濾器類 //cn=*name*模糊查詢
//cn=name 精確查詢 // String searchFilter = "(objectClass="+type+")"; String searchFilter = "(sAMAccountName="+name+")"; //查詢域帳號 // 建立搜尋控制器 SearchControls searchCtls = new SearchControls(); String returnedAtts[]={"description","sAMAccountName","userAccountControl"};
searchCtls.setReturningAttributes(returnedAtts); //設定指定返回的欄位,不設定則返回全部 // 設定搜尋範圍 深度 searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); // 根據設定的域節點、過濾器類和搜尋控制器搜尋LDAP得到結果 NamingEnumeration answer = ldapContext.search(searchBase, searchFilter,searchCtls); // 初始化搜尋結果數為0 int totalResults = 0; int rows = 0; while (answer.hasMoreElements()) {// 遍曆結果集 SearchResult sr = (SearchResult) answer.next();// 得到符合搜尋條件的DN ++rows; String dn = sr.getName(); log.info(dn); Attributes Attrs = sr.getAttributes();// 得到合格屬性集 if (Attrs != null) { try { for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) { Attribute Attr = (Attribute) ne.next();// 得到下一個屬性 // 讀取屬性值 for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) { company = e.next().toString(); JSONObject tempJson = new JSONObject(); tempJson.put(Attr.getID(), company.toString()); resultList.add(tempJson); } } } catch (NamingException e) { log.info("Throw Exception : " + e.getMessage()); } } } log.info("總共使用者數:" + rows); } catch (NamingException e) { log.info("Throw Exception : " + e.getMessage()); }finally { try{ ldapContext.close(); }catch (Exception e){ e.printStackTrace(); } } } return resultList; }
4. 重設使用者密碼
// 管理員重設使用者密碼,後強制使用者首次登入修改密碼public Map<String, String> updateAdPwd(JSONObject json) { String dn = json.getString("dn");//要修改的帳號(這個dn是查詢的使用者資訊裡的dn的值,而不是域帳號) String password = json.getString("password");//新密碼 JSONObject admin = new JSONObject(); admin.put("username","aaaaaaa"); admin.put("password", "bbbbbbb"); Map<String,String> map = new HashMap<String,String>(); LdapContext ldapContext = adLoginSSL(admin); //串連636連接埠域 ModificationItem[] mods = new ModificationItem[2]; if (ldapContext!=null){ try { String newQuotedPassword = "\"" + password + "\""; byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");// unicodePwd:修改的欄位,newUnicodePassword:修改的值 mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("pwdLastSet", "0")); // 首次登入必須修改密碼 // 修改密碼 ldapContext.modifyAttributes(dn, mods); map.put("result", "S"); map.put("message","成功"); }catch (Exception e){ map.put("result","E"); map.put("message", "無法重設密碼"); }finally { try{ ldapContext.close(); }catch (Exception e){ e.printStackTrace(); } } }else { log.info(""); map.put("result","E"); map.put("message", "驗證失敗"); } return map; }
5. 域帳號解鎖
// 表示鎖定的欄位需要測試,不一定這個lockoutTime
public Map<String, String> deblocking(JSONObject json) { JSONObject admin = new JSONObject(); String dn = json.getString("dn"); //被解鎖的帳號(這個dn指的是查詢使用者資訊裡的dn的值,不是域帳號) admin.put("username","aaaaaa"); admin.put("password","bbbbbb"); Map<String,String> map = new HashMap<String,String>(); LdapContext ldapContext = adLogin(admin); ModificationItem[] mods = new ModificationItem[1]; if (ldapContext!=null){ try { // "0" 表示未鎖定,不為0表示鎖定 mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("lockoutTime","0")); // 解鎖域帳號 ldapContext.modifyAttributes(dn, mods); map.put("result", "S"); map.put("message","成功"); }catch (Exception e){ map.put("result","E"); map.put("message", "解鎖失敗"); }finally { try{ ldapContext.close(); }catch (Exception e){ e.printStackTrace(); } } }else { map.put("result","E"); map.put("message", "驗證失敗"); } return map;}
JAVA使用Ldap操作AD域