java查询AD系统用户、新增、删除用户
包含了我查询、删除遇到的坑
1.只能查询1000条的结果。
2.无法删除AD用户下存在手机信息问题。
直接上代码
package com.example.demo.test.adTest;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import java.util.*;
public class ADUserUtils {
LdapContext dc = null;
String root = "DC=ceshi,DC=com"; // LDAP的根节点的DC
String addRoot = "OU=测试部门,OU=XXX公司,DC=ceshi,DC=com"; // 新增用户的节点
String delRoot = "CN=王五,OU=测试部门,OU=XXX公司,DC=ceshi,DC=com"; // LDAP的根节点的DC
public static void main(String[] args) {
String userUrl = "";
ADUserUtils utils = new ADUserUtils();
String newUserName = "王五";
String newUserNameShort = "wangw";
//查询用户
Map str = utils.searchByUserName(utils.root, newUserNameShort);
//新增用户
utils.add(newUserName,newUserNameShort);
//删除AD用户
utils.delete(utils.delRoot);
utils.close();
}
public ADUserUtils() {
super();
init();
}
/**
* @Description:初始化AD域服务连接
* @author maxb
* @date 2022-03-25
*/
public void init() {
Properties env = new Properties();
String adminName = "userName";//AD管理员系统的账号一般:userName@ceshi.com 或者 userName
String adminPassword = "password";//password
String ldapURL = "ldap://" + host + ":" + post;//ip:192.168.0.0.1 port:端口默认389
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");// LDAP工厂类
env.put(Context.SECURITY_AUTHENTICATION, "simple");//LDAP访问安全级别:"none","simple","strong"
env.put(Context.SECURITY_PRINCIPAL, adminName);
env.put(Context.SECURITY_CREDENTIALS, adminPassword);
env.put(Context.PROVIDER_URL, ldapURL);
try {
dc = new InitialLdapContext(env, null);
System.out.println("AD域服务连接认证成功");
} catch (Exception e) {
System.out.println("AD域服务连接认证失败");
e.printStackTrace();
}
}
/**
* @Description:关闭AD域服务连接
* @author maxb
* @date 2022-03-25
*/
public void close() {
if (dc != null) {
try {
dc.close();
} catch (NamingException e) {
System.out.println("NamingException in close():" + e);
}
}
}
/**
* @Description:新增AD域用户
* @author maxb
* @date 2022-03-25
*/
public void add(String newUserName,String newUserNameShort) {
try {
Attributes attrs = new BasicAttributes(true);
attrs.put("objectClass", "user");
attrs.put("samAccountName", newUserNameShort);
attrs.put("displayName", newUserName);
attrs.put("userPrincipalName", newUserNameShort + "@chinatelling.com");
dc.createSubcontext("CN=" + newUserName + "," + addRoot, attrs);
System.out.println("新增AD域用户成功:" + newUserName);
} catch (Exception e) {
e.printStackTrace();
System.out.println("新增AD域用户失败:" + newUserName);
}
}
/**
* @Description:删除AD域用户
* @author maxb
* @date 2022-03-25
*/
public void delete(String dn) {
try {
dc.destroySubcontext(dn);
System.out.println("删除AD域用户成功:" + dn);
} catch (Exception e) {
System.out.println("删除AD域用户失败:" + dn);
e.printStackTrace();
}
}
/**
* @Description:指定搜索节点搜索指定域用户
* @author maxb
* @date 2022-03-25
*/
public Map searchByUserName(String searchBase, String userName) {
Map resultMap = new HashMap();
List<Map<String,String>> userList = new ArrayList<Map<String,String>>();
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String searchFilter = "(&(objectClass=user))";
String returnedAtts[] = { "memberOf", "distinguishedName","Pwd-Last-Set", "User-Password", "cn"}; //定制返回属性
searchCtls.setReturningAttributes(returnedAtts); //设置返回属性集
try {
NamingEnumeration<SearchResult> answer = dc.search(searchBase,searchFilter, searchCtls);
while (answer.hasMoreElements()) {// 遍历结果集
SearchResult sr = answer.next();
Attributes Attrs = sr.getAttributes();// 得到域用户属性集
if (Attrs != null) {
try {
Map<String,String> m = new HashMap();
for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {
Attribute Attr = (Attribute) ne.next();// 得到下一个属性
String key = Attr.getID().toString();
// 读取属性值
for (NamingEnumeration e = Attr.getAll(); e.hasMore();) {
String value= e.next().toString();
m.put(key, value);
}
}
userList.add(m);
} catch (Exception e) {
System.err.println("Throw Exception : " + e);
}
}
}//while
//获取指定用户信息
for (int i = 0; i < userList.size(); i++) {
Map<String, String> m = userList.get(i);
for(Map.Entry<String, String> entry : m.entrySet()){
String mapKey = entry.getKey();
String mapValue = entry.getValue();
System.out.println("第"+(i+1)+"个用户key = "+mapKey+" , value = "+mapValue);
}
}
} catch (Exception e) {
System.err.println("指定搜索节点搜索指定域用户失败");
e.printStackTrace();
}
return resultMap;
}
}
查询过程出现的坑:查询结果只展示1000条数据
- 方案一:直接扩大AD域的MaxPageSize(不推荐),具体可百度查询其他博主的,网上好多
- 方案二:可分页查询(我参考的一位大佬的 分页查询AD结果)
/**
* @Description:指定搜索节点搜索指定域用户(分页)
* @author maxb
* @date 2022-03-26
*/
public Map searchByUserName(String searchBase, String userName) {
Map resultMap = new HashMap();
List<Map<String,String>> userList = new ArrayList<Map<String,String>>();
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
int pageSize = 1000;//程序单次查询最大条数
String searchFilter = "(&(objectClass=user))";
String returnedAtts[] = { "memberOf", "distinguishedName","Pwd-Last-Set", "User-Password", "cn"}; //定制返回属性
searchCtls.setReturningAttributes(returnedAtts); //设置返回属性集
try {
byte[] cookie = null;//用于判断是否还有剩余数据(进行分页)
dc.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.CRITICAL)});
do{
NamingEnumeration<SearchResult> answer = dc.search(searchBase,searchFilter, searchCtls);
Object o = answer.nextElement();
while (answer.hasMoreElements()) {// 遍历结果集
SearchResult sr = answer.next();
Attributes Attrs = sr.getAttributes();// 得到域用户属性集
if (Attrs != null) {
try {
Map<String,String> m = new HashMap();
for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {
Attribute Attr = (Attribute) ne.next();// 得到下一个属性
String key = Attr.getID().toString();
// 读取属性值
for (NamingEnumeration e = Attr.getAll(); e.hasMore();) {
String value= e.next().toString();
m.put(key, value);
}
}
userList.add(m);
} catch (Exception e) {
System.err.println("Throw Exception : " + e);
}
}
}//while
Control[] controls = dc.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
cookie = prrc.getCookie();
}
}
}
// 将cookie提供给LdapContext,让它在接下来的查询中进行换页
dc.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie, Control.CRITICAL)});
}while (cookie != null);
//获取指定用户信息
for (int i = 0; i < userList.size(); i++) {
Map<String, String> m = userList.get(i);
for(Map.Entry<String, String> entry : m.entrySet()){
String mapKey = entry.getKey();
String mapValue = entry.getValue();
System.out.println("第"+(i+1)+"个用户key = "+mapKey+" , value = "+mapValue);
}
}
} catch (Exception e) {
System.err.println("指定搜索节点搜索指定域用户失败");
e.printStackTrace();
}finally {
if (null != dc) {
try {
dc.close();
dc = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
return resultMap;
}
java 删除AD用户出现的坑:
这个坑是因为我们系统里的AD用户用手机登录过邮箱,所以在AD账户下级自动创建了手机信息,导致直接执行删除时,无法删除。报6003错误
解决方案:递归删除
String node= "CN=王五,OU=测试部门,OU=XXX公司,DC=ceshi,DC=com";
public void delTree(String node){
NamingEnumeration<?> ne = null;
try {
ne = dc.listBindings(node);//枚举绑定在指定上下文中的名称,以及绑定到这些名称的对象
while(ne.hasMore()){
Binding bing = (Binding)ne.next();
String newNode = bing.getName() + "," + node;
System.out.println(node + "的子节点" + newNode);
delTree(newNode);//递归
}
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
delete(node);//删除无子节点的节点
}