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/11/01 00:56:41 UTC
svn commit: r590862 - 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 16:56:41 2007
New Revision: 590862
URL: http://svn.apache.org/viewvc?rev=590862&view=rev
Log:
**GERONIMO-3575 Review CertificatePropertiesFileLoginModule
o LoginModule should not add principals when login fails. Added a test to detect if it does.
o Other changes to bring CertificatePropertiesFileLoginModule 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/LoginCertificatePropertiesFileAdvancedTest.java (with props)
geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java (with props)
geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java (with props)
Modified:
geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java
geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java
geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java
Modified: geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java?rev=590862&r1=590861&r2=590862&view=diff
==============================================================================
--- geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java (original)
+++ geronimo/server/branches/2.0/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java Wed Oct 31 16:56:41 2007
@@ -20,11 +20,15 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
+import java.security.Principal;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -67,17 +71,25 @@
private static Log log = LogFactory.getLog(CertificatePropertiesFileLoginModule.class);
public final static String USERS_URI = "usersURI";
public final static String GROUPS_URI = "groupsURI";
-
+ public final static List<String> supportedOptions = Arrays.asList(USERS_URI, GROUPS_URI);
+
private final Map users = new HashMap();
final Map groups = new HashMap();
private Subject subject;
private CallbackHandler handler;
private X500Principal principal;
+ private boolean loginSucceeded;
+ 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);
URI usersURI = new URI((String)options.get(USERS_URI));
@@ -132,7 +144,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[1];
callbacks[0] = new CertificateCallback();
@@ -151,44 +169,65 @@
principal = certificate.getSubjectX500Principal();
if(!users.containsKey(principal.getName())) {
+ // Clear out the private state
+ principal = 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 principals = subject.getPrincipals();
-
- principals.add(principal);
- String userName = (String) users.get(principal.getName());
- principals.add(new GeronimoUserPrincipal(userName));
-
- Iterator e = groups.keySet().iterator();
- while (e.hasNext()) {
- String groupName = (String) e.next();
- Set users = (Set) groups.get(groupName);
- Iterator iter = users.iterator();
- while (iter.hasNext()) {
- String user = (String) iter.next();
- if (userName.equals(user)) {
- principals.add(new GeronimoGroupPrincipal(groupName));
- break;
+ if(loginSucceeded) {
+ allPrincipals.add(principal);
+ String userName = (String) users.get(principal.getName());
+ allPrincipals.add(new GeronimoUserPrincipal(userName));
+
+ Iterator e = groups.keySet().iterator();
+ while (e.hasNext()) {
+ String groupName = (String) e.next();
+ Set users = (Set) groups.get(groupName);
+ Iterator iter = users.iterator();
+ while (iter.hasNext()) {
+ String user = (String) iter.next();
+ if (userName.equals(user)) {
+ allPrincipals.add(new GeronimoGroupPrincipal(groupName));
+ break;
+ }
}
}
+ subject.getPrincipals().addAll(allPrincipals);
}
-
- return true;
+ // Clear out the private state
+ principal = null;
+
+ return loginSucceeded;
}
public boolean abort() throws LoginException {
- principal = null;
-
- return true;
+ if(loginSucceeded) {
+ // Clear out the private state
+ principal = null;
+ allPrincipals.retainAll(Collections.EMPTY_SET);
+ }
+ return loginSucceeded;
}
public boolean logout() throws LoginException {
+ // Clear out the private state
+ loginSucceeded = false;
principal = 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/LoginCertificatePropertiesFileAdvancedTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java?rev=590862&view=auto
==============================================================================
--- geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java (added)
+++ geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java Wed Oct 31 16:56:41 2007
@@ -0,0 +1,142 @@
+/**
+ * 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.ByteArrayInputStream;
+import java.io.File;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+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 CertificatePropertiesFileLoginModule does not add any principals when login failed.
+ *
+ * @version $Rev$ $Date$
+ */
+public class LoginCertificatePropertiesFileAdvancedTest extends AbstractTest {
+ protected AbstractName clientCE;
+ protected AbstractName testCE;
+ protected AbstractName testRealm;
+ protected AbstractName neverFailModule;
+
+ protected X509Certificate badCert;
+ String badCertText = "-----BEGIN CERTIFICATE-----\n"
+ +"MIIBqTCCAVMCBgEV+C5ZTjANBgkqhkiG9w0BAQQFADBdMQwwCgYDVQQDEwNCYWQxEDAOBgNVBAsT\n"
+ +"B015IFVuaXQxDzANBgNVBAoTBk15IE9yZzEQMA4GA1UEBxMHTXkgQ2l0eTELMAkGA1UECBMCQVAx\n"
+ +"CzAJBgNVBAYTAklOMB4XDTA3MTAzMTIyMjg0OFoXDTE3MTAyODIyMjg0OFowXTEMMAoGA1UEAxMD\n"
+ +"QmFkMRAwDgYDVQQLEwdNeSBVbml0MQ8wDQYDVQQKEwZNeSBPcmcxEDAOBgNVBAcTB015IENpdHkx\n"
+ +"CzAJBgNVBAgTAkFQMQswCQYDVQQGEwJJTjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDBoSkFEEJC\n"
+ +"/OtI49Cr8rC9pXpniw8lXG6iUUjEC3VzDuHpqKaCGNdilhVPkRsONsmLySoJDFsZR/w4HrXlwUS1\n"
+ +"AgMBAAEwDQYJKoZIhvcNAQEEBQADQQCe3Xt5J+UoNqpdDN4y6KV4EdQlrMNfqBJnGTE+sdlKV6cN\n"
+ +"PjUnrEF1laqhX4Rx+2u56VBA2SBnEaeADawaXWkD\n"
+ +"-----END CERTIFICATE-----";
+
+ 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", "CertificatePropertiesLoginModule", LoginModuleGBean.getGBeanInfo());
+ testCE = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.realm.providers.CertificatePropertiesFileLoginModule");
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("usersURI", new File(BASEDIR, "src/test/data/data/cert-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", "CertProperties");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(testCE);
+
+ gbean = buildGBeanData("name", "CertificatePropertiesLoginModuleUse", 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", "CertificatePropertiesSecurityRealm", GenericSecurityRealm.getGBeanInfo());
+ testRealm = gbean.getAbstractName();
+ gbean.setAttribute("realmName", "cert-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);
+
+ CertificateFactory certFac = CertificateFactory.getInstance("X.509");
+ badCert = (X509Certificate) certFac.generateCertificate(new ByteArrayInputStream(badCertText.getBytes()));
+ }
+
+ 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 testBadCertificate() throws Exception {
+ LoginContext context = new LoginContext("cert-properties-realm", new CertCallback(badCert));
+
+ context.login();
+ Subject subject = context.getSubject();
+ assertTrue("expected non-null subject", subject != null);
+ assertEquals("expected zero principals", 0, subject.getPrincipals().size());
+ context.logout();
+ }
+}
Propchange: geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/server/branches/2.0/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java?rev=590862&r1=590861&r2=590862&view=diff
==============================================================================
--- geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java (original)
+++ geronimo/server/trunk/framework/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java Wed Oct 31 16:56:41 2007
@@ -20,11 +20,15 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
+import java.security.Principal;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -67,17 +71,25 @@
private static Log log = LogFactory.getLog(CertificatePropertiesFileLoginModule.class);
public final static String USERS_URI = "usersURI";
public final static String GROUPS_URI = "groupsURI";
-
+ public final static List<String> supportedOptions = Arrays.asList(USERS_URI, GROUPS_URI);
+
private final Map users = new HashMap();
final Map groups = new HashMap();
private Subject subject;
private CallbackHandler handler;
private X500Principal principal;
+ private boolean loginSucceeded;
+ 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);
URI usersURI = new URI((String)options.get(USERS_URI));
@@ -132,7 +144,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[1];
callbacks[0] = new CertificateCallback();
@@ -151,44 +169,65 @@
principal = certificate.getSubjectX500Principal();
if(!users.containsKey(principal.getName())) {
+ // Clear out the private state
+ principal = 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 principals = subject.getPrincipals();
-
- principals.add(principal);
- String userName = (String) users.get(principal.getName());
- principals.add(new GeronimoUserPrincipal(userName));
-
- Iterator e = groups.keySet().iterator();
- while (e.hasNext()) {
- String groupName = (String) e.next();
- Set users = (Set) groups.get(groupName);
- Iterator iter = users.iterator();
- while (iter.hasNext()) {
- String user = (String) iter.next();
- if (userName.equals(user)) {
- principals.add(new GeronimoGroupPrincipal(groupName));
- break;
+ if(loginSucceeded) {
+ allPrincipals.add(principal);
+ String userName = (String) users.get(principal.getName());
+ allPrincipals.add(new GeronimoUserPrincipal(userName));
+
+ Iterator e = groups.keySet().iterator();
+ while (e.hasNext()) {
+ String groupName = (String) e.next();
+ Set users = (Set) groups.get(groupName);
+ Iterator iter = users.iterator();
+ while (iter.hasNext()) {
+ String user = (String) iter.next();
+ if (userName.equals(user)) {
+ allPrincipals.add(new GeronimoGroupPrincipal(groupName));
+ break;
+ }
}
}
+ subject.getPrincipals().addAll(allPrincipals);
}
-
- return true;
+ // Clear out the private state
+ principal = null;
+
+ return loginSucceeded;
}
public boolean abort() throws LoginException {
- principal = null;
-
- return true;
+ if(loginSucceeded) {
+ // Clear out the private state
+ principal = null;
+ allPrincipals.retainAll(Collections.EMPTY_SET);
+ }
+ return loginSucceeded;
}
public boolean logout() throws LoginException {
+ // Clear out the private state
+ loginSucceeded = false;
principal = 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/LoginCertificatePropertiesFileAdvancedTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java?rev=590862&view=auto
==============================================================================
--- geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java (added)
+++ geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java Wed Oct 31 16:56:41 2007
@@ -0,0 +1,142 @@
+/**
+ * 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.ByteArrayInputStream;
+import java.io.File;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+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 CertificatePropertiesFileLoginModule does not add any principals when login failed.
+ *
+ * @version $Rev$ $Date$
+ */
+public class LoginCertificatePropertiesFileAdvancedTest extends AbstractTest {
+ protected AbstractName clientCE;
+ protected AbstractName testCE;
+ protected AbstractName testRealm;
+ protected AbstractName neverFailModule;
+
+ protected X509Certificate badCert;
+ String badCertText = "-----BEGIN CERTIFICATE-----\n"
+ +"MIIBqTCCAVMCBgEV+C5ZTjANBgkqhkiG9w0BAQQFADBdMQwwCgYDVQQDEwNCYWQxEDAOBgNVBAsT\n"
+ +"B015IFVuaXQxDzANBgNVBAoTBk15IE9yZzEQMA4GA1UEBxMHTXkgQ2l0eTELMAkGA1UECBMCQVAx\n"
+ +"CzAJBgNVBAYTAklOMB4XDTA3MTAzMTIyMjg0OFoXDTE3MTAyODIyMjg0OFowXTEMMAoGA1UEAxMD\n"
+ +"QmFkMRAwDgYDVQQLEwdNeSBVbml0MQ8wDQYDVQQKEwZNeSBPcmcxEDAOBgNVBAcTB015IENpdHkx\n"
+ +"CzAJBgNVBAgTAkFQMQswCQYDVQQGEwJJTjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDBoSkFEEJC\n"
+ +"/OtI49Cr8rC9pXpniw8lXG6iUUjEC3VzDuHpqKaCGNdilhVPkRsONsmLySoJDFsZR/w4HrXlwUS1\n"
+ +"AgMBAAEwDQYJKoZIhvcNAQEEBQADQQCe3Xt5J+UoNqpdDN4y6KV4EdQlrMNfqBJnGTE+sdlKV6cN\n"
+ +"PjUnrEF1laqhX4Rx+2u56VBA2SBnEaeADawaXWkD\n"
+ +"-----END CERTIFICATE-----";
+
+ 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", "CertificatePropertiesLoginModule", LoginModuleGBean.getGBeanInfo());
+ testCE = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.realm.providers.CertificatePropertiesFileLoginModule");
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("usersURI", new File(BASEDIR, "src/test/data/data/cert-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", "CertProperties");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(testCE);
+
+ gbean = buildGBeanData("name", "CertificatePropertiesLoginModuleUse", 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", "CertificatePropertiesSecurityRealm", GenericSecurityRealm.getGBeanInfo());
+ testRealm = gbean.getAbstractName();
+ gbean.setAttribute("realmName", "cert-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);
+
+ CertificateFactory certFac = CertificateFactory.getInstance("X.509");
+ badCert = (X509Certificate) certFac.generateCertificate(new ByteArrayInputStream(badCertText.getBytes()));
+ }
+
+ 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 testBadCertificate() throws Exception {
+ LoginContext context = new LoginContext("cert-properties-realm", new CertCallback(badCert));
+
+ context.login();
+ Subject subject = context.getSubject();
+ assertTrue("expected non-null subject", subject != null);
+ assertEquals("expected zero principals", 0, subject.getPrincipals().size());
+ context.logout();
+ }
+}
Propchange: geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/server/trunk/framework/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java?rev=590862&r1=590861&r2=590862&view=diff
==============================================================================
--- geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java (original)
+++ geronimo/server/trunk/modules/geronimo-security/src/main/java/org/apache/geronimo/security/realm/providers/CertificatePropertiesFileLoginModule.java Wed Oct 31 16:56:41 2007
@@ -20,11 +20,15 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
+import java.security.Principal;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -67,17 +71,25 @@
private static Log log = LogFactory.getLog(CertificatePropertiesFileLoginModule.class);
public final static String USERS_URI = "usersURI";
public final static String GROUPS_URI = "groupsURI";
-
+ public final static List<String> supportedOptions = Arrays.asList(USERS_URI, GROUPS_URI);
+
private final Map users = new HashMap();
final Map groups = new HashMap();
private Subject subject;
private CallbackHandler handler;
private X500Principal principal;
+ private boolean loginSucceeded;
+ 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);
URI usersURI = new URI((String)options.get(USERS_URI));
@@ -132,7 +144,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[1];
callbacks[0] = new CertificateCallback();
@@ -151,44 +169,65 @@
principal = certificate.getSubjectX500Principal();
if(!users.containsKey(principal.getName())) {
+ // Clear out the private state
+ principal = 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 principals = subject.getPrincipals();
-
- principals.add(principal);
- String userName = (String) users.get(principal.getName());
- principals.add(new GeronimoUserPrincipal(userName));
-
- Iterator e = groups.keySet().iterator();
- while (e.hasNext()) {
- String groupName = (String) e.next();
- Set users = (Set) groups.get(groupName);
- Iterator iter = users.iterator();
- while (iter.hasNext()) {
- String user = (String) iter.next();
- if (userName.equals(user)) {
- principals.add(new GeronimoGroupPrincipal(groupName));
- break;
+ if(loginSucceeded) {
+ allPrincipals.add(principal);
+ String userName = (String) users.get(principal.getName());
+ allPrincipals.add(new GeronimoUserPrincipal(userName));
+
+ Iterator e = groups.keySet().iterator();
+ while (e.hasNext()) {
+ String groupName = (String) e.next();
+ Set users = (Set) groups.get(groupName);
+ Iterator iter = users.iterator();
+ while (iter.hasNext()) {
+ String user = (String) iter.next();
+ if (userName.equals(user)) {
+ allPrincipals.add(new GeronimoGroupPrincipal(groupName));
+ break;
+ }
}
}
+ subject.getPrincipals().addAll(allPrincipals);
}
-
- return true;
+ // Clear out the private state
+ principal = null;
+
+ return loginSucceeded;
}
public boolean abort() throws LoginException {
- principal = null;
-
- return true;
+ if(loginSucceeded) {
+ // Clear out the private state
+ principal = null;
+ allPrincipals.retainAll(Collections.EMPTY_SET);
+ }
+ return loginSucceeded;
}
public boolean logout() throws LoginException {
+ // Clear out the private state
+ loginSucceeded = false;
principal = 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/LoginCertificatePropertiesFileAdvancedTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java?rev=590862&view=auto
==============================================================================
--- geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java (added)
+++ geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java Wed Oct 31 16:56:41 2007
@@ -0,0 +1,142 @@
+/**
+ * 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.ByteArrayInputStream;
+import java.io.File;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+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 CertificatePropertiesFileLoginModule does not add any principals when login failed.
+ *
+ * @version $Rev$ $Date$
+ */
+public class LoginCertificatePropertiesFileAdvancedTest extends AbstractTest {
+ protected AbstractName clientCE;
+ protected AbstractName testCE;
+ protected AbstractName testRealm;
+ protected AbstractName neverFailModule;
+
+ protected X509Certificate badCert;
+ String badCertText = "-----BEGIN CERTIFICATE-----\n"
+ +"MIIBqTCCAVMCBgEV+C5ZTjANBgkqhkiG9w0BAQQFADBdMQwwCgYDVQQDEwNCYWQxEDAOBgNVBAsT\n"
+ +"B015IFVuaXQxDzANBgNVBAoTBk15IE9yZzEQMA4GA1UEBxMHTXkgQ2l0eTELMAkGA1UECBMCQVAx\n"
+ +"CzAJBgNVBAYTAklOMB4XDTA3MTAzMTIyMjg0OFoXDTE3MTAyODIyMjg0OFowXTEMMAoGA1UEAxMD\n"
+ +"QmFkMRAwDgYDVQQLEwdNeSBVbml0MQ8wDQYDVQQKEwZNeSBPcmcxEDAOBgNVBAcTB015IENpdHkx\n"
+ +"CzAJBgNVBAgTAkFQMQswCQYDVQQGEwJJTjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDBoSkFEEJC\n"
+ +"/OtI49Cr8rC9pXpniw8lXG6iUUjEC3VzDuHpqKaCGNdilhVPkRsONsmLySoJDFsZR/w4HrXlwUS1\n"
+ +"AgMBAAEwDQYJKoZIhvcNAQEEBQADQQCe3Xt5J+UoNqpdDN4y6KV4EdQlrMNfqBJnGTE+sdlKV6cN\n"
+ +"PjUnrEF1laqhX4Rx+2u56VBA2SBnEaeADawaXWkD\n"
+ +"-----END CERTIFICATE-----";
+
+ 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", "CertificatePropertiesLoginModule", LoginModuleGBean.getGBeanInfo());
+ testCE = gbean.getAbstractName();
+ gbean.setAttribute("loginModuleClass", "org.apache.geronimo.security.realm.providers.CertificatePropertiesFileLoginModule");
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("usersURI", new File(BASEDIR, "src/test/data/data/cert-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", "CertProperties");
+ gbean.setAttribute("wrapPrincipals", Boolean.TRUE);
+ kernel.loadGBean(gbean, LoginModuleGBean.class.getClassLoader());
+ kernel.startGBean(testCE);
+
+ gbean = buildGBeanData("name", "CertificatePropertiesLoginModuleUse", 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", "CertificatePropertiesSecurityRealm", GenericSecurityRealm.getGBeanInfo());
+ testRealm = gbean.getAbstractName();
+ gbean.setAttribute("realmName", "cert-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);
+
+ CertificateFactory certFac = CertificateFactory.getInstance("X.509");
+ badCert = (X509Certificate) certFac.generateCertificate(new ByteArrayInputStream(badCertText.getBytes()));
+ }
+
+ 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 testBadCertificate() throws Exception {
+ LoginContext context = new LoginContext("cert-properties-realm", new CertCallback(badCert));
+
+ context.login();
+ Subject subject = context.getSubject();
+ assertTrue("expected non-null subject", subject != null);
+ assertEquals("expected zero principals", 0, subject.getPrincipals().size());
+ context.logout();
+ }
+}
Propchange: geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/server/trunk/modules/geronimo-security/src/test/java/org/apache/geronimo/security/jaas/LoginCertificatePropertiesFileAdvancedTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain