参考:
package com.cy.sendmail.util;
import com.cy.sendmail.domain.ADUser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.*;
/**
* @author z
* @title: getInfoFromAD
* @projectName sendmail
* @description: 通过LDAP从AD域获取信息
* @date 2020/11/16 13:49
*/
@Component
public class GetInfoFromAD {
@Value("${ADServer.ip}")
private String ip;
@Value("${ADServer.port}")
private String port;
@Value("${ADServer.adminName}")
private String adminName;
@Value("${ADServer.pwd}")
private String pwd;
@Value("${ADServer.searchBase}")
private String searchBase;
private LdapContext ctx = null;
/**
* 用户认证
*/
public void ldap_connect() {
String url = "ldap://" + ip + ":" + port;
Hashtable hashEnv = new Hashtable();
// LDAP安全访问级别,"none", "simple", "strong"
hashEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
// 管理员账号密码
hashEnv.put(Context.SECURITY_PRINCIPAL, adminName);
hashEnv.put(Context.SECURITY_CREDENTIALS, pwd);
// LDAP工厂类
hashEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
hashEnv.put(Context.PROVIDER_URL, url);
try {
ctx = new InitialLdapContext(hashEnv, null);
System.out.println("域控认证成功");
} catch (Exception e) {
System.out.println("域控认证失败");
e.printStackTrace();
}
}
/**
* 关闭连接
*/
public void ldap_close(){
try{
if(ctx != null) {
ctx.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取域控用户信息
*/
public List<ADUser> getUserInfo() {
int i = 0;
// 用户信息稽核
List<ADUser> userList = new ArrayList<>();
// 域节点,CN-用户,OU-组,DC-域
String searchBase = this.searchBase;
// LDAP搜索过滤器类
String searchFilter = "objectClass=User";
// 搜索控制器
SearchControls searchCtls = new SearchControls();
// 创建搜索控制器
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// 设置返回的用户属性,可以不设置,用户返回属性会很多
String returnedAtts[] = {"memberOf", "name", "mail", "userPrincipalName", "pwdlastset", "lockoutTime", "useraccountcontrol"};
// 设置返回属性集
searchCtls.setReturningAttributes(returnedAtts);
try{
// 根据设置的域节点、过滤器类和搜索控制器搜索LDAP得到结果
NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
// 遍历结果
while (answer.hasMore()) {
ADUser user = new ADUser(); // 定义用户
SearchResult sr = (SearchResult) answer.next();// 根据查询属性返回查询结果
Attributes attrs = sr.getAttributes();// 得到符合条件的属性集
// 获取对象属性
Attribute name = attrs.get("name"); // 用户中文名
user.setDisplayName(name.get().toString());
Attribute mail = attrs.get("mail"); // 用户邮箱
user.setMail(mail == null ? "" : mail.get().toString());
Attribute pwdLastSet = attrs.get("pwdlastset"); // 上次密码修改时间
user.setPwdLastSet(adExpiresToDate(Long.valueOf(pwdLastSet.get().toString()))); // 进行字符戳转换后赋值
Attribute uac = attrs.get("useraccountcontrol");// 用户控制,用于判断用户密码是否永不过期,该属性详情参考上面链接
user.setUserAccountControl(uac.get().toString());
if(!user.getMail().equals("")) { // 有邮箱,且密码设置了非永久不过期的账号
userList.add(user);
System.out.println(++i + "----" +user.toString());
}
}
}catch(Exception e){
e.printStackTrace();
}
return userList;
}
/**
* AD账户时间戳转换,windows NT时间转Date
* @param pwdLastSet
* @return
*/
public Date adExpiresToDate(long pwdLastSet){
long timeStamp = pwdLastSet - 116445312000000000L;
timeStamp = Long.parseLong(String.valueOf(timeStamp).substring(0, 13)) + 57599875L;
return new Date(timeStamp);
}
}
①2022..4.11更新,发现BUG:
当域控用户超过1000条记录时,系统报错超过MaxPageLimit,域控服务器默认只提供1000条,需要在AD域控服务器调整策略,报错信息:
javax.naming.SizeLimitExceededException: [LDAP: error code 4 - SizeLimit Exceeded]: remaining name '***********************'