diff --git a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java index 90b89dc03f..710feafa81 100644 --- a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java +++ b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,14 @@ package net.sf.acegisecurity.adapters.jboss; import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.ui.AbstractIntegrationFilter; +import net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextUtils; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; import java.security.Principal; @@ -28,33 +35,88 @@ import javax.naming.NamingException; import javax.security.auth.Subject; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; /** - * Populates a {@link net.sf.acegisecurity.context.SecureContext} from JBoss' - * java:comp/env/security/subject. + * Populates a {@link net.sf.acegisecurity.context.security.SecureContext} from + * JBoss' java:comp/env/security/subject. * *

- * See {@link AbstractIntegrationFilter} for further information. + * This filter never preserves the Authentication on the + * ContextHolder - it is replaced every request. + *

+ * + *

+ * See {@link HttpSessionContextIntegrationFilter} for further information. *

* * @author Ben Alex * @version $Id$ */ -public class JbossIntegrationFilter extends AbstractIntegrationFilter { +public class JbossIntegrationFilter implements Filter { + //~ Static fields/initializers ============================================= + + private static final Log logger = LogFactory.getLog(JbossIntegrationFilter.class); + //~ Methods ================================================================ /** - * Not supported for this type of well-known location. - * - * @param request DOCUMENT ME! - * @param authentication DOCUMENT ME! + * Does nothing. We use IoC container lifecycle services instead. */ - public void commitToContainer(ServletRequest request, - Authentication authentication) {} + public void destroy() {} - public Object extractFromContainer(ServletRequest request) { + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + SecureContext sc = SecureContextUtils.getSecureContext(); + + Object principal = extractFromContainer(request); + + if ((principal != null) && principal instanceof Authentication) { + sc.setAuthentication((Authentication) principal); + + if (logger.isDebugEnabled()) { + logger.debug( + "ContextHolder updated with Authentication from container: '" + + principal + "'"); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug( + "ContextHolder not set with new Authentication as Principal was: '" + + principal + "'"); + } + } + + chain.doFilter(request, response); + } + + /** + * Does nothing. We use IoC container lifecycle services instead. + * + * @param arg0 ignored + * + * @throws ServletException ignored + */ + public void init(FilterConfig arg0) throws ServletException {} + + /** + * Provided so that unit tests can override. + * + * @return a Context that can be used for lookup + * + * @throws NamingException DOCUMENT ME! + */ + protected Context getLookupContext() throws NamingException { + return new InitialContext(); + } + + private Object extractFromContainer(ServletRequest request) { Subject subject = null; try { @@ -94,15 +156,4 @@ public class JbossIntegrationFilter extends AbstractIntegrationFilter { return null; } - - /** - * Provided so that unit tests can override. - * - * @return a Context that can be used for lookup - * - * @throws NamingException DOCUMENT ME! - */ - protected Context getLookupContext() throws NamingException { - return new InitialContext(); - } } diff --git a/adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilterTests.java b/adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilterTests.java index 6135fbb867..fc2fe7ff60 100644 --- a/adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilterTests.java +++ b/adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilterTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +20,14 @@ import junit.framework.TestCase; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.security.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextUtils; import org.springframework.mock.web.MockHttpServletRequest; +import java.io.IOException; + import java.security.Principal; import java.util.HashSet; @@ -32,6 +37,13 @@ import javax.naming.Context; import javax.security.auth.Subject; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + /** * Tests {@link JbossIntegrationFilter}. @@ -52,15 +64,11 @@ public class JbossIntegrationFilterTests extends TestCase { //~ Methods ================================================================ - public final void setUp() throws Exception { - super.setUp(); - } - public static void main(String[] args) { junit.textui.TestRunner.run(JbossIntegrationFilterTests.class); } - public void testCorrectOperation() { + public void testCorrectOperation() throws Exception { PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", "someone", "password", new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); @@ -68,59 +76,77 @@ public class JbossIntegrationFilterTests extends TestCase { JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext( makeIntoSubject(principal))); - Object result = filter.extractFromContainer(new MockHttpServletRequest()); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockFilterChain chain = new MockFilterChain(); - if (!(result instanceof PrincipalAcegiUserToken)) { - fail("Should have returned PrincipalAcegiUserToken"); - } + filter.doFilter(request, null, chain); - PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result; - assertEquals(principal, result); - - MockHttpServletRequest mockRequest = new MockHttpServletRequest(); - mockRequest.setUserPrincipal(principal); - - filter.commitToContainer(mockRequest, principal); + assertEquals(principal, + SecureContextUtils.getSecureContext().getAuthentication()); + ContextHolder.setContext(null); } - public void testReturnsNullIfContextReturnsSomethingOtherThanASubject() { + public void testReturnsNullIfContextReturnsSomethingOtherThanASubject() + throws Exception { JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext( "THIS_IS_NOT_A_SUBJECT")); - assertEquals(null, - filter.extractFromContainer(new MockHttpServletRequest(null, null))); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockFilterChain chain = new MockFilterChain(); + + filter.doFilter(request, null, chain); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } - public void testReturnsNullIfInitialContextHasNullPrincipal() { + public void testReturnsNullIfInitialContextHasNullPrincipal() + throws Exception { JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext( makeIntoSubject(null))); - assertEquals(null, - filter.extractFromContainer(new MockHttpServletRequest(null, null))); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockFilterChain chain = new MockFilterChain(); + + filter.doFilter(request, null, chain); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } - public void testReturnsNullIfInitialContextHasNullSubject() { + public void testReturnsNullIfInitialContextHasNullSubject() + throws Exception { JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext( null)); - assertEquals(null, - filter.extractFromContainer(new MockHttpServletRequest(null, null))); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockFilterChain chain = new MockFilterChain(); + + filter.doFilter(request, null, chain); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } - public void testReturnsNullIfInitialContextIsNull() { + public void testReturnsNullIfInitialContextIsNull() + throws Exception { JbossIntegrationFilter filter = new MockJbossIntegrationFilter(null); - Object result = filter.extractFromContainer(new MockHttpServletRequest( - null, null)); - assertEquals(null, filter.extractFromContainer(null)); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockFilterChain chain = new MockFilterChain(); + + filter.doFilter(request, null, chain); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } - public void testReturnsNullIfPrincipalNotAnAuthenticationImplementation() { + public void testReturnsNullIfPrincipalNotAnAuthenticationImplementation() + throws Exception { JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext( makeIntoSubject(new Principal() { public String getName() { return "MockPrincipal"; } }))); - assertEquals(null, - filter.extractFromContainer(new MockHttpServletRequest(null, null))); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockFilterChain chain = new MockFilterChain(); + + filter.doFilter(request, null, chain); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } public void testTestingObjectReturnsInitialContext() @@ -129,10 +155,35 @@ public class JbossIntegrationFilterTests extends TestCase { assertTrue(filter.getLookupContext() instanceof Context); } + protected void setUp() throws Exception { + super.setUp(); + ContextHolder.setContext(new SecureContextImpl()); + } + + protected void tearDown() throws Exception { + super.tearDown(); + ContextHolder.setContext(null); + } + + private void executeFilterInContainerSimulator(FilterConfig filterConfig, + Filter filter, ServletRequest request, ServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + filter.init(filterConfig); + filter.doFilter(request, response, filterChain); + filter.destroy(); + } + private Subject makeIntoSubject(Principal principal) { Set principals = new HashSet(); principals.add(principal); return new Subject(false, principals, new HashSet(), new HashSet()); } + + //~ Inner Classes ========================================================== + + private class MockFilterChain implements FilterChain { + public void doFilter(ServletRequest arg0, ServletResponse arg1) + throws IOException, ServletException {} + } } diff --git a/core/src/main/java/org/acegisecurity/Authentication.java b/core/src/main/java/org/acegisecurity/Authentication.java index f7ab4c324c..fcc211950a 100644 --- a/core/src/main/java/org/acegisecurity/Authentication.java +++ b/core/src/main/java/org/acegisecurity/Authentication.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,8 @@ import java.security.Principal; *

* *

- * Stored in a request {@link net.sf.acegisecurity.context.SecureContext}. + * Stored in a request {@link + * net.sf.acegisecurity.context.security.SecureContext}. *

* * @author Ben Alex diff --git a/core/src/main/java/org/acegisecurity/AuthenticationCredentialsNotFoundException.java b/core/src/main/java/org/acegisecurity/AuthenticationCredentialsNotFoundException.java index 567ba55a71..cf720c4c1c 100644 --- a/core/src/main/java/org/acegisecurity/AuthenticationCredentialsNotFoundException.java +++ b/core/src/main/java/org/acegisecurity/AuthenticationCredentialsNotFoundException.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ package net.sf.acegisecurity; /** * Thrown if an authentication request is rejected because there is no {@link * Authentication} object in the {@link - * net.sf.acegisecurity.context.SecureContext}. + * net.sf.acegisecurity.context.security.SecureContext}. * * @author Ben Alex * @version $Id$ diff --git a/core/src/main/java/org/acegisecurity/RunAsManager.java b/core/src/main/java/org/acegisecurity/RunAsManager.java index c0a91fb156..5d496dfa56 100644 --- a/core/src/main/java/org/acegisecurity/RunAsManager.java +++ b/core/src/main/java/org/acegisecurity/RunAsManager.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,8 @@ package net.sf.acegisecurity; * object invocation only. The {@link * net.sf.acegisecurity.intercept.AbstractSecurityInterceptor} will replace * the Authentication object held in the {@link - * net.sf.acegisecurity.context.SecureContext} for the duration of the secure - * object callback only, returning it to the original + * net.sf.acegisecurity.context.security.SecureContext} for the duration of + * the secure object callback only, returning it to the original * Authentication object when the callback ends. *

* diff --git a/core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java b/core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java index bb2981563e..481462d51a 100644 --- a/core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java +++ b/core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,27 +16,47 @@ package net.sf.acegisecurity.adapters; import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.ui.AbstractIntegrationFilter; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import java.io.IOException; + +import java.security.Principal; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; /** - * Populates a {@link net.sf.acegisecurity.context.SecureContext} from the - * container's HttpServletRequest.getUserPrincipal(). + * Populates ContextHolder with the Authentication + * obtained from the container's + * HttpServletRequest.getUserPrincipal(). * *

- * See {@link AbstractIntegrationFilter} for further information. + * Used this filter with container adapters only. + *

+ * + *

+ * This filter never preserves the Authentication on the + * ContextHolder - it is replaced every request. + *

+ * + *

+ * See {@link HttpSessionContextIntegrationFilter} for further information. *

* * @author Ben Alex * @version $Id$ */ -public class HttpRequestIntegrationFilter extends AbstractIntegrationFilter { +public class HttpRequestIntegrationFilter implements Filter { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(HttpRequestIntegrationFilter.class); @@ -44,19 +64,47 @@ public class HttpRequestIntegrationFilter extends AbstractIntegrationFilter { //~ Methods ================================================================ /** - * Not supported for this type of well-known location. - * - * @param request DOCUMENT ME! - * @param authentication DOCUMENT ME! + * Does nothing. We use IoC container lifecycle services instead. */ - public void commitToContainer(ServletRequest request, - Authentication authentication) {} + public void destroy() {} + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + SecureContext sc = SecureContextUtils.getSecureContext(); - public Object extractFromContainer(ServletRequest request) { if (request instanceof HttpServletRequest) { - return ((HttpServletRequest) request).getUserPrincipal(); + Principal principal = ((HttpServletRequest) request) + .getUserPrincipal(); + + if ((principal != null) && principal instanceof Authentication) { + sc.setAuthentication((Authentication) principal); + + if (logger.isDebugEnabled()) { + logger.debug( + "ContextHolder updated with Authentication from container: '" + + principal + "'"); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug( + "ContextHolder not set with new Authentication as Principal was: '" + + principal + "'"); + } + } } else { - return null; + throw new IllegalArgumentException( + "Only HttpServletRequest is acceptable"); } + + chain.doFilter(request, response); } + + /** + * Does nothing. We use IoC container lifecycle services instead. + * + * @param arg0 ignored + * + * @throws ServletException ignored + */ + public void init(FilterConfig arg0) throws ServletException {} } diff --git a/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java b/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java new file mode 100644 index 0000000000..c1ac55f949 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java @@ -0,0 +1,289 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * 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 net.sf.acegisecurity.context; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.InitializingBean; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + + +/** + *

+ * Populates the ContextHolder with information obtained from the + * HttpSession. + *

+ * + *

+ * The HttpSession will be queried to retrieve the + * Context that should be stored against the + * ContextHolder for the duration of the web request. At the end + * of the web request, any updates made to the ContextHolder will + * be persisted back to the HttpSession by this filter. + *

+ * + *

+ * If a valid Context cannot be obtained from the + * HttpSession for whatever reason, a fresh Context + * will be created and used instead. The created object will be of the + * instance defined by the {@link #setContext(Class)} method. + *

+ * + *

+ * No HttpSession will be created by this filter if one does not + * already exist. If at the end of the web request the + * HttpSession does not exist, a HttpSession will + * only be created if the current contents of + * ContextHolder are not {@link + * java.lang.Object#equals(java.lang.Object)} to a new instance + * of {@link #setContext(Class)}. This avoids needless + * HttpSession creation, but automates the storage of changes + * made to the ContextHolder. + *

+ * + *

+ * This filter will only execute once per request, to resolve servlet container + * (specifically Weblogic) incompatibilities. + *

+ * + *

+ * If for whatever reason no HttpSession should ever be + * created (eg this filter is only being used with Basic authentication or + * similar clients that will never present the same jsessionid + * etc), the {@link #setAllowSessionCreation(boolean)} should be set to + * false. Only do this if you really need to conserve server + * memory and are sure ensure all classes using the ContextHolder + * are designed to have no persistence of the Context between web + * requests. + *

+ * + *

+ * This filter MUST be executed BEFORE any authentication procesing mechanisms. + * Authentication processing mechanisms (eg BASIC, CAS processing filters etc) + * expect the ContextHolder to be contain a valid + * SecureContext by the time they execute. + *

+ * + * @author Ben Alex + * @author Patrick Burleson + * @version $Id$ + */ +public class HttpSessionContextIntegrationFilter implements InitializingBean, + Filter { + //~ Static fields/initializers ============================================= + + protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class); + private static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied"; + public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT"; + + //~ Instance fields ======================================================== + + private Class context; + private Object contextObject; + + /** + * Indicates if this filter can create a HttpSession if needed + * (sessions are always created sparingly, but setting this value to false + * will prohibit sessions from ever being created). Defaults to true. + */ + private boolean allowSessionCreation = true; + + //~ Methods ================================================================ + + public void setAllowSessionCreation(boolean allowSessionCreation) { + this.allowSessionCreation = allowSessionCreation; + } + + public boolean isAllowSessionCreation() { + return allowSessionCreation; + } + + public void setContext(Class secureContext) { + this.context = secureContext; + } + + public Class getContext() { + return context; + } + + public void afterPropertiesSet() throws Exception { + if ((this.context == null) + || (!Context.class.isAssignableFrom(this.context))) { + throw new IllegalArgumentException( + "context must be defined and implement Context (typically use net.sf.acegisecurity.context.security.SecureContextImpl)"); + } + + this.contextObject = generateNewContext(); + } + + /** + * Does nothing. We use IoC container lifecycle services instead. + */ + public void destroy() {} + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) { + // ensure that filter is only applied once per request + chain.doFilter(request, response); + } else { + if (request != null) { + request.setAttribute(FILTER_APPLIED, Boolean.TRUE); + } + + if (ContextHolder.getContext() != null) { + if (logger.isWarnEnabled()) { + logger.warn( + "ContextHolder should have been null but contained: '" + + ContextHolder.getContext() + "'; setting to null now"); + } + + ContextHolder.setContext(null); + } + + HttpSession httpSession = null; + + try { + httpSession = ((HttpServletRequest) request).getSession(false); + } catch (IllegalStateException ignored) {} + + if (httpSession != null) { + Object contextObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY); + + if (contextObject != null) { + if (contextObject instanceof Context) { + if (logger.isDebugEnabled()) { + logger.debug( + "Obtained from ACEGI_SECURITY_CONTEXT a valid Context and set to ContextHolder: '" + + contextObject + "'"); + } + + ContextHolder.setContext((Context) contextObject); + } else { + if (logger.isWarnEnabled()) { + logger.warn( + "ACEGI_SECURITY_CONTEXT did not contain a Context but contained: '" + + contextObject + + "'; are you improperly modifying the HttpSession directly (you should always use ContextHolder) or using the HttpSession attribute reserved for this class?"); + } + } + } else { + if (logger.isDebugEnabled()) { + logger.debug( + "HttpSession returned null object for ACEGI_SECURITY_CONTEXT"); + } + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("No HttpSession currently exists"); + } + } + + if (ContextHolder.getContext() == null) { + ContextHolder.setContext(generateNewContext()); + + if (logger.isDebugEnabled()) { + logger.debug( + "As ContextHolder null, setup ContextHolder with a fresh new instance: '" + + ContextHolder.getContext() + "'"); + } + } + + // Proceed with chain + chain.doFilter(request, response); + + // Store context back to HttpSession + try { + httpSession = ((HttpServletRequest) request).getSession(false); + } catch (IllegalStateException ignored) {} + + // Generate a HttpSession only if we need to + if (httpSession == null) { + if (!allowSessionCreation) { + if (logger.isDebugEnabled()) { + logger.debug( + "Whilst ContextHolder contents have changed, the HttpSessionContextIntegrationFilter is prohibited from creating a HttpSession by the allowSessionCreation property being false"); + } + } else if (!contextObject.equals(ContextHolder.getContext())) { + if (logger.isDebugEnabled()) { + logger.debug( + "HttpSession being created as ContextHolder contents are non-default"); + } + + try { + httpSession = ((HttpServletRequest) request).getSession(true); + } catch (IllegalStateException ignored) {} + } else { + if (logger.isDebugEnabled()) { + logger.debug( + "HttpSession still null, but ContextHolder has not changed from default: ' " + + ContextHolder.getContext() + + "'; not creating HttpSession or storing ContextHolder contents"); + } + } + } + + // If HttpSession exists, store current ContextHolder contents + if (httpSession != null) { + httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY, + ContextHolder.getContext()); + + if (logger.isDebugEnabled()) { + logger.debug("Context stored to HttpSession: '" + + ContextHolder.getContext() + "'"); + } + } + + // Remove ContextHolder contents + ContextHolder.setContext(null); + + if (logger.isDebugEnabled()) { + logger.debug( + "ContextHolder set to null as request processing completed"); + } + } + } + + public Context generateNewContext() throws ServletException { + try { + return (Context) this.context.newInstance(); + } catch (InstantiationException ie) { + throw new ServletException(ie); + } catch (IllegalAccessException iae) { + throw new ServletException(iae); + } + } + + /** + * Does nothing. We use IoC container lifecycle services instead. + * + * @param filterConfig ignored + * + * @throws ServletException ignored + */ + public void init(FilterConfig filterConfig) throws ServletException {} +} diff --git a/core/src/main/java/org/acegisecurity/ui/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java b/core/src/main/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java similarity index 96% rename from core/src/main/java/org/acegisecurity/ui/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java rename to core/src/main/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java index 49b2bba2c2..5ed8d7ad7e 100644 --- a/core/src/main/java/org/acegisecurity/ui/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java +++ b/core/src/main/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,12 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.httpinvoker; +package net.sf.acegisecurity.context.httpinvoker; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; diff --git a/core/src/main/java/org/acegisecurity/ui/httpinvoker/package.html b/core/src/main/java/org/acegisecurity/context/httpinvoker/package.html similarity index 100% rename from core/src/main/java/org/acegisecurity/ui/httpinvoker/package.html rename to core/src/main/java/org/acegisecurity/context/httpinvoker/package.html diff --git a/core/src/main/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocation.java b/core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocation.java similarity index 89% rename from core/src/main/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocation.java rename to core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocation.java index 28408fb385..459fe42116 100644 --- a/core/src/main/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocation.java +++ b/core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocation.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.rmi; +package net.sf.acegisecurity.context.rmi; import net.sf.acegisecurity.context.Context; import net.sf.acegisecurity.context.ContextHolder; @@ -34,10 +34,10 @@ import java.lang.reflect.InvocationTargetException; * *

* When constructed on the client via {@link - * net.sf.acegisecurity.ui.rmi.ContextPropagatingRemoteInvocationFactory}, the - * contents of the ContextHolder are stored inside the object. - * The object is then passed to the server that is processing the remote - * invocation. Upon the server invoking the remote invocation, it will + * net.sf.acegisecurity.context.rmi.ContextPropagatingRemoteInvocationFactory}, + * the contents of the ContextHolder are stored inside the + * object. The object is then passed to the server that is processing the + * remote invocation. Upon the server invoking the remote invocation, it will * retrieve the passed contents of the ContextHolder and set them * to the server-side ContextHolder whilst the target object is * invoked. When the target invocation has been completed, the server-side diff --git a/core/src/main/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocationFactory.java b/core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationFactory.java similarity index 93% rename from core/src/main/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocationFactory.java rename to core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationFactory.java index bab65e9751..91946789ab 100644 --- a/core/src/main/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocationFactory.java +++ b/core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationFactory.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.rmi; +package net.sf.acegisecurity.context.rmi; import org.aopalliance.intercept.MethodInvocation; diff --git a/core/src/main/java/org/acegisecurity/ui/rmi/package.html b/core/src/main/java/org/acegisecurity/context/rmi/package.html similarity index 100% rename from core/src/main/java/org/acegisecurity/ui/rmi/package.html rename to core/src/main/java/org/acegisecurity/context/rmi/package.html diff --git a/core/src/main/java/org/acegisecurity/context/SecureContext.java b/core/src/main/java/org/acegisecurity/context/security/SecureContext.java similarity index 89% rename from core/src/main/java/org/acegisecurity/context/SecureContext.java rename to core/src/main/java/org/acegisecurity/context/security/SecureContext.java index 9c6619c32e..b06cefbae1 100644 --- a/core/src/main/java/org/acegisecurity/context/SecureContext.java +++ b/core/src/main/java/org/acegisecurity/context/security/SecureContext.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,10 @@ * limitations under the License. */ -package net.sf.acegisecurity.context; +package net.sf.acegisecurity.context.security; import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.context.Context; /** diff --git a/core/src/main/java/org/acegisecurity/context/SecureContextImpl.java b/core/src/main/java/org/acegisecurity/context/security/SecureContextImpl.java similarity index 69% rename from core/src/main/java/org/acegisecurity/context/SecureContextImpl.java rename to core/src/main/java/org/acegisecurity/context/security/SecureContextImpl.java index 6e46525869..8e7da19277 100644 --- a/core/src/main/java/org/acegisecurity/context/SecureContextImpl.java +++ b/core/src/main/java/org/acegisecurity/context/security/SecureContextImpl.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,11 @@ * limitations under the License. */ -package net.sf.acegisecurity.context; +package net.sf.acegisecurity.context.security; import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.context.ContextImpl; +import net.sf.acegisecurity.context.ContextInvalidException; /** @@ -39,6 +41,25 @@ public class SecureContextImpl extends ContextImpl implements SecureContext { return this.authentication; } + public boolean equals(Object obj) { + if (obj instanceof SecureContextImpl) { + SecureContextImpl test = (SecureContextImpl) obj; + + if ((this.getAuthentication() == null) + && (test.getAuthentication() == null)) { + return true; + } + + if ((this.getAuthentication() != null) + && (test.getAuthentication() != null) + && this.getAuthentication().equals(test.getAuthentication())) { + return true; + } + } + + return false; + } + public String toString() { StringBuffer sb = new StringBuffer(); sb.append(super.toString()); diff --git a/core/src/main/java/org/acegisecurity/context/security/SecureContextUtils.java b/core/src/main/java/org/acegisecurity/context/security/SecureContextUtils.java new file mode 100644 index 0000000000..ad2a30d7bf --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/security/SecureContextUtils.java @@ -0,0 +1,45 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * 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 net.sf.acegisecurity.context.security; + +import net.sf.acegisecurity.context.ContextHolder; + + +/** + * A simple static method for quickly accessing the SecureContext. + * + *

+ * Expects the ContextHolder to be populated and contain a valid + * SecureContext. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class SecureContextUtils { + //~ Methods ================================================================ + + public static SecureContext getSecureContext() { + if ((ContextHolder.getContext() == null) + || !(ContextHolder.getContext() instanceof SecureContext)) { + throw new IllegalStateException("ContextHolder invalid: '" + + ContextHolder.getContext() + + "': are your filters ordered correctly? HttpSessionContextIntegrationFilter should have already executed by this time (look for it in the stack dump below)"); + } + + return (SecureContext) ContextHolder.getContext(); + } +} diff --git a/core/src/main/java/org/acegisecurity/context/security/package.html b/core/src/main/java/org/acegisecurity/context/security/package.html new file mode 100644 index 0000000000..72685b3ea5 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/context/security/package.html @@ -0,0 +1,7 @@ + + +Provides a Context that is designed to be compatible with +Acegi Security. + + + diff --git a/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java b/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java index c945a20389..3b180d55da 100644 --- a/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java +++ b/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ import net.sf.acegisecurity.ConfigAttributeDefinition; import net.sf.acegisecurity.RunAsManager; import net.sf.acegisecurity.context.Context; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; import net.sf.acegisecurity.intercept.event.AuthenticationCredentialsNotFoundEvent; import net.sf.acegisecurity.intercept.event.AuthenticationFailureEvent; import net.sf.acegisecurity.intercept.event.AuthorizationFailureEvent; @@ -104,7 +104,6 @@ import java.util.Set; * object, return the ContextHolder to the object that existed * after the call to AuthenticationManager. * - * *
  • * If an AfterInvocationManager is defined, invoke the invocation * manager and allow it to replace the object due to be returned to the diff --git a/core/src/main/java/org/acegisecurity/taglibs/authz/AclTag.java b/core/src/main/java/org/acegisecurity/taglibs/authz/AclTag.java index 88a3663078..ee38ea6475 100644 --- a/core/src/main/java/org/acegisecurity/taglibs/authz/AclTag.java +++ b/core/src/main/java/org/acegisecurity/taglibs/authz/AclTag.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import net.sf.acegisecurity.acl.AclEntry; import net.sf.acegisecurity.acl.AclManager; import net.sf.acegisecurity.acl.basic.AbstractBasicAclEntry; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java b/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java index 0f0effc8ee..23aa032089 100644 --- a/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java +++ b/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ package net.sf.acegisecurity.taglibs.authz; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.UserDetails; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; import java.io.IOException; diff --git a/core/src/main/java/org/acegisecurity/taglibs/authz/AuthorizeTag.java b/core/src/main/java/org/acegisecurity/taglibs/authz/AuthorizeTag.java index d692012347..05911c1f20 100644 --- a/core/src/main/java/org/acegisecurity/taglibs/authz/AuthorizeTag.java +++ b/core/src/main/java/org/acegisecurity/taglibs/authz/AuthorizeTag.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,15 @@ package net.sf.acegisecurity.taglibs.authz; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; + +import org.springframework.web.util.ExpressionEvaluationUtils; + +import java.util.*; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; -import java.util.*; - -import org.springframework.web.util.ExpressionEvaluationUtils; /** @@ -70,19 +71,18 @@ public class AuthorizeTag extends TagSupport { public int doStartTag() throws JspException { if (((null == ifAllGranted) || "".equals(ifAllGranted)) - && ((null == ifAnyGranted) || "".equals(ifAnyGranted)) - && ((null == ifNotGranted) || "".equals(ifNotGranted))) { + && ((null == ifAnyGranted) || "".equals(ifAnyGranted)) + && ((null == ifNotGranted) || "".equals(ifNotGranted))) { return Tag.SKIP_BODY; } final Collection granted = getPrincipalAuthorities(); - final String evaledIfNotGranted = - ExpressionEvaluationUtils.evaluateString( - "ifNotGranted", ifNotGranted, pageContext); + final String evaledIfNotGranted = ExpressionEvaluationUtils + .evaluateString("ifNotGranted", ifNotGranted, pageContext); + if ((null != evaledIfNotGranted) && !"".equals(evaledIfNotGranted)) { - Set grantedCopy = retainAll( - granted, + Set grantedCopy = retainAll(granted, parseAuthoritiesString(evaledIfNotGranted)); if (!grantedCopy.isEmpty()) { @@ -90,22 +90,20 @@ public class AuthorizeTag extends TagSupport { } } - final String evaledIfAllGranted = - ExpressionEvaluationUtils.evaluateString( - "ifAllGranted", ifAllGranted, pageContext); + final String evaledIfAllGranted = ExpressionEvaluationUtils + .evaluateString("ifAllGranted", ifAllGranted, pageContext); + if ((null != evaledIfAllGranted) && !"".equals(evaledIfAllGranted)) { - if (!granted.containsAll( - parseAuthoritiesString(evaledIfAllGranted))) { + if (!granted.containsAll(parseAuthoritiesString(evaledIfAllGranted))) { return Tag.SKIP_BODY; } } - final String evaledIfAnyGranted = - ExpressionEvaluationUtils.evaluateString( - "ifAnyGranted", ifAnyGranted, pageContext); + final String evaledIfAnyGranted = ExpressionEvaluationUtils + .evaluateString("ifAnyGranted", ifAnyGranted, pageContext); + if ((null != evaledIfAnyGranted) && !"".equals(evaledIfAnyGranted)) { - Set grantedCopy = retainAll( - granted, + Set grantedCopy = retainAll(granted, parseAuthoritiesString(evaledIfAnyGranted)); if (grantedCopy.isEmpty()) { @@ -148,7 +146,7 @@ public class AuthorizeTag extends TagSupport { } private Set retainAll(final Collection granted, - final Set requiredAuthorities) { + final Set requiredAuthorities) { Set grantedCopy = new HashSet(granted); grantedCopy.retainAll(requiredAuthorities); diff --git a/core/src/main/java/org/acegisecurity/ui/AbstractIntegrationFilter.java b/core/src/main/java/org/acegisecurity/ui/AbstractIntegrationFilter.java deleted file mode 100644 index cb72ae32ce..0000000000 --- a/core/src/main/java/org/acegisecurity/ui/AbstractIntegrationFilter.java +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright 2004, 2005 Acegi Technology Pty Limited - * - * 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 net.sf.acegisecurity.ui; - -import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.context.Context; -import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.InitializingBean; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - - -/** - * Automatically populates a {@link net.sf.acegisecurity.context.SecureContext} - * from a subclass-provided Authentication object. - * - *

    - * The container hosting the Acegi Security System for Spring secured - * application is expected to expose an {@link Authentication} object in a - * well-known location. The Authentication object will have been - * created by the Acegi Security System for Spring and placed into the - * well-known location via approaches such as container adapters or container - * sessions. - *

    - * - *

    - * Once the Authentication object has been extracted from the - * well-known location, the AbstractIntegrationFilter handles - * putting it into the {@link ContextHolder}. It then removes it once the - * filter chain has completed. - *

    - * - *

    - * This filter will not abort if an Authentication object cannot - * be obtained from the well-known location. It will simply continue the - * filter chain as normal. - *

    - * - *

    - * If the ContextHolder does not contain a valid {@link - * SecureContext}, one will be created. The created object will be of the - * instance defined by the {@link #setSecureContext(Class)} method. - *

    - * - *

    - * This filter will only execute once per request, to resolve servlet container - * (specifically Weblogic) incompatibilities. - *

    - * - * @author Ben Alex - * @author Patrick Burleson - * @version $Id$ - */ -public abstract class AbstractIntegrationFilter implements InitializingBean, - Filter { - //~ Static fields/initializers ============================================= - - protected static final Log logger = LogFactory.getLog(AbstractIntegrationFilter.class); - private static final String FILTER_APPLIED = "__acegi_integration_filterapplied"; - - //~ Instance fields ======================================================== - - private Class secureContext = SecureContextImpl.class; - - //~ Methods ================================================================ - - public void setSecureContext(Class secureContext) { - this.secureContext = secureContext; - } - - public Class getSecureContext() { - return secureContext; - } - - public void afterPropertiesSet() throws Exception { - if ((this.secureContext == null) - || (!SecureContext.class.isAssignableFrom(this.secureContext))) { - throw new IllegalArgumentException( - "secureContext must be defined and implement SecureContext"); - } - } - - /** - * Writes a new Authentication object to the container's - * well-known location, if supported the subclass. - * - * @param request which may be required by the implementing method to - * access the well-known location for the current principal - * @param authentication the new object to be written to the container - */ - public abstract void commitToContainer(ServletRequest request, - Authentication authentication); - - public void destroy() {} - - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) { - // ensure that filter is only applied once per request - chain.doFilter(request, response); - } else { - if (request != null) { - request.setAttribute(FILTER_APPLIED, Boolean.TRUE); - } - - // Populate authentication information - Object extracted = this.extractFromContainer(request); - - if (extracted instanceof Authentication) { - if (logger.isDebugEnabled()) { - logger.debug("Authentication '" + extracted - + "' added to ContextHolder from container"); - } - - Authentication auth = (Authentication) extracted; - - // Get or create existing SecureContext - SecureContext sc = null; - - if ((ContextHolder.getContext() == null) - || !(ContextHolder.getContext() instanceof SecureContext)) { - try { - sc = (SecureContext) this.secureContext.newInstance(); - } catch (InstantiationException ie) { - throw new ServletException(ie); - } catch (IllegalAccessException iae) { - throw new ServletException(iae); - } - } else { - sc = (SecureContext) ContextHolder.getContext(); - } - - // Add Authentication to SecureContext, and save - sc.setAuthentication(auth); - ContextHolder.setContext((Context) sc); - } else { - if (logger.isDebugEnabled()) { - logger.debug( - "Authentication not added to ContextHolder (could not extract an authentication object from the container which is an instance of Authentication)"); - } - } - - // Proceed with chain - chain.doFilter(request, response); - - // Remove authentication information - if ((ContextHolder.getContext() != null) - && ContextHolder.getContext() instanceof SecureContext) { - // Get context holder - SecureContext secureContext = (SecureContext) ContextHolder - .getContext(); - - if (logger.isDebugEnabled()) { - logger.debug( - "Updating container with new Authentication object ('" - + secureContext.getAuthentication() - + "'), and then removing Authentication from ContextHolder"); - } - - // Update container with new Authentication object (may have been updated during method invocation) - this.commitToContainer(request, - secureContext.getAuthentication()); - - // Remove authentication information from ContextHolder - secureContext.setAuthentication(null); - ContextHolder.setContext((Context) secureContext); - } else { - if (logger.isDebugEnabled()) { - logger.debug( - "ContextHolder does not contain any authentication information"); - } - } - } - } - - /** - * Subclasses must override this method to provide the Object - * that contains the Authentication interface. - * - *

    - * For convenience we have allowed any Object to be returned - * by subclasses, as the abstract class will ensure class casting safety - * and ignore objects that do not implement Authentication. - *

    - * - *

    - * If no Authentication object is available, subclasses should - * return null. - *

    - * - *

    - * If the subclass can locate multiple authentication objects, they should - * return the object that was created by the Acegi Security System for - * Spring (ie the object that implements Authentication). - *

    - * - * @param request the request, which may be of use in extracting the - * authentication object - * - * @return null or an object that implements - * Authentication - */ - public abstract Object extractFromContainer(ServletRequest request); - - public void init(FilterConfig filterConfig) throws ServletException {} -} diff --git a/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java index ac7c69c404..e4ca68576f 100644 --- a/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java @@ -22,8 +22,10 @@ import net.sf.acegisecurity.AuthenticationServiceException; import net.sf.acegisecurity.BadCredentialsException; import net.sf.acegisecurity.DisabledException; import net.sf.acegisecurity.LockedException; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextUtils; import net.sf.acegisecurity.providers.cas.ProxyUntrustedException; -import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -34,6 +36,7 @@ import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -42,15 +45,13 @@ import javax.servlet.http.HttpServletResponse; /** - * Abstract processor of HTTP-based authentication requests, which places the - * resulting Authentication object into the - * HttpSession. + * Abstract processor of browser-based HTTP-based authentication requests. * *

    * This filter is responsible for processing authentication requests. If * authentication is successful, the resulting {@link Authentication} object - * will be placed into the HttpSession with the attribute defined - * by {@link HttpSessionIntegrationFilter#ACEGI_SECURITY_AUTHENTICATION_KEY}. + * will be placed into the ContextHolder, which is guaranteed to + * have already been created by an earlier filter. *

    * *

    @@ -307,6 +308,9 @@ public abstract class AbstractProcessingFilter implements Filter, } } + /** + * Does nothing. We use IoC container lifecycle services instead. + */ public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, @@ -353,6 +357,15 @@ public abstract class AbstractProcessingFilter implements Filter, chain.doFilter(request, response); } + /** + * Does nothing. We use IoC container lifecycle services instead. + * + * @param arg0 ignored + * + * @throws ServletException ignored + */ + public void init(FilterConfig arg0) throws ServletException {} + protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {} @@ -390,8 +403,14 @@ public abstract class AbstractProcessingFilter implements Filter, logger.debug("Authentication success: " + authResult.toString()); } - request.getSession().setAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY, - authResult); + SecureContext sc = SecureContextUtils.getSecureContext(); + sc.setAuthentication(authResult); + + if (logger.isDebugEnabled()) { + logger.debug( + "Updated ContextHolder to contain the following Authentication: '" + + authResult + "'"); + } String targetUrl = (String) request.getSession().getAttribute(ACEGI_SECURITY_TARGET_URL_KEY); request.getSession().removeAttribute(ACEGI_SECURITY_TARGET_URL_KEY); @@ -418,6 +437,14 @@ public abstract class AbstractProcessingFilter implements Filter, protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { + SecureContext sc = SecureContextUtils.getSecureContext(); + sc.setAuthentication(null); + ContextHolder.setContext(sc); + + if (logger.isDebugEnabled()) { + logger.debug("Updated ContextHolder to contain null Authentication"); + } + String failureUrl = authenticationFailureUrl; if (failed instanceof AuthenticationServiceException @@ -451,7 +478,6 @@ public abstract class AbstractProcessingFilter implements Filter, request.getSession().setAttribute(ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed); - request.getSession().removeAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY); onUnsuccessfulAuthentication(request, response); diff --git a/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java index aef5e66e5f..1f5419448f 100644 --- a/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java @@ -18,10 +18,13 @@ package net.sf.acegisecurity.ui.basicauth; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.AuthenticationException; import net.sf.acegisecurity.AuthenticationManager; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextUtils; import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import net.sf.acegisecurity.ui.WebAuthenticationDetails; -import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; @@ -73,7 +76,8 @@ import javax.servlet.http.HttpServletResponse; *

    * If authentication is successful, the resulting {@link Authentication} object * will be placed into the HttpSession with the attribute defined - * by {@link HttpSessionIntegrationFilter#ACEGI_SECURITY_AUTHENTICATION_KEY}. + * by {@link + * HttpSessionContextIntegrationFilter#ACEGI_SECURITY_AUTHENTICATION_KEY}. *

    * *

    @@ -172,6 +176,7 @@ public class BasicProcessingFilter implements Filter, InitializingBean { authRequest.setDetails(new WebAuthenticationDetails(httpRequest)); Authentication authResult; + SecureContext sc = SecureContextUtils.getSecureContext(); try { authResult = authenticationManager.authenticate(authRequest); @@ -182,6 +187,8 @@ public class BasicProcessingFilter implements Filter, InitializingBean { + " failed: " + failed.toString()); } + sc.setAuthentication(null); + ContextHolder.setContext(sc); authenticationEntryPoint.commence(request, response, failed); return; @@ -192,8 +199,8 @@ public class BasicProcessingFilter implements Filter, InitializingBean { logger.debug("Authentication success: " + authResult.toString()); } - httpRequest.getSession().setAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY, - authResult); + sc.setAuthentication(authResult); + ContextHolder.setContext(sc); } chain.doFilter(request, response); diff --git a/core/src/main/java/org/acegisecurity/ui/package.html b/core/src/main/java/org/acegisecurity/ui/package.html index 6d9b03a0b4..23a8f43a2e 100644 --- a/core/src/main/java/org/acegisecurity/ui/package.html +++ b/core/src/main/java/org/acegisecurity/ui/package.html @@ -1,6 +1,6 @@ -Interfaces the system with various end-user authentication approaches, such -as container adapters and web applications. +Authentication processing mechanisms, which respond to the submission of authentication +credentials using various protocols (eg BASIC, CAS, form login etc). diff --git a/core/src/main/java/org/acegisecurity/ui/webapp/HttpSessionIntegrationFilter.java b/core/src/main/java/org/acegisecurity/ui/webapp/HttpSessionIntegrationFilter.java deleted file mode 100644 index e20369c650..0000000000 --- a/core/src/main/java/org/acegisecurity/ui/webapp/HttpSessionIntegrationFilter.java +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright 2004, 2005 Acegi Technology Pty Limited - * - * 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 net.sf.acegisecurity.ui.webapp; - -import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.ui.AbstractIntegrationFilter; - -import java.util.Iterator; -import java.util.List; - -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - - -/** - * Populates a {@link net.sf.acegisecurity.context.SecureContext} from the - * HttpSession. - * - *

    - * The filter will inspect the HttpSession for an attribute with - * the name indicated by {@link #ACEGI_SECURITY_AUTHENTICATION_KEY}. If that - * attribute contains an instance of {@link Authentication}, it will be placed - * into the ContextHolder. - *

    - * - *

    - * This filter is normally used in conjunction with {@link - * AuthenticationProcessingFilter}, which populates the - * HttpSession with an Authentication object based - * on a form login. Similarly, the {@link - * net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter} will populate the - * HttpSession based on a BASIC authentication request. - * Alternatively, users may elect to use their own approach for populating the - * HttpSession. - *

    - * - *

    - * As with other AbstractIntegrationFilters, this filter will - * ensure the ContextHolder is populated with the - * Authentication object for the duration of the HTTP request, - * and is unbound from the ContextHolder at the completion of the - * request. - *

    - * - *

    - * The filter can also copy the Authentication object to any - * number of additional HttpSession attributes. To use this - * capability, provide Strings indicating the additional - * attribute name(s) to {@link #setAdditionalAttributes(List)}. - *

    - * - *

    - * See {@link AbstractIntegrationFilter} for further information. - *

    - * - * @author Ben Alex - * @version $Id$ - */ -public class HttpSessionIntegrationFilter extends AbstractIntegrationFilter { - //~ Static fields/initializers ============================================= - - public static final String ACEGI_SECURITY_AUTHENTICATION_KEY = "ACEGI_SECURITY_AUTHENTICATION"; - - //~ Instance fields ======================================================== - - private List additionalAttributes = null; - - //~ Methods ================================================================ - - public void setAdditionalAttributes(List additionalAttributes) { - validateList(additionalAttributes); - this.additionalAttributes = additionalAttributes; - } - - public List getAdditionalAttributes() { - return additionalAttributes; - } - - public void commitToContainer(ServletRequest request, - Authentication authentication) { - if (request instanceof HttpServletRequest - && ((HttpServletRequest) request).isRequestedSessionIdValid()) { - HttpSession httpSession = ((HttpServletRequest) request).getSession(false); - - if (httpSession != null) { - httpSession.setAttribute(ACEGI_SECURITY_AUTHENTICATION_KEY, - authentication); - updateOtherLocations(httpSession, authentication); - } - } - } - - public Object extractFromContainer(ServletRequest request) { - if (request instanceof HttpServletRequest) { - HttpSession httpSession = null; - - try { - httpSession = ((HttpServletRequest) request).getSession(false); - } catch (IllegalStateException ignored) {} - - if (httpSession != null) { - Object authObject = httpSession.getAttribute(ACEGI_SECURITY_AUTHENTICATION_KEY); - - if (authObject instanceof Authentication) { - updateOtherLocations(httpSession, - (Authentication) authObject); - - return authObject; - } - } - } - - return null; - } - - private void updateOtherLocations(HttpSession session, - Authentication authentication) { - if (additionalAttributes == null) { - return; - } - - Iterator iter = additionalAttributes.iterator(); - - while (iter.hasNext()) { - String attribute = (String) iter.next(); - session.setAttribute(attribute, authentication); - } - } - - private void validateList(List newAdditionalAttributes) { - if (newAdditionalAttributes != null) { - Iterator iter = newAdditionalAttributes.iterator(); - - while (iter.hasNext()) { - Object objectToTest = iter.next(); - - if (!(objectToTest instanceof String)) { - throw new IllegalArgumentException( - "List of additional attributes can only contains Strings!"); - } - } - } - } -} diff --git a/core/src/main/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestFilter.java b/core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestFilter.java similarity index 95% rename from core/src/main/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestFilter.java rename to core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestFilter.java index 6001adfd2b..a0de8842da 100644 --- a/core/src/main/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestFilter.java +++ b/core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestFilter.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.wrapper; +package net.sf.acegisecurity.wrapper; import java.io.IOException; diff --git a/core/src/main/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapper.java b/core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapper.java similarity index 97% rename from core/src/main/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapper.java rename to core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapper.java index ac578b31d3..56042aaf05 100644 --- a/core/src/main/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapper.java +++ b/core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapper.java @@ -13,13 +13,13 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.wrapper; +package net.sf.acegisecurity.wrapper; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.UserDetails; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; import java.security.Principal; diff --git a/core/src/main/java/org/acegisecurity/ui/wrapper/package.html b/core/src/main/java/org/acegisecurity/wrapper/package.html similarity index 100% rename from core/src/main/java/org/acegisecurity/ui/wrapper/package.html rename to core/src/main/java/org/acegisecurity/wrapper/package.html diff --git a/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java b/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java index a1c7fe06b6..eea99f4cd0 100644 --- a/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java +++ b/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java @@ -15,6 +15,8 @@ package net.sf.acegisecurity; +import org.springframework.mock.web.MockHttpSession; + import java.io.BufferedReader; import java.io.IOException; @@ -315,10 +317,20 @@ public class MockHttpServletRequest implements HttpServletRequest { } public HttpSession getSession(boolean arg0) { + if (arg0) { + if (this.session == null) { + this.session = new MockHttpSession(); + } + } + return this.session; } public HttpSession getSession() { + if (this.session == null) { + this.session = new MockHttpSession(); + } + return this.session; } diff --git a/core/src/test/java/org/acegisecurity/TargetObject.java b/core/src/test/java/org/acegisecurity/TargetObject.java index be5daa7de8..0fba7063d1 100644 --- a/core/src/test/java/org/acegisecurity/TargetObject.java +++ b/core/src/test/java/org/acegisecurity/TargetObject.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package net.sf.acegisecurity; import net.sf.acegisecurity.context.Context; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; /** diff --git a/core/src/test/java/org/acegisecurity/adapters/HttpRequestIntegrationFilterTests.java b/core/src/test/java/org/acegisecurity/adapters/HttpRequestIntegrationFilterTests.java index 4528cee39e..d65fad14fb 100644 --- a/core/src/test/java/org/acegisecurity/adapters/HttpRequestIntegrationFilterTests.java +++ b/core/src/test/java/org/acegisecurity/adapters/HttpRequestIntegrationFilterTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,14 @@ package net.sf.acegisecurity.adapters; import junit.framework.TestCase; -import net.sf.acegisecurity.*; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.MockHttpServletRequest; +import net.sf.acegisecurity.MockHttpServletResponse; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.security.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextUtils; +import net.sf.acegisecurity.util.MockFilterChain; /** @@ -41,41 +46,62 @@ public class HttpRequestIntegrationFilterTests extends TestCase { //~ Methods ================================================================ - public final void setUp() throws Exception { - super.setUp(); - } - public static void main(String[] args) { junit.textui.TestRunner.run(HttpRequestIntegrationFilterTests.class); } - public void testCorrectOperation() { + public void testCorrectOperation() throws Exception { HttpRequestIntegrationFilter filter = new HttpRequestIntegrationFilter(); PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", "someone", "password", new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - Object result = filter.extractFromContainer(new MockHttpServletRequest( - principal, null)); - if (!(result instanceof PrincipalAcegiUserToken)) { + MockHttpServletRequest request = new MockHttpServletRequest(principal, + null); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(true); + + filter.doFilter(request, response, chain); + + if (!(SecureContextUtils.getSecureContext().getAuthentication() instanceof PrincipalAcegiUserToken)) { fail("Should have returned PrincipalAcegiUserToken"); } - PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result; - assertEquals(principal, result); - - filter.commitToContainer(new MockHttpServletRequest(principal, null), - principal); + PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) SecureContextUtils.getSecureContext() + .getAuthentication(); + assertEquals(principal, castResult); } - public void testHandlesIfHttpRequestIsNullForSomeReason() { + public void testHandlesIfHttpRequestIsNullForSomeReason() + throws Exception { HttpRequestIntegrationFilter filter = new HttpRequestIntegrationFilter(); - assertEquals(null, filter.extractFromContainer(null)); + + try { + filter.doFilter(null, null, null); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertTrue(true); + } } - public void testHandlesIfThereIsNoPrincipal() { + public void testHandlesIfThereIsNoPrincipal() throws Exception { HttpRequestIntegrationFilter filter = new HttpRequestIntegrationFilter(); - assertEquals(null, - filter.extractFromContainer(new MockHttpServletRequest(null, null))); + MockHttpServletRequest request = new MockHttpServletRequest("foo"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(true); + + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); + filter.doFilter(request, response, chain); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); + } + + protected void setUp() throws Exception { + super.setUp(); + ContextHolder.setContext(new SecureContextImpl()); + } + + protected void tearDown() throws Exception { + super.tearDown(); + ContextHolder.setContext(null); } } diff --git a/core/src/test/java/org/acegisecurity/context/ContextInterceptorTests.java b/core/src/test/java/org/acegisecurity/context/ContextInterceptorTests.java index 4e0317582d..0f773e28da 100644 --- a/core/src/test/java/org/acegisecurity/context/ContextInterceptorTests.java +++ b/core/src/test/java/org/acegisecurity/context/ContextInterceptorTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package net.sf.acegisecurity.context; import junit.framework.TestCase; +import net.sf.acegisecurity.context.security.SecureContextImpl; + import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; diff --git a/core/src/test/java/org/acegisecurity/context/HttpSessionContextIntegrationFilterTests.java b/core/src/test/java/org/acegisecurity/context/HttpSessionContextIntegrationFilterTests.java new file mode 100644 index 0000000000..5aa6714862 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/context/HttpSessionContextIntegrationFilterTests.java @@ -0,0 +1,245 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * 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 net.sf.acegisecurity.context; + +import junit.framework.TestCase; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.MockFilterConfig; +import net.sf.acegisecurity.MockHttpServletRequest; +import net.sf.acegisecurity.MockHttpServletResponse; +import net.sf.acegisecurity.MockHttpSession; +import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken; +import net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextUtils; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + + +/** + * Tests {@link HttpSessionContextIntegrationFilter}. + * + * @author Ben Alex + * @version $Id$ + */ +public class HttpSessionContextIntegrationFilterTests extends TestCase { + //~ Constructors =========================================================== + + public HttpSessionContextIntegrationFilterTests() { + super(); + } + + public HttpSessionContextIntegrationFilterTests(String arg0) { + super(arg0); + } + + //~ Methods ================================================================ + + public static void main(String[] args) { + junit.textui.TestRunner.run(HttpSessionContextIntegrationFilterTests.class); + } + + public void testDetectsMissingOrInvalidContext() throws Exception { + HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter(); + + try { + filter.afterPropertiesSet(); + fail("Shown have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertTrue(true); + } + + try { + filter.setContext(Integer.class); + assertEquals(Integer.class, filter.getContext()); + filter.afterPropertiesSet(); + fail("Shown have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertTrue(true); + } + } + + public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession() + throws Exception { + // Build an Authentication object we simulate came from HttpSession + PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key", + "someone", "password", + new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); + + // Build an Authentication object we simulate our Authentication changed it to + PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key", + "someone", "password", + new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")}); + + // Build a Context to store in HttpSession (simulating prior request) + SecureContext sc = new SecureContextImpl(); + sc.setAuthentication(sessionPrincipal); + + // Build a mock request + MockHttpSession session = new MockHttpSession(); + session.setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, + sc); + + MockHttpServletRequest request = new MockHttpServletRequest(null, + session); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = new MockFilterChain(sessionPrincipal, + updatedPrincipal); + + // Prepare filter + HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter(); + filter.setContext(SecureContextImpl.class); + filter.afterPropertiesSet(); + + // Execute filter + executeFilterInContainerSimulator(new MockFilterConfig(), filter, + request, response, chain); + + // Obtain new/update Authentication from HttpSession + Context context = (Context) session.getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY); + assertEquals(updatedPrincipal, + ((SecureContext) context).getAuthentication()); + } + + public void testHttpSessionCreatedWhenContextHolderChanges() + throws Exception { + // Build an Authentication object we simulate our Authentication changed it to + PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key", + "someone", "password", + new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")}); + + // Build a mock request + MockHttpSession session = null; + MockHttpServletRequest request = new MockHttpServletRequest(null, + session); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = new MockFilterChain(null, updatedPrincipal); + + // Prepare filter + HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter(); + filter.setContext(SecureContextImpl.class); + filter.afterPropertiesSet(); + + // Execute filter + executeFilterInContainerSimulator(new MockFilterConfig(), filter, + request, response, chain); + + // Obtain new/update Authentication from HttpSession + Context context = (Context) request.getSession().getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY); + assertEquals(updatedPrincipal, + ((SecureContext) context).getAuthentication()); + } + + public void testHttpSessionNotCreatedUnlessContextHolderChanges() + throws Exception { + // Build a mock request + MockHttpServletRequest request = new MockHttpServletRequest(null, null); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = new MockFilterChain(null, null); + + // Prepare filter + HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter(); + filter.setContext(SecureContextImpl.class); + filter.afterPropertiesSet(); + + // Execute filter + executeFilterInContainerSimulator(new MockFilterConfig(), filter, + request, response, chain); + + // Obtain new/update Authentication from HttpSession + assertNull(request.getSession(false)); + } + + public void testHttpSessionWithNonContextInWellKnownLocationIsOverwritten() + throws Exception { + // Build an Authentication object we simulate our Authentication changed it to + PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key", + "someone", "password", + new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")}); + + // Build a mock request + MockHttpSession session = new MockHttpSession(); + session.setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, + "NOT_A_CONTEXT_OBJECT"); + + MockHttpServletRequest request = new MockHttpServletRequest(null, + session); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = new MockFilterChain(null, updatedPrincipal); + + // Prepare filter + HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter(); + filter.setContext(SecureContextImpl.class); + filter.afterPropertiesSet(); + + // Execute filter + executeFilterInContainerSimulator(new MockFilterConfig(), filter, + request, response, chain); + + // Obtain new/update Authentication from HttpSession + Context context = (Context) session.getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY); + assertEquals(updatedPrincipal, + ((SecureContext) context).getAuthentication()); + } + + private void executeFilterInContainerSimulator(FilterConfig filterConfig, + Filter filter, ServletRequest request, ServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + filter.init(filterConfig); + filter.doFilter(request, response, filterChain); + filter.destroy(); + } + + //~ Inner Classes ========================================================== + + private class MockFilterChain extends TestCase implements FilterChain { + private Authentication changeContextHolder; + private Authentication expectedOnContextHolder; + + public MockFilterChain(Authentication expectedOnContextHolder, + Authentication changeContextHolder) { + this.expectedOnContextHolder = expectedOnContextHolder; + this.changeContextHolder = changeContextHolder; + } + + private MockFilterChain() {} + + public void doFilter(ServletRequest arg0, ServletResponse arg1) + throws IOException, ServletException { + if (expectedOnContextHolder != null) { + assertEquals(expectedOnContextHolder, + SecureContextUtils.getSecureContext().getAuthentication()); + } + + if (changeContextHolder != null) { + SecureContext sc = SecureContextUtils.getSecureContext(); + sc.setAuthentication(changeContextHolder); + ContextHolder.setContext(sc); + } + } + } +} diff --git a/core/src/test/java/org/acegisecurity/context/SecureContextImplTests.java b/core/src/test/java/org/acegisecurity/context/SecureContextImplTests.java index 838553b61c..01014a1bb6 100644 --- a/core/src/test/java/org/acegisecurity/context/SecureContextImplTests.java +++ b/core/src/test/java/org/acegisecurity/context/SecureContextImplTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ package net.sf.acegisecurity.context; import junit.framework.TestCase; import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; diff --git a/core/src/test/java/org/acegisecurity/ui/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java b/core/src/test/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java similarity index 94% rename from core/src/test/java/org/acegisecurity/ui/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java rename to core/src/test/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java index 258a18851c..97626e9bcf 100644 --- a/core/src/test/java/org/acegisecurity/ui/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java +++ b/core/src/test/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,15 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.httpinvoker; +package net.sf.acegisecurity.context.httpinvoker; import junit.framework.TestCase; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.httpinvoker.AuthenticationSimpleHttpInvokerRequestExecutor; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import java.io.IOException; diff --git a/core/src/test/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocationTests.java b/core/src/test/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationTests.java similarity index 90% rename from core/src/test/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocationTests.java rename to core/src/test/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationTests.java index a64045f4ba..22d4fc0b37 100644 --- a/core/src/test/java/org/acegisecurity/ui/rmi/ContextPropagatingRemoteInvocationTests.java +++ b/core/src/test/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.rmi; +package net.sf.acegisecurity.context.rmi; import junit.framework.TestCase; @@ -21,8 +21,10 @@ import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.MockMethodInvocation; import net.sf.acegisecurity.TargetObject; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.rmi.ContextPropagatingRemoteInvocation; +import net.sf.acegisecurity.context.rmi.ContextPropagatingRemoteInvocationFactory; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.aopalliance.intercept.MethodInvocation; diff --git a/core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java b/core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java index 0204c392b2..8118de2cf6 100644 --- a/core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java +++ b/core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,8 +28,8 @@ import net.sf.acegisecurity.SecurityConfig; import net.sf.acegisecurity.TargetObject; import net.sf.acegisecurity.acl.basic.SomeDomain; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.springframework.context.ApplicationContext; diff --git a/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java b/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java index 981047e252..57ae917f96 100644 --- a/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java +++ b/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,8 +35,8 @@ import net.sf.acegisecurity.MockRunAsManager; import net.sf.acegisecurity.RunAsManager; import net.sf.acegisecurity.context.ContextHolder; import net.sf.acegisecurity.context.ContextImpl; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.intercept.method.AbstractMethodDefinitionSource; import net.sf.acegisecurity.intercept.method.MockMethodDefinitionSource; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; diff --git a/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java b/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java index bbc42c033d..4f0616df18 100644 --- a/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java +++ b/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ import net.sf.acegisecurity.MockJoinPoint; import net.sf.acegisecurity.MockRunAsManager; import net.sf.acegisecurity.TargetObject; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.intercept.method.MethodDefinitionMap; import net.sf.acegisecurity.intercept.method.MethodDefinitionSourceEditor; import net.sf.acegisecurity.providers.TestingAuthenticationToken; diff --git a/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java b/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java index 0a0ba80ec3..95556a22ae 100644 --- a/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java +++ b/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,8 +34,8 @@ import net.sf.acegisecurity.MockRunAsManager; import net.sf.acegisecurity.RunAsManager; import net.sf.acegisecurity.SecurityConfig; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import java.io.IOException; diff --git a/core/src/test/java/org/acegisecurity/taglibs/authz/AclTagTests.java b/core/src/test/java/org/acegisecurity/taglibs/authz/AclTagTests.java index 4ee2f1446a..4470814c45 100644 --- a/core/src/test/java/org/acegisecurity/taglibs/authz/AclTagTests.java +++ b/core/src/test/java/org/acegisecurity/taglibs/authz/AclTagTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,8 @@ import net.sf.acegisecurity.acl.AclManager; import net.sf.acegisecurity.acl.basic.MockAclObjectIdentity; import net.sf.acegisecurity.acl.basic.SimpleAclEntry; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; import org.springframework.context.ApplicationContext; diff --git a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java index 717c667515..86b3317fd8 100644 --- a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java +++ b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,8 @@ import junit.framework.TestCase; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; import net.sf.acegisecurity.providers.dao.User; diff --git a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagAttributeTests.java b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagAttributeTests.java index cef5a96933..92eab3f70c 100644 --- a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagAttributeTests.java +++ b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagAttributeTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import junit.framework.TestCase; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; import javax.servlet.jsp.JspException; diff --git a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagExpressionLanguageTests.java b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagExpressionLanguageTests.java index 5602b54059..6a18e2a650 100644 --- a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagExpressionLanguageTests.java +++ b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagExpressionLanguageTests.java @@ -1,16 +1,34 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * 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 net.sf.acegisecurity.taglibs.authz; import junit.framework.TestCase; + import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; + import org.springframework.mock.web.MockPageContext; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; + /** * Test case to implement commons-el expression language expansion. */ @@ -18,40 +36,37 @@ public class AuthorizeTagExpressionLanguageTests extends TestCase { //~ Instance fields ======================================================== private final AuthorizeTag authorizeTag = new AuthorizeTag(); + private MockPageContext pageContext; private SecureContextImpl context; private TestingAuthenticationToken currentUser; - private MockPageContext pageContext; //~ Methods ================================================================ public void testAllGrantedUsesExpressionLanguageWhenExpressionIsEL() - throws JspException { + throws JspException { pageContext.setAttribute("authority", "ROLE_TELLER"); authorizeTag.setIfAllGranted("${authority}"); - assertEquals( - "allows body - authority var contains ROLE_TELLER", - Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag()); + assertEquals("allows body - authority var contains ROLE_TELLER", + Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag()); } public void testAnyGrantedUsesExpressionLanguageWhenExpressionIsEL() - throws JspException { + throws JspException { pageContext.setAttribute("authority", "ROLE_TELLER"); authorizeTag.setIfAnyGranted("${authority}"); - assertEquals( - "allows body - authority var contains ROLE_TELLER", - Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag()); + assertEquals("allows body - authority var contains ROLE_TELLER", + Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag()); } public void testNotGrantedUsesExpressionLanguageWhenExpressionIsEL() - throws JspException { + throws JspException { pageContext.setAttribute("authority", "ROLE_TELLER"); authorizeTag.setIfNotGranted("${authority}"); - assertEquals( - "allows body - authority var contains ROLE_TELLER", - Tag.SKIP_BODY, authorizeTag.doStartTag()); + assertEquals("allows body - authority var contains ROLE_TELLER", + Tag.SKIP_BODY, authorizeTag.doStartTag()); } protected void setUp() throws Exception { @@ -60,11 +75,8 @@ public class AuthorizeTagExpressionLanguageTests extends TestCase { pageContext = new MockPageContext(); authorizeTag.setPageContext(pageContext); - currentUser = new TestingAuthenticationToken( - "abc", "123", - new GrantedAuthority[]{ - new GrantedAuthorityImpl("ROLE_TELLER"), - }); + currentUser = new TestingAuthenticationToken("abc", "123", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TELLER"),}); context = new SecureContextImpl(); context.setAuthentication(currentUser); diff --git a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagTests.java b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagTests.java index ee94db8194..d8aaf90a40 100644 --- a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagTests.java +++ b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import junit.framework.TestCase; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; import javax.servlet.jsp.JspException; diff --git a/core/src/test/java/org/acegisecurity/ui/AbstractIntegrationFilterTests.java b/core/src/test/java/org/acegisecurity/ui/AbstractIntegrationFilterTests.java deleted file mode 100644 index 247e45e5e3..0000000000 --- a/core/src/test/java/org/acegisecurity/ui/AbstractIntegrationFilterTests.java +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright 2004 Acegi Technology Pty Limited - * - * 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 net.sf.acegisecurity.ui; - -import junit.framework.TestCase; - -import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.GrantedAuthority; -import net.sf.acegisecurity.GrantedAuthorityImpl; -import net.sf.acegisecurity.adapters.MockPrincipal; -import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken; -import net.sf.acegisecurity.context.Context; -import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - - -/** - * Tests {@link AbstractIntegrationFilter}. - * - * @author Ben Alex - * @version $Id$ - */ -public class AbstractIntegrationFilterTests extends TestCase { - //~ Constructors =========================================================== - - public AbstractIntegrationFilterTests() { - super(); - } - - public AbstractIntegrationFilterTests(String arg0) { - super(arg0); - } - - //~ Methods ================================================================ - - public final void setUp() throws Exception { - super.setUp(); - } - - public static void main(String[] args) { - junit.textui.TestRunner.run(AbstractIntegrationFilterTests.class); - } - - public void testContextHolderContentsPreserved() throws Exception { - PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", - "someone", "password", - new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - MockAbstractIntegrationFilterImpl filter = new MockAbstractIntegrationFilterImpl(principal); - MockFilterChain chain = new MockFilterChain(true, principal); - - MockSecureContextImpl secureContext = new MockSecureContextImpl( - "FOO_BAR"); - ContextHolder.setContext(secureContext); - assertEquals(secureContext, ContextHolder.getContext()); - - executeFilterInContainerSimulator(filter, null, null, chain); - - MockSecureContextImpl after = (MockSecureContextImpl) ContextHolder - .getContext(); - assertEquals(secureContext.getInfo(), after.getInfo()); - ContextHolder.setContext(null); - } - - public void testContextHolderHasAuthenticationRemoved() - throws Exception { - PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", - "someone", "password", - new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - MockAbstractIntegrationFilterImpl filter = new MockAbstractIntegrationFilterImpl(principal); - MockFilterChain chain = new MockFilterChain(true, principal); - - SecureContext secureContext = new SecureContextImpl(); - secureContext.setAuthentication(principal); - ContextHolder.setContext(secureContext); - assertEquals(secureContext, ContextHolder.getContext()); - - executeFilterInContainerSimulator(filter, null, null, chain); - - SecureContext after = (SecureContext) ContextHolder.getContext(); - assertEquals(null, after.getAuthentication()); - ContextHolder.setContext(null); - } - - public void testIgnoredWhenConcreteClassReturnsANonAuthenticationObject() - throws Exception { - MockPrincipal principal = new MockPrincipal(); - MockAbstractIntegrationFilterImpl filter = new MockAbstractIntegrationFilterImpl(principal); - MockFilterChain chain = new MockFilterChain(false, null); - - Context before = ContextHolder.getContext(); - - if (before != null) { - if (before instanceof SecureContext) { - assertEquals(null, ((SecureContext) before).getAuthentication()); - } - } - - executeFilterInContainerSimulator(filter, null, null, chain); - - Context after = ContextHolder.getContext(); - - if (after != null) { - if (after instanceof SecureContext) { - assertEquals(null, ((SecureContext) after).getAuthentication()); - } - } - } - - public void testIgnoredWhenConcreteClassReturnsNullAuthenticationObject() - throws Exception { - MockAbstractIntegrationFilterImpl filter = new MockAbstractIntegrationFilterImpl(null); - MockFilterChain chain = new MockFilterChain(false, null); - - Context before = ContextHolder.getContext(); - - if (before != null) { - if (before instanceof SecureContext) { - assertEquals(null, ((SecureContext) before).getAuthentication()); - } - } - - executeFilterInContainerSimulator(filter, null, null, chain); - - Context after = ContextHolder.getContext(); - - if (after != null) { - if (after instanceof SecureContext) { - assertEquals(null, ((SecureContext) after).getAuthentication()); - } - } - } - - public void testRejectsInvalidSecureContextClass() - throws Exception { - MockAbstractIntegrationFilterImpl filter = new MockAbstractIntegrationFilterImpl(null); - - // Test rejects classes not implementing SecureContext - filter.setSecureContext(String.class); - - try { - filter.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - assertTrue(true); - } - - // Test accepts classes implementing SecureContext - filter.setSecureContext(SecureContextImpl.class); - filter.afterPropertiesSet(); - assertTrue(true); - - // Test rejects null - filter.setSecureContext(null); - - try { - filter.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - assertTrue(true); - } - } - - public void testSecureContextSettersGetters() throws Exception { - MockAbstractIntegrationFilterImpl filter = new MockAbstractIntegrationFilterImpl(null); - - // check the default - assertEquals(SecureContextImpl.class, filter.getSecureContext()); - - // check the setter - filter.setSecureContext(null); - assertNull(filter.getSecureContext()); - } - - public void testSuccessWhenConcreteClassReturnsValidAuthenticationObject() - throws Exception { - PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", - "someone", "password", - new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - MockAbstractIntegrationFilterImpl filter = new MockAbstractIntegrationFilterImpl(principal); - MockFilterChain chain = new MockFilterChain(true, principal); - - Context before = ContextHolder.getContext(); - - if (before != null) { - if (before instanceof SecureContext) { - assertEquals(null, ((SecureContext) before).getAuthentication()); - } - } - - executeFilterInContainerSimulator(filter, null, null, chain); - - Context after = ContextHolder.getContext(); - - if (after != null) { - if (after instanceof SecureContext) { - assertEquals(null, ((SecureContext) after).getAuthentication()); - } - } - } - - private void executeFilterInContainerSimulator(Filter filter, - ServletRequest request, ServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - filter.init(null); - filter.doFilter(request, response, filterChain); - filter.destroy(); - } - - //~ Inner Classes ========================================================== - - private class MockAbstractIntegrationFilterImpl - extends AbstractIntegrationFilter { - private Object extractFromContainerResult; - - public MockAbstractIntegrationFilterImpl( - Object extractFromContainerResult) { - this.extractFromContainerResult = extractFromContainerResult; - } - - private MockAbstractIntegrationFilterImpl() { - super(); - } - - public void commitToContainer(ServletRequest request, - Authentication authentication) { - this.extractFromContainerResult = authentication; - } - - public Object extractFromContainer(ServletRequest request) { - return this.extractFromContainerResult; - } - } - - private class MockFilterChain implements FilterChain { - private Authentication expectedAuthenticationObjectInContextHolder; - private boolean expectContextHolderContainSecureContext = false; - - public MockFilterChain( - boolean expectContextHolderContainSecureContext, - Authentication expectedAuthenticationObjectInContextHolder) { - if ((expectedAuthenticationObjectInContextHolder != null) - && !expectContextHolderContainSecureContext) { - throw new IllegalArgumentException( - "If an Authentication object is expected, the ContextHolder should contain a SecureContext"); - } - - this.expectContextHolderContainSecureContext = expectContextHolderContainSecureContext; - this.expectedAuthenticationObjectInContextHolder = expectedAuthenticationObjectInContextHolder; - } - - private MockFilterChain() { - super(); - } - - public void doFilter(ServletRequest request, ServletResponse response) - throws IOException, ServletException { - if (expectContextHolderContainSecureContext) { - Context context = ContextHolder.getContext(); - - if (!(context instanceof SecureContext)) { - fail("ContextHolder should have contained SecureContext"); - } - } else { - if (ContextHolder.getContext() != null) { - fail("ContextHolder should have been null but wasn't"); - } - } - } - } - - private class MockSecureContextImpl extends SecureContextImpl { - private String info; - - public MockSecureContextImpl(String info) { - this.info = info; - } - - private MockSecureContextImpl() { - super(); - } - - public String getInfo() { - return this.info; - } - } -} diff --git a/core/src/test/java/org/acegisecurity/ui/AbstractProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/AbstractProcessingFilterTests.java index 7f2cbf071b..7d1e055621 100644 --- a/core/src/test/java/org/acegisecurity/ui/AbstractProcessingFilterTests.java +++ b/core/src/test/java/org/acegisecurity/ui/AbstractProcessingFilterTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,10 @@ import net.sf.acegisecurity.MockAuthenticationManager; import net.sf.acegisecurity.MockFilterConfig; import net.sf.acegisecurity.MockHttpServletRequest; import net.sf.acegisecurity.MockHttpServletResponse; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.security.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextUtils; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; -import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter; import java.io.IOException; @@ -59,10 +61,6 @@ public class AbstractProcessingFilterTests extends TestCase { //~ Methods ================================================================ - public final void setUp() throws Exception { - super.setUp(); - } - public static void main(String[] args) { junit.textui.TestRunner.run(AbstractProcessingFilterTests.class); } @@ -117,7 +115,7 @@ public class AbstractProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); assertEquals("/myApp/failed.jsp", response.getRedirect()); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } public void testFilterProcessesUrlVariationsRespected() @@ -144,10 +142,10 @@ public class AbstractProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); assertEquals("/logged_in.jsp", response.getRedirect()); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null); + assertNotNull(SecureContextUtils.getSecureContext().getAuthentication()); assertEquals("test", - ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal() - .toString()); + SecureContextUtils.getSecureContext().getAuthentication() + .getPrincipal().toString()); } public void testGettersSetters() { @@ -233,10 +231,10 @@ public class AbstractProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); assertEquals("/logged_in.jsp", response.getRedirect()); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null); + assertNotNull(SecureContextUtils.getSecureContext().getAuthentication()); assertEquals("test", - ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal() - .toString()); + SecureContextUtils.getSecureContext().getAuthentication() + .getPrincipal().toString()); } public void testStartupDetectsInvalidAuthenticationFailureUrl() @@ -327,10 +325,10 @@ public class AbstractProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); assertEquals("/logged_in.jsp", response.getRedirect()); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null); + assertNotNull(SecureContextUtils.getSecureContext().getAuthentication()); assertEquals("test", - ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal() - .toString()); + SecureContextUtils.getSecureContext().getAuthentication() + .getPrincipal().toString()); // Now try again but this time have filter deny access // Setup our HTTP request @@ -346,7 +344,7 @@ public class AbstractProcessingFilterTests extends TestCase { // Test executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } public void testSuccessfulAuthenticationButWithAlwaysUseDefaultTargetUrlCausesRedirectToDefaultTargetUrl() @@ -377,7 +375,7 @@ public class AbstractProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); assertEquals("/foobar", response.getRedirect()); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null); + assertNotNull(SecureContextUtils.getSecureContext().getAuthentication()); } public void testSuccessfulAuthenticationCausesRedirectToSessionSpecifiedUrl() @@ -404,7 +402,17 @@ public class AbstractProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); assertEquals("/my-destination", response.getRedirect()); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null); + assertNotNull(SecureContextUtils.getSecureContext().getAuthentication()); + } + + protected void setUp() throws Exception { + super.setUp(); + ContextHolder.setContext(new SecureContextImpl()); + } + + protected void tearDown() throws Exception { + super.tearDown(); + ContextHolder.setContext(null); } private void executeFilterInContainerSimulator(FilterConfig filterConfig, diff --git a/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java index a71087f7ed..b04880e3b7 100644 --- a/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java +++ b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package net.sf.acegisecurity.ui.basicauth; import junit.framework.TestCase; -import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.MockAuthenticationEntryPoint; import net.sf.acegisecurity.MockAuthenticationManager; import net.sf.acegisecurity.MockFilterConfig; @@ -25,7 +24,9 @@ import net.sf.acegisecurity.MockHttpServletRequest; import net.sf.acegisecurity.MockHttpServletResponse; import net.sf.acegisecurity.MockHttpSession; import net.sf.acegisecurity.UserDetails; -import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter; +import net.sf.acegisecurity.context.ContextHolder; +import net.sf.acegisecurity.context.security.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextUtils; import org.apache.commons.codec.binary.Base64; @@ -64,10 +65,6 @@ public class BasicProcessingFilterTests extends TestCase { //~ Methods ================================================================ - public final void setUp() throws Exception { - super.setUp(); - } - public static void main(String[] args) { junit.textui.TestRunner.run(BasicProcessingFilterTests.class); } @@ -125,7 +122,7 @@ public class BasicProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } public void testGettersSetters() { @@ -167,7 +164,7 @@ public class BasicProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } public void testNormalOperation() throws Exception { @@ -198,10 +195,11 @@ public class BasicProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null); + assertNotNull(SecureContextUtils.getSecureContext().getAuthentication()); assertEquals("marissa", - ((UserDetails) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)) - .getPrincipal()).getUsername()); + ((UserDetails) SecureContextUtils.getSecureContext() + .getAuthentication().getPrincipal()) + .getUsername()); } public void testOtherAuthorizationSchemeIsIgnored() @@ -231,7 +229,7 @@ public class BasicProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); } public void testStartupDetectsMissingAuthenticationEntryPoint() @@ -290,10 +288,11 @@ public class BasicProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null); + assertNotNull(SecureContextUtils.getSecureContext().getAuthentication()); assertEquals("marissa", - ((UserDetails) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)) - .getPrincipal()).getUsername()); + ((UserDetails) SecureContextUtils.getSecureContext() + .getAuthentication().getPrincipal()) + .getUsername()); // NOW PERFORM FAILED AUTHENTICATION // Setup our HTTP request @@ -313,7 +312,7 @@ public class BasicProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); assertEquals(401, response.getError()); } @@ -345,10 +344,20 @@ public class BasicProcessingFilterTests extends TestCase { executeFilterInContainerSimulator(config, filter, request, response, chain); - assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null); + assertNull(SecureContextUtils.getSecureContext().getAuthentication()); assertEquals(401, response.getError()); } + protected void setUp() throws Exception { + super.setUp(); + ContextHolder.setContext(new SecureContextImpl()); + } + + protected void tearDown() throws Exception { + super.tearDown(); + ContextHolder.setContext(null); + } + private void executeFilterInContainerSimulator(FilterConfig filterConfig, Filter filter, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { diff --git a/core/src/test/java/org/acegisecurity/ui/webapp/HttpSessionIntegrationFilterTests.java b/core/src/test/java/org/acegisecurity/ui/webapp/HttpSessionIntegrationFilterTests.java deleted file mode 100644 index c3b3a2ba91..0000000000 --- a/core/src/test/java/org/acegisecurity/ui/webapp/HttpSessionIntegrationFilterTests.java +++ /dev/null @@ -1,199 +0,0 @@ -/* Copyright 2004 Acegi Technology Pty Limited - * - * 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 net.sf.acegisecurity.ui.webapp; - -import junit.framework.TestCase; - -import net.sf.acegisecurity.GrantedAuthority; -import net.sf.acegisecurity.GrantedAuthorityImpl; -import net.sf.acegisecurity.MockHttpServletRequest; -import net.sf.acegisecurity.MockHttpSession; -import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken; - -import java.util.List; -import java.util.Vector; - - -/** - * Tests {@link HttpSessionIntegrationFilter}. - * - * @author Ben Alex - * @version $Id$ - */ -public class HttpSessionIntegrationFilterTests extends TestCase { - //~ Constructors =========================================================== - - public HttpSessionIntegrationFilterTests() { - super(); - } - - public HttpSessionIntegrationFilterTests(String arg0) { - super(arg0); - } - - //~ Methods ================================================================ - - public final void setUp() throws Exception { - super.setUp(); - } - - public static void main(String[] args) { - junit.textui.TestRunner.run(HttpSessionIntegrationFilterTests.class); - } - - public void testCommitFailSilentlyIfNullsProvided() { - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - filter.commitToContainer(null, null); - assertTrue(true); - } - - public void testCommitOperation() { - // Build an Authentication object we want returned - PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", - "someone", "password", - new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - - // Build a mock request - MockHttpSession session = new MockHttpSession(); - MockHttpServletRequest request = new MockHttpServletRequest(null, - session); - - // Try to commit - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - filter.commitToContainer(request, principal); - - // Check it committed the object - Object result = session.getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY); - assertEquals(principal, result); - } - - public void testCommitOperationGracefullyIgnoredIfSessionIsNull() { - PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", - "someone", "password", - new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - - // Build a mock request - MockHttpSession session = null; - MockHttpServletRequest request = new MockHttpServletRequest(null, - session); - - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - filter.commitToContainer(request, principal); - - assertTrue(true); - } - - public void testCorrectOperation() { - // Build a mock session containing the authenticated user - PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", - "someone", "password", - new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - MockHttpSession session = new MockHttpSession(); - session.setAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY, - principal); - - // Confirm filter can extract required credentials from session - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - Object result = filter.extractFromContainer(new MockHttpServletRequest( - null, session)); - - if (!(result instanceof PrincipalAcegiUserToken)) { - fail("Should have returned PrincipalAcegiUserToken"); - } - - PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result; - assertEquals(principal, result); - } - - public void testDetectsInvalidAdditionalAttributes() { - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - List list = new Vector(); - list.add(new Integer(4)); - - try { - filter.setAdditionalAttributes(list); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - assertTrue(true); - } - } - - public void testHandlesIfHttpRequestIsNullForSomeReason() { - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - assertEquals(null, filter.extractFromContainer(null)); - } - - public void testHandlesIfHttpSessionIsNullForSomeReason() { - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - assertEquals(null, - filter.extractFromContainer(new MockHttpServletRequest(null, null))); - } - - public void testHandlesIfThereIsNoPrincipalInTheHttpSession() { - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - assertEquals(null, - filter.extractFromContainer( - new MockHttpServletRequest(null, new MockHttpSession()))); - } - - public void testSettingEmptyListForAdditionalAttributesIsAcceptable() { - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - filter.setAdditionalAttributes(new Vector()); - assertTrue(filter.getAdditionalAttributes() != null); - } - - public void testSettingNullForAdditionalAttributesIsAcceptable() { - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - filter.setAdditionalAttributes(null); - assertNull(filter.getAdditionalAttributes()); - } - - public void testUpdatesAdditionalAttributes() { - // Build a mock session containing the authenticated user - PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("key", - "someone", "password", - new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}); - MockHttpSession session = new MockHttpSession(); - session.setAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY, - principal); - - // Check our attributes are not presently set - assertNull(session.getAttribute("SOME_EXTRA_ATTRIBUTE_1")); - assertNull(session.getAttribute("SOME_EXTRA_ATTRIBUTE_2")); - - // Generate filter - HttpSessionIntegrationFilter filter = new HttpSessionIntegrationFilter(); - List list = new Vector(); - list.add("SOME_EXTRA_ATTRIBUTE_1"); - list.add("SOME_EXTRA_ATTRIBUTE_2"); - filter.setAdditionalAttributes(list); - - // Confirm filter can extract required credentials from session - Object result = filter.extractFromContainer(new MockHttpServletRequest( - null, session)); - - if (!(result instanceof PrincipalAcegiUserToken)) { - fail("Should have returned PrincipalAcegiUserToken"); - } - - PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result; - assertEquals(principal, result); - - // Now double-check it updated our earlier set additionalAttributes - assertEquals(principal, session.getAttribute("SOME_EXTRA_ATTRIBUTE_1")); - assertEquals(principal, session.getAttribute("SOME_EXTRA_ATTRIBUTE_2")); - } -} diff --git a/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestFilterTests.java b/core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestFilterTests.java similarity index 92% rename from core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestFilterTests.java rename to core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestFilterTests.java index eb185435d3..da819735c2 100644 --- a/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestFilterTests.java +++ b/core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestFilterTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,14 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.wrapper; +package net.sf.acegisecurity.wrapper; import junit.framework.TestCase; import net.sf.acegisecurity.MockFilterConfig; import net.sf.acegisecurity.MockHttpServletRequest; +import net.sf.acegisecurity.wrapper.ContextHolderAwareRequestFilter; +import net.sf.acegisecurity.wrapper.ContextHolderAwareRequestWrapper; import java.io.IOException; diff --git a/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapperTests.java b/core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapperTests.java similarity index 95% rename from core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapperTests.java rename to core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapperTests.java index 12a54342a9..eceedea0ea 100644 --- a/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapperTests.java +++ b/core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapperTests.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package net.sf.acegisecurity.ui.wrapper; +package net.sf.acegisecurity.wrapper; import junit.framework.TestCase; @@ -22,10 +22,11 @@ import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.MockHttpServletRequest; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; import net.sf.acegisecurity.providers.dao.User; +import net.sf.acegisecurity.wrapper.ContextHolderAwareRequestWrapper; /** diff --git a/doc/docbook/acegi.xml b/doc/docbook/acegi.xml index d54a7f08f1..a97d9562a8 100644 --- a/doc/docbook/acegi.xml +++ b/doc/docbook/acegi.xml @@ -26,7 +26,7 @@ Reference Documentation - 0.7.0 + 0.8.0 @@ -399,6 +399,43 @@ custom request contexts implement the SecureContext interface. + + + Context Storage + + Central to Acegi Security's design is that the contents of the + ContextHolder (ie the Context) + can be stored between web requests. This is so that a successfully + authenticated principal can be identified on subsequent requests + through the Authentication stored inside a + SecureContext implementation. The + HttpSessionContextIntegrationFilter exists to + automatically copy the contents of a well-defined + HttpSession attribute into the + ContextHolder, then at the end of each request, + copy the ContextHolder contents back into the + HttpSession ready for next request. + + It is essential - and an extremely common error of end users - + that HttpSessionContextIntegrationFilter appears + before any other Acegi Security filter. This is because other Acegi + Security filters (along with all Acegi Security classes) expect the + ContextHolder to contain a valid + SecureContext by the time they are called. Acegi + Security filters also expect to be able to modify the + ContextHolder contents as they see fit, and + something else will store those between requests if necessary. This is + why HttpSessionContextIntegrationFilter must be the + first filter used. + + The HttpSessionContextIntegrationFilter has + been designed to store all types of Context objects + - not merely Acegi Security related contexts. This means, for example, + that you can extend SecureContextImpl to store a + locale or some other parameter, and + HttpSessionContextIntegrationFilter will + automatically manage it between web requests. + @@ -2264,44 +2301,42 @@ public boolean supports(Class clazz); classes "authentication mechanisms". The net.sf.acegisecurity.ui package provides - authentication mechanisms for web applications. There are two major - steps in doing this: + what we call "authentication processing mechanisms". An authentication + processing mechanism is solely concerned with received an + authentication request from the principal, testing if it seems valid, + and if so, placing the authentication request token onto the + ContextHolder. Of course, if the authentication request is invalid, + the authentication processing mechanism is responsible for informing + the principal in whatever way is appropriate to the protocol. - - - Actually authenticate the user and place the resulting - Authentication object in a "well-known - location". - + Recall the HttpSessionContextIntegrationFilter (discussed in the + context section) is responsible for storing the ContextHolder contents + between invocations. This means no authentication processing mechanism + need ever interact directly with HttpSession. Indeed + HttpSessionContextIntegrationFilter has been designed to minimise the + unnecessary creation of HttpSessions, as might occur when using Basic + authentication for example. - - Extract the Authentication object from - the "well-known location" and place in into the - ContextHolder for the duration of the secure - object invocation. - - - - There are several alternatives are available for the first step, - which will be briefly discussed in this chapter. The most popular (and - almost always recommended) approach is HTTP Session Authentication, - which uses the HttpSession object and filters to - authenticate the user. Another approach (commonly use with web - services) is HTTP Basic Authentication, which allows clients to use - HTTP headers to present authentication information to the Acegi - Security System for Spring. Alternatively, you can also use Yale - Central Authentication Service (CAS) for enterprise-wide single sign - on. The final (generally unrecommended) approach is via Container - Adapters, which allow supported web containers to perform the - authentication themselves. HTTP Session and Basic Authentication is - discussed below, whilst CAS and Container Adapters are discussed in - separate sections of this document. + There are several authentication processing mechanisms included + with Acegi Security, which will be briefly discussed in this chapter. + The most popular (and almost always recommended) approach is HTTP Form + Authentication, which uses a login form to authenticate the user. + Another approach (commonly use with web services) is HTTP Basic + Authentication, which allows clients to use HTTP headers to present + authentication information to the Acegi Security System for Spring. + Alternatively, you can also use Yale Central Authentication Service + (CAS) for enterprise-wide single sign on. The final (and generally + unrecommended) approach is via Container Adapters, which allow + supported web containers to perform the authentication themselves. + HTTP Form Authentication and Basic Authentication is discussed below, + whilst CAS and Container Adapters are discussed in separate sections + of this document. - - HTTP Session Authentication + + HTTP Form Authentication - HTTP Session Authentication involves using the + HTTP Form Authentication involves using the AuthenticationProcessingFilter to process a login form. The login form simply contains j_username and j_password input fields, and posts to a URL that is @@ -2346,12 +2381,9 @@ public boolean supports(Class clazz); If authentication is successful, the resulting Authentication object will be placed into the - HttpSession attribute indicated by - HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY. - This becomes the "well-known location" from which the - Authentication object is later extracted. + ContextHolder. - Once the HttpSession has been updated, the + Once the ContextHolder has been updated, the browser will need to be redirected to the target URL. The target URL is usually indicated by the HttpSession attribute specified by @@ -2365,8 +2397,8 @@ public boolean supports(Class clazz); defaultTargetUrl property. Because this authentication approach is fully contained within a - single web application, HTTP Session Authentication is recommended to - be used instead of Container Adapters. + single web application, HTTP Form Authentication is recommended to be + used instead of Container Adapters. @@ -2421,10 +2453,7 @@ public boolean supports(Class clazz); 401 response with a suitable header to retry HTTP Basic authentication. If authentication is successful, the resulting Authentication object will be placed into the - HttpSession attribute indicated by - HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY. - This becomes the "well-known location" from which the - Authentication object is later extracted. + ContextHolder. If the authentication event was successful, or authentication was not attempted because the HTTP header did not contain a supported @@ -2434,94 +2463,32 @@ public boolean supports(Class clazz); as discussed in the previous paragraph. HTTP Basic Authentication is recommended to be used instead of - Container Adapters. It can be used in conjunction with HTTP Session + Container Adapters. It can be used in conjunction with HTTP Form Authentication, as demonstrated in the Contacts sample application. - You can also use it instead of HTTP Session Authentication if you + You can also use it instead of HTTP Form Authentication if you wish. - Well-Known Location Integration + Well-Known Locations - Once a web application has used either HTTP Session - Authentication, HTTP Basic Authentication, or a Container Adapter, an - Authentication object will exist in a well-known - location. The final step in automatically integrating the user - interface with the backend security interceptor is to extract this - Authentication object from the well-known location - and place it into a SecureContext in the - ContextHolder. - - The AbstractIntegrationFilter and its - subclasses provide this well-known location integration. These classes - are standard filters, and at the start of each request they will - attempt to extract the Authentication object from a - well-known location. The Authentication object will - then be added to a SecureContext, the - SecureContext associated with the - ContextHolder for the duration of the request, and - the ContextHolder be cleared when the request is - finished. Four concrete subclasses of - AbstractIntegrationFilter are provided with the - Acegi Security System for Spring: - - - - HttpSessionIntegrationFilter is used - with HTTP Session Authentication, HTTP Basic Authentication, or - any other approach that populates the - HttpSession accordingly. It extracts the - Authentication object from the - HttpSession attribute indicated by - HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY. - - - - HttpRequestIntegrationFilter is used - with Catalina, Jetty and Resin Container Adapters. It extracts - the authentication information from - HttpServletRequest.getUserPrincipal(). - - - - JbossIntegrationFilter is used with the - JBoss Container Adapter. It extracts the authentication from - java:comp/env/security/subject. - - - - To define the HttpSessionIntegrationFilter - (recommended), simply add the following to your web.xml: - - <filter> - <filter-name>Acegi Security System for Spring HttpSession Integration Filter</filter-name> - <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class> - <init-param> - <param-name>targetClass</param-name> - <param-value>net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter</param-value> - </init-param> -</filter> - -<filter-mapping> - <filter-name>Acegi Security System for Spring HttpSession Integration Filter</filter-name> - <url-pattern>/*</url-pattern> -</filter-mapping> - - You will also need to add the following line to your application - context: - - <bean id="httpSessionIntegrationFilter" class="net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter" /> - - Once in the ContextHolder, the standard Acegi - Security System for Spring classes can be used. Because - ContextHolder is a standard object which is - populated using a filter at the container level, JSPs and Servlets do - not need to use Spring's MVC packages. This enables those applications - that use other MVC frameworks to still leverage Spring's other - capabilities, with full authentication and authorization support. The - debug.jsp page provided with the sample application - demonstrates accessing the ContextHolder - independent of Spring's MVC packages. + Prior to release 0.8.0, Acegi Security referred to "well-known + locations" in discussions about storing the + Authentication. This approach did not explicitly + separate the function of HttpSession storage of + ContextHolder contents from the processing of + authentication requests received through various protocols. In + addition, the previous approach did not facilitate storage of + non-Authentication objects between requests, which + was limiting usefulness of the ContextHolder system + to member of the community. For these reasons, the notion of + well-known locations was abandoned, the + HttpSessionContextIntegrationFilter was + established, and the purpose of authentication processing mechanisms + was explicitly defined and limited to interaction with the + ContextHolder only. There is no need to refer to + well-known locations any more and we hope this clearer separation of + responsibilities enhances understanding of the project. @@ -2531,13 +2498,14 @@ public boolean supports(Class clazz); Overview - Early versions of the Acegi Security System for Spring + Very early versions of the Acegi Security System for Spring exclusively used Container Adapters for interfacing authentication with end users. Whilst this worked well, it required considerable time to support multiple container versions and the configuration itself was relatively time-consuming for developers. For this reason the HTTP - Session Authentication and HTTP Basic Authentication approaches were - developed, and are today recommended for most applications. + Form Authentication and HTTP Basic Authentication approaches were + developed, and are today recommended for almost all + applications. Container Adapters enable the Acegi Security System for Spring to integrate directly with the containers used to host end user @@ -2546,7 +2514,10 @@ public boolean supports(Class clazz); containers (such as isUserInRole() and form-based or basic authentication), whilst benefiting from the enhanced security interception capabilities provided by the Acegi Security System for - Spring. + Spring (it should be noted that Acegi Security also offers + ContextHolderAwareRequestWrapper to deliver + isUserInRole() and similar Servlet Specification + compatibility methods). The integration between a container and the Acegi Security System for Spring is achieved through an adapter. The adapter provides @@ -4208,8 +4179,8 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT - /webServices/**=basicProcessingFilter,httpSessionIntegrationFilter,securityEnforcementFilter - /**=authenticationProcessingFilter,httpSessionIntegrationFilter,securityEnforcementFilter + /webServices/**=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,securityEnforcementFilter + /**=httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,securityEnforcementFilter </value> </property> </bean> @@ -4228,8 +4199,8 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); As you can see, FitlerChainProxy requires the duplication of filter names for different request patterns (in the - above example, httpSessionIntegrationFilter and - securityEnforcementFilter are duplicated). This + above example, httpSessionContextIntegrationFilter + and securityEnforcementFilter are duplicated). This design decision was made to enable FilterChainProxy to specify different Filter invocation orders for different URI patterns, and also to improve both the expressiveness @@ -4238,6 +4209,20 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); and clarity of which Filters should be invoked. + You may have noticed we have declared two + HttpSessionContextIntegrationFilters in the filter + chain (ASC is short for + allowSessionCreation, a property of + HttpSessionContextIntegrationFilter). As web + services will never present a jsessionid on future + requests, creating HttpSessions for such user + agents would be wasteful. If you had a high-volume application which + required maximum scalability, we recommend you use the approach shown + above. For smaller applications, using a single + HttpSessionContextIntegrationFilter (with its + default allowSessionCreation as + true) would likely be sufficient. + In relation to lifecycle issues, the FilterChainProxy will always delegate init(FilterConfig) and destroy() @@ -4259,7 +4244,7 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); Filter Ordering The order that filters are defined in web.xml - is important. + is important. NB: THE FILTER ORDER CHANGED FROM VERSION 0.8.0. Irrespective of which filters you are actually using, the order of the <filter-mapping>s should be as @@ -4267,33 +4252,41 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); - Acegi Channel Processing Filter - (ChannelProcessingFilter) + ChannelProcessingFilter, because it might + need to redirect to a different protocol - Acegi Authentication Processing Filter - (AuthenticationProcessingFilter) + HttpSessionContextIntegrationFilter, so a + Context can be setup in the + ContextHolder at the beginning of a web + request, and any changes to the Context can be copied to the + HttpSession when the web request ends (ready + for use with the next web request) - Acegi CAS Processing Filter - (CasProcessingFilter) + Authentication processing mechanisms - + AuthenticationProcessingFilter, + CasProcessingFilter, + BasicProcessingFilter, HttpRequestIntegrationFilter, + JbossIntegrationFilter etc - so that the + ContextHolder can be modified to contain a + valid Authentication request token - Acegi HTTP BASIC Authorization Filter - (BasicProcessingFilter) + The ContextHolderAwareRequestFilter, if + you are using it to install an Acegi Security aware + HttpServletRequestWrapper into your servlet + container - Acegi Security System for Spring HTTP Session Integration - Filter (HttpSessionIntegrationFilter) - - - - Acegi HTTP Request Security Filter - (SecurityEnforcementFilter) + SecurityEnforcementFilter, to protect web + URIs and catch any Acegi Security exceptions so that an + appropriate AuthenticationEntryPoint can be + launched @@ -4353,7 +4346,7 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1);
    Context on ContextHolder is of type: - net.sf.acegisecurity.context.SecureContextImpl + net.sf.acegisecurity.context.secure.SecureContextImpl The Context implements SecureContext. diff --git a/doc/xdocs/changes.xml b/doc/xdocs/changes.xml index d3e918f409..f476133ba3 100644 --- a/doc/xdocs/changes.xml +++ b/doc/xdocs/changes.xml @@ -45,6 +45,7 @@ Additional debug-level logging AuthenticationProcessingFilter now provides hook for extra credentials (eg postcodes) New WebAuthenticationDetails class now used by processing filters for Authentication.setDetails() + Significantly refactor "well-known location model" to authentication processing mechanism and HttpSessionContextIntegrationFilter model Major CVS repository restructure to support Maven and eliminate libraries diff --git a/doc/xdocs/upgrade/upgrade-070-080.html b/doc/xdocs/upgrade/upgrade-070-080.html new file mode 100644 index 0000000000..9e403fe189 --- /dev/null +++ b/doc/xdocs/upgrade/upgrade-070-080.html @@ -0,0 +1,38 @@ + + +Acegi Security - Upgrading from version 0.7.0 to 0.8.0 + + +

    Upgrading from 0.7.0 to 0.8.0

    + +

    +The following should help most casual users of the project update their +applications: + +

      + +
    • HttpSessionIntegrationFilter has been removed. Use net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter instead. + Note you will need to set the mandatory "context" property to something like "net.sf.acegisecurity.context.security.SecureContextImpl". + It's not the default because we want no dependencies between the context package and the rest of Acegi Security.

    • + +
    • Filter ordering has changed. See the reference guide for confirmation of the correct ordering. Basically you should have + HttpSessionContextIntegrationFilter appear before any of your authentication mechanisms.

    • + +
    • IoC container hosted filter chains can now be used instead of lengthy web.xml declarations. See the reference guide or the + Contacts Sample for further information.

    • + +
    • Certain classes have been moved to new packages: ContextHolderAwareRequestWrapper (and its filter), + AuthenticationSimpleHttpInvokerRequestExecutor, ContextPropagatingRemoteInvocation, + SecureContext (and its implementation). These classes were moved as part of refactorings aimed at + improving the simplicity of the project's design.

    • + +
    • The JaasAuthenticationCallbackHandler interface has had it's setAuthentication method removed. The handle method now takes both the Callback and Authentication objects as arguments.

    • + +
    • Added AuthenticationException to the AutenticationEntryPoint.commence method signature.

    • + +
    • Added AccessDeniedException to the SecurityEncorcementFilter.sendAccessDeniedError method signature.

    • + +
    + + + diff --git a/doc/xdocs/upgrade/upgrade-070-100.html b/doc/xdocs/upgrade/upgrade-070-100.html deleted file mode 100644 index 4274289125..0000000000 --- a/doc/xdocs/upgrade/upgrade-070-100.html +++ /dev/null @@ -1,22 +0,0 @@ - - -Acegi Security - Upgrading from version 0.7.0 to 1.0.0 - - -

    Upgrading from 0.7.0 to 1.0.0

    - -

    -The following should help most casual users of the project update their -applications: - -

      - -
    • The JaasAuthenticationCallbackHandler interface has had it's setAuthentication method removed. - The handle method now takes both the Callback and Authentication objects as arguments.
    • -
    • Added AuthenticationException to the AutenticationEntryPoint.commence method signature.
    • -
    • Added AccessDeniedException to the SecurityEncorcementFilter.sendAccessDeniedError method signature.
    • - -
    - - - diff --git a/samples/attributes/src/main/java/sample/attributes/Main.java b/samples/attributes/src/main/java/sample/attributes/Main.java index 744aa2fa01..1e883b10de 100644 --- a/samples/attributes/src/main/java/sample/attributes/Main.java +++ b/samples/attributes/src/main/java/sample/attributes/Main.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ import net.sf.acegisecurity.AccessDeniedException; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; import org.springframework.context.support.ClassPathXmlApplicationContext; diff --git a/samples/attributes/src/test/java/sample/attributes/BankTests.java b/samples/attributes/src/test/java/sample/attributes/BankTests.java index 08b7022b25..922dc41697 100644 --- a/samples/attributes/src/test/java/sample/attributes/BankTests.java +++ b/samples/attributes/src/test/java/sample/attributes/BankTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import net.sf.acegisecurity.AccessDeniedException; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.TestingAuthenticationToken; import org.springframework.context.support.ClassPathXmlApplicationContext; diff --git a/samples/contacts/src/main/java/sample/contact/ClientApplication.java b/samples/contacts/src/main/java/sample/contact/ClientApplication.java index d290c5711a..dde1cd2fa3 100644 --- a/samples/contacts/src/main/java/sample/contact/ClientApplication.java +++ b/samples/contacts/src/main/java/sample/contact/ClientApplication.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,8 @@ package sample.contact; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; -import net.sf.acegisecurity.context.SecureContextImpl; +import net.sf.acegisecurity.context.security.SecureContext; +import net.sf.acegisecurity.context.security.SecureContextImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.springframework.beans.factory.ListableBeanFactory; diff --git a/samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java b/samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java index 8a10cbf07a..79136e25f3 100644 --- a/samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java +++ b/samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import net.sf.acegisecurity.acl.basic.BasicAclExtendedDao; import net.sf.acegisecurity.acl.basic.NamedEntityObjectIdentity; import net.sf.acegisecurity.acl.basic.SimpleAclEntry; import net.sf.acegisecurity.context.ContextHolder; -import net.sf.acegisecurity.context.SecureContext; +import net.sf.acegisecurity.context.security.SecureContext; import org.springframework.beans.factory.InitializingBean; diff --git a/samples/contacts/src/main/webapp/ca/WEB-INF/applicationContext-acegi-security.xml b/samples/contacts/src/main/webapp/ca/WEB-INF/applicationContext-acegi-security.xml index f143de378e..2f50907407 100644 --- a/samples/contacts/src/main/webapp/ca/WEB-INF/applicationContext-acegi-security.xml +++ b/samples/contacts/src/main/webapp/ca/WEB-INF/applicationContext-acegi-security.xml @@ -21,7 +21,7 @@ CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT - /**=httpRequestIntegrationFilter + /**=httpSessionContextIntegrationFilter,httpRequestIntegrationFilter @@ -46,6 +46,10 @@ + + net.sf.acegisecurity.context.security.SecureContextImpl + + diff --git a/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml b/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml index 4f32126756..53183b7f23 100644 --- a/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml +++ b/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml @@ -19,7 +19,7 @@ CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT - /**=channelProcessingFilter,casProcessingFilter,basicProcessingFilter,httpSessionIntegrationFilter,securityEnforcementFilter + /**=channelProcessingFilter,httpSessionContextIntegrationFilter,casProcessingFilter,basicProcessingFilter,securityEnforcementFilter @@ -47,7 +47,9 @@ Contacts Realm - + + net.sf.acegisecurity.context.security.SecureContextImpl + diff --git a/samples/contacts/src/main/webapp/common/secure/debug.jsp b/samples/contacts/src/main/webapp/common/secure/debug.jsp index 3e647615d0..d0a918d429 100644 --- a/samples/contacts/src/main/webapp/common/secure/debug.jsp +++ b/samples/contacts/src/main/webapp/common/secure/debug.jsp @@ -1,6 +1,6 @@ <%@ page import="net.sf.acegisecurity.context.Context" %> <%@ page import="net.sf.acegisecurity.context.ContextHolder" %> -<%@ page import="net.sf.acegisecurity.context.SecureContext" %> +<%@ page import="net.sf.acegisecurity.context.security.SecureContext" %> <%@ page import="net.sf.acegisecurity.Authentication" %> <%@ page import="net.sf.acegisecurity.GrantedAuthority" %> <%@ page import="net.sf.acegisecurity.adapters.AuthByAdapter" %> diff --git a/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml b/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml index e52d16b16d..95ca7effc9 100644 --- a/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml +++ b/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml @@ -15,13 +15,13 @@ + of "httpSessionContextIntegrationFilter" in the list below --> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT - /**=authenticationProcessingFilter,basicProcessingFilter,httpSessionIntegrationFilter,securityEnforcementFilter + /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,securityEnforcementFilter @@ -75,7 +75,9 @@ Contacts Realm - + + net.sf.acegisecurity.context.security.SecureContextImpl +