JAVA修改AD域密码_免证书认证

更改用户账户密码,必须要使用ssl方式登录到AD。

网上大部分教程使用TrustStore的方式连接,

        Hashtable env = new Hashtable();
        System.setProperty("javax.net.ssl.trustStore", KEYSTORE);
        System.setProperty("javax.net.ssl.trustStorePassword", KEYSTORE_PWD);
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, ADMIN_NAME);
        env.put(Context.SECURITY_CREDENTIALS, ADMIN_PASSWORD);
        env.put(Context.SECURITY_PROTOCOL, "ssl");
        env.put(Context.PROVIDER_URL, LDAP_SSL_URL);
try {
            ctx =  new InitialLdapContext(env, null);//new InitialDirContext(HashEnv);// 初始化上下文
        } catch (AuthenticationException e) {
            System.out.println("身份验证失败!"+e.toString());
            e.printStackTrace();
        } catch (CommunicationException e) {
            System.out.println("AD域连接失败!"+e.toString());
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("身份验证未知异常!"+e.toString());
            e.printStackTrace();
        } finally{
            return ctx;
        }  

最后ssl连接失败,报如下错误:javax.naming.CommunicationException: simple bind failed: xxxx:636 [Root exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]。

也有部分教程提到了绕过ssl的方式,但是都只有部分代码,直到遇到了这段代码

原地址:JAVA修改AD域密码_免证书

下载地址:JNDI免证书推送AD域密码.zip

完整代码如下:

package org.util.ad;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.SortControl;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;

public class LdapSSLUtil {
    private final static String adminName = "xxx";
    private final static String adminPassword = "xxxx";
    private final String ldapURL = "LDAPS://xxx.xxx.xxx:636";   //注意,必须使用域名加636端口
    private final String factory = "com.sun.jndi.ldap.LdapCtxFactory";
    private final String BASEN = "OU=xx,DC=xx,DC=xx";
    private LdapContext ctx = null;

    private final Control[] sortConnCtls = new SortControl[1];

    /**
     * 用户认证
     *
     * @param userName
     * @param password
     */
    public void ldap_connect(String userName, String password) {

        Hashtable<String, Object> env = new Hashtable<String, Object>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, factory);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, userName);
        env.put(Context.SECURITY_CREDENTIALS, password);
        env.put(Context.PROVIDER_URL, ldapURL);
        env.put(Context.SECURITY_PROTOCOL, "ssl");
        env.put("java.naming.ldap.factory.socket", "org.util.ad.DummySSLSocketFactory");

        try {

            // 初始化ldapcontext,方式1
//            ctx = new InitialLdapContext(env, null);
            //方式2
            sortConnCtls[0] = new SortControl("sAMAccountName", Control.CRITICAL);
            ctx = new InitialLdapContext(env, sortConnCtls);

            System.out.println("认证成功");
        } catch (Exception e) {
            System.out.println("认证失败");
            e.printStackTrace();
        }
    }

    //关闭连接
    public void close_connect() {
        try {
            if (ctx != null) {
                ctx.close();
            }
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查找用户信息
     *
     * @param cn
     * @return
     */
    public Attributes getUser(String cn) {
        Attributes attrs = null;
        SearchControls contro = new SearchControls();
        contro.setSearchScope(SearchControls.SUBTREE_SCOPE);
        try {
            //有的企业员工的dn不是有cn开头的,而是由uid开头的,这个因企业而异
            //使用cn,若存在重名用户,则返回的是最后一个员工,存在bug
//            NamingEnumeration<SearchResult> en = ctx.search(BASEN, "cn=" + cn, contro);
            //使用sAMAccountName,避免重名,比如存在四个张伟
            NamingEnumeration<SearchResult> en = ctx.search(BASEN, "sAMAccountName=" + cn, contro);
            if (en == null || !en.hasMoreElements()) {
                System.out.println("未找到该用户:" + cn);
                return null;
            }
            while (en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    attrs = si.getAttributes();
                    //attrs是用户的一些相关属性,一些很重要的属性
                    System.out.println(attrs);
                }
            }
        } catch (NamingException e) {
            System.out.println("查找用户异常。。。");
            e.printStackTrace();
        }
        return attrs;
    }

    /**
     * 获取用户的dn
     *
     * @param cn
     * @return
     */
    public String getUserDN(String cn) {
        Attributes attrs = getUser(cn);
        //distinguishedname这个属性即是用户的dn,可以打印看看
        String userDN = attrs.get("distinguishedname").toString().split(":")[1].trim();
        return userDN;
    }

    //解锁账号和下次登录需要修改密码
    public void enableUser(String userName) {
        String userDN = getUserDN(userName);
        BasicAttributes attrsbu = new BasicAttributes();

        //这个是重点,下面有话有说
        attrsbu.put("userAccountControl", "512");
        attrsbu.put("pwdLastSet", "0");

        try {
            ctx.modifyAttributes(userDN, DirContext.REPLACE_ATTRIBUTE, attrsbu);
            System.out.println("解锁账号成功");
        } catch (NamingException e) {
            System.out.println("解锁账号失败");
            e.printStackTrace();
        }
    }

    //重置密码
    public void updateUserPassword(String cn, String newPassword) throws
            UnsupportedEncodingException, NamingException {

        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));

        // 修改密码
        String userDN = getUserDN(cn);
        ctx.modifyAttributes(userDN, mods);

    }

    /**
     * AD账户时间戳转换
     * @param accountExpiresL
     * @return
     */
    public static Date adExpiresToDate(long accountExpiresL){
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(1601, 0, 1, 0, 0);
        accountExpiresL = accountExpiresL/ 10000 + calendar.getTime().getTime();
        return new Date(accountExpiresL);
    }

    /**
     * 获取AD账户失效日期
     * @param account
     * @return
     */
    public  Date getAccountExpiresToDate(String account){
        Attributes attrs = getUser(account);
        //distinguishedname这个属性即是用户的dn,可以打印看看
        String accountexpires = attrs.get("accountexpires").toString().split(":")[1].trim();
//        return accountexpires;
        System.out.println(accountexpires);
        Long expiresLong = Long.parseLong(accountexpires);
        Date expiresDate  = adExpiresToDate(expiresLong);
        System.out.println(expiresDate);
        return expiresDate;
    }

    /**
     * 上次密码修改时间
     * @param account
     * @return
     */
    public Date getPwdLastSetTime(String account){
        Attributes attrs = getUser(account);
        //distinguishedname这个属性即是用户的dn,可以打印看看
        String pwdlastset = attrs.get("pwdlastset").toString().split(":")[1].trim();
//        return accountexpires;
        System.out.println(pwdlastset);
        Long pwdlastsetLong = Long.parseLong(pwdlastset);
        Date pwdLastSetDate  = adExpiresToDate(pwdlastsetLong);
        System.out.println(pwdLastSetDate);
        return pwdLastSetDate;
    }

    public static void main(String[] args)throws Exception{
        LdapSSLUtil ldapUtil = new LdapSSLUtil();
        ldapUtil.ldap_connect(adminName, adminPassword);
        String account = "xxx";
        //重置密码
        ldapUtil.updateUserPassword(account,"xxxx");
        ldapUtil.getUserDN(account);
        ldapUtil.getAccountExpiresToDate(account);
        ldapUtil.getPwdLastSetTime(account);

        ldapUtil.close_connect();

    }
}

参考:

https://blog.csdn.net/xuxiaoqun0_0/article/details/82052218

https://blogs.msdn.microsoft.com/alextch/2012/05/15/how-to-set-active-directory-password-from-java-application/

https://www.iteye.com/blog/chnic-2065877

https://my.oschina.net/haison/blog/678354?p={{page}}

https://blog.csdn.net/laxsong/article/details/51344002

https://www.cnblogs.com/sunjiguang/p/9257585.html

https://www.bbsmax.com/A/q4zVZ0nGzK/

https://www.cnblogs.com/nidongde/p/5364622.html

https://blog.csdn.net/hc1017/article/details/81293323?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://blog.csdn.net/qq_41207282/article/details/97133887#comments

https://blog.csdn.net/hct368/article/details/97247258

https://www.cnblogs.com/amoyzhu/p/9259264.html

https://blog.51cto.com/gaowenlong/1969586

https://blog.51cto.com/gaowenlong/1969585

原文地址:https://www.cnblogs.com/huanghongbo/p/12409209.html

时间: 2024-10-31 23:22:28

JAVA修改AD域密码_免证书认证的相关文章

通过JAVA开发的修改AD用户的工具,修改AD用户密码时报错

今天遇到1个用户反馈的问题,他们通过JAVA开发了一个工具(修改AD用户密码),在此工具中如果将LDAP指向1台辅助DC时就报错,详细信息如下: 问题描述: ========= 通过JAVA开发的修改AD用户密码的工具,LDAP指向1台辅助域控时,修改用户密码报错,JAVA上报错如下: javax.naming.CommunicationException: simple bind failed: 10.10.10.23:636 [Root exception is javax.net.ssl.

使用java连接AD域,验证账号密码是否正确

eb项目中有时候客户要求我们使用ad域进行身份确认,不再另外做一套用户管理系统.其实客户就是只要一套账号可以访问所有的OA,CRM等办公系统.这就是第三方验证.一般有AD域,Ldap,Radius,邮件服务器等.最常用的要数AD域了.因为window系统在国内占据了大量的江山.做起来也很方便.我这篇文章就是写,如何用java去实现AD域的身份验证.好了,直接看代码吧: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

AD 域服务简介(三)- Java 对 AD 域用户的增删改查操作

博客地址:http://www.moonxy.com 关于AD 域服务器搭建及其使用,请参阅:AD 域服务简介(一) - 基于 LDAP 的 AD 域服务器搭建及其使用 Java 获取 AD 域用户,请参阅:AD 域服务简介(二)- Java 获取 AD 域用户 一.前言 在日常的开发中,为了实现单点登录,需要对域用户进行增删改查操作,以维持最新的用户信息,确保系统的安全. 二.Java 对 AD 域用户的增删改查操作 package com.moonxy.ad; import java.uti

AD 域服务简介(二)- Java 获取 AD 域用户

博客地址:http://www.moonxy.com 一.前言 先简单简单回顾上一篇博文中关于 AD 域和 LDAP目录访问协议的基本概念. AD(Active Directory)活动目录,动态的建立整个域模式网络中的对象的数据库或索引,使用的协议为 LDAP,安装了AD 的服务器称为 DC 域控制器,存储整个域的对象的信息并周期性更新,其中的对象分为三大类:资源(如印表机).服务(如电子邮件).和用户(即帐户或用户,以及组). 通常大家都会将 LDAP 与关系数据库相比,认为 LDAP 是另

.net 修改AD域中的密码

1.通过vs 2013 新建一个web站点(不是空项目),这个会带一下模板, 2.然后新建一个页面UpdatePassWord.aspx aspx页面内容: <%@ Page Title="UpdatePassWord" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="UpdatePassWord.a

Windows server 2012 R2 AD域密码过期邮件提醒

最近接领导指示,说要做一个域密码提醒的服务,这样会更人性化些,员工也就不必等过期了来找管理员重置.但是但是本人不懂脚本,就干脆从网上找了些链接做为参考,这里感谢此链接的作者 https://www.yeboyzq.com/windowsserver/632.html 以下是最终的过程 Import-Module Activedirectory $alladuser=get-aduser -searchbase "ou=,ou=,dc=*,dc=com" -Filter 'Passwor

使用JAVA进行ad域身份验证常用属性详解

一些变态的公司经常对开发者提出一些变态的问题.比如在oa系统中,要求登录验证必须使用ad域进行登录.还有的如登录crm系统必须使用公司的阿里云邮箱账号进行身份验证等等. 作为程序员我们只能按照客户的需求进行完善系统.毕竟客户才是我们的衣食父母,没办法拒绝.我这里就列举一些,在系统中集成ad域身份验证的一些配置信息,并一一解释他们的作用. 直接看代码: public boolean login() { // 判断必填字段是否全部填写 if (StringUtils.isEmpty(this.use

修改AD域中密码的过期时间

开始---管理工具----Active Directory管理中心 ,鼠标右键点击域,打开域的属性配置窗口,选属性编辑器,找到MaxPwdAge属性,设置为想要的时间.格式为<d:hh:mm:ss>.中间要有冒号.可以填入无和从不--------------如:(无) 和 (从不)  备注()是英文输入法中的括号!!!!永不,代表的是永不过期. (但建议明确指定方便维护.这个地方最容易被忽视.) 同时更新域内的组策略 右键编辑 使生效:强制同步到本地客户端:gpupdate /force 如果

java访问ad域

1.活动目录(AD) Active Directory 是用于 Windows Server 的目录服务.它存储着网络上各种对象的有关信息,并使该信息易于管理员和用户查找及使用.Active Directory 目录服务使用结构化的数据存储作为目录信息的逻辑层次结构的基础. 通过登录验证以及目录中对象的访问控制,将安全性集成到 Active Directory 中. 目录服务,如 Active Directory,提供了用于存储目录数据并使该数据可由网络用户和管理员使用的方法.例如,Active