• JNDI 连接Windows Active Directory 教程


    這編主要是描述 Java JNDI 連 Windows Active Directory 的教程.
    包括認證, 新增用戶, 修改密碼 及 取得用戶資料.


    開始教程:
    1. 建立 IIS SSL
    2. 將 CA Certificate 加入至 jre keystore 裡
    3. JNDI 連 AD

    1. 建立 IIS SSL:
    Install Windows 2003 Server:

    Install AD:
    Start -> Run -> dcpromote
    domain name : joeyta-DOT-local
    NT domain name : joeytaserver
    即 Fully Qualified Domain Name (FQDN) 為 joeytaserver.joeyta-DOT-local

    先安裝 IIS , 再安裝 CA.

    Install IIS:
    Start -> Programs -> Administrative Tools -> Configure Your Server Wizard
    ->> Next -> Next -> Application server (IIS, ASP.NET) -> Next

    進入 http://joeyserver.joeyta.local/postinfo.html 表示安裝成功.

    Install CA:
    Start -> Settings -> Control Panel -> Add or Remove Programs
    ->> Add/Remove Windows Components
    選擇 Certificate Services -> Next
    選擇 Enterprise root CA -> Next
    Common name for this CA: testca -> Next

    進入 http://joeyserver.joeyta.local/CertSrv 表示安裝成功.


    Generating a Certificate Signing Request:
    Start -> Programs -> Administrative Tools -> Internet Information Services (IIS) Manager
    ->> Internet Information Services -> (local computer) -> Web Sites
    -> > 右鍵點選 Default Web Site -> Properties
    選擇 "Directory Security" -> Server Certificate
    ->> Create a new certificate -> Prepare the request now, but send it later
    一直按 Next , 需要注意的是 Common name 必須為 joeyserver.joeyta.local, 這是給使用者連 ssl 的 website.
    最後產生 certificate request file , 預設為 c:/certreq.txt


    Request a certificate on CA:
    進入 http://joeyserver.joeyta.local/CertSrv
    按 Request a certificate -> advanced certificate request
    -> Submit a certificate request by using a base-64-encoded CMC or PKCS#10 file, or submit a renewal request by using a base-64-encoded PKCS#7 file
    使用 notepad 打開 c:/certreq.txt , copy c:/certreq.txt 內容貼至 Saved Request:
    Certificate Template 選擇 Web Server, 按 Submit
    然後點選 Download certificate , 將 certnew.cer 儲存至 c:/certnew.cer


    Installing a Certificate:
    Start -> Programs -> Administrative Tools -> Internet Information Services (IIS) Manager
    ->> Internet Information Services -> (local computer) -> Web Sites
    -> > 右鍵點選 Default Web Site -> Properties
    選擇 "Directory Security" -> Server Certificate
    ->> Process the pending request and install the certificate -> Next
    Path and file name: c:/certnew.cer -> Next
    SSL port this web site should use: 443 -> Next -> Next -> Finish


    2. 將 CA Certificate 加入至 jre keystore 裡:
    進入 http://joeyserver.joeyta.local/CertSrv
    點選 Download a CA certificate, certificate chain, or CRL
    點選 Download CA certificate , 然後下載並改名為 c:/testca_cert.cer

    然後執行 command:
    c:/temp>keytool -import -alias testca_cert -file "/testca_cert.cer" -keystore "/jdk1.5.0_09/jre/lib/security/cacerts" -storepass "changeit"

    出現 Trusted this certificate? 按 "y" 即新增成功.


    3. JNDI 連 AD:

    /***************************** LDAPFastBind.java *****************/
    package test.ldap;

    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Hashtable;

    import javax.naming.AuthenticationException;
    import javax.naming.Context;
    import javax.naming.NamingEnumeration;
    import javax.naming.NamingException;
    import javax.naming.directory.Attribute;
    import javax.naming.directory.Attributes;
    import javax.naming.directory.BasicAttribute;
    import javax.naming.directory.BasicAttributes;
    import javax.naming.directory.DirContext;
    import javax.naming.directory.ModificationItem;
    import javax.naming.directory.SearchControls;
    import javax.naming.directory.SearchResult;
    import javax.naming.ldap.Control;
    import javax.naming.ldap.InitialLdapContext;
    import javax.naming.ldap.LdapContext;
    import javax.naming.ldap.StartTlsRequest;
    import javax.naming.ldap.StartTlsResponse;

    class FastBindConnectionControl implements Control {
        public byte[] getEncodedValue() {
            return null;
        }

        public String getID() {
            return "1.2.840.113556.1.4.1781";
        }

        public boolean isCritical() {
            return true;
        }
    }

    public class LDAPFastBind {
        public Hashtable env = null;

        public LdapContext ctx = null;

        public Control[] connCtls = null;

        public LDAPFastBind(String ldapurl) {
            env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY,
                    "com.sun.jndi.ldap.LdapCtxFactory");
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
            env.put(Context.PROVIDER_URL, ldapurl);
            
            env.put(Context.SECURITY_PROTOCOL,"ssl");

            String keystore = "/jdk1.5.0_09/jre/lib/security/cacerts";
            System.setProperty("javax.net.ssl.trustStore",keystore);
            
            connCtls = new Control[] { new FastBindConnectionControl() };

            // first time we initialize the context, no credentials are supplied
            // therefore it is an anonymous bind.

            try {
                ctx = new InitialLdapContext(env, connCtls);

            } catch (NamingException e) {
                System.out.println("Naming exception " + e);
            }
        }

        public boolean Authenticate(String username, String password) {
            try {
                ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, username);
                ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
                ctx.reconnect(connCtls);
                System.out.println(username + " is authenticated");
                return true;
            }

            catch (AuthenticationException e) {
                System.out.println(username + " is not authenticated");
                System.out.println(e);
                return false;
            } catch (NamingException e) {
                System.out.println(username + " is not authenticated");
                System.out.println(e);
                return false;
            }
        }

        public void finito() {
            try {
                ctx.close();
                System.out.println("Context is closed");
            } catch (NamingException e) {
                System.out.println("Context close failure " + e);
            }
        }

        public void printUserAccountControl() {
            try {

                // Create the search controls
                SearchControls searchCtls = new SearchControls();

                // Specify the search scope
                searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

                // specify the LDAP search filter
                //String searchFilter = "(&(objectClass=user)(CN=test))";
                //String searchFilter = "(&(objectClass=group))";
                String searchFilter = "(&(objectClass=user)(CN=peter lee))";

                // Specify the Base for the search
                String searchBase = "DC=joeyta,DC=local";

                // initialize counter to total the group members
                int totalResults = 0;

                // Specify the attributes to return
                String returnedAtts[] = { "givenName", "mail" };
                searchCtls.setReturningAttributes(returnedAtts);

                // Search for objects using the filter
                NamingEnumeration answer = ctx.search(searchBase, searchFilter,
                        searchCtls);

                // Loop through the search results
                while (answer.hasMoreElements()) {
                    SearchResult sr = (SearchResult) answer.next();

                    System.out.println(">>>" + sr.getName());

                    // Print out the groups

                    Attributes attrs = sr.getAttributes();
                    if (attrs != null) {

                        try {
                            for (NamingEnumeration ae = attrs.getAll(); ae
                                    .hasMore();) {
                                Attribute attr = (Attribute) ae.next();
                                System.out.println("Attribute: " + attr.getID());
                                for (NamingEnumeration e = attr.getAll(); e
                                        .hasMore(); totalResults++) {

                                    System.out.println(" " + totalResults + ". "
                                            + e.next());
                                }

                            }

                        } catch (NamingException e) {
                            System.err.println("Problem listing membership: " + e);
                        }

                    }
                }

                System.out.println("Total attrs: " + totalResults);

            }

            catch (NamingException e) {
                System.err.println("Problem searching directory: " + e);
            }

        }
        
        public boolean adminChangePassword(String sUserName, String sNewPassword){
            try {
            
                //set password is a ldap modfy operation
                ModificationItem[] mods = new ModificationItem[1];

                //Replace the "unicdodePwd" attribute with a new value
                //Password must be both Unicode and a quoted string
                String newQuotedPassword = "/"" + sNewPassword + "/"";
                byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");

                mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));

                // Perform the update
                ctx.modifyAttributes(sUserName, mods);
            
                System.out.println("Reset Password for: " + sUserName);    
                
                return true;
            }
            catch (NamingException e) {
                System.out.println("Problem resetting password: " + e);
            }
            catch (UnsupportedEncodingException e) {
                System.out.println("Problem encoding password: " + e);
            }
            return false;
        }
        
        public boolean userChangePassword(String sUserName, String sOldPassword, String sNewPassword){
            try {
                //StartTlsResponse tls = (StartTlsResponse)ctx.extendedOperation(new StartTlsRequest());
                //tls.negotiate();
                
                //change password is a single ldap modify operation
                //that deletes the old password and adds the new password
                ModificationItem[] mods = new ModificationItem[2];

                //Firstly delete the "unicdodePwd" attribute, using the old password
                //Then add the new password,Passwords must be both Unicode and a quoted string
                String oldQuotedPassword = "/"" + sOldPassword + "/"";
                byte[] oldUnicodePassword = oldQuotedPassword.getBytes("UTF-16LE");
                String newQuotedPassword = "/"" + sNewPassword + "/"";
                byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
            
                mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("unicodePwd", oldUnicodePassword));
                mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));

                // Perform the update
                ctx.modifyAttributes(sUserName, mods);
            
                System.out.println("Changed Password for: " + sUserName);    
                //tls.close();
                return true;

            }
            catch (NamingException e) {
                System.err.println("Problem changing password: " + e);
            }
            catch (UnsupportedEncodingException e) {
                System.err.println("Problem encoding password: " + e);
            } catch ( Exception e){
                System.err.println("Problem: " + e);            
            }
            return false;
        }
        
        public boolean createNewUser(String sGroupName, String sUserName){
            try {
                // Create attributes to be associated with the new user
                Attributes attrs = new BasicAttributes(true);
                
                //These are the mandatory attributes for a user object
                //Note that Win2K3 will automagically create a random
                //samAccountName if it is not present. (Win2K does not)
                attrs.put("objectClass","user");
                attrs.put("sAMAccountName","AlanT");
                attrs.put("cn","Alan Tang");

                //These are some optional (but useful) attributes
                attrs.put("givenName","Alan");
                attrs.put("sn","Tang");
                attrs.put("displayName","Alan Tang");
                attrs.put("description","Engineer");
                attrs.put("userPrincipalName","alan-AT-joeyta.local");
                attrs.put("mail","alang-AT-mail.joeyta-DOT-local");
                attrs.put("telephoneNumber","123 456 789");
                
                //some useful constants from lmaccess.h
                int UF_ACCOUNTDISABLE = 0x0002;
                int UF_PASSWD_NOTREQD = 0x0020;
                int UF_PASSWD_CANT_CHANGE = 0x0040;
                int UF_NORMAL_ACCOUNT = 0x0200;
                int UF_DONT_EXPIRE_PASSWD = 0x10000;
                int UF_PASSWORD_EXPIRED = 0x800000;
            
                //Note that you need to create the user object before you can
                //set the password. Therefore as the user is created with no
                //password, user AccountControl must be set to the following
                //otherwise the Win2K3 password filter will return error 53
                //unwilling to perform.

                attrs.put("userAccountControl",Integer.toString(UF_NORMAL_ACCOUNT + UF_PASSWD_NOTREQD + UF_PASSWORD_EXPIRED+ UF_ACCOUNTDISABLE));    
            
                // Create the context
                Context result = ctx.createSubcontext(sUserName, attrs);
                System.out.println("Created disabled account for: " + sUserName);
                
                //now that we've created the user object, we can set the
                //password and change the userAccountControl
                //and because password can only be set using SSL/TLS
                //lets use StartTLS

                //StartTlsResponse tls = (StartTlsResponse)ctx.extendedOperation(new StartTlsRequest());
                //tls.negotiate();
            
                //set password is a ldap modfy operation
                //and we'll update the userAccountControl
                //enabling the acount and force the user to update ther password
                //the first time they login
                ModificationItem[] mods = new ModificationItem[2];
            
                //Replace the "unicdodePwd" attribute with a new value
                //Password must be both Unicode and a quoted string
                String newQuotedPassword = "/"P-AT-ssw0rd/"";
                byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");

                mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));
                mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl",Integer.toString(UF_NORMAL_ACCOUNT + UF_PASSWORD_EXPIRED)));
            
                // Perform the update
                ctx.modifyAttributes(sUserName, mods);
                System.out.println("Set password & updated userccountControl");


                //now add the user to a group.

                    try    {
                        ModificationItem member[] = new ModificationItem[1];
                        member[0]= new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("member", sUserName));
                    
                        ctx.modifyAttributes(sGroupName,member);
                        System.out.println("Added user to group: " + sGroupName);

                    }
                    catch (NamingException e) {
                         System.err.println("Problem adding user to group: " + e);
                    }
                //Could have put tls.close()  prior to the group modification
                //but it seems to screw up the connection  or context ?
                //tls.close();
            
                System.out.println("Successfully created User: " + sUserName);
                return true;
                
            }
            catch (NamingException e) {
                System.err.println("Problem creating object: " + e);
            }
        
            catch (IOException e) {
                System.err.println("Problem creating object: " + e);            
            }
            return false;
        }

        public boolean addUserToGroup(LdapContext ctx, String userDN, String groupDN) {
            try{
                ModificationItem[] mods = new ModificationItem[1];
                mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("member", userDN));
                ctx.modifyAttributes(groupDN, mods);
                System.out.println("Added user " + userDN + " to group " + groupDN);
                return true;
            } catch (NamingException ne){
                System.err.println("Problem add user to group: " + ne);
            }
            return false;
        }

        public boolean removeUserFromGroup(LdapContext ctx, String userDN, String groupDN) {
            try{
                ModificationItem[] mods = new ModificationItem[1];
                mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("member", userDN));
                ctx.modifyAttributes(groupDN, mods);
                System.out.println("Remove user " + userDN + " from group " + groupDN);
                return true;
            } catch (NamingException ne){
                System.err.println("Problem remove user from group: " + ne);
            }        
            return false;
        }    
        
    }
    /***************************** LDAPFastBind.java *****************/




    /***************************** LDAPClient.java *****************/
    package test.ldap;

    class LDAPClient {
        public static void main(String[] args) {
            // Could also use ldaps over port 636 to protect the communication to
            // the
            // Active Directory domain controller. Would also need to add
            // env.put(Context.SECURITY_PROTOCOL,"ssl") to the "server" code
            //String ldapurl = "ldap://joeyserver.joeyta.local:389";
            String ldapurl = "ldap://joeyserver.joeyta.local:636";

            LDAPFastBind ctx = new LDAPFastBind(ldapurl);    
            
            String sAdminUserName = "CN=Administrator,CN=Users,DC=joeyta,DC=local";
            String sAdminPassword = "I@mRoot";        
            
    //        String sUserName = "CN=peter lee,CN=Users,DC=joeyta,DC=local";
            String sUserName = "joeyta//peter";        
    //        String sUserName = "peter@joeyta.local";
            
            String sOldPassword = "P@ssw0rd";
            String sNewPassword = "P@$w0rd";
            
            String sNewUserName = "CN=Alan Tang,CN=Users,DC=joyeta,DC=local";
            String sNewGroupName = "CN=test,CN=Users,DC=joeyta,DC=local";        
            
            boolean IsAuthenticated = ctx.Authenticate(sAdminUserName, sAdminPassword);        
    //        boolean IsAuthenticated = ctx.Authenticate(sUserName, sOldPassword);
                    
            ctx.printUserAccountControl();
            
            ctx.createNewUser(sNewGroupName, sNewUserName);
            
            //boolean IsAdminSuccessChangePWD = ctx.adminChangePassword(sUserName,sNewPassword);
            //boolean IsUserSuccessChangePWD = ctx.userChangePassword(sUserName,sOldPassword,sNewPassword);
            
            ctx.finito();

        }
    }
    /***************************** LDAPClient.java *****************/
     连接来源:http://www.sawin.cn/doc/SP/Java/TheEdge202.htm
  • 相关阅读:
    Zookeeper_ZAB协议
    Zookeeper_Paxos算法
    Eureka的表兄弟Zookeeper理论基础
    SSE:服务器推送事件
    BIO、NIO、AIO入门认识
    c语言float、double数据保留2位小数
    c语言在8位bmp位图上画一个框并另存
    C语言在24真彩位图上指定位置处画一条横线
    vs2010 opengl 环境搭建
    osg模型操作之替代节点
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157386.html
Copyright © 2020-2023  润新知