You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by dj...@apache.org on 2007/05/16 00:29:02 UTC
svn commit: r538344 - in /geronimo/server/trunk/modules:
geronimo-jetty6-builder/src/main/java/org/apache/geronimo/jetty6/deployment/
geronimo-jetty6/ geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/
geronimo-jetty6/src/main/java/org/apache/ge...
Author: djencks
Date: Tue May 15 15:28:57 2007
New Revision: 538344
URL: http://svn.apache.org/viewvc?view=rev&rev=538344
Log:
GERONIMO-3154 Implement security for jetty using only spec compliant jacc calls
Modified:
geronimo/server/trunk/modules/geronimo-jetty6-builder/src/main/java/org/apache/geronimo/jetty6/deployment/JettyModuleBuilder.java
geronimo/server/trunk/modules/geronimo-jetty6/pom.xml
geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/JettyWebAppContext.java
geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/handler/JettySecurityHandler.java
geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/AbstractWebModuleTest.java
geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/SecurityTest.java
Modified: geronimo/server/trunk/modules/geronimo-jetty6-builder/src/main/java/org/apache/geronimo/jetty6/deployment/JettyModuleBuilder.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-jetty6-builder/src/main/java/org/apache/geronimo/jetty6/deployment/JettyModuleBuilder.java?view=diff&rev=538344&r1=538343&r2=538344
==============================================================================
--- geronimo/server/trunk/modules/geronimo-jetty6-builder/src/main/java/org/apache/geronimo/jetty6/deployment/JettyModuleBuilder.java (original)
+++ geronimo/server/trunk/modules/geronimo-jetty6-builder/src/main/java/org/apache/geronimo/jetty6/deployment/JettyModuleBuilder.java Tue May 15 15:28:57 2007
@@ -23,15 +23,12 @@
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import java.net.URL;
-import java.security.Permission;
import java.security.PermissionCollection;
-import java.security.Permissions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -531,15 +528,6 @@
webModuleData.setAttribute("policyContextID", policyContextID);
ComponentPermissions componentPermissions = buildSpecSecurityConfig(webApp, securityRoles, rolePermissions);
- webModuleData.setAttribute("excludedPermissions", componentPermissions.getExcludedPermissions());
- PermissionCollection checkedPermissions = new Permissions();
- for (PermissionCollection permissionsForRole : rolePermissions.values()) {
- for (Enumeration iterator2 = permissionsForRole.elements(); iterator2.hasMoreElements();) {
- Permission permission = (Permission) iterator2.nextElement();
- checkedPermissions.add(permission);
- }
- }
- webModuleData.setAttribute("checkedPermissions", checkedPermissions);
earContext.addSecurityContext(policyContextID, componentPermissions);
DefaultPrincipal defaultPrincipal = ((SecurityConfiguration) earContext.getSecurityConfiguration()).getDefaultPrincipal();
@@ -867,9 +855,9 @@
private void addServlets(AbstractName webModuleName,
Module module,
ServletType[] servletTypes,
- Map servletMappings,
- Set securityRoles,
- Map rolePermissions,
+ Map<String, Set<String>> servletMappings,
+ Set<String> securityRoles,
+ Map<String, PermissionCollection> rolePermissions,
EARContext moduleContext) throws DeploymentException {
// this TreeSet will order the ServletTypes based on whether
@@ -901,16 +889,16 @@
}
/**
- * @param webModuleName
- * @param module
- * @param previousServlet
- * @param servletType
- * @param servletMappings
- * @param securityRoles
- * @param rolePermissions
- * @param moduleContext
+ * @param webModuleName AbstractName of the web module
+ * @param module the web module being added
+ * @param previousServlet the servlet to start before this one in init order
+ * @param servletType XMLObject specifying the servlet configuration
+ * @param servletMappings Map of servlet name to set of ServletMapping strings for this web app
+ * @param securityRoles security roles in the web app
+ * @param rolePermissions RolePermissions for the roles this servlet needs to access
+ * @param moduleContext deployment context for this module
* @return AbstractName of servlet gbean added
- * @throws DeploymentException
+ * @throws DeploymentException if something goes wrong
*/
private AbstractName addServlet(AbstractName webModuleName,
Module module,
@@ -992,7 +980,7 @@
servletData.setAttribute("loadOnStartup", loadOnStartup);
}
- Set mappings = (Set) servletMappings.get(servletName);
+ Set mappings = servletMappings.get(servletName);
servletData.setAttribute("servletMappings", mappings == null ? Collections.EMPTY_SET : mappings);
//run-as
Modified: geronimo/server/trunk/modules/geronimo-jetty6/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-jetty6/pom.xml?view=diff&rev=538344&r1=538343&r2=538344
==============================================================================
--- geronimo/server/trunk/modules/geronimo-jetty6/pom.xml (original)
+++ geronimo/server/trunk/modules/geronimo-jetty6/pom.xml Tue May 15 15:28:57 2007
@@ -37,6 +37,7 @@
<groupId>org.apache.geronimo.modules</groupId>
<artifactId>geronimo-security-builder</artifactId>
<version>${version}</version>
+ <scope>test</scope>
</dependency>
<dependency>
@@ -63,30 +64,30 @@
<artifactId>jetty</artifactId>
</dependency>
- <dependency>
- <groupId>org.apache.tomcat.extras</groupId>
- <artifactId>juli</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.tomcat.extras</groupId>
- <artifactId>juli-adapters</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- </dependency>
+ <!--<dependency>-->
+ <!--<groupId>org.apache.tomcat.extras</groupId>-->
+ <!--<artifactId>juli</artifactId>-->
+ <!--</dependency>-->
+
+ <!--<dependency>-->
+ <!--<groupId>org.apache.tomcat.extras</groupId>-->
+ <!--<artifactId>juli-adapters</artifactId>-->
+ <!--</dependency>-->
+
+ <!--<dependency>-->
+ <!--<groupId>commons-collections</groupId>-->
+ <!--<artifactId>commons-collections</artifactId>-->
+ <!--</dependency>-->
- <dependency>
- <groupId>commons-primitives</groupId>
- <artifactId>commons-primitives</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.myfaces.core</groupId>
- <artifactId>myfaces-api</artifactId>
- </dependency>
+ <!--<dependency>-->
+ <!--<groupId>commons-primitives</groupId>-->
+ <!--<artifactId>commons-primitives</artifactId>-->
+ <!--</dependency>-->
+
+ <!--<dependency>-->
+ <!--<groupId>org.apache.myfaces.core</groupId>-->
+ <!--<artifactId>myfaces-api</artifactId>-->
+ <!--</dependency>-->
<dependency>
<groupId>xerces</groupId>
Modified: geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/JettyWebAppContext.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/JettyWebAppContext.java?view=diff&rev=538344&r1=538343&r2=538344
==============================================================================
--- geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/JettyWebAppContext.java (original)
+++ geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/JettyWebAppContext.java Tue May 15 15:28:57 2007
@@ -29,7 +29,7 @@
import java.util.Map;
import java.util.Set;
-import javax.faces.FactoryFinder;
+//import javax.faces.FactoryFinder;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.naming.Context;
@@ -127,8 +127,6 @@
String policyContextID,
String securityRealmName,
DefaultPrincipal defaultPrincipal,
- PermissionCollection checkedPermissions,
- PermissionCollection excludedPermissions,
Holder holder,
@@ -163,13 +161,10 @@
}
JettySecurityHandler securityHandler = null;
if (securityRealmName != null) {
- securityHandler = new JettySecurityHandler();
InternalJAASJettyRealm internalJAASJettyRealm = jettyContainer.addRealm(securityRealmName);
//wrap jetty realm with something that knows the dumb realmName
JAASJettyRealm realm = new JAASJettyRealm(realmName, internalJAASJettyRealm);
- securityHandler.setUserRealm(realm);
-
- securityHandler.init(policyContextID, defaultPrincipal, checkedPermissions, excludedPermissions, classLoader);
+ securityHandler = new JettySecurityHandler(authenticator, realm, policyContextID, defaultPrincipal, classLoader);
}
ServletHandler servletHandler = new ServletHandler();
@@ -242,7 +237,6 @@
webAppContext.setWelcomeFiles(welcomeFiles);
setLocaleEncodingMapping(localeEncodingMapping);
setErrorPages(errorPages);
- webAppContext.getSecurityHandler().setAuthenticator(authenticator);
setTagLibMap(tagLibMap);
if (!distributable) {
@@ -365,7 +359,8 @@
LogFactory.release(webClassLoader);
// need to release the JSF factories. Otherwise, we'll leak ClassLoaders.
- FactoryFinder.releaseFactories();
+ //should be done in a myfaces gbean
+// FactoryFinder.releaseFactories();
log.debug("JettyWebAppContext stopped");
}
@@ -598,9 +593,6 @@
infoBuilder.addAttribute("securityRealmName", String.class, true);
infoBuilder.addAttribute("defaultPrincipal", DefaultPrincipal.class, true);
- infoBuilder.addAttribute("checkedPermissions", PermissionCollection.class, true);
- infoBuilder.addAttribute("excludedPermissions", PermissionCollection.class, true);
-
infoBuilder.addAttribute("holder", Holder.class, true);
infoBuilder.addReference("J2EEServer", J2EEServer.class);
@@ -641,9 +633,6 @@
"policyContextID",
"securityRealmName",
"defaultPrincipal",
-
- "checkedPermissions",
- "excludedPermissions",
"holder",
Modified: geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/handler/JettySecurityHandler.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/handler/JettySecurityHandler.java?view=diff&rev=538344&r1=538343&r2=538344
==============================================================================
--- geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/handler/JettySecurityHandler.java (original)
+++ geronimo/server/trunk/modules/geronimo-jetty6/src/main/java/org/apache/geronimo/jetty6/handler/JettySecurityHandler.java Tue May 15 15:28:57 2007
@@ -32,21 +32,22 @@
import org.apache.geronimo.common.DeploymentException;
import org.apache.geronimo.common.GeronimoSecurityException;
+import org.apache.geronimo.jetty6.JAASJettyPrincipal;
+import org.apache.geronimo.jetty6.JAASJettyRealm;
+import org.apache.geronimo.jetty6.JettyContainer;
import org.apache.geronimo.security.Callers;
import org.apache.geronimo.security.ContextManager;
import org.apache.geronimo.security.IdentificationPrincipal;
import org.apache.geronimo.security.SubjectId;
import org.apache.geronimo.security.deploy.DefaultPrincipal;
import org.apache.geronimo.security.util.ConfigurationUtil;
-import org.apache.geronimo.jetty6.JAASJettyPrincipal;
-import org.apache.geronimo.jetty6.JAASJettyRealm;
-import org.apache.geronimo.jetty6.JettyContainer;
import org.mortbay.jetty.HttpException;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Response;
import org.mortbay.jetty.security.Authenticator;
import org.mortbay.jetty.security.FormAuthenticator;
import org.mortbay.jetty.security.SecurityHandler;
+import org.mortbay.jetty.security.UserRealm;
public class JettySecurityHandler extends SecurityHandler {
@@ -56,32 +57,16 @@
private String formLoginPath;
- private PermissionCollection checked;
-
- private PermissionCollection excludedPermissions;
-
-
private JAASJettyRealm realm;
- public JettySecurityHandler() {
- }
-
- public boolean hasConstraints() {
- return true;
- }
-
- public void init(String policyContextID,
- DefaultPrincipal defaultPrincipal,
- PermissionCollection checkedPermissions,
- PermissionCollection excludedPermissions,
+ public JettySecurityHandler(Authenticator authenticator,
+ JAASJettyRealm userRealm,
+ String policyContextID,
+ DefaultPrincipal defaultPrincipal,
ClassLoader classLoader) {
+ setAuthenticator(authenticator);
this.policyContextID = policyContextID;
- this.defaultPrincipal = generateDefaultPrincipal(defaultPrincipal,classLoader);
- this.checked = checkedPermissions;
- this.excludedPermissions = excludedPermissions;
-
- Authenticator authenticator = getAuthenticator();
if (authenticator instanceof FormAuthenticator) {
String formLoginPath = ((FormAuthenticator) authenticator).getLoginPage();
if (formLoginPath.indexOf('?') > 0) {
@@ -95,16 +80,23 @@
/**
* Register our default principal with the ContextManager
*/
+ this.defaultPrincipal = generateDefaultPrincipal(defaultPrincipal, classLoader);
+
Subject defaultSubject = this.defaultPrincipal.getSubject();
ContextManager.registerSubject(defaultSubject);
SubjectId id = ContextManager.getSubjectId(defaultSubject);
defaultSubject.getPrincipals().add(new IdentificationPrincipal(id));
- this.realm = (JAASJettyRealm)getUserRealm();
+ setUserRealm(userRealm);
+ this.realm = userRealm;
assert realm != null;
}
+ public boolean hasConstraints() {
+ return true;
+ }
+
public void doStop(JettyContainer jettyContainer) throws Exception {
- try{
+ try {
super.doStop();
}
finally {
@@ -148,19 +140,14 @@
/**
* Check the security constraints using JACC.
- *
- * @param pathInContext
- * path in context
- * @param request
- * HTTP request
- * @param response
- * HTTP response
+ *
+ * @param pathInContext path in context
+ * @param request HTTP request
+ * @param response HTTP response
* @return true if the path in context passes the security check, false if
* it fails or a redirection has occured during authentication.
*/
- public boolean checkSecurityConstraints(String pathInContext,
- Request request, Response response) throws HttpException,
- IOException {
+ public boolean checkSecurityConstraints(String pathInContext, Request request, Response response) throws IOException {
if (formLoginPath != null) {
String pathToBeTested = (pathInContext.indexOf('?') > 0 ? pathInContext
.substring(0, pathInContext.indexOf('?'))
@@ -181,112 +168,91 @@
transportType = "NONE";
}
String substitutedPathInContext = pathInContext;
- if (substitutedPathInContext.indexOf("%3A") > -1) substitutedPathInContext = substitutedPathInContext.replaceAll("%3A", "%3A%3A");
- if (substitutedPathInContext.indexOf(":") > -1) substitutedPathInContext = substitutedPathInContext.replaceAll(":", "%3A");
-
- WebUserDataPermission wudp = new WebUserDataPermission(substitutedPathInContext, new String[] { request.getMethod() }, transportType);
- WebResourcePermission webResourcePermission = new WebResourcePermission(request);
- Principal user = obtainUser(pathInContext, request, response, webResourcePermission, wudp);
-
- if (user == null) {
+ if (substitutedPathInContext.indexOf("%3A") > -1)
+ substitutedPathInContext = substitutedPathInContext.replaceAll("%3A", "%3A%3A");
+ if (substitutedPathInContext.indexOf(":") > -1)
+ substitutedPathInContext = substitutedPathInContext.replaceAll(":", "%3A");
+
+
+ Authenticator authenticator = getAuthenticator();
+ boolean isAuthenticated = false;
+
+ if (authenticator instanceof FormAuthenticator
+ && pathInContext.endsWith(FormAuthenticator.__J_SECURITY_CHECK)) {
+ /**
+ * This is a post request to __J_SECURITY_CHECK. Stop now after authentication.
+ * Whether or not authentication succeeded, we return.
+ */
+ authenticator.authenticate(realm, pathInContext, request, response);
return false;
}
- if (user == SecurityHandler.__NOBODY) {
- return true;
+ // attempt to access an unprotected resource that is not the
+ // j_security_check.
+ // if we are logged in, return the logged in principal.
+ if (request != null) {
+ // null response appears to prevent redirect to login page
+ Principal user = authenticator.authenticate(realm, pathInContext,
+ request, null);
+ if (user == null || user == SecurityHandler.__NOBODY) {
+ //TODO use run-as as nextCaller if present
+ ContextManager.setCallers(defaultPrincipal.getSubject(), defaultPrincipal.getSubject());
+ request.setUserPrincipal(new NotChecked());
+ } else if (user != null) {
+ isAuthenticated = true;
+ }
}
+
AccessControlContext acc = ContextManager.getCurrentContext();
/**
- * JACC v1.0 secion 4.1.1
+ * JACC v1.0 section 4.1.1
*/
-
+ WebUserDataPermission wudp = new WebUserDataPermission(substitutedPathInContext, new String[]{request.getMethod()}, transportType);
acc.checkPermission(wudp);
+ WebResourcePermission webResourcePermission = new WebResourcePermission(request);
/**
- * JACC v1.0 secion 4.1.2
+ * JACC v1.0 section 4.1.2
*/
- acc.checkPermission(webResourcePermission);
+ if (isAuthenticated) {
+ //current user is logged in, this is the actual check
+ acc.checkPermission(webResourcePermission);
+ } else {
+ //user is not logged in: if access denied, try to log them in.
+ try {
+ acc.checkPermission(webResourcePermission);
+ } catch (AccessControlException e) {
+ //not logged in: try to log them in.
+ Principal user = authenticator.authenticate(realm, pathInContext, request, response);
+ if (user == SecurityHandler.__NOBODY) {
+ return true;
+ }
+ if (user == null) {
+ throw e;
+ }
+ }
+ }
+
} catch (HttpException he) {
response.sendError(he.getStatus(), he.getReason());
return false;
} catch (AccessControlException ace) {
- response.sendError(403);
+ if (!response.isCommitted()) {
+ response.sendError(403);
+ }
return false;
}
return true;
}
/**
- * Obtain an authenticated user, if one is required. Otherwise return the
- * default principal. <p/> Also set the current caller for JACC security
- * checks for the default principal. This is automatically done by
- * <code>JAASJettyRealm</code>.
- *
- * @param pathInContext
- * path in context
- * @param request
- * HTTP request
- * @param response
- * HTTP response
- * @return <code>null</code> if there is no authenticated user at the
- * moment and security checking should not proceed and servlet
- * handling should also not proceed, e.g. redirect.
- * <code>SecurityConstraint.__NOBODY</code> if security checking
- * should not proceed and servlet handling should proceed, e.g.
- * login page.
- */
- private Principal obtainUser(String pathInContext, Request request,
- Response response, WebResourcePermission resourcePermission,
- WebUserDataPermission dataPermission) throws IOException {
- boolean unauthenticated = !(checked.implies(resourcePermission) || checked.implies(dataPermission));
- boolean forbidden = excludedPermissions.implies(resourcePermission) || excludedPermissions.implies(dataPermission);
-
- Authenticator authenticator = getAuthenticator();
- if (!unauthenticated && !forbidden) {
- return authenticator.authenticate(realm, pathInContext, request,
- response);
- } else if (authenticator instanceof FormAuthenticator
- && pathInContext.endsWith(FormAuthenticator.__J_SECURITY_CHECK)) {
- /**
- * This could be a post request to __J_SECURITY_CHECK.
- */
- return authenticator.authenticate(realm, pathInContext, request,
- response);
- }
-
- // attempt to access an unprotected resource that is not the
- // j_security_check.
- // if we are logged in, return the logged in principal.
- if (request != null) {
- try {
- // null response appears to prevent redirect to login page
- Principal user = authenticator.authenticate(realm, pathInContext,
- request, null);
- if (user != null) {
- return user;
- }
- } catch (Exception e) {
- // the Jetty authenticator tries to write something to the response if
- // there is a failure. Ignore any errors and continue as if this failed.
- }
- }
-
- /**
- * No authentication is required. Return the defaultPrincipal.
- */
- //TODO use run-as as nextCaller if present
- ContextManager.setCallers(defaultPrincipal.getSubject(), defaultPrincipal.getSubject());
- return defaultPrincipal;
- }
-
- /**
* Generate the default principal from the security config.
- *
- * @param defaultPrincipal
- * The Geronimo security configuration.
- * @param classLoader
+ *
+ * @param defaultPrincipal The Geronimo security configuration.
+ * @param classLoader to load principals for the default subject
* @return the default principal
+ * @throws org.apache.geronimo.common.GeronimoSecurityException if the default principal cannot be constructed
*/
protected JAASJettyPrincipal generateDefaultPrincipal(
DefaultPrincipal defaultPrincipal, ClassLoader classLoader)
Modified: geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/AbstractWebModuleTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/AbstractWebModuleTest.java?view=diff&rev=538344&r1=538343&r2=538344
==============================================================================
--- geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/AbstractWebModuleTest.java (original)
+++ geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/AbstractWebModuleTest.java Tue May 15 15:28:57 2007
@@ -111,8 +111,6 @@
policyContextId,
securityRealmName,
defaultPrincipal,
- checkedPermissions,
- excludedPermissions,
null,
null,
transactionManager,
Modified: geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/SecurityTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/SecurityTest.java?view=diff&rev=538344&r1=538343&r2=538344
==============================================================================
--- geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/SecurityTest.java (original)
+++ geronimo/server/trunk/modules/geronimo-jetty6/src/test/java/org/apache/geronimo/jetty6/SecurityTest.java Tue May 15 15:28:57 2007
@@ -73,14 +73,14 @@
buildPrincipalRoleMap(securityConfig, roleDesignates, principalRoleMap);
PermissionCollection uncheckedPermissions = new Permissions();
+ uncheckedPermissions.add(new WebUserDataPermission("/protected/*", ""));
PermissionCollection excludedPermissions = new Permissions();
- excludedPermissions.add(new WebResourcePermission("/auth/login.html", ""));
- excludedPermissions.add(new WebUserDataPermission("/auth/login.html", ""));
+ uncheckedPermissions.add(new WebResourcePermission("/auth/logon.html", ""));
+ uncheckedPermissions.add(new WebUserDataPermission("/auth/logon.html", ""));
Map rolePermissions = new HashMap();
PermissionCollection permissions = new Permissions();
- permissions.add(new WebUserDataPermission("/protected/*", ""));
permissions.add(new WebResourcePermission("/protected/*", ""));
rolePermissions.put("content-administrator", permissions);
rolePermissions.put("auto-administrator", permissions);