Index: modules/auth/src/main/java/common/org/apache/harmony/auth/module/LdapLoginModule.java =================================================================== --- modules/auth/src/main/java/common/org/apache/harmony/auth/module/LdapLoginModule.java (revision 0) +++ modules/auth/src/main/java/common/org/apache/harmony/auth/module/LdapLoginModule.java (revision 0) @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.auth.module; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Map; + +import javax.naming.AuthenticationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.apache.harmony.auth.LdapPrincipal; +import org.apache.harmony.auth.UserPrincipal; + +public class LdapLoginModule extends SharedStateManager implements LoginModule { + + private static enum LdapAuthMode{ + search_first("search-first mode"), + authentication_first("authentication-first mode"), + authentication_only("authentication-only mode"); + + private String strValue; + LdapAuthMode(String str){ + strValue = str; + } + + public String toString(){ + return strValue; + } + }; + + //harmony lacks ldap provider + private final String LDAP_FACTORY = ""; + + private LoginModuleUtils.LoginModuleStatus status = new LoginModuleUtils.LoginModuleStatus(); + + private Subject subject; + + private CallbackHandler callbackHandler; + + private Map options; + + private String ldapUserProvider; + + private String userID; + + private char[] userPassword; + + private LdapPrincipal ldapPrincipal; + + private UserPrincipal userPrincipal; + + private UserPrincipal extraUserPrincipal; + + private boolean useSSL = false; + + private LdapAuthMode ldapAuthMode; + + private String userFilter; + + private String authIdentity; + + private String authzIdentity; + + private String ldapPrincipalEntryName; + + public boolean abort() throws LoginException { + LoginModuleUtils.ACTION action = status.checkAbout(); + if (action.equals(LoginModuleUtils.ACTION.no_action)) { + if (status.isLoggined()) { + return true; + } else { + return false; + } + } + clear(); + debugUtil.recordDebugInfo("[LdapLoginModule] aborted authentication\n"); + if(status.isCommitted()){ + debugUtil.recordDebugInfo("[LdapLoginModule]: logged out Subject\n"); + } + debugUtil.printAndClearDebugInfo(); + status.logouted(); + return true; + } + + public boolean commit() throws LoginException { + LoginModuleUtils.ACTION action = status.checkCommit(); + switch (action) { + case no_action: + return true; + case logout: + clear(); + throw new LoginException("Fail to login"); + default: + if (subject.isReadOnly()) { + clear(); + throw new LoginException("Subject is readonly."); + } + subject.getPrincipals().add(ldapPrincipal); + debugUtil.recordDebugInfo("[LdapLoginModule] added LadpPrincipal \""+ ldapPrincipalEntryName + "\" to Subject\n"); + subject.getPrincipals().add(userPrincipal); + debugUtil.recordDebugInfo("[LdapLoginModule] added UserPrincipal \""+ userID + "\" to Subject\n"); + if(extraUserPrincipal != null){ + subject.getPrincipals().add(extraUserPrincipal); + debugUtil.recordDebugInfo("[LdapLoginModule] added UserPrincipal \""+ authzIdentity + "\" to Subject\n"); + } + debugUtil.printAndClearDebugInfo(); + status.committed(); + clearPass(); + return true; + } + } + + @SuppressWarnings("unchecked") + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + this.subject = subject; + this.callbackHandler = callbackHandler; + this.sharedState = (Map) sharedState; + if (null == options) { + throw new NullPointerException(); + } + this.options = options; + debugUtil = new DebugUtil(options); + prepareSharedState(sharedState,options); + processForOptions(); + status.initialized(); + } + + public boolean login() throws LoginException { + LoginModuleUtils.ACTION action = status.checkLogin(); + if (action.equals(LoginModuleUtils.ACTION.no_action)) { + return true; + } + getLdapParameters(); + loginWithSharedState(); +/* if(useFirstPass || tryFirstPass){ + getUserIdentityFromSharedStatus(); + } + else{ + getUserIdentityFromCallbackHandler(); + } + boolean passAuth = false; + passAuth = mainAuthenticationProcess(); + if (!passAuth) { + if(tryFirstPass){ + recordDebugInfo("[LdapLoginModule] tryFirstPass failed with:" + new FailedLoginException("Login incorrect").toString() + "\n"); + getUserIdentityFromCallbackHandler(); + passAuth = mainAuthenticationProcess(); + if(!passAuth){ + recordDebugInfo("[LdapLoginModule] regular authentication failed\n"); + printAndClearDebugInfo(); + throw new FailedLoginException("Cannot bind to LDAP server"); + } + else{ + recordDebugInfo("[LdapLoginModule] regular authentication succeeded\n"); + } + } + else { + if (useFirstPass) { + recordDebugInfo("[LdapLoginModule] useFirstPass failed with:" + + new FailedLoginException("Cannot bind to LDAP server") + .toString() + "\n"); + } else { + recordDebugInfo("[LdapLoginModule] regular authentication failed\n"); + } + printAndClearDebugInfo(); + throw new FailedLoginException("Cannot bind to LDAP server"); + } + } + else{ + if(tryFirstPass){ + recordDebugInfo("[LdapLoginModule] tryFirstPass "); + } + else if(useFirstPass){ + recordDebugInfo("[LdapLoginModule] useFirstPass "); + } + else{ + recordDebugInfo("[LdapLoginModule] authentication "); + } + recordDebugInfo("succeeded\n"); + } + storePass();*/ + try { + getPrinclpalsFromLdap(); + } catch (InvalidNameException e) { + throw new LoginException("Error to get principal from ldap"); + } + debugUtil.printAndClearDebugInfo(); + status.logined(); + return true; + } + + public boolean logout() throws LoginException { + LoginModuleUtils.ACTION action = status.checkLogout(); + if (action.equals(LoginModuleUtils.ACTION.no_action)) { + return true; + } + clear(); + debugUtil.recordDebugInfo("[LdapLoginModule] logged out Subject\n"); + debugUtil.printAndClearDebugInfo(); + status.logouted(); + return true; + } + + private void clear() throws LoginException { + LoginModuleUtils.clearPassword(userPassword); + userPassword = null; + if (ldapPrincipal != null) { + subject.getPrincipals().remove(ldapPrincipal); + ldapPrincipal = null; + } + + if (userPrincipal != null) { + subject.getPrincipals().remove(userPrincipal); + userPrincipal = null; + } + + if (extraUserPrincipal != null) { + subject.getPrincipals().remove(extraUserPrincipal); + extraUserPrincipal = null; + } + status.logouted(); + } + + protected boolean mainAuthenticationProcess() throws LoginException{ + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_FACTORY); + env.put(Context.PROVIDER_URL, ldapUserProvider); + if(useSSL){ + env.put(Context.SECURITY_PROTOCOL, "ssl"); + } + DirContext ctx; + debugUtil.recordDebugInfo("[LdapLoginModule] attempting to authenticate user: "+ userID +"\n"); + try{ + if(ldapAuthMode == LdapAuthMode.search_first){ + boolean logined = false; + env.put(Context.SECURITY_AUTHENTICATION, "none"); + ctx = new InitialDirContext(env); + SearchControls constraints = new SearchControls(); + constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); + debugUtil.recordDebugInfo("[LdapLoginModule] searching for entry belonging to user: "+ userID +"\n"); + NamingEnumeration enumer = ctx.search("", userFilter, constraints); + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + while(enumer.hasMore()){ + NameClassPair item = (NameClassPair) enumer.next(); + try{ + env.put(Context.SECURITY_PRINCIPAL, "simple"); + env.put(Context.SECURITY_PRINCIPAL, item.getNameInNamespace()); + env.put(Context.SECURITY_CREDENTIALS, new String(userPassword)); + ctx = new InitialDirContext(env); + ldapPrincipalEntryName = item.getNameInNamespace(); + debugUtil.recordDebugInfo("[LdapLoginModule] found entry: " + ldapPrincipalEntryName + "\n"); + logined = true; + break; + } + catch(AuthenticationException e){ + + } + } + if(!logined){ + return false; + } + } + else{ + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, authIdentity); + env.put(Context.SECURITY_CREDENTIALS, new String(userPassword)); + try{ + ctx = new InitialDirContext(env); + } + catch(AuthenticationException e){ + return false; + } + if(ldapAuthMode == LdapAuthMode.authentication_only){ + ldapPrincipalEntryName = authIdentity; + } + else{ + SearchControls constraints = new SearchControls(); + constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); + debugUtil.recordDebugInfo("[LdapLoginModule] searching for entry belonging to user: "+ userID +"\n"); + NamingEnumeration enumer = ctx.search("", userFilter, constraints); + if(enumer.hasMore()){ + NameClassPair item = (NameClassPair) enumer.next(); + ldapPrincipalEntryName = item.getNameInNamespace(); + debugUtil.recordDebugInfo("[LdapLoginModule] found entry: " + ldapPrincipalEntryName + "\n"); + } + else{ + return false; + } + } + } + } + catch(NamingException e){ + return false; + } + return true; + } + + private void processForOptions() { + Object optionValue = null; + + optionValue = options.get("useSSL"); + if (optionValue != null && optionValue.equals("true")) { + useSSL = true; + } + + userFilter = (String)options.get("userFilter"); + authIdentity = (String)options.get("authIdentity"); + authzIdentity = (String)options.get("authzIdentity"); + if(authIdentity==null){ + ldapAuthMode = LdapAuthMode.search_first; + } + else if(userFilter==null){ + ldapAuthMode = LdapAuthMode.authentication_only; + } + else{ + ldapAuthMode = LdapAuthMode.authentication_first; + } + debugUtil.recordDebugInfo("[LdapLoginModule] "+ ldapAuthMode + "\n"); + if(useSSL){ + debugUtil.recordDebugInfo("[LdapLoginModule] SSL enabled\n"); + } + else{ + debugUtil.recordDebugInfo("[LdapLoginModule] SSL disabled\n"); + } + debugUtil.printAndClearDebugInfo(); + } + + private void getLdapParameters()throws LoginException{ + ldapUserProvider = (String)options.get("userProvider"); + if (ldapUserProvider == null) { + throw new LoginException("Unable to locate the LDAP directory service"); + } + debugUtil.recordDebugInfo("[LdapLoginModule] user provider: " + ldapUserProvider + "\n"); + } + + protected void getUserIdentityFromCallbackHandler() throws LoginException { + + if (callbackHandler == null) { + throw new LoginException("no CallbackHandler available"); + } + ArrayList callbacks = new ArrayList(); + NameCallback jndiNameCallback = new NameCallback("User ID"); + callbacks.add(jndiNameCallback); + PasswordCallback jndiPasswordCallback = new PasswordCallback( + "User Password", false); + callbacks.add(jndiPasswordCallback); + try { + callbackHandler.handle(callbacks.toArray(new Callback[callbacks + .size()])); + } catch (Exception e) { + throw new LoginException(e.toString()); + } + userID = jndiNameCallback.getName(); + userPassword = jndiPasswordCallback.getPassword(); + } + + private void getPrinclpalsFromLdap() throws InvalidNameException{ + ldapPrincipal = new LdapPrincipal(ldapPrincipalEntryName); + userPrincipal = new UserPrincipal(userID); + if(authzIdentity != null){ + extraUserPrincipal = new UserPrincipal(authzIdentity); + } + } + + @Override + protected String getModuleName() { + return "LdapLoginModule"; + } + + @Override + protected String getUserName() { + return userID; + } + + @Override + protected char[] getUserPassword() { + return userPassword; + } + + @Override + protected void setUserName(String userName) { + this.userID = userName; + } + + @Override + protected void setUserPassword(char[] userPassword) { + this.userPassword = userPassword; + } +} Property changes on: modules\auth\src\main\java\common\org\apache\harmony\auth\module\LdapLoginModule.java ___________________________________________________________________ Name: svn:eol-style + native