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

 

重要備注:雖然該方式可以避免使用TrustStore認證的方式,但是ad域控服務器仍然需要添加信任證書,如下

 且該證書對應的域名必須和AD域控所管理的域保持一致(也可能是AD域對應的證書服務器頒發的證書,我們的域控恰好是對應的證書服務器),域控處於dccn.com, 則證書不能使用例如abc.test.com,否則會報DNS異常如下:

javax.naming.CommunicationException: simple bind failed: cdt.xxx.cn:636 [Root exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching cdstest.huanghongbo.cn found.]

 

 

 

完整代碼如下:

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 {
    //ldap用戶登錄的3種方式
//方式1. 域\account
private final static String adminName = "tylincn02\\tylinoap";
//方式2. account@域
// private final static String adminName = "tylinoap@tylincn.com";
//方式3. cn用戶(網上最常見的方式可能會有重名的情況,不適用於用戶查找,不推薦)
// private final static String adminName = "cn=tylinoap,OU=ITUSER,DC=tylincn,DC=com";

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

    }
}

 關於AD用戶

 

 

 

 

參考:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM