java 操作AD域代码(跳过证书版)

1、AD域操作类 

@Slf4j
public class ADOperator {
    private final DomainConfigModel adConfig;
    private static final int ADS_UF_ACCOUNTDISABLE = 0x00000002;//账号禁用位
    private static final int ADS_UF_NORMAL_ACCOUNT = 0x0200;//普通账号

    /**
     * 构造函数
     *
     * @param adConfig AD域配置信息
     */
    public ADOperator(DomainConfigModel adConfig) {
        this.adConfig = adConfig;
    }

    /**
     * 构造函数
     *
     * @param path       AD域路径
     * @param adminUser  AD域用户名
     * @param adminPwd   AD域密码
     * @param suffixPath AD域根路径
     */
    public ADOperator(String path, String adminUser, String adminPwd, String suffixPath) {
        this.adConfig = new DomainConfigModel(adminUser, adminPwd, path, suffixPath);
    }

    /**
     * 添加用户
     *
     * @param userInfo 域用户信息
     * @return
     */
    public String addUser(DomainUser userInfo) {
        StringBuilder message = new StringBuilder();
        if (!createOrg(userInfo.getDepartment()))
            return message.append("组织创建失败").toString();
        message.append("组织创建成功;");
        if (!createGroup(userInfo.getDepartment(), userInfo.getDepartment()))
            return message.append("用户组创建失败").toString();
        message.append("用户组创建成功;");
        try {
            DirContext ldapContext = getLdapContext();
            if (!existsUser(userInfo.getAdUserName())) {
                BasicAttributes attrs = new BasicAttributes(true);
                attrs.put("objectClass", "user");
                attrs.put("displayName", userInfo.getName());// 显示名称
                attrs.put("sAMAccountName", userInfo.getAdUserName());
                attrs.put("mail", userInfo.getEmail());
                attrs.put("telephoneNumber", userInfo.getMobile());
                ldapContext.createSubcontext("CN=" + userInfo.getUserName() + "," + getOrgADPath(userInfo.getDepartment()), attrs);
            }
            message.append("用户账号创建成功;");

            if (disabledOrOnUser(userInfo.getAdUserName(), false))
                message.append("用户账号启用成功;");
            else
                message.append("用户账号启用失败;");

            SearchResult result = findObject(adConfig.getSuffixPath(), "person", userInfo.getAdUserName());
            assert result != null;
            //设置密码
            if (StringUtils.isNotEmpty(userInfo.getPwd())) {
                ModificationItem[] mods1 = new ModificationItem[1];
                mods1[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
                        new BasicAttribute("unicodePwd", createUnicodePassword(userInfo.getPwd())));
                ldapContext.modifyAttributes(result.getName() + "," + adConfig.getSuffixPath(), mods1);
            }
            message.append("用户账号密码设置成功;");

            //添加用户至用户组
            ModificationItem[] mods2 = new ModificationItem[1];
            mods2[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("member", result.getName() + "," + adConfig.getSuffixPath()));
            ldapContext.modifyAttributes("CN=" + userInfo.getDepartment() + "," + getOrgADPath(userInfo.getDepartment()), mods2);
            message.append("添加用户至组成功;正常");
        } catch (NamingException e) {
            log.error("创建用户过程中出错,用户信息为{},错误为{}", JSON.toJSONString(userInfo), e.getMessage());
            message.append("失败");
        }
        return message.toString();
    }

    /** 更新AD用户信息(只能更新组织、手机号、邮箱)
     * @param userInfo 需要更新的用户信息
     * @return
     */
    public boolean updateUser(DomainUser userInfo) {
        if (!createOrg(userInfo.getDepartment()))
            throw new SyncDataException("创建组织失败");

        if (!createGroup(userInfo.getDepartment(), userInfo.getDepartment()))
            throw new SyncDataException("创建用户组失败");
        SearchResult result = findObject(adConfig.getSuffixPath(), "person", userInfo.getAdUserName());
        assert result != null;
        DirContext ldapContext = null;
        try {
            ldapContext = getLdapContext();
            ModificationItem[] mods = new ModificationItem[2];
            mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("telephoneNumber", userInfo.getMobile()));
            mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("mail", userInfo.getEmail()));
            ldapContext.modifyAttributes(result.getName() + "," + adConfig.getSuffixPath(), mods);

            //添加用户至用户组
            ModificationItem[] mods1 = new ModificationItem[1];
            mods1[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("member", result.getName() + "," + adConfig.getSuffixPath()));
            ldapContext.modifyAttributes("CN=" + userInfo.getDepartment() + "," + getOrgADPath(userInfo.getDepartment()), mods1);

            ldapContext.rename(result.getName() + "," + adConfig.getSuffixPath(), "CN=" + userInfo.getUserName() + "," + getOrgADPath(userInfo.getDepartment()));
            return true;
        } catch (NamingException e) {
            log.error("更新用户过程中出错,用户信息为{},错误为{}", JSON.toJSONString(userInfo), e.getMessage());
            return false;
        }
    }

    /**
     * 禁用/启用账号
     *
     * @param account  用户ad账号
     * @param disabled 是否禁用
     * @return
     */
    public boolean disabledOrOnUser(String account, boolean disabled) {
        if (!existsUser(account))
            return false;
        SearchResult result = findObject(adConfig.getSuffixPath(), "person", account);//根据账号查找到用户信息
        try {
            assert result != null;
            Attributes attr = result.getAttributes();
            Attribute controlAttr = attr.get("userAccountControl");//获取“账号选项”属性
            ModificationItem[] mods = new ModificationItem[1];
            if (null != controlAttr) {//若存在该属性,则替换,否则新增
                int newControlVal;
                if (disabled)//若禁用账号,则设置禁用标志位,否则取消禁用标志位
                    newControlVal = Integer.parseInt(controlAttr.get().toString()) | ADS_UF_ACCOUNTDISABLE;
                else
                    newControlVal = Integer.parseInt(controlAttr.get().toString()) & ~ADS_UF_ACCOUNTDISABLE;
                mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl", Integer.toString(newControlVal)));
            } else {
                if (disabled)//若禁用账号,则设置禁用标志位,否则不操作
                    mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("userAccountControl", Integer.toString(ADS_UF_ACCOUNTDISABLE)));
            }

            getLdapContext().modifyAttributes(result.getName() + "," + adConfig.getSuffixPath(), mods);
            return true;
        } catch (NamingException e) {
            log.error("禁用/启用用户过程中出错,用户账号为{},错误为{}", account, e.getMessage());
            return false;
        }
    }

    /**
     * 删除用户
     *
     * @param account 用户ad账号
     * @return
     */
    public boolean deleteUser(String account) {
        if (!existsUser(account))
            return true;
        SearchResult result = findObject(adConfig.getSuffixPath(), "person", account);
        try {
            assert result != null;
            getLdapContext().destroySubcontext(result.getName());
            return true;
        } catch (NamingException e) {
            log.error("删除用户过程中出错,用户账号为{},错误为{}", account, e.getMessage());
            return false;
        }
    }

    /**
     * 判断ad账号是否在AD域内
     *
     * @param account AD账号
     * @return
     */
    public boolean existsUser(String account) {
        SearchResult result = findObject(adConfig.getSuffixPath(), "person", account);
        return null != result;
    }

    /**
     * 创建组织
     *
     * @param orgFullPath 组织全路径(父子路径间以-分隔)
     * @return
     */
    public boolean createOrg(String orgFullPath) {
        String parentOrgPath = "";
        String org = "";
        if (orgFullPath.indexOf('-') > -1) {
            int lastIndexOf = orgFullPath.lastIndexOf('-');
            parentOrgPath = orgFullPath.substring(0, lastIndexOf);
            org = orgFullPath.substring(lastIndexOf + 1);
        } else
            org = orgFullPath;
        return createOrg(parentOrgPath, org);
    }

    /**
     * 创建组织
     *
     * @param parentOrgPath 父组织全路径(父子路径间以-分隔),为空则表示父组织为根路径
     * @param org           当前组织
     * @return
     */
    public boolean createOrg(String parentOrgPath, String org) {
        if (existsOrg(parentOrgPath, org))
            return true;
        if (StringUtils.isNotEmpty(parentOrgPath)) {
            String parent_parentOrgPath = "";
            String parentOrg = "";
            if (parentOrgPath.indexOf('-') > -1) {
                int lastIndexOf = parentOrgPath.lastIndexOf('-');
                parent_parentOrgPath = parentOrgPath.substring(0, lastIndexOf);
                parentOrg = parentOrgPath.substring(lastIndexOf + 1);
            } else
                parentOrg = parentOrgPath;
            if (existsOrg(parent_parentOrgPath, parentOrg) || createOrg(parent_parentOrgPath, parentOrg)) {
                try {
                    DirContext ldapContext = getLdapContext();
                    Attributes attr = new BasicAttributes(true);
                    attr.put("objectClass", "organizationalUnit");
                    ldapContext.createSubcontext("OU=" + org + "," + getOrgADPath(parentOrgPath), attr);
                    return true;
                } catch (NamingException e) {
                    log.error("创建组织过程中出错,父组织信息为{},当前组织信息为{},错误信息为{}", parentOrgPath, org, e.getMessage());
                    return false;
                }
            } else
                return false;
        } else {
            if (existsOrg("", parentOrgPath))
                return true;
            else {
                return createOrg("", parentOrgPath);
            }
        }
    }

    /**
     * 判断父组织中是否存在该组织
     *
     * @param parentOrg 父组织全路径(父子路径间以-分隔),为空则表示父组织为根路径
     * @param org       当前组织
     * @return
     */
    public boolean existsOrg(String parentOrg, String org) {
        SearchResult result = findObject(getOrgADPath(parentOrg), "org", org);
        return null != result;
    }

    /**
     * 创建用户组
     *
     * @param orgPath   用户组所在组织全路径
     * @param groupName 组名
     * @return
     */
    public boolean createGroup(String orgPath, String groupName) {
        if (existsGroup(orgPath, groupName))
            return true;
        try {
            DirContext ldapContext = getLdapContext();
            Attributes attr = new BasicAttributes(true);
            attr.put("objectClass", "group");
            ldapContext.createSubcontext("CN=" + groupName + "," + getOrgADPath(orgPath), attr);
            return true;
        } catch (NamingException e) {
            log.error("创建用户组过程中出错,组织路径为{},用户组名为{},错误为{}", orgPath, groupName, e.getMessage());
            return false;
        }
    }

    /**
     * 判断组织中是否存在该组
     *
     * @param orgPath 组织全路径(父子路径间以-分隔),为空则表示组织路径为根路径
     * @param group   组名
     * @return
     */
    public boolean existsGroup(String orgPath, String group) {
        SearchResult result = findObject(getOrgADPath(orgPath), "group", group);
        return null != result;
    }

    /**
     * 密码加密
     *
     * @param password 密码
     * @return
     */
    private byte[] createUnicodePassword(String password) {
        String quotedPassword = "\"" + password + "\"";
        return quotedPassword.getBytes(StandardCharsets.UTF_16LE);
    }

    /**
     * 根据组织路径生成AD组织路径
     *
     * @param orgPath 组织全路径(父子路径间以-分隔),为空则表示组织路径为根路径
     * @return
     */
    private String getOrgADPath(String orgPath) {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isNotEmpty(orgPath)) {
            if (orgPath.indexOf('-') < 0) {
                sb.append("OU=").append(orgPath).append(",");
            } else {
                String[] split = orgPath.split("-");
                for (int i = split.length - 1; i >= 0; i--) {
                    if (StringUtils.isNotEmpty(split[i]))
                        sb.append("OU=").append(split[i]).append(",");
                }
            }
        }
        sb.append(adConfig.getSuffixPath());
        return sb.toString();
    }

    /**
     * 根据分类和用户名查找AD域下的项
     *
     * @param searchBase 查找节点
     * @param category   分类(person、group、org)
     * @param name       用户名
     * @return
     */
    private SearchResult findObject(String searchBase, String category, String name) {
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        String filter = "";
        if (category.equals("person"))
            filter = String.format("(&(objectCategory=%s)(sAMAccountName=%s))", category, name);
        else if (category.equals("group"))
            filter = String.format("(&(objectCategory=%s)(cn=%s))", category, name);
        else if (category.equals("org"))
            filter = String.format("(&(objectCategory=organizationalUnit)(ou=%s))", name);
        try {
            DirContext ldapContext = getLdapContext();
            NamingEnumeration<SearchResult> search = ldapContext.search(searchBase, filter, controls);
            if (search.hasMoreElements())
                return search.next();
        } catch (NamingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取ldap操作上下文
     *
     * @return
     * @throws NamingException
     */
    private DirContext getLdapContext() throws NamingException {
        //解决No subject alternative DNS name xxxxx的错误
        Security.setProperty("jdk.tls.disabledAlgorithms", "");
        System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
        Properties prop = new Properties();
        prop.setProperty(Context.SECURITY_PROTOCOL, "ssl");
        prop.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        prop.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
        prop.setProperty(Context.SECURITY_PRINCIPAL, adConfig.getAdminUser());
        prop.setProperty(Context.SECURITY_CREDENTIALS, adConfig.getAdminPwd());
        prop.setProperty(Context.PROVIDER_URL, adConfig.getPath());
        prop.setProperty("java.naming.ldap.factory.socket", "com.simon.common.utils.AD.DummySSLSocketFactory");//注意,此处的com.simon.common.utils.AD.DummySSLSocketFactory指的是你本地的DummySSLSocketFactory类所在的路径
        return new InitialLdapContext(prop, null);
    }
}

2、跳过证书的配置类

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();
    }
}
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];
    }
}

3、AD域配置信息类

注意:

1、账号和密码必须是管理员账号

2、path为ldap路径,例如:LDAP://ip地址/

3、suffixPath为域组织的根路径,即所有域组织单位的公共路径。例如:OU=***,DC=***,DC=***

@Data
@AllArgsConstructor
public class DomainConfigModel {
    /**
     * 域服务器账号
     */
    private String adminUser;
    /**
     * 域服务器密码
     */
    private String adminPwd;
    /**
     * 域服务器地址
     */
    private String path;
    /**
     * 域根路径
     */
    private String suffixPath;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值