这编主要是描述 Java JNDI 连 Windows Active Directory 的教程 包括认证 新增用户 修改密码 及 取得用户资料 作者原文: 开始教程: 建立 IIS SSL 将 CA Certificate 加入至 jre keystore 里 JNDI 连 AD 建立 IIS SSL: Install Windows Server: Install AD: Start > Run > dcpromote domain name : joeytaDOTlocal NT domain name : joeytaserver 即 Fully Qualified Domain Name (FQDN) 为 joeytaserverjoeytaDOTlocal 先安装 IIS 再安装 CA Install IIS: Start > Programs > Administrative Tools > Configure Your Server Wizard >> Next > Next > Application server (IIS ASPNET) > Next 进入 表示安装成功 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 进入 表示安装成功 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 必须为 joeyserverjoeytalocal 这是给使用者连 ssl 的 website 最后产生 certificate request file 预设为 c:\certreqtxt Request a certificate on CA: 进入 按 Request a certificate > advanced certificate request > Submit a certificate request by using a baseencoded CMC or PKCS# file or submit a renewal request by using a baseencoded PKCS# file 使用 notepad 打开 c:\certreqtxt copy c:\certreqtxt 内容贴至 Saved Request: Certificate Template 选择 Web Server 按 Submit 然后点选 Download certificate 将 certnewcer 储存至 c:\certnewcer 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:\certnewcer > Next SSL port this web site should use: > Next > Next > Finish 将 CA Certificate 加入至 jre keystore 里: 进入 点选 Download a CA certificate certificate chain or CRL 点选 Download CA certificate 然后下载并改名为 c:\testca_certcer 然后执行 command: c:\temp>keytool import alias testca_cert file /testca_certcer keystore /jdk_/jre/lib/security/cacerts storepass changeit 出现 Trusted this certificate? 按 y 即新增成功
JNDI 连 AD: /***************************** LDAPFastBindjava *****************/ package testldap; import javaioIOException; import javaioUnsupportedEncodingException; import javautilHashtable; import javaxnamingAuthenticationException; import javaxnamingContext; import javaxnamingNamingEnumeration; import javaxnamingNamingException; import javaxnamingdirectoryAttribute; import javaxnamingdirectoryAttributes; import javaxnamingdirectoryBasicAttribute; import javaxnamingdirectoryBasicAttributes; import javaxnamingdirectoryDirContext; import javaxnamingdirectoryModificationItem; import javaxnamingdirectorySearchControls; import javaxnamingdirectorySearchResult; import javaxnamingldapControl; import javaxnamingldapInitialLdapContext; import javaxnamingldapLdapContext; import javaxnamingldapStartTlsRequest; import javaxnamingldapStartTlsResponse; class FastBindConnectionControl implements Control { public byte[] getEncodedValue() { return null; } public String getID() { return ; } 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(); envput(ContextINITIAL_CONTEXT_FACTORY comsunjndildapLdapCtxFactory); envput(ContextSECURITY_AUTHENTICATION simple); envput(ContextPROVIDER_URL ldapurl); envput(ContextSECURITY_PROTOCOLssl); String keystore = /jdk_/jre/lib/security/cacerts; SystemsetProperty(ssltrustStorekeystore); 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) { Systemoutprintln(Naming exception + e); } } public boolean Authenticate(String username String password) { try { ctxaddToEnvironment(ContextSECURITY_PRINCIPAL username); ctxaddToEnvironment(ContextSECURITY_CREDENTIALS password); ctxreconnect(connCtls); Systemoutprintln(username + is authenticated); return true; } catch (AuthenticationException e) { Systemoutprintln(username + is not authenticated); Systemoutprintln(e); return false; } catch (NamingException e) { Systemoutprintln(username + is not authenticated); Systemoutprintln(e); return false; } } public void finito() { try { ctxclose(); Systemoutprintln(Context is closed); } catch (NamingException e) { Systemoutprintln(Context close failure + e); } } public void printUserAccountControl() { try { // Create the search controls SearchControls searchCtls = new SearchControls(); // Specify the search scope searchCtlssetSearchScope(SearchControlsSUBTREE_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=joeytaDC=local; // initialize counter to total the group members int totalResults = ; // Specify the attributes to return String returnedAtts[] = { givenName mail }; searchCtlssetReturningAttributes(returnedAtts); // Search for objects using the filter NamingEnumeration answer = ctxsearch(searchBase searchFilter searchCtls); // Loop through the search results while (answerhasMoreElements()) { SearchResult sr = (SearchResult) answernext(); Systemoutprintln(>>> + srgetName()); // Print out the groups Attributes attrs = srgetAttributes(); if (attrs != null) { try { for (NamingEnumeration ae = attrsgetAll(); ae hasMore();) { Attribute attr = (Attribute) aenext(); Systemoutprintln(Attribute: + attrgetID()); for (NamingEnumeration e = attrgetAll(); e hasMore(); totalResults++) { Systemoutprintln( + totalResults + + enext()); } } } catch (NamingException e) { Systemerrprintln(Problem listing membership: + e); } } } Systemoutprintln(Total attrs: + totalResults); } catch (NamingException e) { Systemerrprintln(Problem searching directory: + e); } } public boolean adminChangePassword(String sUserName String sNewPassword){ try { //set password is a ldap modfy operation ModificationItem[] mods = new ModificationItem[]; //Replace the unicdodePwd attribute with a new value //Password must be both Unicode and a quoted string String newQuotedPassword = \ + sNewPassword + \; byte[] newUnicodePassword = newQuotedPasswordgetBytes(UTFLE); mods[] = new ModificationItem(DirContextREPLACE_ATTRIBUTE new BasicAttribute(unicodePwd newUnicodePassword)); // Perform the update ctxmodifyAttributes(sUserName mods); Systemoutprintln(Reset Password for: + sUserName); return true; } catch (NamingException e) { Systemoutprintln(Problem resetting password: + e); } catch (UnsupportedEncodingException e) { Systemoutprintln(Problem encoding password: + e); } return false; } public boolean userChangePassword(String sUserName String sOldPassword String sNewPassword){ try { //StartTlsResponse tls= //(StartTlsResponse)ctxextendedOperation(new StartTlsRequest()); //tlsnegotiate(); //change password is a single ldap modify operation //that deletes the old password and adds the new password ModificationItem[] mods = new ModificationItem[]; //Firstly delete the unicdodePwd attribute using the old password //Then add the new passwordPasswords must be both Unicode and a quoted string String oldQuotedPassword = \ + sOldPassword + \; byte[] oldUnicodePassword = oldQuotedPasswordgetBytes(UTFLE); String newQuotedPassword = \ + sNewPassword + \; byte[] newUnicodePassword = newQuotedPasswordgetBytes(UTFLE); mods[] = new ModificationItem(DirContextREMOVE_ATTRIBUTE new BasicAttribute(unicodePwd oldUnicodePassword)); mods[] = new ModificationItem(DirContextADD_ATTRIBUTE new BasicAttribute(unicodePwd newUnicodePassword)); // Perform the update ctxmodifyAttributes(sUserName mods); Systemoutprintln(Changed Password for: + sUserName); //tlsclose(); return true; } catch (NamingException e) { Systemerrprintln(Problem changing password: + e); } catch (UnsupportedEncodingException e) { Systemerrprintln(Problem encoding password: + e); } catch ( Exception e){ Systemerrprintln(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 WinK will automagically create a random //samAccountName if it is not present (WinK does not) attrsput(objectClassuser); attrsput(sAMAccountNameAlanT); attrsput(cnAlan Tang); //These are some optional (but useful) attributes attrsput(givenNameAlan); attrsput(snTang); attrsput(displayNameAlan Tang); attrsput(descriptionEngineer); attrsput(userPrincipalNamealanATjoeytalocal); attrsput(mailalangATmailjoeytaDOTlocal); attrsput(telephoneNumber ); //some useful constants from lmaccessh int UF_ACCOUNTDISABLE = x; int UF_PASSWD_NOTREQD = x; int UF_PASSWD_CANT_CHANGE = x; int UF_NORMAL_ACCOUNT = x; int UF_DONT_EXPIRE_PASSWD = x; int UF_PASSWORD_EXPIRED = x; //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 WinK password filter will return error //unwilling to perform attrsput(userAccountControlIntegertoString (UF_NORMAL_ACCOUNT + UF_PASSWD_NOTREQD + UF_PASSWORD_EXPIRED+ UF_ACCOUNTDISABLE)); // Create the context Context result = ctxcreateSubcontext(sUserName attrs); Systemoutprintln(Created disabled account for: + sUserName); //now that weve 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)ctxextendedOperation (new StartTlsRequest()); //tlsnegotiate(); //set password is a ldap modfy operation //and well update the userAccountControl //enabling the acount and force the user to update ther password //the first time they login ModificationItem[] mods = new ModificationItem[]; //Replace the unicdodePwd attribute with a new value //Password must be both Unicode and a quoted string String newQuotedPassword = \PATsswrd\; byte[] newUnicodePassword = newQuotedPasswordgetBytes(UTFLE); mods[] = new ModificationItem(DirContextREPLACE_ATTRIBUTE new BasicAttribute(unicodePwd newUnicodePassword)); mods[] = new ModificationItem(DirContextREPLACE_ATTRIBUTE new BasicAttribute(userAccountControl IntegertoString(UF_NORMAL_ACCOUNT + UF_PASSWORD_EXPIRED))); // Perform the update ctxmodifyAttributes(sUserName mods); Systemoutprintln(Set password & updated userccountControl); //now add the user to a group try{ ModificationItem member[] = new ModificationItem[]; member[]= new ModificationItem(DirContextADD_ATTRIBUTE new BasicAttribute(member sUserName)); ctxmodifyAttributes(sGroupNamemember); Systemoutprintln(Added user to group: + sGroupName); } catch (NamingException e) { Systemerrprintln(Problem adding user to group: + e); } //Could have put tlsclose()prior to the group modification //but it seems to screw up the connectionor context ? //tlsclose(); Systemoutprintln(Successfully created User: + sUserName); return true; } catch (NamingException e) { Systemerrprintln(Problem creating object: + e); } catch (IOException e) { Systemerrprintln(Problem creating object: + e); } return false; } public boolean addUserToGroup(LdapContext ctx String userDN String groupDN) { try{ ModificationItem[] mods = new ModificationItem[]; mods[] = new ModificationItem(DirContextADD_ATTRIBUTE new BasicAttribute(member userDN)); ctxmodifyAttributes(groupDN mods); Systemoutprintln(Added user + userDN + to group + groupDN); return true; } catch (NamingException ne){ Systemerrprintln(Problem add user to group: + ne); } return false; } public boolean removeUserFromGroup(LdapContext ctx String userDN String groupDN) { try{ ModificationItem[] mods = new ModificationItem[]; mods[] = new ModificationItem(DirContextREMOVE_ATTRIBUTE new BasicAttribute(member userDN)); ctxmodifyAttributes(groupDN mods); Systemoutprintln(Remove user + userDN + from group + groupDN); return true; } catch (NamingException ne){ Systemerrprintln(Problem remove user from group: + ne); } return false; } } /***************************** LDAPFastBindjava *****************/ /***************************** LDAPClientjava *****************/ package testldap; class LDAPClient { public static void main(String[] args) { // Could also use ldaps over port to protect the communication to // the // Active Directory domain controller Would also need to add // envput(ContextSECURITY_PROTOCOLssl) to the server code //String ldapurl = ldap://joeyserverjoeytalocal:; String ldapurl = ldap://joeyserverjoeytalocal:; LDAPFastBind ctx = new LDAPFastBind(ldapurl); String sAdminUserName = CN=AdministratorCN=UsersDC=joeytaDC=local; String sAdminPassword = I@mRoot; //String sUserName = CN=peter leeCN=UsersDC=joeytaDC=local; String sUserName = joeyta\\peter; //String sUserName = peter@joeytalocal; String sOldPassword = P@sswrd; String sNewPassword = P@$$wrd; String sNewUserName = CN=Alan TangCN=UsersDC=joyetaDC=local; String sNewGroupName = CN=testCN=UsersDC=joeytaDC=local; boolean IsAuthenticated = ctxAuthenticate(sAdminUserName sAdminPassword); //boolean IsAuthenticated = ctxAuthenticate(sUserName sOldPassword); ctxprintUserAccountControl(); ctxcreateNewUser(sNewGroupName sNewUserName); //boolean IsAdminSuccessChangePWD = //ctxadminChangePassword(sUserNamesNewPassword); //boolean IsUserSuccessChangePWD = //ctxuserChangePassword(sUserNamesOldPasswordsNewPassword); ctxfinito(); } } /***************************** LDAPClientjava *****************/ 参考资料: ;id=&sty=&tpg=&age= a?forumID=&start= |