JAVA使用Ldap操作AD域的方法示例
项目上遇到的需要在集成操作域用户的信息的功能,第一次接触ad域,因为不了解而且网上其他介绍不明确,比较费时,这里记录下。
说明:
(1).特别注意:Java操作查询域用户信息获取到的数据和域管理员在电脑上操作查询的数据可能会存在差异(同一个意思的表示字段,两者可能不同)。
(2).连接ad域有两个地址:ldap://XXXXX.com:389和ldap://XXXXX.com:636(SSL)。
(3).端口389用于一般的连接,例如登录,查询等非密码操作,端口636安全性较高,用户密码相关操作,例如修改密码等。
(4). 域控可能有多台服务器,之间数据同步不及时,可能会导致已经修改的数据被覆盖掉,这个要么域控缩短同步的时间差,要么同时修改每一台服务器的数据。
1.389登录
//只要不抛出异常就是验证通过 publicLdapContextadLogin(JSONObjectjson){ Stringusername=json.getString("username"); Stringpassword=json.getString("password"); Stringserver="ldap://XXXXXXX.com:389"; try{ Hashtableenv=newHashtable (); //用户名称,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"); LdapContextldapContext=newInitialLdapContext(env,null); log.info("ldapContext:"+ldapContext); log.info("用户"+username+"登录验证成功"); returnldapContext; }catch(NamingExceptione){ log.info("用户"+username+"登录验证失败"); log.info("错误信息:"+e.getExplanation()); returnnull; } }
2.636登录验证(需要导入证书)
//证书提前倒入的Java库中 //参考:https://www.cnblogs.com/moonson/p/4454159.html LdapContextadLoginSSL(JSONObjectjson){ Stringusername=json.getString("username"); Stringpassword=json.getString("password"); Hashtableenv=newHashtable(); StringjavaHome=System.getProperty("java.home"); Stringkeystore=javaHome+"/lib/security/cacerts"; log.info("java.home,{}",keystore); //加载导入jdk的域证书 System.setProperty("javax.net.ssl.trustStore",keystore); System.setProperty("javax.net.ssl.trustStorePassword","changeit"); StringLDAP_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{ LdapContextldapContext=newInitialLdapContext(env,null); log.info("认证成功");//这里可以改成异常抛出。 returnldapContext; }catch(javax.naming.AuthenticationExceptione){ log.info("认证失败:{}",e.getMessage()); }catch(Exceptione){ log.info("认证出错:{}",e.getMessage()); } returnnull; }
3.查询域用户信息
publicListgetUserKey(JSONObjectjson){ JSONObjectadmin=newJSONObject(); admin.put("username","Aaaaa"); admin.put("password","bbbbbbbb"); Stringname=json.getString("name"); log.info("需要查询的ad信息:{}",name); ListresultList=newJSONArray(); LdapContextldapContext=adLogin(admin);//连接到域控 if(ldapContext!=null){ Stringcompany=""; Stringresult=""; try{ //域节点 StringsearchBase="DC=XXXXXXX,DC=com"; //LDAP搜索过滤器类 //cn=*name*模糊查询 //cn=name精确查询 //StringsearchFilter="(objectClass="+type+")"; StringsearchFilter="(sAMAccountName="+name+")";//查询域帐号 //创建搜索控制器 SearchControlssearchCtls=newSearchControls(); StringreturnedAtts[]={"description","sAMAccountName","userAccountControl"}; searchCtls.setReturningAttributes(returnedAtts);//设置指定返回的字段,不设置则返回全部 //设置搜索范围深度 searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); //根据设置的域节点、过滤器类和搜索控制器搜索LDAP得到结果 NamingEnumerationanswer=ldapContext.search(searchBase,searchFilter,searchCtls); //初始化搜索结果数为0 inttotalResults=0; introws=0; while(answer.hasMoreElements()){//遍历结果集 SearchResultsr=(SearchResult)answer.next();//得到符合搜索条件的DN ++rows; Stringdn=sr.getName(); log.info(dn); AttributesAttrs=sr.getAttributes();//得到符合条件的属性集 if(Attrs!=null){ try{ for(NamingEnumerationne=Attrs.getAll();ne.hasMore();){ AttributeAttr=(Attribute)ne.next();//得到下一个属性 //读取属性值 for(NamingEnumeratione=Attr.getAll();e.hasMore();totalResults++){ company=e.next().toString(); JSONObjecttempJson=newJSONObject(); tempJson.put(Attr.getID(),company.toString()); resultList.add(tempJson); } } }catch(NamingExceptione){ log.info("ThrowException:"+e.getMessage()); } } } log.info("总共用户数:"+rows); }catch(NamingExceptione){ log.info("ThrowException:"+e.getMessage()); }finally{ try{ ldapContext.close(); }catch(Exceptione){ e.printStackTrace(); } } } returnresultList; }
4.重置用户密码
//管理员重置用户密码,后强制用户首次登录修改密码 publicMapupdateAdPwd(JSONObjectjson){ Stringdn=json.getString("dn");//要修改的帐号(这个dn是查询的用户信息里的dn的值,而不是域账号) Stringpassword=json.getString("password");//新密码 JSONObjectadmin=newJSONObject(); admin.put("username","aaaaaaa"); admin.put("password","bbbbbbb"); Map map=newHashMap (); LdapContextldapContext=adLoginSSL(admin);//连接636端口域 ModificationItem[]mods=newModificationItem[2]; if(ldapContext!=null){ try{ StringnewQuotedPassword="\""+password+"\""; byte[]newUnicodePassword=newQuotedPassword.getBytes("UTF-16LE"); //unicodePwd:修改的字段,newUnicodePassword:修改的值 mods[0]=newModificationItem(DirContext.REPLACE_ATTRIBUTE, newBasicAttribute("unicodePwd",newUnicodePassword)); mods[1]=newModificationItem(DirContext.REPLACE_ATTRIBUTE, newBasicAttribute("pwdLastSet","0"));//首次登录必须修改密码 //修改密码 ldapContext.modifyAttributes(dn,mods); map.put("result","S"); map.put("message","成功"); }catch(Exceptione){ map.put("result","E"); map.put("message","无法重置密码"); }finally{ try{ ldapContext.close(); }catch(Exceptione){ e.printStackTrace(); } } }else{ log.info(""); map.put("result","E"); map.put("message","验证失败"); } returnmap; }
5.域账号解锁
//表示锁定的字段需要测试,不一定这个lockoutTime publicMapdeblocking(JSONObjectjson){ JSONObjectadmin=newJSONObject(); Stringdn=json.getString("dn");//被解锁的帐号(这个dn指的是查询用户信息里的dn的值,不是域账号) admin.put("username","aaaaaa"); admin.put("password","bbbbbb"); Map map=newHashMap (); LdapContextldapContext=adLogin(admin); ModificationItem[]mods=newModificationItem[1]; if(ldapContext!=null){ try{ //"0"表示未锁定,不为0表示锁定 mods[0]=newModificationItem(DirContext.REPLACE_ATTRIBUTE, newBasicAttribute("lockoutTime","0")); //解锁域帐号 ldapContext.modifyAttributes(dn,mods); map.put("result","S"); map.put("message","成功"); }catch(Exceptione){ map.put("result","E"); map.put("message","解锁失败"); }finally{ try{ ldapContext.close(); }catch(Exceptione){ e.printStackTrace(); } } }else{ map.put("result","E"); map.put("message","验证失败"); } returnmap; }
Java通过Ldap操作AD的增删改查询
packagecom.smnpc.util; importjava.util.Hashtable; importjava.util.Vector; importjavax.naming.Context; importjavax.naming.NamingEnumeration; importjavax.naming.NamingException; importjavax.naming.directory.Attribute; importjavax.naming.directory.Attributes; importjavax.naming.directory.BasicAttribute; importjavax.naming.directory.BasicAttributes; importjavax.naming.directory.DirContext; importjavax.naming.directory.InitialDirContext; importjavax.naming.directory.ModificationItem; importjavax.naming.directory.SearchControls; importjavax.naming.directory.SearchResult; importjavax.naming.ldap.LdapContext; /** *Java通过Ldap操作AD的增删该查询 *@authorguob */ publicclassLdapbyUser{ DirContextdc=null; Stringroot="dc=example,dc=com";//LDAP的根节点的DC /** * *@paramdn类似于"CN=RyanHanson,dc=example,dc=com" *@paramemployeeID是Ad的一个员工号属性 */ publicLdapbyUser(Stringdn,StringemployeeID){ init(); //add();//添加节点 //delete("ou=hi,dc=example,dc=com");//删除"ou=hi,dc=example,dc=com"节点 //renameEntry("ou=new,o=neworganization,dc=example,dc=com","ou=neworganizationalUnit,o=neworganization,dc=example,dc=com");//重命名节点"ou=new,o=neworganization,dc=example,dc=com" //searchInformation("dc=example,dc=com","","sAMAccountName=guob");//遍历所有根节点 modifyInformation(dn,employeeID);//修改 //Ldapbyuserinfo("guob");//遍历指定节点的分节点 close(); } /** * *Ldap连接 * *@returnLdapContext */ publicvoidinit(){ Hashtableenv=newHashtable(); StringLDAP_URL="ldap://xxxx:389";//LDAP访问地址 StringadminName="example\\user";//注意用户名的写法:domain\User或 StringadminPassword="userpassword";//密码 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL,LDAP_URL); env.put(Context.SECURITY_AUTHENTICATION,"simple"); env.put(Context.SECURITY_PRINCIPAL,adminName); env.put(Context.SECURITY_CREDENTIALS,adminPassword); try{ dc=newInitialDirContext(env);//初始化上下文 System.out.println("认证成功");//这里可以改成异常抛出。 }catch(javax.naming.AuthenticationExceptione){ System.out.println("认证失败"); }catch(Exceptione){ System.out.println("认证出错:"+e); } } /** *添加 */ publicvoidadd(StringnewUserName){ try{ BasicAttributesattrs=newBasicAttributes(); BasicAttributeobjclassSet=newBasicAttribute("objectClass"); objclassSet.add("sAMAccountName"); objclassSet.add("employeeID"); attrs.put(objclassSet); attrs.put("ou",newUserName); dc.createSubcontext("ou="+newUserName+","+root,attrs); }catch(Exceptione){ e.printStackTrace(); System.out.println("Exceptioninadd():"+e); } } /** *删除 * *@paramdn */ publicvoiddelete(Stringdn){ try{ dc.destroySubcontext(dn); }catch(Exceptione){ e.printStackTrace(); System.out.println("Exceptionindelete():"+e); } } /** *重命名节点 * *@paramoldDN *@paramnewDN *@return */ publicbooleanrenameEntry(StringoldDN,StringnewDN){ try{ dc.rename(oldDN,newDN); returntrue; }catch(NamingExceptionne){ System.err.println("Error:"+ne.getMessage()); returnfalse; } } /** *修改 * *@return */ publicbooleanmodifyInformation(Stringdn,StringemployeeID){ try{ System.out.println("updating...\n"); ModificationItem[]mods=newModificationItem[1]; /*修改属性*/ //Attributeattr0=newBasicAttribute("employeeID","W20110972"); //mods[0]=newModificationItem(DirContext.REPLACE_ATTRIBUTE,attr0); /*删除属性*/ //Attributeattr0=newBasicAttribute("description", //"陈轶"); //mods[0]=newModificationItem(DirContext.REMOVE_ATTRIBUTE, //attr0); /*添加属性*/ Attributeattr0=newBasicAttribute("employeeID",employeeID); mods[0]=newModificationItem(DirContext.ADD_ATTRIBUTE,attr0); /*修改属性*/ dc.modifyAttributes(dn+",dc=example,dc=com",mods); returntrue; }catch(NamingExceptione){ e.printStackTrace(); System.err.println("Error:"+e.getMessage()); returnfalse; } } /** *关闭Ldap连接 */ publicvoidclose(){ if(dc!=null){ try{ dc.close(); }catch(NamingExceptione){ System.out.println("NamingExceptioninclose():"+e); } } } /** *@parambase:根节点(在这里是"dc=example,dc=com") *@paramscope:搜索范围,分为"base"(本节点),"one"(单层),""(遍历) *@paramfilter:指定子节点(格式为"(objectclass=*)",*是指全部,你也可以指定某一特定类型的树节点) */ publicvoidsearchInformation(Stringbase,Stringscope,Stringfilter){ SearchControlssc=newSearchControls(); if(scope.equals("base")){ sc.setSearchScope(SearchControls.OBJECT_SCOPE); }elseif(scope.equals("one")){ sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); }else{ sc.setSearchScope(SearchControls.SUBTREE_SCOPE); } NamingEnumerationne=null; try{ ne=dc.search(base,filter,sc); //UsetheNamingEnumerationobjecttocyclethrough //theresultset. while(ne.hasMore()){ System.out.println(); SearchResultsr=(SearchResult)ne.next(); Stringname=sr.getName(); if(base!=null&&!base.equals("")){ System.out.println("entry:"+name+","+base); }else{ System.out.println("entry:"+name); } Attributesat=sr.getAttributes(); NamingEnumerationane=at.getAll(); while(ane.hasMore()){ Attributeattr=(Attribute)ane.next(); StringattrType=attr.getID(); NamingEnumerationvalues=attr.getAll(); Vectorvals=newVector(); //AnotherNamingEnumerationobject,thistime //toiteratethroughattributevalues. while(values.hasMore()){ ObjectoneVal=values.nextElement(); if(oneValinstanceofString){ System.out.println(attrType+":"+(String)oneVal); }else{ System.out.println(attrType+":"+newString((byte[])oneVal)); } } } } }catch(Exceptionnex){ System.err.println("Error:"+nex.getMessage()); nex.printStackTrace(); } } /** *查询 * *@throwsNamingException */ publicvoidLdapbyuserinfo(StringuserName){ //Createthesearchcontrols SearchControlssearchCtls=newSearchControls(); //Specifythesearchscope searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); //specifytheLDAPsearchfilter StringsearchFilter="sAMAccountName="+userName; //SpecifytheBaseforthesearch搜索域节点 StringsearchBase="DC=example,DC=COM"; inttotalResults=0; StringreturnedAtts[]={"url","whenChanged","employeeID","name", "userPrincipalName","physicalDeliveryOfficeName", "departmentNumber","telephoneNumber","homePhone","mobile", "department","sAMAccountName","whenChanged","mail"};//定制返回属性 searchCtls.setReturningAttributes(returnedAtts);//设置返回属性集 //searchCtls.setReturningAttributes(null);//不定制属性,将返回所有的属性集 try{ NamingEnumerationanswer=dc.search(searchBase,searchFilter, searchCtls); if(answer==null||answer.equals(null)){ System.out.println("answerisnull"); }else{ System.out.println("answernotnull"); } while(answer.hasMoreElements()){ SearchResultsr=(SearchResult)answer.next(); System.out .println("************************************************"); System.out.println("getname="+sr.getName()); AttributesAttrs=sr.getAttributes(); if(Attrs!=null){ try{ for(NamingEnumerationne=Attrs.getAll();ne .hasMore();){ AttributeAttr=(Attribute)ne.next(); System.out.println("AttributeID=" +Attr.getID().toString()); //读取属性值 for(NamingEnumeratione=Attr.getAll();e .hasMore();totalResults++){ Stringuser=e.next().toString();//接受循环遍历读取的userPrincipalName用户属性 System.out.println(user); } //System.out.println("---------------"); ////读取属性值 //Enumerationvalues=Attr.getAll(); //if(values!=null){//迭代 //while(values.hasMoreElements()){ //System.out.println("2AttributeValues=" //+values.nextElement()); //} //} //System.out.println("---------------"); } }catch(NamingExceptione){ System.err.println("ThrowException:"+e); } } } System.out.println("Number:"+totalResults); }catch(Exceptione){ e.printStackTrace(); System.err.println("ThrowException:"+e); } } /** *主函数用于测试 *@paramargs */ publicstaticvoidmain(String[]args){ newLdapbyUser("CN=RyanHanson","bbs.it-home.org"); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。