You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by le...@apache.org on 2007/10/10 07:32:04 UTC
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/
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<String,?> 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<String,?> 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<String, ?> 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<UnixNumericGroupPrincipal> 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<String, ?> sharedState, Map<String, ?> 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<String, String> env = new Hashtable<String, String>();
+ 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<String, String>();
+ 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<UnixNumericGroupPrincipal>();
+ unixNumericGroupPrincipals.add(new UnixNumericGroupPrincipal(gidNumber,
+ true));
+ }
+
+ protected void getUserIdentityFromCallbackHandler() throws LoginException {
+
+ if (callbackHandler == null) {
+ throw new LoginException("no CallbackHandler available");
+ }
+ ArrayList<Callback> callbacks = new ArrayList<Callback>();
+ 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<String, Object> sharedState;
+
+ @SuppressWarnings("unchecked")
+ protected void prepareSharedState(Map<String, ?> sharedState,
+ final Map<String, ?> options) {
+ this.sharedState = (Map<String, Object>) 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<String, String> options = new HashMap<String, String>();
+
+ 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<Principal> 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<String, String> emptyOptions = new HashMap<String, String>();
+ 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<Principal> 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<String, Object> status = new HashMap<String, Object>();
+ 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<String, Object>();
+ 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