<%@ page contentType="text/html; charset=gb2312"%> JNDI 连接Windows Active Directory 教程
网站公告:   ◆北天JAVA技术网热情为java爱好者服务,本网内容包括JAVA(JSP、servlet、EJB、webservice、j2ee、javabean、应用服务器、JavaScript),数据库(MYSQL、SQL Server、Sybase、Oracle、DB2、数据库综合知识),设计研究(设计模式、Struts、Spring、Hibernate、设计框架、设计综合知识),WEB2.0新技术(主要介绍AJAX),以及各种技术的入门、实例、例子等等,欢迎各位多来坐坐!◆  诚邀各位JAVA爱好者加盟!◆  本网站内容丰富,更新快,保证每周20篇以上!  
加入收藏
设为首页
联系站长
承接项目
  相关资源:网站首页 | 免费培训学院 | 技术论坛 | JAVA聊天室 | 作家专栏 | 开发工具 | 认证考试 | 会员俱乐部
  JAVA技术初学者园地 | jsp与servlet | javascript | Java源代码 | EJB | web service | 应用服务器 | JAVA综合知识
  设计研究设计模式 | 设计框架 | Struts | Spring | Hibernate | 开源项目 | 面向对象设计 | 设计综合知识
  数 据 库MYSQL | SQL Server | Sybase | Oracle | DB2 | Informix | Access | 数据库综合知识
  其他资源:AJAX新技术 | 网站开发 | ERP软件 | OA办公软件 | 商业智能BI | 开发综合知识 | 承接项目 | 项目试用

 
 
JNDI 连接Windows Active Directory 教程
     发布者: 发布时间:2007-03-07

摘要:

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

作者原文:http://blog.matrix.org.cn/joeyta/entry/20070302

開始教程:
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.javaworld.com.tw/jute/post/view?bid=7&id=164710&sty=1&tpg=1&age=0
http://forum.java.sun.com/forum.jspa?forumID=51&start=0
(转载文章请保留出处:北天JAVA技术网(www.java114.com))
 
更多精彩文章:
使用 Google Ajax Search API
使用模板模式简化DAO操作Hibernate
使用Spring来创建一个简单的工作流引擎
JMX+J2SE5.0实现Web应用的安全管理
JSP和JSF合并 共同打造完美的Web应用
Eclipse 3.3M5 新版发布 直接下载
 
最近评论:
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(1455)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(5945)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(3048)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(4213)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(7068)
        
冰封的往事!
wow power leveling,wow gold,wow power leveling,wow gold max(2342)
        
冰封的往事!
wow power leveling,wow gold,WoW Gold,wow gold max(3827)
        
冰封的往事!
wow power leveling,wow gold,WoW Gold,wow gold max(7838)
        
飞舞的传奇!
传世私服,传世私服.传奇世界私服传奇世界私服,传世私服传世私服, 传奇世界私服传奇世界私服.传奇私服传奇私服. max(1224)
        
标 题:   
内 容:   
 
                                  
 
免责声明:该文章由网友发表,如果对您造成侵权,请联系站长

首页 - 承接项目 - 网站地图 - 联系我们 -
版权所有北天JAVA技术工作室 ICP证号:粤ICP备06079815号