Return-Path: Delivered-To: apmail-harmony-commits-archive@www.apache.org Received: (qmail 12966 invoked from network); 10 Oct 2007 05:32:57 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 10 Oct 2007 05:32:57 -0000 Received: (qmail 63614 invoked by uid 500); 10 Oct 2007 05:32:45 -0000 Delivered-To: apmail-harmony-commits-archive@harmony.apache.org Received: (qmail 63588 invoked by uid 500); 10 Oct 2007 05:32:44 -0000 Mailing-List: contact commits-help@harmony.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@harmony.apache.org Delivered-To: mailing list commits@harmony.apache.org Received: (qmail 63466 invoked by uid 99); 10 Oct 2007 05:32:44 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 09 Oct 2007 22:32:44 -0700 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 10 Oct 2007 05:32:55 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 4A4651A9832; Tue, 9 Oct 2007 22:32:05 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r583360 - in /harmony/enhanced/classlib/trunk/modules/auth: META-INF/ make/ src/main/java/common/org/apache/harmony/auth/module/ src/test/java/common/org/apache/harmony/auth/tests/module/ Date: Wed, 10 Oct 2007 05:32:04 -0000 To: commits@harmony.apache.org From: leoli@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20071010053205.4A4651A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: leoli Date: Tue Oct 9 22:32:03 2007 New Revision: 583360 URL: http://svn.apache.org/viewvc?rev=583360&view=rev Log: Apply patch for HARMONY-4719([classlib][auth]Harmony lacks support for JndiLoginModule). Added: harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/DebugUtil.java (with props) harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/JndiLoginModule.java (with props) harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/SharedStateManager.java (with props) harmony/enhanced/classlib/trunk/modules/auth/src/test/java/common/org/apache/harmony/auth/tests/module/JndiLoginModuleTest.java (with props) Modified: harmony/enhanced/classlib/trunk/modules/auth/META-INF/MANIFEST.MF harmony/enhanced/classlib/trunk/modules/auth/make/exclude.common Modified: harmony/enhanced/classlib/trunk/modules/auth/META-INF/MANIFEST.MF URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/auth/META-INF/MANIFEST.MF?rev=583360&r1=583359&r2=583360&view=diff ============================================================================== --- harmony/enhanced/classlib/trunk/modules/auth/META-INF/MANIFEST.MF (original) +++ harmony/enhanced/classlib/trunk/modules/auth/META-INF/MANIFEST.MF Tue Oct 9 22:32:03 2007 @@ -24,6 +24,8 @@ java.util.zip, javax.crypto, javax.crypto.spec, + javax.naming, + javax.naming.directory, org.apache.harmony.kernel.vm, org.apache.harmony.security, org.apache.harmony.security.asn1, @@ -31,8 +33,8 @@ org.apache.harmony.security.utils, org.apache.harmony.security.x501, org.apache.harmony.testframework.serialization;hy_usage=test;resolution:=optional, - tests.support.resource;hy_usage=test;resolution:=optional, - tests.support;hy_usage=test;resolution:=optional + tests.support;hy_usage=test;resolution:=optional, + tests.support.resource;hy_usage=test;resolution:=optional Export-Package: javax.security.auth, javax.security.auth.callback, javax.security.auth.kerberos, Modified: harmony/enhanced/classlib/trunk/modules/auth/make/exclude.common URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/auth/make/exclude.common?rev=583360&r1=583359&r2=583360&view=diff ============================================================================== --- harmony/enhanced/classlib/trunk/modules/auth/make/exclude.common (original) +++ harmony/enhanced/classlib/trunk/modules/auth/make/exclude.common Tue Oct 9 22:32:03 2007 @@ -1,2 +1,4 @@ # excluded to avoid random failures org/apache/harmony/auth/tests/module/Krb5LoginModuleTest.java +# jndi provider does not exist now +org/apache/harmony/auth/tests/module/JndiLoginModuleTest.java \ No newline at end of file Added: harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/DebugUtil.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/DebugUtil.java?rev=583360&view=auto ============================================================================== --- harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/DebugUtil.java (added) +++ harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/DebugUtil.java Tue Oct 9 22:32:03 2007 @@ -0,0 +1,52 @@ +/* + * 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.Map; + +public class DebugUtil { + + private boolean debugFlag = false; + + private StringBuilder loginDebugInfo = null; + + public DebugUtil(final Map options){ + processDebugSwitch(options); + } + + protected void recordDebugInfo(String debugInfo){ + if(debugFlag) + loginDebugInfo.append(debugInfo); + } + + protected void printAndClearDebugInfo(){ + if(debugFlag) + { + System.out.print(loginDebugInfo.toString()); + loginDebugInfo = new StringBuilder(); + } + } + + private void processDebugSwitch(final Map options){ + Object optionValue = options.get("debug"); + if (optionValue != null && optionValue.equals("true")) { + debugFlag = true; + loginDebugInfo = new StringBuilder(); + } + } +} Propchange: harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/DebugUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Added: harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/JndiLoginModule.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/JndiLoginModule.java?rev=583360&view=auto ============================================================================== --- harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/JndiLoginModule.java (added) +++ harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/JndiLoginModule.java Tue Oct 9 22:32:03 2007 @@ -0,0 +1,322 @@ +/* + * 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.security.Principal; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; + +import javax.naming.Context; +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttributes; +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.UnixNumericGroupPrincipal; +import org.apache.harmony.auth.UnixNumericUserPrincipal; +import org.apache.harmony.auth.UnixPrincipal; + +public class JndiLoginModule extends SharedStateManager implements LoginModule { + + public final String USER_PROVIDER = "group.provider.url"; + + public final String GROUP_PROVIDER = "user.provider.url"; + + //harmony lacks jndi provider + private final String JNDI_FACTORY = ""; + + private LoginModuleUtils.LoginModuleStatus status = new LoginModuleUtils.LoginModuleStatus(); + + private Subject subject; + + private CallbackHandler callbackHandler; + + private Map options; + + private String jndiUserProvider; + + private String jndiGroupProvider; + + private String userID; + + private char[] userPassword; + + private Long uidNumber; + + private Long gidNumber; + + private UnixPrincipal unixPrincipal; + + private UnixNumericUserPrincipal unixNumericUserPrincipal; + + private Set unixNumericGroupPrincipals; + + 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("[JndiLoginModule] aborted authentication failed\n"); + if(status.isCommitted()){ + debugUtil.recordDebugInfo("[JndiLoginModule]: 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(unixPrincipal); + debugUtil.recordDebugInfo("[JndiLoginModule] added UnixPrincipal to Subject\n"); + subject.getPrincipals().add(unixNumericUserPrincipal); + debugUtil.recordDebugInfo("[JndiLoginModule] added UnixNumericUserPrincipal to Subject\n"); + for (Principal principal : unixNumericGroupPrincipals) { + subject.getPrincipals().add(principal); + } + debugUtil.recordDebugInfo("[JndiLoginModule] added UnixNumericGroupPrincipal(s) 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; + if (null == options) { + throw new NullPointerException(); + } + this.options = options; + debugUtil = new DebugUtil(options); + prepareSharedState(sharedState, options); + status.initialized(); + } + + public boolean login() throws LoginException { + LoginModuleUtils.ACTION action = status.checkLogin(); + if (action.equals(LoginModuleUtils.ACTION.no_action)) { + return true; + } + getJndiParameters(); + loginWithSharedState(); + debugUtil.recordDebugInfo("[JndiLoginModule] user: '"+ userID + "' has UID: " + uidNumber + "\n"); + debugUtil.recordDebugInfo("[JndiLoginModule] user: '"+ userID + "' has GID: " + gidNumber + "\n"); + getPrinclpalsFromJndi(); + 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("[JndiLoginModule] logged out Subject\n"); + debugUtil.printAndClearDebugInfo(); + status.logouted(); + return true; + } + + private void getJndiParameters() throws LoginException { + jndiUserProvider = (String) options.get("user.provider.url"); + jndiGroupProvider = (String) options.get("group.provider.url"); + if (jndiUserProvider == null) { + throw new LoginException("Unable to locate JNDI user provider"); + } + if (jndiGroupProvider == null) { + throw new LoginException("Unable to locate JNDI group provider"); + } + debugUtil.recordDebugInfo("[JndiLoginModule] user provider: " + jndiUserProvider + "\n" + +"[JndiLoginModule] group provider: " + jndiGroupProvider + + "\n"); + } + + //not accomplished yet + protected boolean mainAuthenticationProcess() throws LoginException { + + //check group provider + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY); + env.put(Context.PROVIDER_URL, jndiGroupProvider); + try { + DirContext context = new InitialDirContext(env); + context.close(); + } catch (NamingException e) { + throw new LoginException(e.toString()); + } + //check user + env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY); + env.put(Context.PROVIDER_URL, jndiUserProvider); + Attribute passwordAttr; + Attribute uidNumberAttr; + Attribute gidNumberAttr; + String jndiUserPassword = ""; + try { + DirContext context = new InitialDirContext(env); + SearchControls constraints = new SearchControls(); + constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); + Attributes attrs = new BasicAttributes("uid", userID); + NamingEnumeration ne = context.search("", attrs); + String[] attrIds = new String[] { "userPassword", "uidNumber", + "gidNumber" }; + if (ne.hasMore()) { + NameClassPair item = (NameClassPair) ne.next(); + Attributes userAttrs = context.getAttributes(item.getName(), + attrIds); + passwordAttr = userAttrs.get("userPassword"); + if (passwordAttr == null) { + throw new LoginException("Cannot get user password"); + } + jndiUserPassword = new String((byte[])passwordAttr.get()); + if (!jndiUserPassword.equals(crypto(new String(userPassword)))) { + return false; + } + + uidNumberAttr = userAttrs.get("uidNumber"); + if (uidNumberAttr == null) { + throw new LoginException("Cannot get uidNumber information"); + } + uidNumber = Long.valueOf((String) uidNumberAttr.get()); + + gidNumberAttr = userAttrs.get("gidNumber"); + if (gidNumberAttr == null) { + throw new LoginException("Cannot get gidNumber information"); + } + gidNumber = Long.valueOf((String) gidNumberAttr.get()); + } + } catch (NamingException e) { + throw new LoginException(e.toString()); + } + + return true; + } + + private void getPrinclpalsFromJndi() { + unixPrincipal = new UnixPrincipal(userID); + unixNumericUserPrincipal = new UnixNumericUserPrincipal(uidNumber); + unixNumericGroupPrincipals = new HashSet(); + unixNumericGroupPrincipals.add(new UnixNumericGroupPrincipal(gidNumber, + true)); + } + + 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 clear() throws LoginException { + LoginModuleUtils.clearPassword(userPassword); + userPassword = null; + if (unixPrincipal != null) { + subject.getPrincipals().remove(unixPrincipal); + unixPrincipal = null; + } + + if (unixNumericUserPrincipal != null) { + subject.getPrincipals().remove(unixNumericUserPrincipal); + unixNumericUserPrincipal = null; + } + + if (unixNumericGroupPrincipals != null) { + for (UnixNumericGroupPrincipal ungp : unixNumericGroupPrincipals) + subject.getPrincipals().remove(ungp); + unixNumericGroupPrincipals.clear(); + unixNumericGroupPrincipals = null; + } + status.logouted(); + } + + private String crypto(String userPassword) { + //need to implement a crypto algorithm + return userPassword; + } + + protected void setUserName(String userName){ + this.userID = userName; + } + + protected void setUserPassword(char[] userPassword){ + this.userPassword = userPassword; + } + + protected String getUserName(){ + return userID; + } + + protected char[] getUserPassword(){ + return userPassword; + } + + protected String getModuleName(){ + return "JndiLoginModule"; + } +} Propchange: harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/JndiLoginModule.java ------------------------------------------------------------------------------ svn:eol-style = native Added: harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/SharedStateManager.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/SharedStateManager.java?rev=583360&view=auto ============================================================================== --- harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/SharedStateManager.java (added) +++ harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/SharedStateManager.java Tue Oct 9 22:32:03 2007 @@ -0,0 +1,185 @@ +/* + * 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.Map; + +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginException; + +abstract public class SharedStateManager { + + private boolean useFirstPass = false; + + private boolean tryFirstPass = false; + + private boolean storePass = false; + + private boolean clearPass = false; + + protected DebugUtil debugUtil; + + protected Map sharedState; + + @SuppressWarnings("unchecked") + protected void prepareSharedState(Map sharedState, + final Map options) { + this.sharedState = (Map) sharedState; + + useFirstPass = false; + tryFirstPass = false; + storePass = false; + clearPass = false; + Object optionValue = null; + + optionValue = options.get("useFirstPass"); + if (optionValue != null && optionValue.equals("true")) { + useFirstPass = true; + } + + optionValue = options.get("tryFirstPass"); + if (optionValue != null && optionValue.equals("true")) { + tryFirstPass = true; + useFirstPass = false; + } + + optionValue = options.get("storePass"); + if (optionValue != null && optionValue.equals("true")) { + storePass = true; + } + + optionValue = options.get("clearPass"); + if (optionValue != null && optionValue.equals("true")) { + clearPass = true; + storePass = false; + } + } + + protected void loginWithSharedState() throws LoginException { + if (useFirstPass || tryFirstPass) { + getUserIdentityFromSharedStatus(); + } else { + getUserIdentityFromCallbackHandler(); + } + boolean passAuth = false; + passAuth = mainAuthenticationProcess(); + if (!passAuth) { + if (tryFirstPass) { + debugUtil.recordDebugInfo("[" + + getModuleName() + + "] tryFirstPass failed with:" + + new FailedLoginException("Login incorrect") + .toString() + "\n"); + getUserIdentityFromCallbackHandler(); + passAuth = mainAuthenticationProcess(); + if (!passAuth) { + debugUtil.recordDebugInfo("[" + getModuleName() + + "] regular authentication failed\n"); + debugUtil.printAndClearDebugInfo(); + throw new FailedLoginException("Login incorrect"); + } else { + debugUtil.recordDebugInfo("[" + getModuleName() + + "] regular authentication succeeded\n"); + } + } else { + if (useFirstPass) { + debugUtil.recordDebugInfo("[" + + getModuleName() + + "] useFirstPass failed with:" + + new FailedLoginException("Login incorrect") + .toString() + "\n"); + } else { + debugUtil.recordDebugInfo("[" + getModuleName() + + "] regular authentication failed\n"); + } + debugUtil.printAndClearDebugInfo(); + throw new FailedLoginException("Login incorrect"); + } + } else { + if (tryFirstPass) { + debugUtil.recordDebugInfo("[" + getModuleName() + + "] tryFirstPass "); + } else if (useFirstPass) { + debugUtil.recordDebugInfo("[" + getModuleName() + + "] useFirstPass "); + } else { + debugUtil.recordDebugInfo("[" + getModuleName() + + "] regular authentication "); + } + debugUtil.recordDebugInfo("succeeded\n"); + } + storePass(); + } + + private void getUserIdentityFromSharedStatus() throws LoginException { + if (sharedState == null) + throw new LoginException("No shared status"); + String userName = (String) sharedState + .get("javax.security.auth.login.name"); + char[] userPassword = (char[]) sharedState + .get("javax.security.auth.login.password"); + if (userName == null || userPassword == null) { + throw new LoginException( + "Cannot get user ID or user password from shared state"); + } + setUserName(userName); + setUserPassword(userPassword); + } + + protected void storePass() throws LoginException { + if (storePass) { + if (sharedState == null) { + throw new LoginException("No Shared State"); + } + if (sharedState.get("javax.security.auth.login.name") == null) { + sharedState + .put("javax.security.auth.login.name", getUserName()); + } + if (sharedState.get("javax.security.auth.login.password") == null) { + sharedState.put("javax.security.auth.login.password", + getUserPassword()); + } + } + } + + protected void clearPass() throws LoginException { + if (clearPass) { + if (sharedState == null) { + throw new LoginException("No Shared State"); + } + sharedState.remove("javax.security.auth.login.name"); + sharedState.remove("javax.security.auth.login.password"); + } + } + + abstract protected boolean mainAuthenticationProcess() + throws LoginException; + + abstract protected void getUserIdentityFromCallbackHandler() + throws LoginException; + + abstract protected void setUserName(String userName); + + abstract protected String getUserName(); + + abstract protected void setUserPassword(char[] userPassword); + + abstract protected char[] getUserPassword(); + + abstract protected String getModuleName(); +} Propchange: harmony/enhanced/classlib/trunk/modules/auth/src/main/java/common/org/apache/harmony/auth/module/SharedStateManager.java ------------------------------------------------------------------------------ svn:eol-style = native Added: harmony/enhanced/classlib/trunk/modules/auth/src/test/java/common/org/apache/harmony/auth/tests/module/JndiLoginModuleTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/auth/src/test/java/common/org/apache/harmony/auth/tests/module/JndiLoginModuleTest.java?rev=583360&view=auto ============================================================================== --- harmony/enhanced/classlib/trunk/modules/auth/src/test/java/common/org/apache/harmony/auth/tests/module/JndiLoginModuleTest.java (added) +++ harmony/enhanced/classlib/trunk/modules/auth/src/test/java/common/org/apache/harmony/auth/tests/module/JndiLoginModuleTest.java Tue Oct 9 22:32:03 2007 @@ -0,0 +1,329 @@ +/* + * 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.tests.module; + +import java.io.IOException; +import java.security.Principal; +import java.util.HashMap; +import java.util.Set; + +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.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; + +import junit.framework.TestCase; + +import org.apache.harmony.auth.module.JndiLoginModule; + +public class JndiLoginModuleTest extends TestCase { + + // module options + private HashMap options = new HashMap(); + + private final String LDAP_SERVER_LOCATION = ""; + + private final String USER_PROVIDER_URL = "ldap://" + LDAP_SERVER_LOCATION + + ":389/ou=People,o=JNDITutorial,dc=my-domain,dc=com"; + + private final String GROUP_PROVIDER_URL = "ldap://" + LDAP_SERVER_LOCATION + + ":389/ou=Groups,o=JNDITutorial,dc=my-domain,dc=com"; + + protected void setUp() throws Exception { + options.put("user.provider.url", USER_PROVIDER_URL); + options.put("group.provider.url", GROUP_PROVIDER_URL); + } + + @Override + protected void tearDown() throws Exception { + options.clear(); + } + + /** + * Test method for + * {@link org.apache.harmony.auth.module.JndiLoginModule#abort()}. + */ + public void test_abort() throws LoginException { + JndiLoginModule jlm = new JndiLoginModule(); + try { + assertFalse("Should return false if login failed or no login", jlm + .abort()); + } catch (LoginException e) { + fail("Abort failed"); + } + Subject subject = new Subject(); + subject.setReadOnly(); + jlm.initialize(subject, null, null, options); + try { + assertFalse("Should return false if login failed or no login", jlm + .abort()); + } catch (Exception e) { + fail("Not any exception here"); + } + subject = new Subject(); + jlm.initialize(subject, new FaultCallbackHandler(), null, options); + try { + jlm.login(); + fail("login should fail"); + } catch (LoginException e) { + assertFalse("Should return false because of login failure", jlm + .abort()); + } + subject = new Subject(); + jlm.initialize(subject, new MockCallbackHandler(), null, options); + jlm.login(); + assertTrue("Should return true if login was successful", jlm.abort()); + } + + /** + * Test method for + * {@link org.apache.harmony.auth.module.JndiLoginModule#commit()}. + */ + public void test_commit() { + JndiLoginModule module = new JndiLoginModule(); + Subject subject = new Subject(); + module.initialize(subject, new MockCallbackHandler(), null, options); + try { + assertTrue("Login should be successful", module.login()); + module.commit(); + } catch (LoginException e) { + fail("Login shouldn't fail"); + } + Set principals = subject.getPrincipals(); + assertFalse("Should get at least one principal", principals.isEmpty()); + subject = new Subject(); + subject.setReadOnly(); + module.initialize(subject, new MockCallbackHandler(), null, options); + try { + assertFalse("Commit shouldn't be successful", module.commit()); + fail("Should throw LoginException here because of trying to clear read-only subject"); + } catch (LoginException e) { + // expected LoginException here + } + } + + /** + * Test method for + * {@link org.apache.harmony.auth.module.JndiLoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)}. + */ + public void test_initialize() { + JndiLoginModule module = new JndiLoginModule(); + try { + module.initialize(null, null, null, null); + fail("Should throw NullPointerException here."); + } catch (NullPointerException e) { + // expected NullPointerException + } + } + + /** + * Test method for + * {@link org.apache.harmony.auth.module.JndiLoginModule#login()}. + */ + public void test_login() { + JndiLoginModule module = new JndiLoginModule(); + HashMap emptyOptions = new HashMap(); + module.initialize(null, new MockCallbackHandler(), null, emptyOptions); + try { + module.login(); + fail("Should throw LoginException here."); + } catch (LoginException e) { + // expected LoginException + } + + Subject subject = new Subject(); + module.initialize(subject, new MockCallbackHandler(), null, options); + try { + assertTrue("Login should be successful", module.login()); + } catch (LoginException e) { + fail("Login shouldn't fail"); + } + module.initialize(subject, new FaultCallbackHandler(), null, options); + try { + assertFalse("Login shouldn't be successful", module.login()); + fail("Login should fail"); + } catch (LoginException e) { + // expected Loginexception here + } + } + + /** + * Test method for + * {@link org.apache.harmony.auth.module.JndiLoginModule#logout()}. + */ + public void test_logout() { + JndiLoginModule module = new JndiLoginModule(); + Subject subject = new Subject(); + module.initialize(subject, new MockCallbackHandler(), null, options); + try { + assertTrue("Login should be successful", module.login()); + module.commit(); + } catch (LoginException e) { + fail("Login shouldn't fail"); + } + Set principals = subject.getPrincipals(); + assertFalse("Should get at least one principal", principals.isEmpty()); + try { + assertTrue("Should be true", module.logout()); + } catch (LoginException e) { + fail("Logout failed"); + } + principals = subject.getPrincipals(); + assertTrue("Principals should be cleared", principals.isEmpty()); + } + + public void test_optionsAndSharedStatus() throws LoginException { + options.put("debug", "true"); + options.put("useFirstPass", "true"); + HashMap status = new HashMap(); + status.put("javax.security.auth.login.name", "leo"); + status.put("javax.security.auth.login.password", "faultPass" + .toCharArray()); + JndiLoginModule module = new JndiLoginModule(); + Subject subject = new Subject(); + module.initialize(subject, new MockCallbackHandler(), status, options); + try { + module.login(); + fail("Should be failed for using password from shared state"); + } catch (LoginException e) { + // expected LoginException here + } + + options.remove("useFirstPass"); + options.put("tryFirstPass", "true"); + module.initialize(subject, new MockCallbackHandler(), status, options); + try { + module.login(); + module.commit(); + } catch (LoginException e) { + fail("Login should be failed"); + } finally { + module.logout(); + } + + options.remove("tryFirstPass"); + options.put("clearPass", "true"); + status.put("javax.security.auth.login.name", "leo"); + status.put("javax.security.auth.login.password", "passw0rd" + .toCharArray()); + module.initialize(subject, new MockCallbackHandler(), status, options); + try { + module.login(); + module.commit(); + assertNull( + "javax.security.auth.login.name in shared state should be null when clearPass switch on", + status.get("javax.security.auth.login.name")); + assertNull( + "javax.security.auth.login.password in shared state should be null when clearPass switch on", + status.get("javax.security.auth.login.password")); + } catch (LoginException e) { + fail("Login shouldn't fail"); + } finally { + module.logout(); + } + + status = new HashMap(); + options.remove("clearPass"); + options.put("storePass", "true"); + module.initialize(subject, new FaultCallbackHandler(), status, options); + try { + module.login(); + module.commit(); + } catch (LoginException e) { + assertNull( + "javax.security.auth.login.name in shared state should be null when login failed", + status.get("javax.security.auth.login.name")); + assertNull( + "javax.security.auth.login.password in shared state should be null when login failed", + status.get("javax.security.auth.login.password")); + } finally { + module.logout(); + } + + module.initialize(subject, new MockCallbackHandler(), status, options); + try { + module.login(); + module.commit(); + } catch (LoginException e) { + fail("Login failed"); + } finally { + module.logout(); + } + assertNotNull( + "javax.security.auth.login.name should be stored in shared state when storePass switch on", + status.get("javax.security.auth.login.name")); + assertNotNull( + "javax.security.auth.login.password should be stored in shared state when storePass switch on", + status.get("javax.security.auth.login.password")); + + status.put("javax.security.auth.login.name", "tester"); + status.put("javax.security.auth.login.password", "testerPass"); + module.initialize(subject, new MockCallbackHandler(), status, options); + try { + module.login(); + module.commit(); + } catch (LoginException e) { + fail("Login failed"); + } finally { + module.logout(); + } + assertEquals("Should't override the username value in sharedState", + status.get("javax.security.auth.login.name"), "tester"); + assertEquals("Should't override the password value in sharedState", + status.get("javax.security.auth.login.password"), "testerPass"); + } + + static private class MockCallbackHandler implements CallbackHandler { + + public void handle(Callback[] callbacks) throws IOException, + UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof NameCallback) { + NameCallback nc = (NameCallback) callbacks[i]; + nc.setName("leo"); + } else if (callbacks[i] instanceof PasswordCallback) { + PasswordCallback pc = (PasswordCallback) callbacks[i]; + pc.setPassword("passw0rd".toCharArray()); + } else { + throw new Error(callbacks[i].getClass().toString()); + } + } + } + } + + static private class FaultCallbackHandler implements CallbackHandler { + + public void handle(Callback[] callbacks) throws IOException, + UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof NameCallback) { + NameCallback nc = (NameCallback) callbacks[i]; + nc.setName("leo"); + } else if (callbacks[i] instanceof PasswordCallback) { + PasswordCallback pc = (PasswordCallback) callbacks[i]; + pc.setPassword("password".toCharArray()); + } else { + throw new Error(callbacks[i].getClass().toString()); + } + } + } + } +} Propchange: harmony/enhanced/classlib/trunk/modules/auth/src/test/java/common/org/apache/harmony/auth/tests/module/JndiLoginModuleTest.java ------------------------------------------------------------------------------ svn:eol-style = native