猫咪家
首页
分类
标签
归档
关于
管理员
2021-05-30
1274
JAVA控制AD域进行基本的操作详解
```java 一、安装域控服务器 什么是域控服务器我就不多说了,请各位自行百度,安装的教程在下面的连接里:http://www.jb51.net/os/windows/win2008/69883.html 二、安装证书控制服务 1. AD域控安装证书服务 https://wenku.baidu.com/view/91fad77b5acfa1c7aa00ccbc.html 2. 从ad域上拿ca证书文件 http://ad域服务器IP/certsrv/ 1)点链接:下载 CA证书、证书链或CRL 2)选择编码base64 3)点链接:下载 CA证书 ps:这里采用的是结合ad服务器上的证书颁发机构,如果要采用第三方机构发布的证书需要另行配置,详情看我的另一篇文章。 3. 根据CA证书生成keystore文件 三、ping通虚拟机 我相信大部分人做这个开发应该是在虚拟机上做开发测试的,ping通虚拟机是必不可少的。 四、编写Java代码 如果你完成了上述步骤,那么恭喜你,基本的环境你已经搭建完成了,现在可以开始我们的开发。首先介绍一下AD域的用户存储,实际上就是一个ldap的目录存储过程,所以我们可以根据对ldap的访问模式访问到ad域上的对象,例如我想访问AD与上名为上海的OU下的一个用户test1,那么我可以访问“CN=test1,OU=上海,DC=adserv,DC=com”(后面的DC是我的域控服务器的名字如:adserv.com)。知道了如何访问指定对象,那么接下来的事情不是变得简单了?下面是我借鉴了网上的一些大牛的代码,自己编写的操作类如有什么异常,非常欢迎您的指点哦 1.第一步 创建Ldap连接,因为AD域的连接控制本质上就是对Ldap的控制,所以获取了ldap的连接就是获取了AD域的操作权。 2.第二步 完成上述代码之后下面的增删查改,只要通过getConnect()方法获取链接就可以进行操作。 a.添加用户操作新建用户的话一般新建在一个OU(组织结构)中,而我的需求中是要对在添加用户的时候输入用户名和所属OU,用户不存在则创建,若该用户存在就移入新的OU,如果OU不存就逐层创建OU再保存这个用户。用户信息的话是使用一个Attributes对象进行包装由前台传进来的(这里需要说明的是,每一个对象都有自己特定的类型,所以我们在创建对象时必须要确定创建的类型,就是下文的type,我将他提取出来),具体的对象属性可以参考这篇文章《AD域用户属性》还有对新的用户账号的权限设置《AD用户属性userAccountControl的详细解释》,下面是实现代码: public static boolean addUser(String userOU, String userName,String passWord, Attributes attrs, String type)throws NamingException { final int UF_PASSWD_NOTREQD = 0x0020; final int UF_NORMAL_ACCOUNT = 0x0200; final int UF_PASSWORD_EXPIRED = 0x800000; LdapContext ctx = null; String userDN = ""; try { if (!"organizationalUnit".equals(type)) { userDN = "CN=" + userName + ","; } else { userDN = "OU=" + userName + ","; } ctx = getConn(); // create the organizational structure that does not exist String[] OU = userOU.split(","); String ou = ""; for (int i = OU.length - 1; i >= 0; i--) { ou = "OU=" + OU[i] + "," + ou; if (i == 0) userDN = userDN + ou + "DC=adserv,DC=com"; String OUDN = ou + "DC=adserv,DC=com"; try { ctx.getAttributes(OUDN); } catch (NameNotFoundException e) { addOU(OUDN); } } try { if ("organizationalUnit".equals(type)) { attrs.put("objectClass", "organizationalUnit"); ctx.createSubcontext(userDN, attrs); return true; } // required attributes attrs.put("objectClass", type); attrs.put("sAMAccountName", userName); ctx.createSubcontext(userDN, attrs); } catch (NameAlreadyBoundException e) { if("organizationalUnit".equals(type)){ System.out.println("The organizational unit already exists"); return false; }else{ String oldDN = searchEntity(userName, type); changeOU(oldDN, ou); modifyUser(attrs, userName, type); System.out.println("User already exists, has been moved into the organization unit"); } } if(passWord!=null){ ModificationItem[] mods = new ModificationItem[2]; // format the password String newQuotedPassword = "\"" + passWord + "\""; //format password byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE"); mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword)); mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl", Integer.toString(UF_NORMAL_ACCOUNT + UF_PASSWORD_EXPIRED + UF_PASSWD_NOTREQD))); // save the password ctx.modifyAttributes(userDN, mods); mods = null;} return true; } catch (NamingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (ctx != null) { ctx.close(); ctx = null; } } return false; } ps:如果使用的389接口的话使用上述代码还是能实现创建对象,但是创建时会报错(据我估计就是安全错误,要求你使用ssl),并且创建的对象时无法设置密码的,但是如果你们可以不使用ssl设置密码的话请教教我,谢谢。、 b.用户删除 删除操作较为简单,确定删的对象类型(对象类型会在下面内容中介绍)就可以了。代码如下: public static boolean delEntity(String entityName,String entityType) throws NamingException { LdapContext ctx = null; try{ String DN=searchEntity(entityName,entityType); ctx=getConn(); if(DN!=null){ ctx.destroySubcontext(DN); }else{ System.out.println("delete Entity not exist"); return false; } return true; } catch (Exception e) { System.err.println("Problem: " + e); } finally { if (ctx != null) { ctx.close(); ctx = null; } } return false; } c.查找对象 查找兑现,与上次对象一样,要确定对象的类型,并且要确定对象名称。 我收集了几个对象的类型表达: 用户:(&(objectCategory=person)(objectClass=user); 策划机:computer;组:group; 接洽人:contact ;共享文件夹:volume; 打印机:printQueue 下面是查找的实现代码: public static String searchEntity(String entityName, String entityType) throws NamingException { LdapContext ctx = null; String OUName = ""; try { ctx = getConn(); SearchControls searchCtls = new SearchControls(); searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); String searchFilter = null; if ("user".equals(entityType)) { searchFilter = "(&(objectCategory=person)(objectClass=user)(cn=" + entityName + "))"; } else { String[] OUList = entityName.split(","); entityName = ""; for (int i = OUList.length - 1; i >= 0; i--) { entityName = "OU=" + OUList[i] + "," + entityName; OUName = OUList[0]; } searchFilter = "(&(objectCategory=organizationalUnit)(objectclass=organizationalUnit)(OU=" + OUName + "))"; } String searchBase = "DC=adserv,DC=com"; String returnedAtts[] = { "memberOf" }; searchCtls.setReturningAttributes(returnedAtts); NamingEnumeration<SearchResult> answer = ctx.search(searchBase, searchFilter, searchCtls); SearchResult sr = null; while (answer.hasMoreElements()) { sr = (SearchResult) answer.next(); if (!"".equals(OUName)) return entityName + "DC=adserv,DC=com"; return sr.getName() + ",DC=adserv,DC=com"; } } catch (NullPointerException e) { System.out.println("Entity not exist"); } catch (Exception e) { e.printStackTrace(); } finally { if (ctx != null) { ctx.close(); ctx = null; } } return null; } c.修改对象 修改对象的属性可以同个对对象的数据进行修改,封装传入,程序会比较两个对象比较修改过得地方修改保存,为修改的就不修改代码如下: public static boolean modifyUser(Attributes attrs, String entityName,String entityType) throws NamingException { LdapContext ctx = null; try { String userDN=searchEntity(entityName,entityType); ctx=getConn(); ctx.modifyAttributes(userDN, DirContext.REPLACE_ATTRIBUTE, attrs); return true; } catch (Exception e) { System.err.println("Problem: " + e); } finally { if (ctx != null) { try { ctx.close(); } catch (NamingException e) { e.printStackTrace(); } ctx = null; } } return false; } 修改对象的组织结构则是对对象名字进行修改: public static boolean changeOU(String olduserDN, String newOU) throws NamingException { LdapContext ctx =null; try{ ctx=getConn(); String[] user=olduserDN.split(","); String newDN=user[0]+","+newOU+user[user.length-2]+","+user[user.length-1]; ctx.rename(olduserDN,newDN); return true; }catch(Exception e){ e.printStackTrace(); } finally { if (ctx != null) { ctx.close(); ctx = null; } } return false; } 好了,今天暂时给大家介绍到这里,之后我会简单的介绍一下组等其他对象的操作。目前,我能做已经能做到对AD域上的大部分对象的处理,如组,打印机,联系人,上面这一段代码,复制进入就能用了,有什么问题需要讨论可以随时发私信给我。 -----------------------------2017/12/5---------------------------------------- 有读者说有一部分代码没有发出来,拉下了不好意思,现在补上 addOU:添加组织机构方法 public static boolean addOU(String OUDN) throws NamingException { LdapContext ctx = null; try { ctx = getConn(); // create a new OU Attributes attrs = new BasicAttributes(true); attrs.put("objectClass", "organizationalUnit"); ctx.createSubcontext(OUDN, attrs); return true; } catch (Exception e) { e.printStackTrace(); } finally { if (ctx != null) { ctx.close(); ctx = null; } } return false; } getConn:获取ad域连接; getConnectionFromFool:获取ad域连接池 /** * 获取连接通道,如果是636接口就返回加密通道,否则返回普通通道 * @param keyStore keyStore的文件目录 * @param sslPassWord keyStore的密码 * @param adPassWord ad域密码 * @param ldapUrl ad域地址 * @param port 使用的接口类型636/389 * @return * @throws NamingException */ public static LdapContext getConnectionFromFool(String keyStore, String sslPassWord, String adPassWord, String ldapUrl, String port) throws NamingException { Properties env = new Properties(); if ("636".equals(port)) { System.setProperty("javax.net.ssl.trustStore", keyStore); System.setProperty("javax.net.ssl.trustStorePassword", sslPassWord); env.put(Context.SECURITY_PROTOCOL, "ssl"); } env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://" + ldapUrl); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "cn=Administrator,cn=Users,dc=adserv,dc=com");//第一个cn为你的ad域管理员账户名 env.put(Context.SECURITY_CREDENTIALS, adPassWord); env.put("com.sun.jndi.ldap.connect.pool", "true"); env.put("java.naming.referral", "follow"); return new InitialLdapContext(env, null); } public static LdapContext getConn() throws NamingException { //这边就是读取配置文件中的接口 // String port = null; // if (DomainPushConfig.getInstance().useSsl) { // port = SSL_LDAP_URL_Port; // } else { // port = WITHOUT_SSL_LDAP_URL_Port; // } 下面为389连接 return getConnectionFromFool(KEYSTORE, SSL_PASSWORD, AD_PASSWORD, LDAP_URL, 389); } 构造用户对象用于测试 Attributes attrs = new BasicAttributes(true); attrs.put("Title", "工程师"); attrs.put("Department", "部门"); attrs.put("Company", "机构"); attrs.put("objectClass","user"); attrs.put("userPrincipalName",userName + "@adserv.com"); ———————————————— 版权声明:本文为CSDN博主「RYCookie」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/a6877321/article/details/71517292 ```
###Hello world!
Java
评论
发布
留言
评论