You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by va...@apache.org on 2007/10/31 21:15:51 UTC
svn commit: r590807 - in /geronimo/server:
branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/
branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/
trunk/framework/module...
Author: vamsic007
Date: Wed Oct 31 13:15:48 2007
New Revision: 590807
URL: http://svn.apache.org/viewvc?rev=590807&view=rev
Log:
**GERONIMO-3571 Review PropertiesFileLoginModule
o LoginModule should not add principals when login fails. Added a test to detect the same.
o Other changes to bring PropertiesFileLoginModule in line with http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASLMDevGuide.html
**: This fix can use a thorough review.
Added:
geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java (with props)
geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java (with props)
geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java (with props)
Modified:
geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java
geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java
geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java
Modified: geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java?rev=590807&r1=590806&r2=590807&view=diff
==============================================================================
--- geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java (original)
+++ geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java Wed Oct 31 13:15:48 2007
@@ -23,9 +23,12 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -66,6 +69,7 @@
public final static String GROUPS_URI = "groupsURI";
public final static String DIGEST = "digest";
public final static String ENCODING = "encoding";
+ public final static List<String> supportedOptions = Arrays.asList(USERS_URI, GROUPS_URI, DIGEST, ENCODING);
private static Log log = LogFactory.getLog(PropertiesFileLoginModule.class);
final Properties users = new Properties();
@@ -73,14 +77,21 @@
private String digest;
private String encoding;
+ private boolean loginSucceeded;
private Subject subject;
private CallbackHandler handler;
private String username;
private String password;
+ private final Set<Principal> allPrincipals = new HashSet<Principal>();
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
this.subject = subject;
this.handler = callbackHandler;
+ for(Object option: options.keySet()) {
+ if(!supportedOptions.contains(option)) {
+ log.warn("Ignoring option: "+option+". Not supported.");
+ }
+ }
try {
ServerInfo serverInfo = (ServerInfo) options.get(JaasLoginModuleUse.SERVERINFO_LM_OPTION);
final String users = (String) options.get(USERS_URI);
@@ -152,7 +163,13 @@
}
+ /**
+ * This LoginModule is not to be ignored. So, this method should never return false.
+ * @return true if authentication succeeds, or throw a LoginException such as FailedLoginException
+ * if authentication fails
+ */
public boolean login() throws LoginException {
+ loginSucceeded = false;
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("User name");
@@ -167,6 +184,9 @@
assert callbacks.length == 2;
username = ((NameCallback) callbacks[0]).getName();
if (username == null || username.equals("")) {
+ // Clear out the private state
+ username = null;
+ password = null;
throw new FailedLoginException();
}
String realPassword = users.getProperty(username);
@@ -177,41 +197,65 @@
char[] entered = ((PasswordCallback) callbacks[1]).getPassword();
password = entered == null ? null : new String(entered);
if (!checkPassword(realPassword, password)) {
+ // Clear out the private state
+ username = null;
+ password = null;
throw new FailedLoginException();
}
+
+ loginSucceeded = true;
return true;
}
+ /*
+ * @exception LoginException if login succeeded but commit failed.
+ *
+ * @return true if login succeeded and commit succeeded, or false if login failed but commit succeeded.
+ */
public boolean commit() throws LoginException {
- Set<Principal> principals = subject.getPrincipals();
-
- principals.add(new GeronimoUserPrincipal(username));
-
- for (Map.Entry<String, Set<String>> entry : groups.entrySet()) {
- String groupName = entry.getKey();
- Set<String> users = entry.getValue();
- for (String user : users) {
- if (username.equals(user)) {
- principals.add(new GeronimoGroupPrincipal(groupName));
- break;
+ if(loginSucceeded) {
+ if(username != null) {
+ allPrincipals.add(new GeronimoUserPrincipal(username));
+ }
+ for (Map.Entry<String, Set<String>> entry : groups.entrySet()) {
+ String groupName = entry.getKey();
+ Set<String> users = entry.getValue();
+ for (String user : users) {
+ if (username.equals(user)) {
+ allPrincipals.add(new GeronimoGroupPrincipal(groupName));
+ break;
+ }
}
}
+ subject.getPrincipals().addAll(allPrincipals);
}
+ // Clear out the private state
+ username = null;
+ password = null;
- return true;
+ return loginSucceeded;
}
public boolean abort() throws LoginException {
- username = null;
- password = null;
-
- return true;
+ if(loginSucceeded) {
+ // Clear out the private state
+ username = null;
+ password = null;
+ allPrincipals.retainAll(Collections.EMPTY_SET);
+ }
+ return loginSucceeded;
}
public boolean logout() throws LoginException {
+ // Clear out the private state
+ loginSucceeded = false;
username = null;
password = null;
- //todo: should remove principals added by commit
+ if(!subject.isReadOnly()) {
+ // Remove principals added by this LoginModule
+ subject.getPrincipals().removeAll(allPrincipals);
+ }
+ allPrincipals.retainAll(Collections.EMPTY_SET);
return true;
}
Added: geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java?rev=590807&view=auto
==============================================================================
--- geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java (added)
+++ geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java Wed Oct 31 13:15:48 2007
@@ -0,0 +1,123 @@
+/**
+ * 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.geronimo.security.jaas;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+
+import org.apache.geronimo.gbean.AbstractName;
+import org.apache.geronimo.gbean.GBeanData;
+import org.apache.geronimo.security.AbstractTest;
+import org.apache.geronimo.security.realm.GenericSecurityRealm;
+
+
+/**
+ * This test makes sure that PropertiesFileLoginModule does not add any principals when login fails
+ * @version $Rev$ $Date$
+ */
+public class LoginPropertiesFileAdvancedTest extends AbstractTest {
+ protected AbstractName clientCE;
+ protected AbstractName testCE;
+ protected AbstractName testRealm;
+ protected AbstractName neverFailModule;
+
+ public void setUp() throws Exception {
+ needServerInfo = true;
+ needLoginConfiguration = true;
+ super.setUp();
+
+ GBeanData gbean;
+
+ gbean = buildGBeanData("name", "NeverFailLoginModule", LoginModuleGBean.getGBeanInfo());
+ neverFailModule = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.jaas.NeverFailLoginModule");
+ gbean.setAttribute("options", null);
+ gbean.setAttribute("loginDomainName", "NeverFailDomain");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(neverFailModule);
+
+ gbean = buildGBeanData("name", "PropertiesLoginModule", LoginModuleGBean.getGBeanInfo());
+ testCE = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.realm.providers.PropertiesFileLoginModule");
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("usersURI", new File(BASEDIR, "src/test/data/data/users.properties").toURI().toString());
+ props.put("groupsURI", new File(BASEDIR, "src/test/data/data/groups.properties").toURI().toString());
+ gbean.setAttribute("options", props);
+ gbean.setAttribute("loginDomainName", "TestProperties");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(testCE);
+
+ gbean = buildGBeanData("name", "PropertiesLoginModuleUse", JaasLoginModuleUse.getGBeanInfo());
+ AbstractName propsUseName = gbean.getAbstractName();
+ gbean.setAttribute("controlFlag", LoginModuleControlFlag.OPTIONAL);
+ gbean.setReferencePattern("LoginModule", testCE);
+ kernel.loadGBean(gbean, JaasLoginModuleUse.class.getClassLoader());
+ kernel.startGBean(propsUseName);
+
+ gbean = buildGBeanData("name", "NeverFailLoginModuleUse", JaasLoginModuleUse.getGBeanInfo());
+ AbstractName neverFailUseName = gbean.getAbstractName();
+ gbean.setAttribute("controlFlag", LoginModuleControlFlag.REQUIRED);
+ gbean.setReferencePattern("LoginModule", neverFailModule);
+ gbean.setReferencePattern("Next", propsUseName);
+ kernel.loadGBean(gbean, JaasLoginModuleUse.class.getClassLoader());
+ kernel.startGBean(neverFailUseName);
+
+ gbean = buildGBeanData("name", "PropertiesSecurityRealm", GenericSecurityRealm.getGBeanInfo());
+ testRealm = gbean.getAbstractName();
+ gbean.setAttribute("realmName", "properties-realm");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ gbean.setReferencePattern("LoginModuleConfiguration", neverFailUseName);
+ gbean.setReferencePattern("ServerInfo", serverInfo);
+ kernel.loadGBean(gbean, GenericSecurityRealm.class.getClassLoader());
+
+ kernel.startGBean(loginConfiguration);
+ kernel.startGBean(testRealm);
+ }
+
+ public void tearDown() throws Exception {
+ kernel.stopGBean(testRealm);
+ kernel.stopGBean(loginConfiguration);
+ kernel.stopGBean(testCE);
+ kernel.stopGBean(neverFailModule);
+ kernel.stopGBean(serverInfo);
+
+ kernel.unloadGBean(testRealm);
+ kernel.unloadGBean(loginConfiguration);
+ kernel.unloadGBean(testCE);
+ kernel.unloadGBean(neverFailModule);
+ kernel.unloadGBean(serverInfo);
+
+ super.tearDown();
+ }
+
+ public void testBadPasswordLogin() throws Exception {
+ LoginContext context = new LoginContext("properties-realm", new UsernamePasswordCallback("alan", "bad"));
+
+ context.login();
+ Subject subject = context.getSubject();
+ assertTrue("expected non-null subject", subject != null);
+ assertTrue("expected zero principals", subject.getPrincipals().size() == 0);
+ context.logout();
+ }
+}
Propchange: geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java?rev=590807&r1=590806&r2=590807&view=diff
==============================================================================
--- geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java (original)
+++ geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java Wed Oct 31 13:15:48 2007
@@ -23,9 +23,12 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -66,6 +69,7 @@
public final static String GROUPS_URI = "groupsURI";
public final static String DIGEST = "digest";
public final static String ENCODING = "encoding";
+ public final static List<String> supportedOptions = Arrays.asList(USERS_URI, GROUPS_URI, DIGEST, ENCODING);
private static Log log = LogFactory.getLog(PropertiesFileLoginModule.class);
final Properties users = new Properties();
@@ -73,14 +77,21 @@
private String digest;
private String encoding;
+ private boolean loginSucceeded;
private Subject subject;
private CallbackHandler handler;
private String username;
private String password;
+ private final Set<Principal> allPrincipals = new HashSet<Principal>();
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
this.subject = subject;
this.handler = callbackHandler;
+ for(Object option: options.keySet()) {
+ if(!supportedOptions.contains(option)) {
+ log.warn("Ignoring option: "+option+". Not supported.");
+ }
+ }
try {
ServerInfo serverInfo = (ServerInfo) options.get(JaasLoginModuleUse.SERVERINFO_LM_OPTION);
final String users = (String) options.get(USERS_URI);
@@ -152,7 +163,13 @@
}
+ /**
+ * This LoginModule is not to be ignored. So, this method should never return false.
+ * @return true if authentication succeeds, or throw a LoginException such as FailedLoginException
+ * if authentication fails
+ */
public boolean login() throws LoginException {
+ loginSucceeded = false;
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("User name");
@@ -167,6 +184,9 @@
assert callbacks.length == 2;
username = ((NameCallback) callbacks[0]).getName();
if (username == null || username.equals("")) {
+ // Clear out the private state
+ username = null;
+ password = null;
throw new FailedLoginException();
}
String realPassword = users.getProperty(username);
@@ -177,41 +197,65 @@
char[] entered = ((PasswordCallback) callbacks[1]).getPassword();
password = entered == null ? null : new String(entered);
if (!checkPassword(realPassword, password)) {
+ // Clear out the private state
+ username = null;
+ password = null;
throw new FailedLoginException();
}
+
+ loginSucceeded = true;
return true;
}
+ /*
+ * @exception LoginException if login succeeded but commit failed.
+ *
+ * @return true if login succeeded and commit succeeded, or false if login failed but commit succeeded.
+ */
public boolean commit() throws LoginException {
- Set<Principal> principals = subject.getPrincipals();
-
- principals.add(new GeronimoUserPrincipal(username));
-
- for (Map.Entry<String, Set<String>> entry : groups.entrySet()) {
- String groupName = entry.getKey();
- Set<String> users = entry.getValue();
- for (String user : users) {
- if (username.equals(user)) {
- principals.add(new GeronimoGroupPrincipal(groupName));
- break;
+ if(loginSucceeded) {
+ if(username != null) {
+ allPrincipals.add(new GeronimoUserPrincipal(username));
+ }
+ for (Map.Entry<String, Set<String>> entry : groups.entrySet()) {
+ String groupName = entry.getKey();
+ Set<String> users = entry.getValue();
+ for (String user : users) {
+ if (username.equals(user)) {
+ allPrincipals.add(new GeronimoGroupPrincipal(groupName));
+ break;
+ }
}
}
+ subject.getPrincipals().addAll(allPrincipals);
}
+ // Clear out the private state
+ username = null;
+ password = null;
- return true;
+ return loginSucceeded;
}
public boolean abort() throws LoginException {
- username = null;
- password = null;
-
- return true;
+ if(loginSucceeded) {
+ // Clear out the private state
+ username = null;
+ password = null;
+ allPrincipals.retainAll(Collections.EMPTY_SET);
+ }
+ return loginSucceeded;
}
public boolean logout() throws LoginException {
+ // Clear out the private state
+ loginSucceeded = false;
username = null;
password = null;
- //todo: should remove principals added by commit
+ if(!subject.isReadOnly()) {
+ // Remove principals added by this LoginModule
+ subject.getPrincipals().removeAll(allPrincipals);
+ }
+ allPrincipals.retainAll(Collections.EMPTY_SET);
return true;
}
Added: geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java?rev=590807&view=auto
==============================================================================
--- geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java (added)
+++ geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java Wed Oct 31 13:15:48 2007
@@ -0,0 +1,123 @@
+/**
+ * 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.geronimo.security.jaas;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+
+import org.apache.geronimo.gbean.AbstractName;
+import org.apache.geronimo.gbean.GBeanData;
+import org.apache.geronimo.security.AbstractTest;
+import org.apache.geronimo.security.realm.GenericSecurityRealm;
+
+
+/**
+ * This test makes sure that PropertiesFileLoginModule does not add any principals when login fails
+ * @version $Rev$ $Date$
+ */
+public class LoginPropertiesFileAdvancedTest extends AbstractTest {
+ protected AbstractName clientCE;
+ protected AbstractName testCE;
+ protected AbstractName testRealm;
+ protected AbstractName neverFailModule;
+
+ public void setUp() throws Exception {
+ needServerInfo = true;
+ needLoginConfiguration = true;
+ super.setUp();
+
+ GBeanData gbean;
+
+ gbean = buildGBeanData("name", "NeverFailLoginModule", LoginModuleGBean.getGBeanInfo());
+ neverFailModule = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.jaas.NeverFailLoginModule");
+ gbean.setAttribute("options", null);
+ gbean.setAttribute("loginDomainName", "NeverFailDomain");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(neverFailModule);
+
+ gbean = buildGBeanData("name", "PropertiesLoginModule", LoginModuleGBean.getGBeanInfo());
+ testCE = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.realm.providers.PropertiesFileLoginModule");
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("usersURI", new File(BASEDIR, "src/test/data/data/users.properties").toURI().toString());
+ props.put("groupsURI", new File(BASEDIR, "src/test/data/data/groups.properties").toURI().toString());
+ gbean.setAttribute("options", props);
+ gbean.setAttribute("loginDomainName", "TestProperties");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(testCE);
+
+ gbean = buildGBeanData("name", "PropertiesLoginModuleUse", JaasLoginModuleUse.getGBeanInfo());
+ AbstractName propsUseName = gbean.getAbstractName();
+ gbean.setAttribute("controlFlag", LoginModuleControlFlag.OPTIONAL);
+ gbean.setReferencePattern("LoginModule", testCE);
+ kernel.loadGBean(gbean, JaasLoginModuleUse.class.getClassLoader());
+ kernel.startGBean(propsUseName);
+
+ gbean = buildGBeanData("name", "NeverFailLoginModuleUse", JaasLoginModuleUse.getGBeanInfo());
+ AbstractName neverFailUseName = gbean.getAbstractName();
+ gbean.setAttribute("controlFlag", LoginModuleControlFlag.REQUIRED);
+ gbean.setReferencePattern("LoginModule", neverFailModule);
+ gbean.setReferencePattern("Next", propsUseName);
+ kernel.loadGBean(gbean, JaasLoginModuleUse.class.getClassLoader());
+ kernel.startGBean(neverFailUseName);
+
+ gbean = buildGBeanData("name", "PropertiesSecurityRealm", GenericSecurityRealm.getGBeanInfo());
+ testRealm = gbean.getAbstractName();
+ gbean.setAttribute("realmName", "properties-realm");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ gbean.setReferencePattern("LoginModuleConfiguration", neverFailUseName);
+ gbean.setReferencePattern("ServerInfo", serverInfo);
+ kernel.loadGBean(gbean, GenericSecurityRealm.class.getClassLoader());
+
+ kernel.startGBean(loginConfiguration);
+ kernel.startGBean(testRealm);
+ }
+
+ public void tearDown() throws Exception {
+ kernel.stopGBean(testRealm);
+ kernel.stopGBean(loginConfiguration);
+ kernel.stopGBean(testCE);
+ kernel.stopGBean(neverFailModule);
+ kernel.stopGBean(serverInfo);
+
+ kernel.unloadGBean(testRealm);
+ kernel.unloadGBean(loginConfiguration);
+ kernel.unloadGBean(testCE);
+ kernel.unloadGBean(neverFailModule);
+ kernel.unloadGBean(serverInfo);
+
+ super.tearDown();
+ }
+
+ public void testBadPasswordLogin() throws Exception {
+ LoginContext context = new LoginContext("properties-realm", new UsernamePasswordCallback("alan", "bad"));
+
+ context.login();
+ Subject subject = context.getSubject();
+ assertTrue("expected non-null subject", subject != null);
+ assertTrue("expected zero principals", subject.getPrincipals().size() == 0);
+ context.logout();
+ }
+}
Propchange: geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java?rev=590807&r1=590806&r2=590807&view=diff
==============================================================================
--- geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java (original)
+++ geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/PropertiesFileLoginModule.java Wed Oct 31 13:15:48 2007
@@ -23,9 +23,12 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -66,6 +69,7 @@
public final static String GROUPS_URI = "groupsURI";
public final static String DIGEST = "digest";
public final static String ENCODING = "encoding";
+ public final static List<String> supportedOptions = Arrays.asList(USERS_URI, GROUPS_URI, DIGEST, ENCODING);
private static Log log = LogFactory.getLog(PropertiesFileLoginModule.class);
final Properties users = new Properties();
@@ -73,14 +77,21 @@
private String digest;
private String encoding;
+ private boolean loginSucceeded;
private Subject subject;
private CallbackHandler handler;
private String username;
private String password;
+ private final Set<Principal> allPrincipals = new HashSet<Principal>();
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
this.subject = subject;
this.handler = callbackHandler;
+ for(Object option: options.keySet()) {
+ if(!supportedOptions.contains(option)) {
+ log.warn("Ignoring option: "+option+". Not supported.");
+ }
+ }
try {
ServerInfo serverInfo = (ServerInfo) options.get(JaasLoginModuleUse.SERVERINFO_LM_OPTION);
final String users = (String) options.get(USERS_URI);
@@ -152,7 +163,13 @@
}
+ /**
+ * This LoginModule is not to be ignored. So, this method should never return false.
+ * @return true if authentication succeeds, or throw a LoginException such as FailedLoginException
+ * if authentication fails
+ */
public boolean login() throws LoginException {
+ loginSucceeded = false;
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("User name");
@@ -167,6 +184,9 @@
assert callbacks.length == 2;
username = ((NameCallback) callbacks[0]).getName();
if (username == null || username.equals("")) {
+ // Clear out the private state
+ username = null;
+ password = null;
throw new FailedLoginException();
}
String realPassword = users.getProperty(username);
@@ -177,41 +197,65 @@
char[] entered = ((PasswordCallback) callbacks[1]).getPassword();
password = entered == null ? null : new String(entered);
if (!checkPassword(realPassword, password)) {
+ // Clear out the private state
+ username = null;
+ password = null;
throw new FailedLoginException();
}
+
+ loginSucceeded = true;
return true;
}
+ /*
+ * @exception LoginException if login succeeded but commit failed.
+ *
+ * @return true if login succeeded and commit succeeded, or false if login failed but commit succeeded.
+ */
public boolean commit() throws LoginException {
- Set<Principal> principals = subject.getPrincipals();
-
- principals.add(new GeronimoUserPrincipal(username));
-
- for (Map.Entry<String, Set<String>> entry : groups.entrySet()) {
- String groupName = entry.getKey();
- Set<String> users = entry.getValue();
- for (String user : users) {
- if (username.equals(user)) {
- principals.add(new GeronimoGroupPrincipal(groupName));
- break;
+ if(loginSucceeded) {
+ if(username != null) {
+ allPrincipals.add(new GeronimoUserPrincipal(username));
+ }
+ for (Map.Entry<String, Set<String>> entry : groups.entrySet()) {
+ String groupName = entry.getKey();
+ Set<String> users = entry.getValue();
+ for (String user : users) {
+ if (username.equals(user)) {
+ allPrincipals.add(new GeronimoGroupPrincipal(groupName));
+ break;
+ }
}
}
+ subject.getPrincipals().addAll(allPrincipals);
}
+ // Clear out the private state
+ username = null;
+ password = null;
- return true;
+ return loginSucceeded;
}
public boolean abort() throws LoginException {
- username = null;
- password = null;
-
- return true;
+ if(loginSucceeded) {
+ // Clear out the private state
+ username = null;
+ password = null;
+ allPrincipals.retainAll(Collections.EMPTY_SET);
+ }
+ return loginSucceeded;
}
public boolean logout() throws LoginException {
+ // Clear out the private state
+ loginSucceeded = false;
username = null;
password = null;
- //todo: should remove principals added by commit
+ if(!subject.isReadOnly()) {
+ // Remove principals added by this LoginModule
+ subject.getPrincipals().removeAll(allPrincipals);
+ }
+ allPrincipals.retainAll(Collections.EMPTY_SET);
return true;
}
Added: geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java?rev=590807&view=auto
==============================================================================
--- geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java (added)
+++ geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java Wed Oct 31 13:15:48 2007
@@ -0,0 +1,123 @@
+/**
+ * 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.geronimo.security.jaas;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+
+import org.apache.geronimo.gbean.AbstractName;
+import org.apache.geronimo.gbean.GBeanData;
+import org.apache.geronimo.security.AbstractTest;
+import org.apache.geronimo.security.realm.GenericSecurityRealm;
+
+
+/**
+ * This test makes sure that PropertiesFileLoginModule does not add any principals when login fails
+ * @version $Rev$ $Date$
+ */
+public class LoginPropertiesFileAdvancedTest extends AbstractTest {
+ protected AbstractName clientCE;
+ protected AbstractName testCE;
+ protected AbstractName testRealm;
+ protected AbstractName neverFailModule;
+
+ public void setUp() throws Exception {
+ needServerInfo = true;
+ needLoginConfiguration = true;
+ super.setUp();
+
+ GBeanData gbean;
+
+ gbean = buildGBeanData("name", "NeverFailLoginModule", LoginModuleGBean.getGBeanInfo());
+ neverFailModule = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.jaas.NeverFailLoginModule");
+ gbean.setAttribute("options", null);
+ gbean.setAttribute("loginDomainName", "NeverFailDomain");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(neverFailModule);
+
+ gbean = buildGBeanData("name", "PropertiesLoginModule", LoginModuleGBean.getGBeanInfo());
+ testCE = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.realm.providers.PropertiesFileLoginModule");
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("usersURI", new File(BASEDIR, "src/test/data/data/users.properties").toURI().toString());
+ props.put("groupsURI", new File(BASEDIR, "src/test/data/data/groups.properties").toURI().toString());
+ gbean.setAttribute("options", props);
+ gbean.setAttribute("loginDomainName", "TestProperties");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(testCE);
+
+ gbean = buildGBeanData("name", "PropertiesLoginModuleUse", JaasLoginModuleUse.getGBeanInfo());
+ AbstractName propsUseName = gbean.getAbstractName();
+ gbean.setAttribute("controlFlag", LoginModuleControlFlag.OPTIONAL);
+ gbean.setReferencePattern("LoginModule", testCE);
+ kernel.loadGBean(gbean, JaasLoginModuleUse.class.getClassLoader());
+ kernel.startGBean(propsUseName);
+
+ gbean = buildGBeanData("name", "NeverFailLoginModuleUse", JaasLoginModuleUse.getGBeanInfo());
+ AbstractName neverFailUseName = gbean.getAbstractName();
+ gbean.setAttribute("controlFlag", LoginModuleControlFlag.REQUIRED);
+ gbean.setReferencePattern("LoginModule", neverFailModule);
+ gbean.setReferencePattern("Next", propsUseName);
+ kernel.loadGBean(gbean, JaasLoginModuleUse.class.getClassLoader());
+ kernel.startGBean(neverFailUseName);
+
+ gbean = buildGBeanData("name", "PropertiesSecurityRealm", GenericSecurityRealm.getGBeanInfo());
+ testRealm = gbean.getAbstractName();
+ gbean.setAttribute("realmName", "properties-realm");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ gbean.setReferencePattern("LoginModuleConfiguration", neverFailUseName);
+ gbean.setReferencePattern("ServerInfo", serverInfo);
+ kernel.loadGBean(gbean, GenericSecurityRealm.class.getClassLoader());
+
+ kernel.startGBean(loginConfiguration);
+ kernel.startGBean(testRealm);
+ }
+
+ public void tearDown() throws Exception {
+ kernel.stopGBean(testRealm);
+ kernel.stopGBean(loginConfiguration);
+ kernel.stopGBean(testCE);
+ kernel.stopGBean(neverFailModule);
+ kernel.stopGBean(serverInfo);
+
+ kernel.unloadGBean(testRealm);
+ kernel.unloadGBean(loginConfiguration);
+ kernel.unloadGBean(testCE);
+ kernel.unloadGBean(neverFailModule);
+ kernel.unloadGBean(serverInfo);
+
+ super.tearDown();
+ }
+
+ public void testBadPasswordLogin() throws Exception {
+ LoginContext context = new LoginContext("properties-realm", new UsernamePasswordCallback("alan", "bad"));
+
+ context.login();
+ Subject subject = context.getSubject();
+ assertTrue("expected non-null subject", subject != null);
+ assertTrue("expected zero principals", subject.getPrincipals().size() == 0);
+ context.logout();
+ }
+}
Propchange: geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginPropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain