需求:员工在线更改域账号密码;解锁域账号;
环境:SpringBoot+Java8+Ldap。
必要条件:一个能改密码和解锁账号的超级管理员账号;
认证LDAP服务,跳过证书
连接LDAP,代码如下
private static DirContext ctx = null;
private static final String adminName = "cn=aaa,ou=AAAA,DC=cccc,DC=dddd,DC=com";
private static final String adminPassword = "43sdrs";
private static final String ldapUrl = "ldaps://aaa.ddddd.com:636";
public static void ldapConnect() throws NamingException {
Hashtable<Object, Object> env = new Hashtable<Object, Object>();
//解决No subject alternative DNS name xxxxx的错误
Security.setProperty("jdk.tls.disabledAlgorithms", "");
System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, adminName);
env.put(Context.SECURITY_CREDENTIALS, adminPassword);
env.put(Context.PROVIDER_URL, ldapUrl);
//绕过证书认证,别忘记输入正确的类路径
env.put("java.naming.ldap.factory.socket", "com.xxx.bbb.DummySSLSocketFactory");
ctx = new InitialDirContext(env);
}
跳过证书
需要用到三个类DummySSLSocketFactory,DummyTrustManager和TrustAllTrustManager
- DummySSLSocketFactory
public class DummySSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory factory;
public DummySSLSocketFactory() {
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[]{new DummyTrustManager()}, new java.security.SecureRandom());
factory = (SSLSocketFactory) sslcontext.getSocketFactory();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static SocketFactory getDefault() {
return new DummySSLSocketFactory();
}
public Socket createSocket(Socket socket, String s, int i, boolean flag) throws IOException {
return factory.createSocket(socket, s, i, flag);
}
public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr1, int j) throws IOException {
return factory.createSocket(inaddr, i, inaddr1, j);
}
public Socket createSocket(InetAddress inaddr, int i) throws IOException {
return factory.createSocket(inaddr, i);
}
public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
return factory.createSocket(s, i, inaddr, j);
}
public Socket createSocket(String s, int i) throws IOException {
return factory.createSocket(s, i);
}
public String[] getDefaultCipherSuites() {
return factory.getSupportedCipherSuites();
}
public String[] getSupportedCipherSuites() {
return factory.getSupportedCipherSuites();
}
}
- DummyTrustManager
public class DummyTrustManager implements X509TrustManager {
public void checkClientTrusted( X509Certificate[] cert, String authType) {
return;
}
public void checkServerTrusted( X509Certificate[] cert, String authType) {
return;
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
- TrustAllTrustManager
public class TrustAllTrustManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
}
修改域账号密码
public static void updatePwd(String account, String newPwd) throws Exception {
String userDN = getUserDomain(account);
if (StringUtils.isBlank(userDN)) {
return;
}
String newQuotedPassword = String.format("\"%s\"", newPwd);
byte[] newUnicodePassword;
newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
ModificationItem[] mods = new ModificationItem[1];
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
new BasicAttribute("unicodePwd", newUnicodePassword));
ctx.modifyAttributes(userDN, mods);
}
解锁域账号
public static void unlock(String account) throws NamingException {
String userDN = getUserDomain(account);
log.info("userDN:{}", userDN);
BasicAttributes basicAttributes = new BasicAttributes();
//512,表示Normal即正常账号
basicAttributes.put("userAccountControl", "512");
//lockOutTime表示已经锁住的事件,需要置为0可以立即解锁
basicAttributes.put("lockOutTime", "0");
ctx.modifyAttributes(userDN, DirContext.REPLACE_ATTRIBUTE, basicAttributes);
}
获取用户的域账号信息
private static String getUserDomain(String account) throws NamingException {
String userDN = null;
SearchControls contro = new SearchControls();
contro.setSearchScope(2);
NamingEnumeration<SearchResult> en = ctx.search("DC=aaa,DC=bbbbb,DC=com", "cn=" + account, contro);
if (en == null || !en.hasMoreElements()) {
return null;
}
while (en.hasMoreElements()) {
Object obj = en.nextElement();
if (obj instanceof SearchResult) {
SearchResult si = (SearchResult) obj;
Attributes attrs = si.getAttributes();
userDN = (String) attrs.get("distinguishedName").get();
break;
}
}
return userDN;
}
关闭LDAP连接
public static void closeConnect() {
try {
if (ctx != null) {
ctx.close();
}
} catch (NamingException e) {
e.printStackTrace();
}
}
示例
/**
解锁域账号
**/
public static void main(String[] args) {
try {
LdapSSLUtil.ldapConnect();
LdapSSLUtil.enableUser(adName);
} catch (Exception e) {
log.error("发送错误:{}", e.getMessage(), e);
} finally {
LdapSSLUtil.closeConnect();
}
}
参考链接
https://www.cnblogs.com/huanghongbo/p/12409209.html