java - 使用Java更改AD密码

标签 java active-directory ldap

我与 AD 的连接良好。我可以验证并检查失败的验证的错误消息。

我遇到的问题来自于尝试更改密码。此时我已经建立了一个 LDAPContext(是的,它是一个 SSL 连接)。问题来自于不知道在“用户名”参数中使用什么值。我尝试了所有我能想到的变体,最终得到了以下三个错误之一:

A) NO_OBJECT - 我假设这意味着它已正确连接到 AD,但找不到我要查找的内容。

B) DIR_ERROR - 我假设这意味着它可以正确进入 AD,但不知道我想让它在之后做什么。

C) 某种类型的引用错误仅在我不限定 DC 时发生,所以我认为这几乎是给定的。

这是我正在使用的代码:

public void changePassword(String username, String password) {
    ModificationItem[] mods = new ModificationItem[1];
    String newQuotedPassword = "\"" + password + "\"";
    byte[] newUnicodePassword = newQuotedPassword.getBytes();
    try {
        newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));
    try {

        ldapContext.modifyAttributes(username, mods);
    } catch (NamingException e) {
        System.out.println("Error changing password for '" + username + "': " + e.getMessage());
        e.printStackTrace();
    }           
}       

最佳答案

这是一个工作示例:

Main.java:

package io.fouad.ldap;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import java.io.UnsupportedEncodingException;
import java.util.Hashtable;

public class Main
{
    public static void main(String[] args)
    {
        final String LDAP_SERVERS = "ldap://AD_SERVER:636 ldap://AD_SERVER2:636"; // separated by single spaces
        final String LDAP_CONNECT_TIMEOUT_MS = "10000"; // 10 seconds
        final String LDAP_READ_TIMEOUT_MS = "10000"; // 10 seconds
        final String AUTHENTICATION_DOMAIN = "domain.com";
        final String USERNAME = "username";
        final String OLD_PASSWORD = "123";
        final String NEW_PASSWORD = "456";
        final String TARGET_BASE_DN = "dc=domain,dc=com";

        Hashtable<String, String> ldapEnv = new Hashtable<>();
        ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        ldapEnv.put(Context.PROVIDER_URL, LDAP_SERVERS);
        ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
        ldapEnv.put("java.naming.ldap.version", "3");
        ldapEnv.put(Context.SECURITY_PRINCIPAL, USERNAME + "@" + AUTHENTICATION_DOMAIN);
        ldapEnv.put(Context.SECURITY_CREDENTIALS, OLD_PASSWORD);
        ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl");
        ldapEnv.put("java.naming.ldap.factory.socket", "io.fouad.ldap.MySSLSocketFactory");
        //ldapEnv.put("com.sun.jndi.ldap.connect.timeout", LDAP_CONNECT_TIMEOUT_MS);
        //ldapEnv.put("com.sun.jndi.ldap.read.timeout", LDAP_READ_TIMEOUT_MS);
        DirContext ldapContext = null;

        try
        {
            ldapContext = new InitialDirContext(ldapEnv);
        }
        catch(AuthenticationException e)
        {
            System.out.println("Wrong username/password!");
            e.printStackTrace();
        }
        catch(NamingException e)
        {
            e.printStackTrace();
        }

        if(ldapContext == null) return;


        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        NamingEnumeration objects = null;
        try
        {
            objects = ldapContext.search(TARGET_BASE_DN, String.format("(&(objectClass=user)(sAMAccountName=%s))", USERNAME), searchControls);
        }
        catch(NamingException e)
        {
            e.printStackTrace();
        }

        if(objects == null) return;

        try
        {
            if(objects.hasMore())
            {
                SearchResult entry = (SearchResult) objects.next();
                ModificationItem[] mods = new ModificationItem[2];
                mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("unicodePwd", getPasswordByteArray(OLD_PASSWORD)));
                mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("unicodePwd", getPasswordByteArray(NEW_PASSWORD)));
                ldapContext.modifyAttributes(entry.getName() + "," + TARGET_BASE_DN, mods);

                System.out.println("Successfully changed the password!");
            }
            else
            {
                System.out.println("User (" + USERNAME + ") was not found!");
            }
        }
        catch(NamingException e)
        {
            e.printStackTrace();
        }

        System.out.println("DONE!");

    }

    private static byte[] getPasswordByteArray(String password)
    {
        String quotedPassword = "\"" + password + "\"";
        try
        {
            return quotedPassword.getBytes("UTF-16LE");
        }
        catch(UnsupportedEncodingException e)
        {
            e.printStackTrace();
            return null;
        }
    }
}

MySSLSocketFactory.java:(使用它需要您自担风险)

package io.fouad.ldap;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

public class MySSLSocketFactory extends SSLSocketFactory
{
    private SSLSocketFactory socketFactory;

    public MySSLSocketFactory()
    {
        try
        {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] {new X509TrustManager()
            {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s){}

                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s){}

                @Override
                public X509Certificate[] getAcceptedIssuers()
                {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());

            socketFactory = ctx.getSocketFactory();
        }
        catch(Exception ex)
        {
            ex.printStackTrace(System.err);
        }
    }

    public static SocketFactory getDefault()
    {
        return new MySSLSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites()
    {
        return socketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites()
    {
        return socketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException
    {
        return socketFactory.createSocket(socket, string, i, bln);
    }

    @Override
    public Socket createSocket(String string, int i) throws IOException
    {
        return socketFactory.createSocket(string, i);
    }

    @Override
    public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException
    {
        return socketFactory.createSocket(string, i, ia, i1);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i) throws IOException
    {
        return socketFactory.createSocket(ia, i);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException
    {
        return socketFactory.createSocket(ia, i, ia1, i1);
    }
}

关于java - 使用Java更改AD密码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1396375/

相关文章:

php - ldap_set_rebind_proc() 函数在任何 PHP Windows 发行版中都不起作用

java - java 1.8.181版本如何禁用端点识别

sql - 模拟 Active Directory 以进行异地开发

java - 当我滚动放置的图像时,自行创建的图形消失

java - 如何获取类的实例

Azure Active Directory 设备管理

active-directory - UserPrincipal.RefreshExpiredPassword() 更新什么?

java - 如何在 JPA 存储库方法中使用部分组合键来获取数据?

java - java 数组和静态方法

c# - 从给定 AD 组中的 Active Directory 获取用户列表