adc 2004/06/27 13:37:38
Modified: modules/jetty/src/java/org/apache/geronimo/jetty JAASJettyPrincipal.java JAASJettyRealm.java JettyServer.java JettyXMLConfiguration.java modules/jetty/src/java/org/apache/geronimo/jetty/deployment JettyModuleBuilder.java modules/jetty/src/test/org/apache/geronimo/jetty ApplicationTest.java Added: modules/jetty/src/java/org/apache/geronimo/jetty JettyServletHolder.java JettyWebAppContext.java JettyWebAppHandler.java JettyWebAppJACCContext.java modules/jetty/src/test/org/apache/geronimo/jetty SecurityTest.java Removed: modules/jetty/src/java/org/apache/geronimo/jetty JettyWebApplicationContext.java Log: Added JACC to Jetty. Revision Changes Path 1.2 +11 -1 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JAASJettyPrincipal.java Index: JAASJettyPrincipal.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JAASJettyPrincipal.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JAASJettyPrincipal.java 30 May 2004 19:09:57 -0000 1.1 +++ JAASJettyPrincipal.java 27 Jun 2004 20:37:38 -0000 1.2 @@ -18,6 +18,7 @@ import javax.security.auth.Subject; import java.security.Principal; +import java.util.Stack; /** @@ -26,6 +27,7 @@ public class JAASJettyPrincipal implements Principal { private String name; private Subject subject; + private Stack stack = new Stack(); public JAASJettyPrincipal(String name) { this.name = name; @@ -41,5 +43,13 @@ void setSubject(Subject subject) { this.subject = subject; + } + + void push(Subject roleDesignate) { + stack.push(roleDesignate); + } + + Subject pop() { + return (Subject) stack.pop(); } } 1.5 +48 -26 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JAASJettyRealm.java Index: JAASJettyRealm.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JAASJettyRealm.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- JAASJettyRealm.java 5 Jun 2004 07:53:21 -0000 1.4 +++ JAASJettyRealm.java 27 Jun 2004 20:37:38 -0000 1.5 @@ -16,21 +16,29 @@ */ package org.apache.geronimo.jetty; -import java.security.Principal; -import java.util.HashMap; +import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; +import javax.security.jacc.WebRoleRefPermission; +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.Principal; +import java.util.HashMap; +import java.util.Stack; +import org.mortbay.http.HttpRequest; +import org.mortbay.http.UserRealm; +import org.mortbay.jaas.callback.DefaultCallbackHandler; +import org.mortbay.util.LogSupport; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.geronimo.gbean.GBeanInfo; import org.apache.geronimo.gbean.GBeanInfoFactory; import org.apache.geronimo.gbean.GBeanLifecycle; import org.apache.geronimo.gbean.WaitingException; -import org.mortbay.http.HttpRequest; -import org.mortbay.http.UserRealm; -import org.mortbay.jaas.callback.DefaultCallbackHandler; -import org.mortbay.util.LogSupport; +import org.apache.geronimo.security.ContextManager; /** @@ -40,10 +48,10 @@ private static Log log = LogFactory.getLog(JAASJettyRealm.class); - protected final JettyContainer container; - protected String realmName; - protected String loginModuleName; - protected HashMap userMap = new HashMap(); + private final JettyContainer container; + private String realmName; + private String loginModuleName; + private HashMap userMap = new HashMap(); public JAASJettyRealm(JettyContainer container) { this.container = container; @@ -65,9 +73,8 @@ return (Principal) userMap.get(username); } - public Principal authenticate(String username, - Object credentials, - HttpRequest request) { + public Principal authenticate(String username, Object credentials, HttpRequest request) { + try { JAASJettyPrincipal userPrincipal = (JAASJettyPrincipal) userMap.get(username); @@ -85,10 +92,13 @@ //set up the login context LoginContext loginContext = new LoginContext(loginModuleName, - callbackHandler); + callbackHandler); loginContext.login(); + ContextManager.registerSubject(loginContext.getSubject()); + ContextManager.setCurrentCaller(loginContext.getSubject()); + //login success userPrincipal = new JAASJettyPrincipal(username); userPrincipal.setSubject(loginContext.getSubject()); @@ -102,33 +112,45 @@ } } + public void logout(Principal user) { + JAASJettyPrincipal principal = (JAASJettyPrincipal) user; + + userMap.remove(principal.getName()); + ContextManager.unregisterSubject(principal.getSubject()); + } + public boolean reauthenticate(Principal user) { // TODO This is not correct if auth can expire! We need to + + ContextManager.setCurrentCaller(((JAASJettyPrincipal)user).getSubject()); + // get the user out of the cache return (userMap.get(user.getName()) != null); } - public boolean isUserInRole(Principal user, String role) { - //TODO - return true; + public void disassociate(Principal user) { + // do nothing } - public void disassociate(Principal user) { - //TODO + public boolean isUserInRole(Principal user, String role) { + AccessControlContext acc = ContextManager.getCurrentContext(); + try { + acc.checkPermission(new WebRoleRefPermission(JettyServletHolder.getJettyServletHolder().getName(), role)); + } catch (AccessControlException e) { + return false; + } + return true; } public Principal pushRole(Principal user, String role) { - //TODO + ((JAASJettyPrincipal)user).push(ContextManager.getCurrentCaller()); + ContextManager.setCurrentCaller(JettyServer.getCurrentWebAppContext().getRoleDesignate(role)); return user; } public Principal popRole(Principal user) { - //TODO + ContextManager.setCurrentCaller(((JAASJettyPrincipal)user).pop()); return user; - } - - public void logout(Principal user) { - log.warn(LogSupport.NOT_IMPLEMENTED); } public void doStart() throws WaitingException, Exception { 1.2 +18 -1 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyServer.java Index: JettyServer.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyServer.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JettyServer.java 30 May 2004 19:09:57 -0000 1.1 +++ JettyServer.java 27 Jun 2004 20:37:38 -0000 1.2 @@ -24,6 +24,8 @@ import org.mortbay.http.UserRealm; import org.mortbay.jetty.Server; +import org.apache.geronimo.security.ContextManager; + /** * @version $Revision$ $Date$ @@ -31,6 +33,7 @@ public class JettyServer extends Server { private Map realmDelegates = new HashMap(); + private final static ThreadLocal currentWebAppContext = new ThreadLocal(); public UserRealm addRealm(UserRealm realm) { RealmDelegate delegate = (RealmDelegate) realmDelegates.get(realm.getName()); @@ -55,6 +58,20 @@ public void removeRealm(UserRealm realm) { realmDelegates.remove(realm.getName()); + } + + public static void setCurrentWebAppContext(JettyWebAppJACCContext context) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) sm.checkPermission(ContextManager.SET_CONTEXT); + + currentWebAppContext.set(context); + } + + public static JettyWebAppJACCContext getCurrentWebAppContext() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) sm.checkPermission(ContextManager.GET_CONTEXT); + + return (JettyWebAppJACCContext) currentWebAppContext.get(); } private class RealmDelegate implements UserRealm { 1.2 +85 -31 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyXMLConfiguration.java Index: JettyXMLConfiguration.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyXMLConfiguration.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JettyXMLConfiguration.java 30 May 2004 19:09:57 -0000 1.1 +++ JettyXMLConfiguration.java 27 Jun 2004 20:37:38 -0000 1.2 @@ -16,16 +16,19 @@ */ package org.apache.geronimo.jetty; +import javax.security.auth.Subject; import javax.security.jacc.PolicyConfiguration; import javax.security.jacc.PolicyContextException; import javax.security.jacc.WebResourcePermission; +import javax.security.jacc.WebRoleRefPermission; import javax.security.jacc.WebUserDataPermission; import javax.servlet.UnavailableException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.io.IOException; +import java.net.MalformedURLException; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import org.mortbay.jetty.servlet.XMLConfiguration; @@ -33,7 +36,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.geronimo.jetty.JettyWebApplicationContext; import org.apache.geronimo.security.GeronimoSecurityException; import org.apache.geronimo.security.RealmPrincipal; import org.apache.geronimo.security.deploy.Principal; @@ -41,26 +43,31 @@ import org.apache.geronimo.security.deploy.Role; import org.apache.geronimo.security.deploy.Security; import org.apache.geronimo.security.jacc.RoleMappingConfiguration; +import org.apache.geronimo.security.util.ConfigurationUtil; import org.apache.geronimo.security.util.URLPattern; /** + * JettyXMLConfiguration reads the web-app configuration and translates them + * into corresponding JACC policy permissions. + * * @version $Revision$ $Date$ */ public class JettyXMLConfiguration extends XMLConfiguration { private static Log log = LogFactory.getLog(JettyXMLConfiguration.class); - private HashSet securityRoles = new HashSet(); - private HashMap uncheckedPatterns = new HashMap(); - private HashMap excludedPatterns = new HashMap(); - private HashMap rolesPatterns = new HashMap(); - private HashSet allSet = new HashSet(); - private HashMap allMap = new HashMap(); - private HashSet allRoles = new HashSet(); + private Set securityRoles = new HashSet(); + private Map uncheckedPatterns = new HashMap(); + private Map excludedPatterns = new HashMap(); + private Map rolesPatterns = new HashMap(); + private Set allSet = new HashSet(); + private Map allMap = new HashMap(); + private Set allRoles = new HashSet(); + private Map roleRefs = new HashMap(); - public JettyXMLConfiguration(JettyWebApplicationContext context) { + public JettyXMLConfiguration(JettyWebAppContext context) { super(context); } @@ -73,10 +80,39 @@ } } + protected void initServlet(XmlParser.Node node) + throws ClassNotFoundException, UnavailableException, IOException, MalformedURLException { + + super.initServlet(node); + + String name = node.getString("servlet-name", false, true); + if (name == null) name = node.getString("servlet-class", false, true); + + Iterator sRefsIter = node.iterator("security-role-ref"); + while (sRefsIter.hasNext()) { + XmlParser.Node securityRef = (XmlParser.Node) sRefsIter.next(); + String roleName = securityRef.getString("role-name", false, true); + String roleLink = securityRef.getString("role-link", false, true); + + if (roleName != null && roleName.length() > 0 && roleLink != null && roleLink.length() > 0) { + if (log.isDebugEnabled()) log.debug("link role " + roleName + " to " + roleLink + " for " + this); + + Set refs = (Set) roleRefs.get(roleLink); + if (refs == null) { + refs = new HashSet(); + roleRefs.put(roleLink, refs); + } + refs.add(new WebRoleRefPermission(name, roleName)); + } else { + log.warn("Ignored invalid security-role-ref element: " + "servlet-name=" + name + ", " + securityRef); + } + } + } + /** * Translate the web deployment descriptors into equivalent security * permissions. These permissions are placed into the appropriate - * <code>PolicyConfiguration</code> object as defined in the JAAC spec. + * <code>PolicyConfiguration</code> object as defined in the JACC spec. * * @param node the deployment descriptor from which to obtain the * security constraints that are to be translated. @@ -91,7 +127,7 @@ XmlParser.Node auths = node.get("auth-constraint"); - HashMap currentPatterns; + Map currentPatterns; if (auths == null) { currentPatterns = uncheckedPatterns; } else if (auths.size() == 0) { @@ -157,9 +193,19 @@ } protected void initSecurityRole(XmlParser.Node node) { + super.initSecurityRole(node); + securityRoles.add(node.get("role-name").toString(false, true)); } + /** + * This method dumps the intermediate security information into the JACC + * PolicyConfiguration. + * + * @param configuration the JACC PolicyConfiguration + * @param security the augmented security information from the geronimo-web.xml file + * @throws GeronimoSecurityException + */ public void configure(PolicyConfiguration configuration, Security security) throws GeronimoSecurityException { try { @@ -257,12 +303,16 @@ configuration.addToUncheckedPolicy(new WebUserDataPermission(name, actions)); } + JettyWebAppJACCContext context = (JettyWebAppJACCContext) getWebApplicationContext(); RoleMappingConfiguration roleMapper = (RoleMappingConfiguration) configuration; - Iterator rollMappings = security.getRollMappings().iterator(); + Iterator rollMappings = security.getRoleMappings().iterator(); while (rollMappings.hasNext()) { Role role = (Role) rollMappings.next(); + String roleName = role.getRoleName(); + + if (!securityRoles.contains(roleName)) throw new GeronimoSecurityException("Role does not exist in this configuration"); - if (!securityRoles.contains(role.getRoleName())) throw new GeronimoSecurityException("Role does not exist in this configuration"); + Subject roleDesignate = new Subject(); Iterator realms = role.getRealms().iterator(); while (realms.hasNext()) { @@ -273,27 +323,31 @@ while (principals.hasNext()) { Principal principal = (Principal) principals.next(); - Class clazz = Class.forName(principal.getClassName()); - Constructor constructor = clazz.getDeclaredConstructor(new Class[]{String.class}); - java.security.Principal p = (java.security.Principal) constructor.newInstance(new Object[]{principal.getPrincipalName()}); - principalSet.add(new RealmPrincipal(realm.getRealmName(), p)); + RealmPrincipal realmPrincipal = ConfigurationUtil.generateRealmPrincipal(principal, realm.getRealmName()); + + if (realmPrincipal == null) throw new GeronimoSecurityException("Unable to create realm principal"); + + principalSet.add(realmPrincipal); + if (principal.isDesignatedRunAs()) roleDesignate.getPrincipals().add(realmPrincipal); } - roleMapper.addRoleMapping(role.getRoleName(), principalSet); + roleMapper.addRoleMapping(roleName, principalSet); + } + + if (roleDesignate.getPrincipals().size() > 0) context.setRoleDesignate(roleName, roleDesignate); + } + + Iterator keys = roleRefs.keySet().iterator(); + while (keys.hasNext()) { + String roleLink = (String) keys.next(); + iter = ((Set) roleRefs.get(roleLink)).iterator(); + + while (iter.hasNext()) { + configuration.addToRole(roleLink, (WebRoleRefPermission) iter.next()); } } } catch (ClassCastException cce) { throw new GeronimoSecurityException("Policy configuration object does not implement RoleMappingConfiguration", cce.getCause()); } catch (PolicyContextException e) { - throw new GeronimoSecurityException(e); - } catch (IllegalAccessException e) { - throw new GeronimoSecurityException(e); - } catch (NoSuchMethodException e) { - throw new GeronimoSecurityException(e); - } catch (InvocationTargetException e) { - throw new GeronimoSecurityException(e); - } catch (InstantiationException e) { - throw new GeronimoSecurityException(e); - } catch (ClassNotFoundException e) { throw new GeronimoSecurityException(e); } } 1.1 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyServletHolder.java Index: JettyServletHolder.java =================================================================== /** * * Copyright 2004 The Apache Software Foundation * * Licensed 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.jetty; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.UnavailableException; import java.io.IOException; import org.mortbay.jetty.servlet.ServletHandler; import org.mortbay.jetty.servlet.ServletHolder; /** * This ServletHolder's sole purpose is to provide the thread's current * ServletHolder for realms that are interested in the current servlet, e.g. * current servlet name. * @see org.apache.geronimo.jetty.JAASJettyRealm#isUserInRole(java.security.Principal, java.lang.String) * @version $Revision: 1.1 $ $Date: 2004/06/27 20:37:38 $ */ public class JettyServletHolder extends ServletHolder { private static final ThreadLocal currentServletHolder = new ThreadLocal(); public JettyServletHolder() { super(); } public JettyServletHolder(ServletHandler handler, String name, String className) { super(handler, name, className); } public JettyServletHolder(ServletHandler handler, String name, String className, String forcedPath) { super(handler,name, className, forcedPath); } /** * Service a request with this servlet. Set the ThreadLocal to hold the * current JettyServletHolder. * @param request * @param response * @throws ServletException * @throws UnavailableException * @throws IOException */ public void handle(ServletRequest request, ServletResponse response) throws ServletException, UnavailableException, IOException { currentServletHolder.set(this); super.handle(request, response); } /** * Provide the thread's current JettyServletHolder * @return the thread's current JettyServletHolder * @see org.apache.geronimo.jetty.JAASJettyRealm#isUserInRole(java.security.Principal, java.lang.String) */ static JettyServletHolder getJettyServletHolder() { return (JettyServletHolder) currentServletHolder.get(); } } 1.1 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyWebAppContext.java Index: JettyWebAppContext.java =================================================================== /** * * Copyright 2003-2004 The Apache Software Foundation * * Licensed 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.jetty; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.Set; import javax.resource.ResourceException; import javax.transaction.TransactionManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.geronimo.gbean.GBeanInfo; import org.apache.geronimo.gbean.GBeanInfoFactory; import org.apache.geronimo.gbean.GBeanLifecycle; import org.apache.geronimo.gbean.WaitingException; import org.apache.geronimo.kernel.config.ConfigurationParent; import org.apache.geronimo.naming.java.ReadOnlyContext; import org.apache.geronimo.naming.java.RootContext; import org.apache.geronimo.transaction.DefaultInstanceContext; import org.apache.geronimo.transaction.InstanceContext; import org.apache.geronimo.transaction.TrackedConnectionAssociator; import org.apache.geronimo.transaction.TransactionContext; import org.apache.geronimo.transaction.UnspecifiedTransactionContext; import org.apache.geronimo.transaction.UserTransactionImpl; import org.mortbay.http.HttpException; import org.mortbay.http.HttpRequest; import org.mortbay.http.HttpResponse; import org.mortbay.jetty.servlet.WebApplicationContext; /** * Wrapper for a WebApplicationContext that sets up its J2EE environment. * * @version $Revision: 1.1 $ $Date: 2004/06/27 20:37:38 $ */ public class JettyWebAppContext extends WebApplicationContext implements GBeanLifecycle { private static Log log = LogFactory.getLog(JettyWebAppContext.class); private final ConfigurationParent config; private final URI uri; private final JettyContainer container; private final ReadOnlyContext componentContext; private final TransactionManager txManager; private final TrackedConnectionAssociator associator; private final UserTransactionImpl userTransaction; private final ClassLoader classLoader; // @todo get these from DD private final Set unshareableResources; private final Set applicationManagedSecurityResources; private boolean contextPriorityClassLoader = false; public JettyWebAppContext() { this(null, null, null, null, null, null, null, null, null, null); } public JettyWebAppContext(ConfigurationParent config, URI uri, JettyContainer container, ReadOnlyContext compContext, Set unshareableResources, Set applicationManagedSecurityResources, TransactionManager txManager, TrackedConnectionAssociator associator, UserTransactionImpl userTransaction, ClassLoader classLoader) { super(); this.config = config; this.uri = uri; this.container = container; this.componentContext = compContext; this.unshareableResources = unshareableResources; this.applicationManagedSecurityResources = applicationManagedSecurityResources; this.txManager = txManager; this.associator = associator; this.userTransaction = userTransaction; this.classLoader = classLoader; setConfiguration(new JettyXMLConfiguration(this)); } /** * getContextPriorityClassLoader. * * @return True if this context should give web application class in preference over the containers * classes, as per the servlet specification recommendations. */ public boolean getContextPriorityClassLoader() { return contextPriorityClassLoader; } /** * setContextPriorityClassLoader. * * @param b True if this context should give web application class in preference over the containers * classes, as per the servlet specification recommendations. */ public void setContextPriorityClassLoader(boolean b) { contextPriorityClassLoader = b; } /** * init the classloader. Uses the value of contextPriorityClassLoader to * determine if the context needs to create its own classloader. */ protected void initClassLoader(boolean forceContextLoader) throws MalformedURLException, IOException { setClassLoaderJava2Compliant(!contextPriorityClassLoader); if (!contextPriorityClassLoader) { // TODO - once geronimo is correctly setting up the classpath, this should be uncommented. // At the moment, the g classloader does not appear to know about the WEB-INF classes and lib. // setClassLoader(Thread.currentThread().getContextClassLoader()); } super.initClassLoader(forceContextLoader); if (log.isDebugEnabled()) { log.debug("classloader for " + getContextPath() + ": " + getClassLoader()); } } public void handle(String pathInContext, String pathParams, HttpRequest httpRequest, HttpResponse httpResponse) throws HttpException, IOException { // save previous state ReadOnlyContext oldComponentContext = RootContext.getComponentContext(); InstanceContext oldInstanceContext = null; try { // set up java:comp JNDI Context RootContext.setComponentContext(componentContext); // Turn on the UserTransaction userTransaction.setOnline(true); if (TransactionContext.getContext() == null) { TransactionContext.setContext(new UnspecifiedTransactionContext()); } try { oldInstanceContext = associator.enter(new DefaultInstanceContext(unshareableResources, applicationManagedSecurityResources)); } catch (ResourceException e) { throw new RuntimeException(e); } super.handle(pathInContext, pathParams, httpRequest, httpResponse); } finally { try { associator.exit(oldInstanceContext); } catch (ResourceException e) { throw new RuntimeException(e); } finally { userTransaction.setOnline(false); RootContext.setComponentContext(oldComponentContext); } } } public void doStart() throws WaitingException, Exception { userTransaction.setUp(txManager, associator); if (uri.isAbsolute()) { setWAR(uri.toString()); } else { setWAR(new URL(config.getBaseURL(), uri.toString()).toString()); } if (userTransaction != null) { userTransaction.setOnline(true); } container.addContext(this); ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(classLoader); super.start(); } finally { Thread.currentThread().setContextClassLoader(oldCL); } log.info("JettyWebAppContext started"); } public void doStop() throws WaitingException, Exception { while (true) { try { super.stop(); break; } catch (InterruptedException e) { continue; } } container.removeContext(this); if (userTransaction != null) { userTransaction.setOnline(false); } log.info("JettyWebAppContext stopped"); } public void doFail() { try { super.stop(); } catch (InterruptedException e) { } container.removeContext(this); log.info("JettyWebAppContext failed"); } public static final GBeanInfo GBEAN_INFO; static { GBeanInfoFactory infoFactory = new GBeanInfoFactory("Jetty WebApplication Context", JettyWebAppContext.class); infoFactory.addAttribute("URI", URI.class, true); infoFactory.addAttribute("ContextPath", String.class, true); infoFactory.addAttribute("ContextPriorityClassLoader", Boolean.TYPE, true); infoFactory.addAttribute("ComponentContext", ReadOnlyContext.class, true); infoFactory.addAttribute("UnshareableResources", Set.class, true); infoFactory.addAttribute("ApplicationManagedSecurityResources", Set.class, true); infoFactory.addAttribute("UserTransaction", UserTransactionImpl.class, true); infoFactory.addAttribute("classLoader", ClassLoader.class, false); infoFactory.addReference("Configuration", ConfigurationParent.class); infoFactory.addReference("JettyContainer", JettyContainer.class); infoFactory.addReference("TransactionManager", TransactionManager.class); infoFactory.addReference("TrackedConnectionAssociator", TrackedConnectionAssociator.class); infoFactory.setConstructor(new String[]{ "Configuration", "URI", "JettyContainer", "ComponentContext", "UnshareableResources", "ApplicationManagedSecurityResources", "TransactionManager", "TrackedConnectionAssociator", "UserTransaction", "classLoader"}); GBEAN_INFO = infoFactory.getBeanInfo(); } public static GBeanInfo getGBeanInfo() { return GBEAN_INFO; } } 1.1 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyWebAppHandler.java Index: JettyWebAppHandler.java =================================================================== /** * * Copyright 2004 The Apache Software Foundation * * Licensed 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.jetty; import org.mortbay.jetty.servlet.ServletHolder; import org.mortbay.jetty.servlet.WebApplicationHandler; /** * A class extension to <code>WebApplicationHandler</code> whose sole purpose * is to override the implementation of <code>newServletHolder()</code> so * that it returns an instance of <code>JettyServletHolder</code>. The class * <code>JettyServletHolder</code> tracks which servlet is currently being * handled by the current thread. This allows <code>JAASJettyRealm</code> * to obtain the name of the servlet that is being handled so that it can * generate the proper JACC permission. * * @version $Revision: 1.1 $ $Date: 2004/06/27 20:37:38 $ * @see org.apache.geronimo.jetty.JettyServletHolder * @see org.apache.geronimo.jetty.JAASJettyRealm#isUserInRole(java.security.Principal, java.lang.String) */ public class JettyWebAppHandler extends WebApplicationHandler { /** * Return an instance of <code>JettyServletHolder</code>. * <p/> * This method overrides <code>WebApplicationHandler</code>'s implementation. * * @param name The name of the servlet. * @param servletClass The class name of the servlet. * @param forcedPath If non null, the request attribute * javax.servlet.include.servlet_path will be set to this path before * service is called. * @return an instance of <code>JettyServletHolder</code> * @see org.mortbay.jetty.servlet.WebApplicationHandler#newServletHolder(java.lang.String, java.lang.String, java.lang.String) */ public ServletHolder newServletHolder(String name, String servletClass, String forcedPath) { if (_nameMap.containsKey(name)) throw new IllegalArgumentException("Named servlet already exists: " + name); ServletHolder holder = new JettyServletHolder(this, name, servletClass, forcedPath); _nameMap.put(holder.getName(), holder); return holder; } } 1.1 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/JettyWebAppJACCContext.java Index: JettyWebAppJACCContext.java =================================================================== /** * * Copyright 2003-2004 The Apache Software Foundation * * Licensed 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.jetty; import javax.security.auth.Subject; import javax.security.jacc.PolicyConfiguration; import javax.security.jacc.PolicyConfigurationFactory; import javax.security.jacc.PolicyContext; import javax.security.jacc.PolicyContextException; import javax.security.jacc.WebResourcePermission; import javax.security.jacc.WebUserDataPermission; import javax.transaction.TransactionManager; import java.io.IOException; import java.net.URI; import java.security.AccessControlContext; import java.security.AccessControlException; import java.security.Principal; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.mortbay.http.Authenticator; import org.mortbay.http.HttpException; import org.mortbay.http.HttpRequest; import org.mortbay.http.HttpResponse; import org.mortbay.http.PathMap; import org.mortbay.http.SecurityConstraint; import org.mortbay.http.UserRealm; import org.mortbay.jetty.servlet.FormAuthenticator; import org.mortbay.jetty.servlet.ServletHttpRequest; import org.mortbay.util.LazyList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.geronimo.gbean.GBeanInfo; import org.apache.geronimo.gbean.GBeanInfoFactory; import org.apache.geronimo.gbean.WaitingException; import org.apache.geronimo.kernel.config.ConfigurationParent; import org.apache.geronimo.naming.java.ReadOnlyContext; import org.apache.geronimo.security.ContextManager; import org.apache.geronimo.security.GeronimoSecurityException; import org.apache.geronimo.security.IdentificationPrincipal; import org.apache.geronimo.security.PrimaryRealmPrincipal; import org.apache.geronimo.security.RealmPrincipal; import org.apache.geronimo.security.SubjectId; import org.apache.geronimo.security.deploy.DefaultPrincipal; import org.apache.geronimo.security.deploy.Security; import org.apache.geronimo.security.util.ConfigurationUtil; import org.apache.geronimo.transaction.TrackedConnectionAssociator; import org.apache.geronimo.transaction.UserTransactionImpl; /** * A class extension to <code>JettyWebAppContext</code> whose purpose is to * provide JACC security checks. * * @version $Revision: 1.1 $ $Date: 2004/06/27 20:37:38 $ * @see org.mortbay.jetty.servlet.WebApplicationContext#checkSecurityConstraints(java.lang.String, org.mortbay.http.HttpRequest, org.mortbay.http.HttpResponse) */ public class JettyWebAppJACCContext extends JettyWebAppContext { private static Log log = LogFactory.getLog(JettyWebAppJACCContext.class); private final String policyContextID; private final Security securityConfig; private PolicyConfigurationFactory factory; private PolicyConfiguration policyConfiguration; private Map roleDesignates = new HashMap(); private JAASJettyPrincipal defaultPrincipal; private PathMap _constraintMap = new PathMap(); public JettyWebAppJACCContext() { this(null, null, null, null, null, null, null, null, null, null, null, null); } public JettyWebAppJACCContext(ConfigurationParent config, URI uri, JettyContainer container, ReadOnlyContext compContext, String policyContextID, Security securityConfig, Set unshareableResources, Set applicationManagedSecurityResources, TransactionManager txManager, TrackedConnectionAssociator associator, UserTransactionImpl userTransaction, ClassLoader classLoader) { super(config, uri, container, compContext, unshareableResources, applicationManagedSecurityResources, txManager, associator, userTransaction, classLoader); this.policyContextID = policyContextID; this.securityConfig = securityConfig; setConfiguration(new JettyXMLConfiguration(this)); defaultPrincipal = generateDefaultPrincipal(securityConfig); /** * We want to use our own web-app handler. */ addHandler(new JettyWebAppHandler()); } public String getPolicyContextID() { return policyContextID; } public Security getSecurityConfig() { return securityConfig; } public Subject getRoleDesignate(String roleName) { return (Subject) roleDesignates.get(roleName); } void setRoleDesignate(String roleName, Subject subject) { roleDesignates.put(roleName, subject); } /** * Handler request. * Call each HttpHandler until request is handled. * * @param pathInContext Path in context * @param pathParams Path parameters such as encoded Session ID * @param httpRequest * @param httpResponse * @throws HttpException * @throws IOException */ public void handle(String pathInContext, String pathParams, HttpRequest httpRequest, HttpResponse httpResponse) throws HttpException, IOException { String savedPolicyContextID = PolicyContext.getContextID(); JettyWebAppJACCContext savedContext = JettyServer.getCurrentWebAppContext(); try { PolicyContext.setContextID(policyContextID); JettyServer.setCurrentWebAppContext(this); super.handle(pathInContext, pathParams, httpRequest, httpResponse); } finally { JettyServer.setCurrentWebAppContext(savedContext); PolicyContext.setContextID(savedPolicyContextID); } } /** * Keep our own copy of security constraints.<p/> * <p/> * We keep our own copy of security constraints because Jetty's copy is * private. We use these constraints not for any authorization descitions * but, to decide whether we should attempt to authenticate the request. * * @param pathSpec The path spec to which the secuiryt cosntraint applies * @param sc the security constraint * @todo Jetty to provide access to this map so we can remove this method * @see org.mortbay.http.HttpContext#addSecurityConstraint(java.lang.String, org.mortbay.http.SecurityConstraint) */ public void addSecurityConstraint(String pathSpec, SecurityConstraint sc) { super.addSecurityConstraint(pathSpec, sc); Object scs = _constraintMap.get(pathSpec); scs = LazyList.add(scs, sc); _constraintMap.put(pathSpec, scs); if (log.isDebugEnabled()) log.debug("added " + sc + " at " + pathSpec); } /** * Check the security constraints using JACC. * * @param pathInContext path in context * @param request HTTP request * @param response HTTP response * @return <code>true</code> if the path in context passes the security * check, <code>false</code> if it fails or a redirection has occured * during authentication. * @throws HttpException * @throws IOException */ public boolean checkSecurityConstraints(String pathInContext, HttpRequest request, HttpResponse response) throws HttpException, IOException { try { Principal user = obtainUser(pathInContext, request, response); if (user == null) return false; if (user == SecurityConstraint.__NOBODY) return true; AccessControlContext acc = ContextManager.getCurrentContext(); ServletHttpRequest servletHttpRequest = (ServletHttpRequest) request.getWrapper(); /** * JACC v1.0 secion 4.1.1 */ acc.checkPermission(new WebUserDataPermission(servletHttpRequest)); /** * JACC v1.0 secion 4.1.2 */ acc.checkPermission(new WebResourcePermission(servletHttpRequest)); } catch (HttpException he) { response.sendError(he.getCode(), he.getReason()); return false; } catch (AccessControlException ace) { response.sendError(HttpResponse.__403_Forbidden); 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. * @throws HttpException * @throws IOException */ public Principal obtainUser(String pathInContext, HttpRequest request, HttpResponse response) throws HttpException, IOException { List scss = _constraintMap.getMatches(pathInContext); String pattern = null; boolean unauthenticated = false; boolean forbidden = false; if (scss != null && scss.size() > 0) { // for each path match // Add only constraints that have the correct method // break if the matching pattern changes. This allows only // constraints with matching pattern and method to be combined. loop: for (int m = 0; m < scss.size(); m++) { Map.Entry entry = (Map.Entry) scss.get(m); Object scs = entry.getValue(); String p = (String) entry.getKey(); for (int c = 0; c < LazyList.size(scs); c++) { SecurityConstraint sc = (SecurityConstraint) LazyList.get(scs, c); if (!sc.forMethod(request.getMethod())) continue; if (pattern != null && !pattern.equals(p)) break loop; pattern = p; // Check the method applies if (!sc.forMethod(request.getMethod())) continue; // Combine auth constraints. if (sc.getAuthenticate()) { if (!sc.isAnyRole()) { List scr = sc.getRoles(); if (scr == null || scr.size() == 0) { forbidden = true; break loop; } } } else { unauthenticated = true; break loop; } } } } UserRealm realm = getRealm(); Authenticator authenticator = getAuthenticator(); Principal user = null; if (!unauthenticated && !forbidden) { if (realm == null) { log.warn("Realm Not Configured"); throw new HttpException(HttpResponse.__500_Internal_Server_Error, "Realm Not Configured"); } // Handle pre-authenticated request if (authenticator != null) { // User authenticator. user = authenticator.authenticate(realm, pathInContext, request, response); } else { // don't know how authenticate log.warn("Mis-configured Authenticator for " + request.getPath()); throw new HttpException(HttpResponse.__500_Internal_Server_Error, "Mis-configured Authenticator for " + request.getPath()); } return user; } else if (authenticator instanceof FormAuthenticator && pathInContext.endsWith(FormAuthenticator.__J_SECURITY_CHECK)) { /** * This could be a post request to __J_SECURITY_CHECK. */ if (realm == null) { log.warn("Realm Not Configured"); throw new HttpException(HttpResponse.__500_Internal_Server_Error, "Realm Not Configured"); } return authenticator.authenticate(realm, pathInContext, request, response); } /** * No authentication is required. Return the defaultPrincipal. */ ContextManager.setCurrentCaller(defaultPrincipal.getSubject()); return defaultPrincipal; } /** * Generate the default principal from the security config. * * @param securityConfig The Geronimo security configuration. * @return the default principal * @throws GeronimoSecurityException */ protected JAASJettyPrincipal generateDefaultPrincipal(Security securityConfig) throws GeronimoSecurityException { JAASJettyPrincipal result = new JAASJettyPrincipal("default"); Subject defaultSubject = new Subject(); DefaultPrincipal principal = securityConfig.getDefaultPrincipal(); RealmPrincipal realmPrincipal = ConfigurationUtil.generateRealmPrincipal(principal.getPrincipal(), principal.getRealmName()); if (realmPrincipal == null) throw new GeronimoSecurityException("Unable to create realm principal"); PrimaryRealmPrincipal primaryRealmPrincipal = ConfigurationUtil.generatePrimaryRealmPrincipal(principal.getPrincipal(), principal.getRealmName()); if (primaryRealmPrincipal == null) throw new GeronimoSecurityException("Unable to create primary realm principal"); defaultSubject.getPrincipals().add(realmPrincipal); defaultSubject.getPrincipals().add(primaryRealmPrincipal); result.setSubject(defaultSubject); return result; } public void doStart() throws WaitingException, Exception { super.doStart(); /** * Register our default principal with the ContextManager */ Subject defaultSubject = defaultPrincipal.getSubject(); ContextManager.registerSubject(defaultSubject); SubjectId id = ContextManager.getSubjectId(defaultSubject); defaultSubject.getPrincipals().add(new IdentificationPrincipal(id)); log.debug("Default subject " + id + " for JACC policy '" + ((JettyWebAppJACCContext) getHttpContext()).getPolicyContextID() + "' registered."); /** * Get the JACC policy configuration that's associated with this * web application and configure it with the geronimo security * configuration. The work for this is done by the class * JettyXMLConfiguration. */ try { factory = PolicyConfigurationFactory.getPolicyConfigurationFactory(); policyConfiguration = factory.getPolicyConfiguration(policyContextID, true); ((JettyXMLConfiguration) this.getConfiguration()).configure(policyConfiguration, securityConfig); policyConfiguration.commit(); } catch (ClassNotFoundException e) { // do nothing } catch (PolicyContextException e) { // do nothing } catch (GeronimoSecurityException e) { // do nothing } /** * Register the role designates with the context manager. * * THIS MUST BE RUN AFTER JettyXMLConfiguration.configure() */ Iterator iter = roleDesignates.keySet().iterator(); while (iter.hasNext()) { String roleName = (String) iter.next(); Subject roleDesignate = (Subject) roleDesignates.get(roleName); ContextManager.registerSubject(roleDesignate); id = ContextManager.getSubjectId(roleDesignate); roleDesignate.getPrincipals().add(new IdentificationPrincipal(id)); log.debug("Role designate " + id + " for role '" + roleName + "' for JACC policy '" + ((JettyWebAppJACCContext) getHttpContext()).getPolicyContextID() + "' registered."); } log.info("JettyWebAppJACCContext started with JACC policy '" + policyContextID + "'"); } public void doStop() throws WaitingException, Exception { super.doStop(); /** * Unregister the default principal and role designates */ log.debug("Default subject " + ContextManager.getSubjectId(defaultPrincipal.getSubject()) + " for JACC policy " + ((JettyWebAppJACCContext) getHttpContext()).getPolicyContextID() + "' unregistered."); ContextManager.unregisterSubject(defaultPrincipal.getSubject()); Iterator iter = roleDesignates.keySet().iterator(); while (iter.hasNext()) { String roleName = (String) iter.next(); Subject roleDesignate = (Subject) roleDesignates.get(roleName); ContextManager.unregisterSubject(roleDesignate); log.debug("Role designate " + ContextManager.getSubjectId(roleDesignate) + " for role '" + roleName + "' for JACC policy '" + ((JettyWebAppJACCContext) getHttpContext()).getPolicyContextID() + "' unregistered."); } /** * Delete the policy configuration for this web application */ if (policyConfiguration != null) policyConfiguration.delete(); log.info("JettyWebAppJACCContext with JACC policy '" + policyContextID + "' stopped"); } public void doFail() { super.doFail(); try { if (policyConfiguration != null) policyConfiguration.delete(); } catch (PolicyContextException e) { // do nothing } log.info("JettyWebAppJACCContext failed"); } public static final GBeanInfo GBEAN_INFO; static { GBeanInfoFactory infoFactory = new GBeanInfoFactory("Jetty JACC WebApplication Context", JettyWebAppJACCContext.class, JettyWebAppContext.GBEAN_INFO); infoFactory.addAttribute("SecurityConfig", Security.class, true); infoFactory.addAttribute("PolicyContextID", String.class, true); infoFactory.setConstructor(new String[]{ "Configuration", "URI", "JettyContainer", "ComponentContext", "PolicyContextID", "SecurityConfig", "UnshareableResources", "ApplicationManagedSecurityResources", "TransactionManager", "TrackedConnectionAssociator", "UserTransaction", "classLoader"}); GBEAN_INFO = infoFactory.getBeanInfo(); } public static GBeanInfo getGBeanInfo() { return GBEAN_INFO; } } 1.12 +21 -7 incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/deployment/JettyModuleBuilder.java Index: JettyModuleBuilder.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/jetty/src/java/org/apache/geronimo/jetty/deployment/JettyModuleBuilder.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- JettyModuleBuilder.java 22 Jun 2004 00:00:22 -0000 1.11 +++ JettyModuleBuilder.java 27 Jun 2004 20:37:38 -0000 1.12 @@ -52,7 +52,8 @@ import org.apache.geronimo.j2ee.deployment.Module; import org.apache.geronimo.j2ee.deployment.ModuleBuilder; import org.apache.geronimo.j2ee.deployment.WebModule; -import org.apache.geronimo.jetty.JettyWebApplicationContext; +import org.apache.geronimo.jetty.JettyWebAppContext; +import org.apache.geronimo.jetty.JettyWebAppJACCContext; import org.apache.geronimo.naming.deployment.ENCConfigBuilder; import org.apache.geronimo.naming.java.ComponentContextBuilder; import org.apache.geronimo.naming.java.ReadOnlyContext; @@ -268,8 +269,16 @@ UserTransaction userTransaction = new UserTransactionImpl(); ReadOnlyContext compContext = buildComponentContext(earContext, webModule, webApp, jettyWebApp, userTransaction, cl); - GBeanMBean gbean = new GBeanMBean(JettyWebApplicationContext.GBEAN_INFO, cl); + Security security = buildSecurityConfig(jettyWebApp); + + GBeanMBean gbean; try { + if (security == null) { + gbean = new GBeanMBean(JettyWebAppContext.GBEAN_INFO, cl); + } else { + gbean = new GBeanMBean(JettyWebAppJACCContext.GBEAN_INFO, cl); + } + URI warRoot = null; if (!webModule.getURI().equals(URI.create("/"))) { warRoot = URI.create(webModule.getURI() + "/"); @@ -282,8 +291,10 @@ gbean.setAttribute("URI", warRoot); gbean.setAttribute("ContextPath", webModule.getContextRoot()); gbean.setAttribute("ContextPriorityClassLoader", Boolean.valueOf(jettyWebApp.getContextPriorityClassloader())); - gbean.setAttribute("SecurityConfig", buildSecurityConfig(jettyWebApp)); - gbean.setAttribute("PolicyContextID", PolicyContextID); + if (security != null) { + gbean.setAttribute("SecurityConfig", security); + gbean.setAttribute("PolicyContextID", PolicyContextID); + } gbean.setAttribute("ComponentContext", compContext); gbean.setAttribute("UserTransaction", userTransaction); setResourceEnvironment(gbean, webApp.getResourceRefArray(), jettyWebApp.getResourceRefArray()); @@ -343,10 +354,12 @@ } private static Security buildSecurityConfig(JettyWebAppType jettyWebApp) { - Security security = new Security(); + Security security = null; JettySecurityType securityType = jettyWebApp.getSecurity(); if (securityType != null) { + security = new Security(); + security.setUseContextHandler(securityType.getUseContextHandler()); JettyDefaultPrincipalType defaultPrincipalType = securityType.getDefaultPrincipal(); @@ -378,7 +391,7 @@ role.getRealms().add(realm); } - security.getRollMappings().add(role); + security.getRoleMappings().add(role); } } } @@ -391,6 +404,7 @@ principal.setClassName(principalType.getClass1()); principal.setPrincipalName(principalType.getName()); + principal.setDesignatedRunAs(principalType.isSetDesignatedRunAs()); return principal; } 1.12 +5 -3 incubator-geronimo/modules/jetty/src/test/org/apache/geronimo/jetty/ApplicationTest.java Index: ApplicationTest.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/jetty/src/test/org/apache/geronimo/jetty/ApplicationTest.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- ApplicationTest.java 15 Jun 2004 21:37:39 -0000 1.11 +++ ApplicationTest.java 27 Jun 2004 20:37:38 -0000 1.12 @@ -53,13 +53,15 @@ private GBeanMBean tm; private GBeanMBean ctc; + public void testDummy() throws Exception { + } + public void testApplication() throws Exception { URL url = Thread.currentThread().getContextClassLoader().getResource("deployables/war1/"); - GBeanMBean app = new GBeanMBean(JettyWebApplicationContext.GBEAN_INFO); + GBeanMBean app = new GBeanMBean(JettyWebAppContext.GBEAN_INFO); app.setAttribute("URI", URI.create(url.toString())); app.setAttribute("ContextPath", "/test"); app.setAttribute("ComponentContext", null); - app.setAttribute("PolicyContextID", null); UserTransactionImpl userTransaction = new UserTransactionImpl(); app.setAttribute("UserTransaction", userTransaction); app.setReferencePatterns("Configuration", Collections.EMPTY_SET); 1.1 incubator-geronimo/modules/jetty/src/test/org/apache/geronimo/jetty/SecurityTest.java Index: SecurityTest.java =================================================================== /** * * Copyright 2003-2004 The Apache Software Foundation * * Licensed 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.jetty; import javax.management.MBeanServer; import javax.management.ObjectName; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; import java.util.Collections; import java.util.HashSet; import java.util.Set; import junit.framework.TestCase; import org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTrackingCoordinator; import org.apache.geronimo.gbean.jmx.GBeanMBean; import org.apache.geronimo.jetty.connector.HTTPConnector; import org.apache.geronimo.kernel.Kernel; import org.apache.geronimo.system.serverinfo.ServerInfo; import org.apache.geronimo.transaction.GeronimoTransactionManager; import org.apache.geronimo.transaction.UserTransactionImpl; /** * @version $Revision: 1.1 $ $Date: 2004/06/27 20:37:38 $ */ public class SecurityTest extends TestCase { private Kernel kernel; private GBeanMBean container; private ObjectName containerName; private Set containerPatterns; private ObjectName connectorName; private MBeanServer mbServer; private GBeanMBean connectorGBean; private GBeanMBean serverInfoGBean; private ObjectName serverInfoName; private GBeanMBean jaasRealmGBean; private ObjectName jaasRealmName; private GBeanMBean propertiesRealmGBean; private ObjectName propertiesRealmName; private ObjectName loginServiceName; private GBeanMBean loginServiceGBean; private ObjectName appName; private ObjectName tmName; private ObjectName tcaName; private GBeanMBean tm; private GBeanMBean ctc; public void testDummy() throws Exception { } public void XtestApplication() throws Exception { URL url = Thread.currentThread().getContextClassLoader().getResource("deployables/war3/"); GBeanMBean app = new GBeanMBean(JettyWebAppContext.GBEAN_INFO); app.setAttribute("URI", URI.create(url.toString())); app.setAttribute("ContextPath", "/test"); app.setAttribute("ComponentContext", null); UserTransactionImpl userTransaction = new UserTransactionImpl(); app.setAttribute("UserTransaction", userTransaction); app.setReferencePatterns("Configuration", Collections.EMPTY_SET); app.setReferencePatterns("JettyContainer", containerPatterns); app.setReferencePatterns("TransactionManager", Collections.singleton(tmName)); app.setReferencePatterns("TrackedConnectionAssociator", Collections.singleton(tcaName)); start(appName, app); HttpURLConnection connection = (HttpURLConnection) new URL("http://localhost:5678/test/protected/hello.txt").openConnection(); connection.setInstanceFollowRedirects(false); assertEquals(HttpURLConnection.HTTP_MOVED_TEMP, connection.getResponseCode()); String cookie = connection.getHeaderField("Set-Cookie"); String location = connection.getHeaderField("Location"); cookie = cookie.substring(0, cookie.lastIndexOf(';')); location = location.substring(0, location.lastIndexOf('/')) + "/j_security_check?j_username=alan&j_password=starcraft"; connection = (HttpURLConnection) new URL(location).openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Cookie", cookie); connection.setInstanceFollowRedirects(false); assertEquals(HttpURLConnection.HTTP_MOVED_TEMP, connection.getResponseCode()); connection = (HttpURLConnection) new URL("http://localhost:5678/test/protected/hello.txt").openConnection(); connection.setRequestProperty("Cookie", cookie); connection.setInstanceFollowRedirects(false); BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); assertEquals(HttpURLConnection.HTTP_OK, connection.getResponseCode()); assertEquals("Hello World", reader.readLine()); connection.disconnect(); } private void start(ObjectName name, Object instance) throws Exception { mbServer.registerMBean(instance, name); mbServer.invoke(name, "start", null, null); } private void stop(ObjectName name) throws Exception { mbServer.invoke(name, "stop", null, null); mbServer.unregisterMBean(name); } protected void setUp() throws Exception { containerName = new ObjectName("geronimo.jetty:role=Container"); containerPatterns = Collections.singleton(containerName); connectorName = new ObjectName("geronimo.jetty:role=Connector"); appName = new ObjectName("geronimo.jetty:app=test"); tmName = new ObjectName("geronimo.test:role=TransactionManager"); tcaName = new ObjectName("geronimo.test:role=ConnectionTrackingCoordinator"); kernel = new Kernel("geronimo.kernel", "test"); kernel.boot(); mbServer = kernel.getMBeanServer(); container = new GBeanMBean(JettyContainerImpl.GBEAN_INFO); serverInfoGBean = new GBeanMBean(ServerInfo.GBEAN_INFO); serverInfoName = new ObjectName("geronimo.system:role=ServerInfo"); serverInfoGBean.setAttribute("BaseDirectory", "."); connectorGBean = new GBeanMBean(HTTPConnector.GBEAN_INFO); connectorGBean.setAttribute("Port", new Integer(5678)); connectorGBean.setReferencePatterns("JettyContainer", containerPatterns); jaasRealmGBean = new GBeanMBean("org.apache.geronimo.jetty.JAASJettyRealm"); jaasRealmName = new ObjectName("geronimo.jetty:role=JaasRealm"); jaasRealmGBean.setReferencePatterns("JettyContainer", containerPatterns); jaasRealmGBean.setAttribute("Name", "Test JAAS Realm"); jaasRealmGBean.setAttribute("LoginModuleName", "jaasTest"); loginServiceGBean = new GBeanMBean("org.apache.geronimo.security.jaas.LoginService"); loginServiceName = new ObjectName("geronimo.security:type=LoginService"); loginServiceGBean.setReferencePatterns("Realms", Collections.singleton(new ObjectName("geronimo.security:type=SecurityRealm,*"))); loginServiceGBean.setAttribute("ReclaimPeriod", new Long(1000 * 1000)); loginServiceGBean.setAttribute("Algorithm", "HmacSHA1"); loginServiceGBean.setAttribute("Password", "secret"); propertiesRealmGBean = new GBeanMBean("org.apache.geronimo.security.realm.providers.PropertiesFileSecurityRealm"); propertiesRealmName = new ObjectName("geronimo.security:type=SecurityRealm,realm=demo-properties-realm"); propertiesRealmGBean.setReferencePatterns("ServerInfo", Collections.singleton(serverInfoName)); propertiesRealmGBean.setAttribute("RealmName", "demo-properties-realm"); propertiesRealmGBean.setAttribute("MaxLoginModuleAge", new Long(1 * 1000)); propertiesRealmGBean.setAttribute("UsersURI", (new File(new File("."), "src/test-resources/data/users.properties")).toURI()); propertiesRealmGBean.setAttribute("GroupsURI", (new File(new File("."), "src/test-resources/data/groups.properties")).toURI()); start(serverInfoName, serverInfoGBean); start(propertiesRealmName, propertiesRealmGBean); start(containerName, container); start(loginServiceName, loginServiceGBean); start(jaasRealmName, jaasRealmGBean); start(connectorName, connectorGBean); tm = new GBeanMBean(GeronimoTransactionManager.GBEAN_INFO); Set patterns = new HashSet(); patterns.add(ObjectName.getInstance("geronimo.management:J2eeType=ManagedConnectionFactory,*")); tm.setReferencePatterns("resourceManagers", patterns); start(tmName, tm); ctc = new GBeanMBean(ConnectionTrackingCoordinator.GBEAN_INFO); start(tcaName, ctc); } protected void tearDown() throws Exception { stop(tcaName); stop(tmName); stop(connectorName); stop(jaasRealmName); stop(loginServiceName); stop(containerName); stop(propertiesRealmName); stop(serverInfoName); kernel.shutdown(); } }