AD操作的正删改查代码以及遇到的常见问题

package com.devops.devopsauth.ad.util;

import com.devops.devopscommon.exception.ServerException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
import java.util.Hashtable;

/**
 * 工具类,处理AD相关的用户操作
 * 并置为final不允许继承变更
 **/
@Slf4j
@Component
public final class ADUserUtil {

    private DirContext dc = null;
    @Value("${devops.app.ad.root}")
    private String root;
    @Value("${devops.app.ad.adminName}")
    private String adminName;
    @Value("${devops.app.ad.adminPassword}")
    private String adminPassword;
    @Value("${devops.app.ad.ldapURL}")
    private String ldapURL;
    @Value("${devops.app.ad.keystore}")
    private String keystore;

    public void  getDirContext() throws ServerException {
        // ladp的一些配置
        Hashtable env = new Hashtable();
        log.info(keystore);

        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.SECURITY_PROTOCOL, "ssl");
        env.put(Context.PROVIDER_URL, ldapURL);

        try {
            // 初始化ldapcontext
            dc = new InitialLdapContext(env, null);
        }catch (Exception e) {
            log.error("AD域服务连接认证失败",e);
            throw new ServerException("AD域名连接认证失败!");
        }
    }
    /**
     * @Description:关闭AD域服务连接
     * @author moonxy
     * @date 2018-05-15
     */
    public void close() throws ServerException {
        if (dc != null) {
            try {
                dc.close();
            } catch (NamingException e) {
                log.error("NamingException in close():", e);
                throw new ServerException("关闭AD服务连接失败",e);
            }
        }
    }

    /**
     * 新增AD用户
     * @param newUserName - 对应userCode
     * @param displayName -实际姓名
     * @param password - 密码
     * @throws ServerException
     */
    public void add(String newUserName, String displayName, String password) throws ServerException {
        try {
            Attributes attrs = new BasicAttributes(true);
            attrs.put("objectClass", "user");
            attrs.put("samAccountName", newUserName);
            attrs.put("displayName", displayName);
            attrs.put("userAccountControl","512");
            final byte[] quotedPasswordBytes = ('"'+password+'"').getBytes("UTF-16LE");
            attrs.put(new BasicAttribute("unicodePwd", quotedPasswordBytes));
            attrs.put("userPassword",password);
            attrs.put("userPrincipalName", newUserName + "@stosystem.com");
            attrs.put("cn", newUserName);
            attrs.put("sn", newUserName);
            dc.createSubcontext("CN=" + newUserName + "," + root, attrs);
            log.info("新增AD域用户成功:" + newUserName);
        } catch (Exception e) {
            log.info("新增AD域用户失败:" + newUserName,e);
            throw new ServerException("新增AD用户失败");
        }
    }

    /**
     * @Description:删除AD域用户
     * @author moonxy
     * @date 2018-05-15
     */
    public void delete(String userName) throws ServerException {
        try {
            dc.destroySubcontext("CN="+ userName + ","+ root);
            log.info("删除AD域用户成功:" + userName);
        } catch (Exception e) {
            log.error("删除AD域用户失败:" + userName,e);
            throw new ServerException("删除AD域用户失败:"+userName);
        }
    }

    /**
     * @Description:重命名AD域用户
     * @author moonxy
     * @date 2018-05-15
     */
    public boolean renameEntry(String oldDN, String newDN) {
        try {
            dc.rename(oldDN, newDN);
            log.info("重命名AD域用户成功");
            return true;
        } catch (NamingException ne) {
            log.error("重命名AD域用户失败",ne);
            return false;
        }
    }

    /**
     * 修改AD用户属性
     * @param dn
     * @param fieldValue
     * @param type -add/remove/replace  新增/删除/覆盖
     * @return
     */
    public boolean modifyInformation(String dn, String fieldValue, String type) {
        try {
            ModificationItem[] mods = new ModificationItem[1];
            // 修改属性
            Attribute attr0 = new BasicAttribute("homePhone",fieldValue);
            mods[0] = new ModificationItem("add".equals(type)?
                    DirContext.ADD_ATTRIBUTE :("remove".equals(type) ? DirContext.REMOVE_ATTRIBUTE : DirContext.REPLACE_ATTRIBUTE), attr0);
            dc.modifyAttributes(dn + "," + root, mods);
            log.info("修改AD域用户属性成功");
            return true;
        } catch (Exception e) {
            log.error("修改AD域用户属性失败",e);
            return false;
        }
    }

    /**
     * @Description:搜索指定节点下的所有AD域用户
     * (经 测试此查询只返回了部分用户,可能是有返回条数的限制,使用时请注意,使用searchByUserName更精确)
     * @author moonxy
     * @date 2018-05-15
     */
    public void searchInformation(String searchBase) throws ServerException {
        try {
            SearchControls searchCtls = new SearchControls();
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            String searchFilter = "objectClass=user";
            String returnedAtts[] = { "memberOf" };
            searchCtls.setReturningAttributes(returnedAtts);
            NamingEnumeration<SearchResult> answer = dc.search(searchBase, searchFilter, searchCtls);
            while (answer.hasMoreElements()) {
                SearchResult sr = answer.next();
                log.info("<<<::[" + sr.getName() + "]::>>>>");
            }
        } catch (Exception e) {
            log.error("查询指定节点下的AD用户异常",e);
            throw new ServerException("查询指定节点AD域用户异常");
        }
    }

    /**
     * 启用用户
     * @param userName
     */
    public void enablePerson(String userName) throws ServerException {
        try {
            ModificationItem[] mods = new ModificationItem[1];
            mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,new BasicAttribute("userAccountControl", "512"));

            dc.modifyAttributes("cn="+userName + "," + root, mods);
            log.info("启用用户成功!");
        }catch(Exception e) {
            log.error("启用用户失败",e);
            throw new ServerException("启用AD用户失败");
        }
    }

    /**
     * @Description:指定搜索节点搜索指定域用户
     * @author moonxy
     * @date 2018-05-15
     */
    public SearchResult searchByUserName(String searchBase, String userName){
        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        String searchFilter = "sAMAccountName=" + userName;
        //定制返回属性
        String returnedAtts[] = { "sAMAccountName" };
        //设置返回属性集
        searchCtls.setReturningAttributes(returnedAtts);
        try {
            NamingEnumeration<SearchResult> answer = dc.search(searchBase, searchFilter, searchCtls);
            return answer.next();
        } catch (Exception e) {
            log.error("指定搜索节点搜索指定域用户失败,未查询到用户",e);
            return null;
        }
    }

    /**
     * 修改指定用户密码
     * @param name
     * @param newPassword
     */
    public void changePassword(String name, String newPassword) throws ServerException {
        String userName = ("CN="+ name + ","+ root); //用户
        try {
            ModificationItem[] mods = new ModificationItem[1];
            String newQuotedPassword = "\"" + newPassword + "\"";
            byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
            mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
                    new BasicAttribute("unicodePwd", newUnicodePassword));
            // 修改密码
            dc.modifyAttributes(userName, mods);
            log.info("Reset Password for: " + userName);
            dc.close();
        } catch (Exception e) {
            log.error("Problem resetting password", e);
            if (e.toString().indexOf("LDAP: error code") > 0) {
                // 得到ldap返回的错误吗
                String errorMsg = e.toString();
                int startNum = errorMsg.toString().indexOf("LDAP: error code") + 17;
                errorMsg = errorMsg.substring(startNum, startNum + 19);
                int endNum = errorMsg.toString().indexOf(" - ");
                errorMsg = errorMsg.substring(0, endNum);

                if ("49".equals(errorMsg)) {
                    errorMsg = "域控管理员账户/密码错误";
                } else if ("32".equals(errorMsg) || "34".equals(errorMsg)) {
                    errorMsg = "域内账户错误";
                } else if ("10".equals(errorMsg)) {
                    errorMsg = "dc错误";
                } else {
                    errorMsg = "修改失败,错误吗:" + errorMsg;
                }
                log.error("Problem resetting password(ldap):" + errorMsg);
            } else {
                if (e.toString().indexOf(
                        "algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext") > 0) {
                    log.error("Problem resetting password(ldap):" + "证书无效/证书密码错误");
                }

                if (e.toString().indexOf(
                        "the trustAnchors parameter must be non-empty") > 0) {
                    log.error("Problem resetting password(ldap):" + "证书不存在");
                }
            }
            throw new ServerException("修改指定用户密码失败");
        }
    }

}

 

上一篇:用户注册界面


下一篇:异常 | 求你别再写满屏的try-catch了,用全局异常好吗?- 夹私货-行测