Forráskód Böngészése

implemented unit tests for portlet support

John Lewis 18 éve
szülő
commit
8396f04ae6
15 módosított fájl, 1410 hozzáadás és 54 törlés
  1. 1 1
      sandbox/portlet/pom.xml
  2. 1 1
      sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/PortletAuthenticationProvider.java
  3. 1 1
      sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/PortletAuthenticationToken.java
  4. 20 12
      sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/populator/ContainerPortletAuthoritiesPopulator.java
  5. 1 1
      sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/populator/DaoPortletAuthoritiesPopulator.java
  6. 45 38
      sandbox/portlet/src/main/java/org/acegisecurity/ui/portlet/PortletProcessingInterceptor.java
  7. 372 0
      sandbox/portlet/src/test/java/org/acegisecurity/context/PortletSessionContextIntegrationInterceptorTests.java
  8. 117 0
      sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/PortletAuthenticationProviderTests.java
  9. 63 0
      sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/PortletAuthenticationTokenTests.java
  10. 128 0
      sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/PortletTestUtils.java
  11. 90 0
      sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/cache/EhCacheBasedUserCacheTests.java
  12. 127 0
      sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/populator/ContainerPortletAuthoritiesPopulatorTests.java
  13. 100 0
      sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/populator/DaoPortletAuthoritiesPopulatorTests.java
  14. 60 0
      sandbox/portlet/src/test/java/org/acegisecurity/ui/portlet/PortletProcessingFilterEntryPointTests.java
  15. 284 0
      sandbox/portlet/src/test/java/org/acegisecurity/ui/portlet/PortletProcessingInterceptorTests.java

+ 1 - 1
sandbox/portlet/pom.xml

@@ -8,7 +8,7 @@
     </parent>
     <artifactId>acegi-security-portlet</artifactId>
     <name>Acegi Security System for Spring - Portlet support</name>
-    <description>Acegi Security System for Spring - Support for JSR-168 Portlets</description>
+    <description>Acegi Security System for Spring - Support for JSR 168 Portlets</description>
     <version>0.1-SNAPSHOT</version>
 
     <repositories>

+ 1 - 1
sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/PortletAuthenticationProvider.java

@@ -34,7 +34,7 @@ import org.springframework.beans.factory.InitializingBean;
 import org.springframework.util.Assert;
 
 /**
- * <p>Processes a JSR-168 Portlet authentication request.  The request will typically
+ * <p>Processes a JSR 168 Portlet authentication request.  The request will typically
  * originate from {@link org.acegisecurity.ui.portlet.PortletProcessingInterceptor}.</p>
  *
  * <p>Be aware that this provider is trusting the portal and portlet container to handle

+ 1 - 1
sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/PortletAuthenticationToken.java

@@ -20,7 +20,7 @@ import org.acegisecurity.GrantedAuthority;
 import org.acegisecurity.providers.AbstractAuthenticationToken;
 
 /**
- * <code>Authentication</code> implementation for JSR-168 Portlet authentication.  <p>The
+ * <code>Authentication</code> implementation for JSR 168 Portlet authentication.  <p>The
  * corresponding authentication provider is  {@link PortletAuthenticationProvider}.</p>
  *
  * @author John A. Lewis

+ 20 - 12
sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/populator/ContainerPortletAuthoritiesPopulator.java

@@ -33,9 +33,10 @@ import org.acegisecurity.userdetails.User;
 import org.acegisecurity.userdetails.UserDetails;
 
 /**
- * Populates the portlet authorities via role information from the portlet container.
+ * <p>Populates the portlet authorities via role information from the portlet container.
  * Primarily it uses the <code>PortletRequest.isUserInRole(role)</code> method to
- * check if the user is in a list of configured roles.
+ * check if the user is in a list of configured roles.</p>
+ *
  * <p>This bean has the following configurable properties:</p>
  * <ul>
  *     <li><code>rolesToCheck</code> : A list of strings containing names of roles to check.
@@ -43,10 +44,16 @@ import org.acegisecurity.userdetails.UserDetails;
  *         of the portlet descriptor in the portlet.xml file.</li>
  *     <li><code>rolePrefix</code> : The prefix to be added onto each role name that as it is
  *         added to the list of authorities.  The default value is 'ROLE_'.</li>
- *     <li><code>userRole</code> : The role that all authenticated users will automatically be
- *         granted.  The default value is 'ROLE_USER'.</li>
+ *     <li><code>userRole</code> : The authority that all authenticated users will automatically
+ *         be granted.  The default value is 'ROLE_USER'.  Set this to null to avoid having any
+ *         value automatically populated.</li>
  * </ul>
  *
+ * <p>This populator depends on finding the <code>PortletRequest<code> when calling the
+ * {@link Authentication#getDetails()} method on the object passed to
+ * {@link #getUserDetails(Authentication)}.  If not, it will throw an
+ * {@link AuthenticationServiceException}.
+ *
  * @author John A. Lewis
  * @since 2.0
  * @version $Id$
@@ -56,14 +63,14 @@ public class ContainerPortletAuthoritiesPopulator
 
 	//~ Static fields/initializers =====================================================================================
 
-	private static final String defaultRolePrefix = "ROLE_";
-	private static final String defaultUserRole = "ROLE_USER";
+	public static final String DEFAULT_ROLE_PREFIX = "ROLE_";
+	public static final String DEFAULT_USER_ROLE = "ROLE_USER";
 
 	//~ Instance fields ================================================================================================
 
-    private List rolesToCheck;
-    private String rolePrefix = defaultRolePrefix;
-    private String userRole = defaultUserRole;
+	private List rolesToCheck;
+	private String rolePrefix = DEFAULT_ROLE_PREFIX;
+	private String userRole = DEFAULT_USER_ROLE;
 
 	//~ Methods ========================================================================================================
 
@@ -77,7 +84,7 @@ public class ContainerPortletAuthoritiesPopulator
 		// see if we can load authorities from the portlet request
 		Object details = authentication.getDetails();
 		if (!(details instanceof PortletRequest)) {
-			throw new AuthenticationServiceException("expected getDetails() to return the PortletRequest object");
+			throw new AuthenticationServiceException("expected Authentication.getDetails() to return a PortletRequest");
 		}
 		GrantedAuthority[] authorities = loadGrantedAuthorities((PortletRequest)details);
 
@@ -89,7 +96,8 @@ public class ContainerPortletAuthoritiesPopulator
 
 		// start the list and add the standard user role
 		ArrayList authorities = new ArrayList();
-		authorities.add(new GrantedAuthorityImpl(getUserRole()));
+		if (this.userRole != null && this.userRole.length() > 0)
+			authorities.add(new GrantedAuthorityImpl(getUserRole()));
 
 		// iterate through the configured list of roles to check (if there is one)
 		if (this.rolesToCheck != null) {
@@ -104,7 +112,7 @@ public class ContainerPortletAuthoritiesPopulator
 			}
 		}
 
-        // return the array of GrantedAuthority objects
+		// return the array of GrantedAuthority objects
 		return (GrantedAuthority[])authorities.toArray(new GrantedAuthority[authorities.size()]);
 	}
 

+ 1 - 1
sandbox/portlet/src/main/java/org/acegisecurity/providers/portlet/populator/DaoPortletAuthoritiesPopulator.java

@@ -38,7 +38,7 @@ public class DaoPortletAuthoritiesPopulator
 
 	//~ Instance fields ================================================================================================
 
-    private UserDetailsService userDetailsService;
+	private UserDetailsService userDetailsService;
 
 	//~ Methods ========================================================================================================
 

+ 45 - 38
sandbox/portlet/src/main/java/org/acegisecurity/ui/portlet/PortletProcessingInterceptor.java

@@ -17,6 +17,7 @@
 package org.acegisecurity.ui.portlet;
 
 import java.io.IOException;
+import java.security.Principal;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -25,6 +26,7 @@ import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
 import javax.portlet.PortletRequest;
 import javax.portlet.PortletResponse;
+import javax.portlet.PortletSession;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
 
@@ -52,8 +54,8 @@ import org.springframework.web.portlet.ModelAndView;
  * {@link Authentication} object will be placed into the <code>SecurityContext</code>, which
  * is guaranteed to have already been created by an earlier interceptor.  If authentication
  * fails, the <code>AuthenticationException</code> will be placed into the
- * <code>PortletSession</code> with the attribute defined by
- * {@link AbstractProcessingFilter#ACEGI_SECURITY_LAST_EXCEPTION_KEY}.</p>
+ * <code>APPLICATION_SCOPE</code> of the <code>PortletSession</code> with the attribute defined
+ * by {@link AbstractProcessingFilter#ACEGI_SECURITY_LAST_EXCEPTION_KEY}.</p>
  *
  *  <p>Some portals do not properly provide the identity of the current user via the
  * <code>getRemoteUser()</code> or <code>getUserPrincipal()</code> methods of the
@@ -167,7 +169,9 @@ public class PortletProcessingInterceptor implements
 				if (logger.isDebugEnabled())
 					logger.debug("Authentication failed - updating ContextHolder to contain null Authentication");
 				ctx.setAuthentication(null);
-				request.getPortletSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed);
+				request.getPortletSession().setAttribute(
+						AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
+						failed, PortletSession.APPLICATION_SCOPE);
 				onUnsuccessfulAuthentication(request, response, failed);
 			}
 		}
@@ -177,7 +181,7 @@ public class PortletProcessingInterceptor implements
 
 	/**
 	 * This method attempts to extract a principal from the portlet request.
-	 * According to the JSR-168 spec, the <code>PortletRequest<code> should return the name
+	 * According to the JSR 168 spec, the <code>PortletRequest<code> should return the name
 	 * of the user in the <code>getRemoteUser()</code> method.  It should also provide a
 	 * <code>java.security.Principal</code> object from the <code>getUserPrincipal()</code>
 	 * method.  We will first try these to come up with a valid username.
@@ -186,22 +190,25 @@ public class PortletProcessingInterceptor implements
 	 * property has been populated, then we will search through the <code>USER_INFO<code>
 	 * map from the request to see if we can find a valid username.
 	 * <p>This method can be overridden by subclasses to provide special handling
-	 * for portals with weak support for the JSR-168 spec.</p>
+	 * for portals with weak support for the JSR 168 spec.</p>
 	 * @param request the portlet request object
 	 * @return the determined principal object, or null if none found
 	 */
 	protected Object getPrincipalFromRequest(PortletRequest request) {
 
 		// first try getRemoteUser()
-		Object principal = request.getRemoteUser();
-		if (principal != null) {
-			return principal;
+		String remoteUser = request.getRemoteUser();
+		if (remoteUser != null) {
+			return remoteUser;
 		}
 
 		// next try getUserPrincipal()
-		principal = request.getUserPrincipal();
-		if (principal != null) {
-			return principal;
+		Principal userPrincipal = request.getUserPrincipal();
+		if (userPrincipal != null) {
+			String userPrincipalName = userPrincipal.getName();
+			if (userPrincipalName != null) {
+				return userPrincipalName;
+			}
 		}
 
 		// last try entries in USER_INFO if any attributes were defined
@@ -213,9 +220,9 @@ public class PortletProcessingInterceptor implements
 				logger.warn("unable to retrieve USER_INFO map from portlet request", e);
 			}
 			if (userInfo != null) {
-			    Iterator i = this.userNameAttributes.iterator();
-			    while(i.hasNext()) {
-					principal = (String)userInfo.get(i.next());
+				Iterator i = this.userNameAttributes.iterator();
+				while(i.hasNext()) {
+					Object principal = (String)userInfo.get(i.next());
 					if (principal != null) {
 						return principal;
 					}
@@ -231,13 +238,13 @@ public class PortletProcessingInterceptor implements
 	 * This method attempts to extract a credentials from the portlet request.
 	 * We are trusting the portal framework to authenticate the user, so all
 	 * we are really doing is trying to put something intelligent in here to
-	 * indicate the user is authenticated.  According to the JSR-168 spec,
+	 * indicate the user is authenticated.  According to the JSR 168 spec,
 	 * PortletRequest.getAuthType() should return a non-null value if the
 	 * user is authenticated and should be null if not authenticated. So we
 	 * will use this as the credentials and the token will be trusted as
 	 * authenticated if the credentials are not null.
 	 * <p>This method can be overridden by subclasses to provide special handling
-	 * for portals with weak support for the JSR-168 spec.  If that is done,
+	 * for portals with weak support for the JSR 168 spec.  If that is done,
 	 * be sure the value is non-null for authenticated users and null for
 	 * non-authenticated users.</p>
 	 * @param request the portlet request object
@@ -255,28 +262,28 @@ public class PortletProcessingInterceptor implements
 	 * @throws AuthenticationException to indicate that authentication attempt is not valid and should be terminated
 	 * @throws IOException
 	 */
-    protected void onPreAuthentication(PortletRequest request, PortletResponse response)
-    	throws AuthenticationException, IOException {}
-
-    /**
-     * Callback for custom processing after a successful authentication attempt.
-     * @param request the portlet request that was authenticated
-     * @param response the portlet response that was authenticated
-     * @param authResult the resulting Authentication object
-     * @throws IOException
-     */
-    protected void onSuccessfulAuthentication(PortletRequest request, PortletResponse response, Authentication authResult)
-    	throws IOException {}
-
-    /**
-     * Callback for custom processing after an unsuccessful authentication attempt.
-     * @param request the portlet request that failed authentication
-     * @param response the portlet response that failed authentication
-     * @param failed the AuthenticationException that occurred
-     * @throws IOException
-     */
-    protected void onUnsuccessfulAuthentication(PortletRequest request, PortletResponse response, AuthenticationException failed)
-    	throws IOException {}
+	protected void onPreAuthentication(PortletRequest request, PortletResponse response)
+		throws AuthenticationException, IOException {}
+
+	/**
+	 * Callback for custom processing after a successful authentication attempt.
+	 * @param request the portlet request that was authenticated
+	 * @param response the portlet response that was authenticated
+	 * @param authResult the resulting Authentication object
+	 * @throws IOException
+	 */
+	protected void onSuccessfulAuthentication(PortletRequest request, PortletResponse response, Authentication authResult)
+		throws IOException {}
+
+	/**
+	 * Callback for custom processing after an unsuccessful authentication attempt.
+	 * @param request the portlet request that failed authentication
+	 * @param response the portlet response that failed authentication
+	 * @param failed the AuthenticationException that occurred
+	 * @throws IOException
+	 */
+	protected void onUnsuccessfulAuthentication(PortletRequest request, PortletResponse response, AuthenticationException failed)
+		throws IOException {}
 
 
 	public AuthenticationManager getAuthenticationManager() {

+ 372 - 0
sandbox/portlet/src/test/java/org/acegisecurity/context/PortletSessionContextIntegrationInterceptorTests.java

@@ -0,0 +1,372 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.context;
+
+import javax.portlet.PortletSession;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.providers.portlet.PortletAuthenticationToken;
+import org.acegisecurity.providers.portlet.PortletTestUtils;
+import org.acegisecurity.userdetails.User;
+import org.springframework.mock.web.portlet.MockActionRequest;
+import org.springframework.mock.web.portlet.MockActionResponse;
+import org.springframework.mock.web.portlet.MockRenderRequest;
+import org.springframework.mock.web.portlet.MockRenderResponse;
+
+/**
+ * Tests {@link PortletSessionContextIntegrationInterceptor}.
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class PortletSessionContextIntegrationInterceptorTests extends TestCase {
+
+	//~ Constructors ===================================================================================================
+
+	public PortletSessionContextIntegrationInterceptorTests() {
+		super();
+	}
+
+	public PortletSessionContextIntegrationInterceptorTests(String arg0) {
+		super(arg0);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public void setUp() throws Exception {
+		super.setUp();
+		SecurityContextHolder.clearContext();
+	}
+
+	public void tearDown() throws Exception {
+		super.tearDown();
+		SecurityContextHolder.clearContext();
+	}
+
+	public void testDetectsIncompatibleSessionProperties() throws Exception {
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		try {
+			interceptor.setAllowSessionCreation(false);
+			interceptor.setForceEagerSessionCreation(true);
+			interceptor.afterPropertiesSet();
+			fail("Shown have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException expected) {
+			// ignore
+		}
+		interceptor.setAllowSessionCreation(true);
+		interceptor.afterPropertiesSet();
+	}
+
+	public void testDetectsMissingOrInvalidContext() throws Exception {
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		try {
+			interceptor.setContext(null);
+			interceptor.afterPropertiesSet();
+			fail("Shown have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException expected) {
+			// ignore
+		}
+		try {
+			interceptor.setContext(Integer.class);
+			assertEquals(Integer.class, interceptor.getContext());
+			interceptor.afterPropertiesSet();
+			fail("Shown have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException expected) {
+			// ignore
+		}
+	}
+
+	public void testNormalRenderRequestProcessing() throws Exception {
+
+		// Build an Authentication object we simulate came from PortletSession
+		PortletAuthenticationToken sessionPrincipal = PortletTestUtils.createAuthenticatedToken();
+		PortletAuthenticationToken baselinePrincipal = PortletTestUtils.createAuthenticatedToken();
+
+		// Build a Context to store in PortletSession (simulating prior request)
+		SecurityContext sc = new SecurityContextImpl();
+		sc.setAuthentication(sessionPrincipal);
+
+		// Build mock request and response
+		MockRenderRequest request = PortletTestUtils.createRenderRequest();
+		MockRenderResponse response = PortletTestUtils.createRenderResponse();
+		request.getPortletSession().setAttribute(
+				PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY,
+				sc, PortletSession.APPLICATION_SCOPE);
+
+		// Prepare interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.afterPropertiesSet();
+
+		// Verify the SecurityContextHolder starts empty
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+
+		// Run preHandleRender phase and verify SecurityContextHolder contains our Authentication
+		interceptor.preHandleRender(request, response, null);
+		assertEquals(baselinePrincipal, SecurityContextHolder.getContext().getAuthentication());
+
+		// Run postHandleRender phase and verify the SecurityContextHolder still contains our Authentication
+		interceptor.postHandleRender(request, response, null, null);
+		assertEquals(baselinePrincipal, SecurityContextHolder.getContext().getAuthentication());
+
+		// Run afterRenderCompletion phase and verify the SecurityContextHolder is empty
+		interceptor.afterRenderCompletion(request, response, null, null);
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+	}
+
+	public void testNormalActionRequestProcessing() throws Exception {
+
+		// Build an Authentication object we simulate came from PortletSession
+		PortletAuthenticationToken sessionPrincipal = PortletTestUtils.createAuthenticatedToken();
+		PortletAuthenticationToken baselinePrincipal = PortletTestUtils.createAuthenticatedToken();
+
+		// Build a Context to store in PortletSession (simulating prior request)
+		SecurityContext sc = new SecurityContextImpl();
+		sc.setAuthentication(sessionPrincipal);
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+		request.getPortletSession().setAttribute(
+				PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY,
+				sc, PortletSession.APPLICATION_SCOPE);
+
+		// Prepare interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.afterPropertiesSet();
+
+		// Verify the SecurityContextHolder starts empty
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+
+		// Run preHandleAction phase and verify SecurityContextHolder contains our Authentication
+		interceptor.preHandleAction(request, response, null);
+		assertEquals(baselinePrincipal, SecurityContextHolder.getContext().getAuthentication());
+
+		// Run afterActionCompletion phase and verify the SecurityContextHolder is empty
+		interceptor.afterActionCompletion(request, response, null, null);
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+	}
+
+	public void testUpdatesCopiedBackIntoSession() throws Exception {
+
+		// Build an Authentication object we simulate came from PortletSession
+		PortletAuthenticationToken sessionPrincipal = PortletTestUtils.createAuthenticatedToken();
+		PortletAuthenticationToken baselinePrincipal = PortletTestUtils.createAuthenticatedToken();
+
+		// Build a Context to store in PortletSession (simulating prior request)
+		SecurityContext sc = new SecurityContextImpl();
+		sc.setAuthentication(sessionPrincipal);
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+		request.getPortletSession().setAttribute(
+				PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY,
+				sc, PortletSession.APPLICATION_SCOPE);
+
+		// Prepare interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.afterPropertiesSet();
+
+		// Verify the SecurityContextHolder starts empty
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+
+		// Run preHandleAction phase and verify SecurityContextHolder contains our Authentication
+		interceptor.preHandleAction(request, response, null);
+		assertEquals(baselinePrincipal, SecurityContextHolder.getContext().getAuthentication());
+
+		// Perform updates to principal
+		sessionPrincipal = PortletTestUtils.createAuthenticatedToken(
+				new User(PortletTestUtils.TESTUSER, PortletTestUtils.TESTCRED, true, true, true, true,
+						new GrantedAuthority[] {new GrantedAuthorityImpl("UPDATEDROLE1")}));
+		baselinePrincipal = PortletTestUtils.createAuthenticatedToken(
+				new User(PortletTestUtils.TESTUSER, PortletTestUtils.TESTCRED, true, true, true, true,
+						new GrantedAuthority[] {new GrantedAuthorityImpl("UPDATEDROLE1")}));
+
+		// Store updated principal into SecurityContextHolder
+		SecurityContextHolder.getContext().setAuthentication(sessionPrincipal);
+
+		// Run afterActionCompletion phase and verify the SecurityContextHolder is empty
+		interceptor.afterActionCompletion(request, response, null, null);
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+
+		// Verify the new principal is stored in the session
+		sc = (SecurityContext)request.getPortletSession().getAttribute(
+				PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY,
+				PortletSession.APPLICATION_SCOPE);
+		assertEquals(baselinePrincipal, sc.getAuthentication());
+	}
+
+	public void testPortletSessionCreatedWhenContextHolderChanges() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+
+		// Prepare the interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.afterPropertiesSet();
+
+		// Execute the interceptor
+		interceptor.preHandleAction(request, response, null);
+		PortletAuthenticationToken principal = PortletTestUtils.createAuthenticatedToken();
+		SecurityContextHolder.getContext().setAuthentication(principal);
+		interceptor.afterActionCompletion(request, response, null, null);
+
+		// Verify Authentication is in the PortletSession
+		SecurityContext sc = (SecurityContext)request.getPortletSession(false).
+				getAttribute(PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY, PortletSession.APPLICATION_SCOPE);
+		assertEquals(principal, ((SecurityContext)sc).getAuthentication());
+	}
+
+	public void testPortletSessionEagerlyCreatedWhenDirected() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+
+		// Prepare the interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.setForceEagerSessionCreation(true); // non-default
+		interceptor.afterPropertiesSet();
+
+		// Execute the interceptor
+		interceptor.preHandleAction(request, response, null);
+		interceptor.afterActionCompletion(request, response, null, null);
+
+		// Check the session is not null
+		assertNotNull(request.getPortletSession(false));
+	}
+
+	public void testPortletSessionNotCreatedUnlessContextHolderChanges() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+
+		// Prepare the interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.afterPropertiesSet();
+
+		// Execute the interceptor
+		interceptor.preHandleAction(request, response, null);
+		interceptor.afterActionCompletion(request, response, null, null);
+
+		// Check the session is null
+		assertNull(request.getPortletSession(false));
+	}
+
+	public void testPortletSessionWithNonContextInWellKnownLocationIsOverwritten()
+			throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+		request.getPortletSession().setAttribute(
+				PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY,
+				"NOT_A_CONTEXT_OBJECT", PortletSession.APPLICATION_SCOPE);
+
+		// Prepare the interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.afterPropertiesSet();
+
+		// Execute the interceptor
+		interceptor.preHandleAction(request, response, null);
+		PortletAuthenticationToken principal = PortletTestUtils.createAuthenticatedToken();
+		SecurityContextHolder.getContext().setAuthentication(principal);
+		interceptor.afterActionCompletion(request, response, null, null);
+
+		// Verify Authentication is in the PortletSession
+		SecurityContext sc = (SecurityContext)request.getPortletSession(false).
+				getAttribute(PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY, PortletSession.APPLICATION_SCOPE);
+		assertEquals(principal, ((SecurityContext)sc).getAuthentication());
+	}
+
+	public void testPortletSessionCreationNotAllowed() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+
+		// Prepare the interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.setAllowSessionCreation(false); // non-default
+		interceptor.afterPropertiesSet();
+
+		// Execute the interceptor
+		interceptor.preHandleAction(request, response, null);
+		PortletAuthenticationToken principal = PortletTestUtils.createAuthenticatedToken();
+		SecurityContextHolder.getContext().setAuthentication(principal);
+		interceptor.afterActionCompletion(request, response, null, null);
+
+		// Check the session is null
+		assertNull(request.getPortletSession(false));
+	}
+
+	public void testUsePortletScopeSession() throws Exception {
+
+		// Build an Authentication object we simulate came from PortletSession
+		PortletAuthenticationToken sessionPrincipal = PortletTestUtils.createAuthenticatedToken();
+		PortletAuthenticationToken baselinePrincipal = PortletTestUtils.createAuthenticatedToken();
+
+		// Build a Context to store in PortletSession (simulating prior request)
+		SecurityContext sc = new SecurityContextImpl();
+		sc.setAuthentication(sessionPrincipal);
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+		request.getPortletSession().setAttribute(
+				PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY,
+				sc, PortletSession.PORTLET_SCOPE);
+
+		// Prepare interceptor
+		PortletSessionContextIntegrationInterceptor interceptor = new PortletSessionContextIntegrationInterceptor();
+		interceptor.setUseApplicationScopePortletSession(false); // non-default
+		interceptor.afterPropertiesSet();
+
+		// Run preHandleAction phase and verify SecurityContextHolder contains our Authentication
+		interceptor.preHandleAction(request, response, null);
+		assertEquals(baselinePrincipal, SecurityContextHolder.getContext().getAuthentication());
+
+		// Perform updates to principal
+		sessionPrincipal = PortletTestUtils.createAuthenticatedToken(
+				new User(PortletTestUtils.TESTUSER, PortletTestUtils.TESTCRED, true, true, true, true,
+						new GrantedAuthority[] {new GrantedAuthorityImpl("UPDATEDROLE1")}));
+		baselinePrincipal = PortletTestUtils.createAuthenticatedToken(
+				new User(PortletTestUtils.TESTUSER, PortletTestUtils.TESTCRED, true, true, true, true,
+						new GrantedAuthority[] {new GrantedAuthorityImpl("UPDATEDROLE1")}));
+
+		// Store updated principal into SecurityContextHolder
+		SecurityContextHolder.getContext().setAuthentication(sessionPrincipal);
+
+		// Run afterActionCompletion phase and verify the SecurityContextHolder is empty
+		interceptor.afterActionCompletion(request, response, null, null);
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+
+		// Verify the new principal is stored in the session
+		sc = (SecurityContext)request.getPortletSession().getAttribute(
+				PortletSessionContextIntegrationInterceptor.ACEGI_SECURITY_CONTEXT_KEY,
+				PortletSession.PORTLET_SCOPE);
+		assertEquals(baselinePrincipal, sc.getAuthentication());
+	}
+
+
+}

+ 117 - 0
sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/PortletAuthenticationProviderTests.java

@@ -0,0 +1,117 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.providers.portlet;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.Authentication;
+import org.acegisecurity.AuthenticationException;
+import org.acegisecurity.BadCredentialsException;
+import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+import org.acegisecurity.userdetails.UserDetails;
+
+/**
+ * Tests {@link PortletAuthenticationProvider}
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class PortletAuthenticationProviderTests extends TestCase {
+
+	//~ Constructors ===================================================================================================
+
+	public PortletAuthenticationProviderTests() {
+		super();
+	}
+
+	public PortletAuthenticationProviderTests(String arg0) {
+		super(arg0);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public void testRequiresPopulator() throws Exception {
+		PortletAuthenticationProvider provider = new PortletAuthenticationProvider();
+		try {
+			provider.afterPropertiesSet();
+			fail("Should have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException failed) {
+			//ignored
+		}
+	}
+
+	public void testNormalOperation() throws Exception {
+		PortletAuthenticationProvider provider = new PortletAuthenticationProvider();
+		provider.setPortletAuthoritiesPopulator(new MockAuthoritiesPopulator(false));
+		provider.afterPropertiesSet();
+		Authentication result = provider.authenticate(PortletTestUtils.createToken());
+		assertNotNull(result);
+		assertNotNull(result.getAuthorities());
+	}
+
+	public void testAuthenticationIsNullWithUnsupportedToken() {
+		PortletAuthenticationProvider provider = new PortletAuthenticationProvider();
+		Authentication request = new UsernamePasswordAuthenticationToken(PortletTestUtils.TESTUSER, PortletTestUtils.TESTCRED);
+		Authentication result = provider.authenticate(request);
+		assertNull(result);
+	}
+
+	public void testFailsWithNoCredentials() {
+		PortletAuthenticationProvider provider = new PortletAuthenticationProvider();
+		provider.setPortletAuthoritiesPopulator(new MockAuthoritiesPopulator(false));
+		try {
+			provider.authenticate(new PortletAuthenticationToken(PortletTestUtils.TESTUSER, null, null));
+			fail("Should have thrown BadCredentialsException");
+		} catch (BadCredentialsException e) {
+			//ignore
+		}
+	}
+
+	public void testPopulatorRejectionCausesFailure() throws Exception {
+		PortletAuthenticationProvider provider = new PortletAuthenticationProvider();
+		provider.setPortletAuthoritiesPopulator(new MockAuthoritiesPopulator(true));
+		try {
+			provider.authenticate(PortletTestUtils.createToken());
+			fail("Should have thrown BadCredentialsException");
+		} catch (BadCredentialsException e) {
+			//ignore
+		}
+	}
+
+	//~ Inner Classes ==================================================================================================
+
+	public static class MockAuthoritiesPopulator implements PortletAuthoritiesPopulator {
+
+		private boolean reject = false;
+
+		public MockAuthoritiesPopulator (boolean reject) {
+			this.reject = reject;
+		}
+
+		public UserDetails getUserDetails(Authentication authentication)
+			throws AuthenticationException {
+			if (authentication.getCredentials() == null)
+				throw new BadCredentialsException("Invalid Credentials");
+			if (reject)
+				throw new BadCredentialsException("Authentication Rejected");
+			return PortletTestUtils.createUser();
+		}
+
+	}
+
+}

+ 63 - 0
sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/PortletAuthenticationTokenTests.java

@@ -0,0 +1,63 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.providers.portlet;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link PortletAuthenticationToken}.
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class PortletAuthenticationTokenTests extends TestCase {
+
+	//~ Constructors ===================================================================================================
+
+	public PortletAuthenticationTokenTests() {}
+
+	public PortletAuthenticationTokenTests(String s) {
+		super(s);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public void setUp() throws Exception {
+		super.setUp();
+	}
+
+	public void testPrincipal() throws Exception {
+		PortletAuthenticationToken token = PortletTestUtils.createToken();
+		assertEquals(PortletTestUtils.TESTUSER, token.getPrincipal());
+	}
+
+	public void testCredentials() throws Exception {
+		PortletAuthenticationToken token = PortletTestUtils.createToken();
+		assertEquals(PortletTestUtils.TESTCRED, token.getCredentials());
+	}
+
+	public void testAuthenticated() throws Exception {
+		PortletAuthenticationToken token = PortletTestUtils.createToken();
+		assertTrue(!token.isAuthenticated());
+		token.setAuthenticated(true);
+		assertTrue(token.isAuthenticated());
+		token.setAuthenticated(false);
+		assertTrue(!token.isAuthenticated());
+	}
+
+}

+ 128 - 0
sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/PortletTestUtils.java

@@ -0,0 +1,128 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.providers.portlet;
+
+import javax.portlet.PortletRequest;
+
+import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.context.SecurityContext;
+import org.acegisecurity.context.SecurityContextHolder;
+import org.acegisecurity.context.SecurityContextImpl;
+import org.acegisecurity.providers.TestingAuthenticationToken;
+import org.acegisecurity.userdetails.User;
+import org.acegisecurity.userdetails.UserDetails;
+import org.springframework.mock.web.portlet.MockActionRequest;
+import org.springframework.mock.web.portlet.MockActionResponse;
+import org.springframework.mock.web.portlet.MockPortletRequest;
+import org.springframework.mock.web.portlet.MockRenderRequest;
+import org.springframework.mock.web.portlet.MockRenderResponse;
+
+/**
+ * Utilities for testing Portlet (JSR 168) based security.
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class PortletTestUtils {
+
+	//~ Static fields/initializers =====================================================================================
+
+	public static final String PORTALROLE1 = "ONE";
+	public static final String PORTALROLE2 = "TWO";
+
+	public static final String TESTUSER = "testuser";
+	public static final String TESTCRED = PortletRequest.FORM_AUTH;
+	public static final String TESTROLE1 = "ROLE_" + PORTALROLE1;
+	public static final String TESTROLE2 = "ROLE_" + PORTALROLE2;
+
+	//~ Methods ========================================================================================================
+
+	public static UserDetails createUser() {
+		return new User(PortletTestUtils.TESTUSER, PortletTestUtils.TESTCRED, true, true, true, true,
+			new GrantedAuthority[] {new GrantedAuthorityImpl(TESTROLE1), new GrantedAuthorityImpl(TESTROLE2)});
+	}
+
+    public static void applyPortletRequestSecurity(MockPortletRequest request) {
+		request.setRemoteUser(TESTUSER);
+		request.setUserPrincipal(new TestingAuthenticationToken(TESTUSER, TESTCRED, null));
+		request.addUserRole(PORTALROLE1);
+		request.addUserRole(PORTALROLE2);
+		request.setAuthType(PortletRequest.FORM_AUTH);
+    }
+
+    public static MockRenderRequest createRenderRequest() {
+		MockRenderRequest request = new MockRenderRequest();
+		applyPortletRequestSecurity(request);
+		return request;
+    }
+
+    public static MockRenderResponse createRenderResponse() {
+		MockRenderResponse response = new MockRenderResponse();
+		return response;
+    }
+
+    public static MockActionRequest createActionRequest() {
+    	MockActionRequest request = new MockActionRequest();
+		applyPortletRequestSecurity(request);
+		return request;
+    }
+
+    public static MockActionResponse createActionResponse() {
+    	MockActionResponse response = new MockActionResponse();
+		return response;
+    }
+
+	public static PortletAuthenticationToken createToken(PortletRequest request) {
+		PortletAuthenticationToken token = new PortletAuthenticationToken(TESTUSER, TESTCRED, null);
+		token.setDetails(request);
+		return token;
+	}
+
+	public static PortletAuthenticationToken createToken() {
+		MockRenderRequest request = createRenderRequest();
+		return createToken(request);
+	}
+
+	public static PortletAuthenticationToken createAuthenticatedToken(UserDetails user) {
+		PortletAuthenticationToken result = new PortletAuthenticationToken(
+				user, user.getPassword(), user.getAuthorities());
+		result.setAuthenticated(true);
+		return result;
+	}
+	public static PortletAuthenticationToken createAuthenticatedToken() {
+		return createAuthenticatedToken(createUser());
+	}
+
+    public static void setupSecurityContext(PortletRequest request) {
+		PortletAuthenticationToken token = createToken(request);
+		SecurityContext context = new SecurityContextImpl();
+		context.setAuthentication(token);
+		SecurityContextHolder.setContext(context);
+    }
+
+    public static void setupSecurityContext() {
+		MockRenderRequest request = createRenderRequest();
+		setupSecurityContext(request);
+    }
+
+    public static void cleanupSecurityContext() {
+		SecurityContextHolder.clearContext();
+    }
+
+}

+ 90 - 0
sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/cache/EhCacheBasedUserCacheTests.java

@@ -0,0 +1,90 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.providers.portlet.cache;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+import net.sf.ehcache.Cache;
+
+import org.acegisecurity.providers.portlet.PortletTestUtils;
+import org.springframework.cache.ehcache.EhCacheFactoryBean;
+
+/**
+ * Tests for {@link EhCacheBasedPortletUserCache}.
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class EhCacheBasedUserCacheTests extends TestCase {
+
+	//~ Static fields/initializers =====================================================================================
+
+	private static EhCacheFactoryBean cacheFactory;
+
+	static {
+		cacheFactory = new EhCacheFactoryBean();
+		cacheFactory.setCacheName("portletUserCache");
+		try {
+			cacheFactory.afterPropertiesSet();
+		} catch (IOException e) {
+			throw new RuntimeException("unable to initialize cache factory", e);
+		}
+	}
+
+	//~ Constructors ===================================================================================================
+
+	public EhCacheBasedUserCacheTests() {
+		super();
+	}
+
+	public EhCacheBasedUserCacheTests(String arg0) {
+		super(arg0);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public final void setUp() throws Exception {
+		super.setUp();
+	}
+
+	private Cache getCache() {
+		return (Cache)cacheFactory.getObject();
+	}
+
+	public void testCacheOperation() throws Exception {
+
+		// Create the cache
+		EhCacheBasedUserCache cache = new EhCacheBasedUserCache();
+		cache.setCache(getCache());
+		cache.afterPropertiesSet();
+
+		// Check it gets stored in the cache
+		cache.putUserInCache(PortletTestUtils.createUser());
+		assertEquals(PortletTestUtils.TESTCRED,
+				cache.getUserFromCache(PortletTestUtils.TESTUSER).getPassword());
+
+		// Check it gets removed from the cache
+		cache.removeUserFromCache(PortletTestUtils.TESTUSER);
+		assertNull(cache.getUserFromCache(PortletTestUtils.TESTUSER));
+
+		// Check it doesn't return values for null user
+		assertNull(cache.getUserFromCache(null));
+	}
+
+}

+ 127 - 0
sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/populator/ContainerPortletAuthoritiesPopulatorTests.java

@@ -0,0 +1,127 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.providers.portlet.populator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.AuthenticationServiceException;
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.providers.portlet.PortletAuthenticationToken;
+import org.acegisecurity.providers.portlet.PortletTestUtils;
+import org.acegisecurity.userdetails.UserDetails;
+
+
+/**
+ * Tests for {@link ContainerPortletAuthoritiesPopulator}
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class ContainerPortletAuthoritiesPopulatorTests extends TestCase {
+
+	//~ Constructors ===================================================================================================
+
+	public ContainerPortletAuthoritiesPopulatorTests() {
+		super();
+	}
+
+	public ContainerPortletAuthoritiesPopulatorTests(String arg0) {
+		super(arg0);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public final void setUp() throws Exception {
+		super.setUp();
+	}
+
+	private List createRolesToCheck() {
+		ArrayList rolesToCheck = new ArrayList();
+		rolesToCheck.add(PortletTestUtils.PORTALROLE1);
+		rolesToCheck.add("BOGUS1");
+		rolesToCheck.add(PortletTestUtils.PORTALROLE2);
+		rolesToCheck.add("BOGUS2");
+		return rolesToCheck;
+	}
+
+	public void testGetGrantedAuthorities() throws Exception {
+		ContainerPortletAuthoritiesPopulator populator = new ContainerPortletAuthoritiesPopulator();
+		UserDetails results = populator.getUserDetails(PortletTestUtils.createToken());
+		assertEquals(1, results.getAuthorities().length);
+		assertEquals(new GrantedAuthorityImpl(ContainerPortletAuthoritiesPopulator.DEFAULT_USER_ROLE), results.getAuthorities()[0]);
+	}
+
+	public void testGetGrantedAuthoritiesCheckRoles() throws Exception {
+		ContainerPortletAuthoritiesPopulator populator = new ContainerPortletAuthoritiesPopulator();
+		populator.setRolesToCheck(createRolesToCheck());
+		UserDetails results = populator.getUserDetails(PortletTestUtils.createToken());
+		assertEquals(3, results.getAuthorities().length);
+		assertEquals(new GrantedAuthorityImpl(ContainerPortletAuthoritiesPopulator.DEFAULT_USER_ROLE), results.getAuthorities()[0]);
+		assertEquals(new GrantedAuthorityImpl(PortletTestUtils.TESTROLE1), results.getAuthorities()[1]);
+		assertEquals(new GrantedAuthorityImpl(PortletTestUtils.TESTROLE2), results.getAuthorities()[2]);
+	}
+
+	public void testGetGrantedAuthoritiesCustomPrefix() throws Exception {
+		String prefix = "IHAVE_";
+		ContainerPortletAuthoritiesPopulator populator = new ContainerPortletAuthoritiesPopulator();
+		populator.setRolesToCheck(createRolesToCheck());
+		populator.setRolePrefix(prefix);
+		UserDetails results = populator.getUserDetails(PortletTestUtils.createToken());
+		assertEquals(3, results.getAuthorities().length);
+		assertEquals(new GrantedAuthorityImpl(ContainerPortletAuthoritiesPopulator.DEFAULT_USER_ROLE), results.getAuthorities()[0]);
+		assertEquals(new GrantedAuthorityImpl(prefix + PortletTestUtils.PORTALROLE1), results.getAuthorities()[1]);
+		assertEquals(new GrantedAuthorityImpl(prefix + PortletTestUtils.PORTALROLE2), results.getAuthorities()[2]);
+	}
+
+	public void testGetGrantedAuthoritiesNullDefault() throws Exception {
+		ContainerPortletAuthoritiesPopulator populator = new ContainerPortletAuthoritiesPopulator();
+		populator.setUserRole(null);
+		UserDetails results = populator.getUserDetails(PortletTestUtils.createToken());
+		assertEquals(0, results.getAuthorities().length);
+	}
+
+	public void testGetGrantedAuthoritiesEmptyDefault() throws Exception {
+		ContainerPortletAuthoritiesPopulator populator = new ContainerPortletAuthoritiesPopulator();
+		populator.setUserRole("");
+		UserDetails results = populator.getUserDetails(PortletTestUtils.createToken());
+		assertEquals(0, results.getAuthorities().length);
+	}
+
+	public void testGetGrantedAuthoritiesForInvalidToken() throws Exception {
+		ContainerPortletAuthoritiesPopulator populator = new ContainerPortletAuthoritiesPopulator();
+		PortletAuthenticationToken token = PortletTestUtils.createToken();
+		token.setDetails(null);
+		try {
+			populator.getUserDetails(token);
+			fail("Should have thrown AuthenticationServiceException");
+		} catch (AuthenticationServiceException e) {
+			// ignore
+		}
+		token.setDetails("bogus");
+		try {
+			populator.getUserDetails(token);
+			fail("Should have thrown AuthenticationServiceException");
+		} catch (AuthenticationServiceException e) {
+			// ignore
+		}
+	}
+
+}

+ 100 - 0
sandbox/portlet/src/test/java/org/acegisecurity/providers/portlet/populator/DaoPortletAuthoritiesPopulatorTests.java

@@ -0,0 +1,100 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.providers.portlet.populator;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.providers.portlet.PortletAuthenticationToken;
+import org.acegisecurity.providers.portlet.PortletTestUtils;
+import org.acegisecurity.userdetails.UserDetails;
+import org.acegisecurity.userdetails.UserDetailsService;
+import org.acegisecurity.userdetails.UsernameNotFoundException;
+import org.springframework.dao.DataAccessException;
+
+
+/**
+ * Tests for {@link DaoPortletAuthoritiesPopulator}
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class DaoPortletAuthoritiesPopulatorTests extends TestCase {
+
+	//~ Constructors ===================================================================================================
+
+	public DaoPortletAuthoritiesPopulatorTests() {
+		super();
+	}
+
+	public DaoPortletAuthoritiesPopulatorTests(String arg0) {
+		super(arg0);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public final void setUp() throws Exception {
+		super.setUp();
+	}
+
+	public void testRequiresDao() throws Exception {
+		DaoPortletAuthoritiesPopulator populator = new DaoPortletAuthoritiesPopulator();
+		try {
+			populator.afterPropertiesSet();
+			fail("Should have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException failed) {
+			// ignored
+		}
+	}
+
+	public void testGetGrantedAuthoritiesForValidUser() throws Exception {
+		DaoPortletAuthoritiesPopulator populator = new DaoPortletAuthoritiesPopulator();
+		populator.setUserDetailsService(new MockAuthenticationDao());
+		populator.afterPropertiesSet();
+		UserDetails results = populator.getUserDetails(PortletTestUtils.createToken());
+		assertEquals(2, results.getAuthorities().length);
+		assertEquals(new GrantedAuthorityImpl(PortletTestUtils.TESTROLE1), results.getAuthorities()[0]);
+		assertEquals(new GrantedAuthorityImpl(PortletTestUtils.TESTROLE2), results.getAuthorities()[1]);
+	}
+
+	public void testGetGrantedAuthoritiesForInvalidUser() throws Exception {
+		DaoPortletAuthoritiesPopulator populator = new DaoPortletAuthoritiesPopulator();
+		populator.setUserDetailsService(new MockAuthenticationDao());
+		populator.afterPropertiesSet();
+		try {
+			populator.getUserDetails(new PortletAuthenticationToken("dummy", "dummy", null));
+			fail("Should have thrown UsernameNotFoundException");
+		} catch (UsernameNotFoundException e) {
+			// ignore
+		}
+	}
+
+	//~ Inner Classes ==================================================================================================
+
+	private class MockAuthenticationDao implements UserDetailsService {
+
+		public UserDetails loadUserByUsername(String username)
+			throws UsernameNotFoundException, DataAccessException {
+			if (PortletTestUtils.TESTUSER.equals(username))
+				return PortletTestUtils.createUser();
+			throw new UsernameNotFoundException("Could not find: " + username);
+		}
+
+	}
+
+}

+ 60 - 0
sandbox/portlet/src/test/java/org/acegisecurity/ui/portlet/PortletProcessingFilterEntryPointTests.java

@@ -0,0 +1,60 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.ui.portlet;
+
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.BadCredentialsException;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+/**
+ * Tests {@link PortletProcessingFilterEntryPoint}.
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class PortletProcessingFilterEntryPointTests extends TestCase {
+
+	//~ Constructors ===================================================================================================
+
+	public PortletProcessingFilterEntryPointTests() {
+		super();
+	}
+
+	public PortletProcessingFilterEntryPointTests(String arg0) {
+		super(arg0);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public final void setUp() throws Exception {
+		super.setUp();
+	}
+
+	public void testNormalOperation() throws Exception {
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		PortletProcessingFilterEntryPoint entryPoint = new PortletProcessingFilterEntryPoint();
+		entryPoint.commence(request, response, new BadCredentialsException(null));
+		assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus());
+	}
+
+}

+ 284 - 0
sandbox/portlet/src/test/java/org/acegisecurity/ui/portlet/PortletProcessingInterceptorTests.java

@@ -0,0 +1,284 @@
+/*
+ * Copyright 2005-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.acegisecurity.ui.portlet;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.Authentication;
+import org.acegisecurity.AuthenticationManager;
+import org.acegisecurity.BadCredentialsException;
+import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.context.SecurityContextHolder;
+import org.acegisecurity.providers.TestingAuthenticationToken;
+import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+import org.acegisecurity.providers.portlet.PortletAuthenticationToken;
+import org.acegisecurity.providers.portlet.PortletTestUtils;
+import org.acegisecurity.ui.AbstractProcessingFilter;
+import org.acegisecurity.userdetails.User;
+import org.springframework.mock.web.portlet.MockActionRequest;
+import org.springframework.mock.web.portlet.MockActionResponse;
+import org.springframework.mock.web.portlet.MockRenderRequest;
+import org.springframework.mock.web.portlet.MockRenderResponse;
+
+/**
+ * Tests {@link PortletProcessingInterceptor}.
+ *
+ * @author John A. Lewis
+ * @since 2.0
+ * @version $Id$
+ */
+public class PortletProcessingInterceptorTests extends TestCase {
+
+	//~ Constructors ===================================================================================================
+
+	public PortletProcessingInterceptorTests() {
+		super();
+	}
+
+	public PortletProcessingInterceptorTests(String arg0) {
+		super(arg0);
+	}
+
+	//~ Methods ========================================================================================================
+
+	public void setUp() throws Exception {
+		super.setUp();
+		SecurityContextHolder.clearContext();
+	}
+
+	public void tearDown() throws Exception {
+		super.tearDown();
+		SecurityContextHolder.clearContext();
+	}
+
+	public void testRequiresAuthenticationManager() throws Exception {
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		try {
+			interceptor.afterPropertiesSet();
+			fail("Expected IllegalArgumentException");
+		} catch (IllegalArgumentException e) {
+			// ignored
+		}
+	}
+
+	public void testNormalRenderRequestProcessing() throws Exception {
+
+		// Build mock request and response
+		MockRenderRequest request = PortletTestUtils.createRenderRequest();
+		MockRenderResponse response = PortletTestUtils.createRenderResponse();
+
+		// Prepare interceptor
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		interceptor.setAuthenticationManager(new MockPortletAuthenticationManager());
+		interceptor.afterPropertiesSet();
+
+		// Execute preHandlerRender phase and verify results
+		interceptor.preHandleRender(request, response, null);
+		assertEquals(PortletTestUtils.createAuthenticatedToken(),
+				SecurityContextHolder.getContext().getAuthentication());
+
+		// Execute postHandlerRender phase and verify nothing changed
+		interceptor.postHandleRender(request, response, null, null);
+		assertEquals(PortletTestUtils.createAuthenticatedToken(),
+				SecurityContextHolder.getContext().getAuthentication());
+
+		// Execute afterRenderCompletion phase and verify nothing changed
+		interceptor.afterRenderCompletion(request, response, null, null);
+		assertEquals(PortletTestUtils.createAuthenticatedToken(),
+				SecurityContextHolder.getContext().getAuthentication());
+	}
+
+	public void testNormalActionRequestProcessing() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+
+		// Prepare interceptor
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		interceptor.setAuthenticationManager(new MockPortletAuthenticationManager());
+		interceptor.afterPropertiesSet();
+
+		// Execute preHandlerAction phase and verify results
+		interceptor.preHandleAction(request, response, null);
+		assertEquals(PortletTestUtils.createAuthenticatedToken(),
+				SecurityContextHolder.getContext().getAuthentication());
+
+		// Execute afterActionCompletion phase and verify nothing changed
+		interceptor.afterActionCompletion(request, response, null, null);
+		assertEquals(PortletTestUtils.createAuthenticatedToken(),
+				SecurityContextHolder.getContext().getAuthentication());
+	}
+
+	public void testAuthenticationFailsWithNoCredentials()
+		throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = new MockActionRequest();
+		MockActionResponse response = new MockActionResponse();
+
+		// Prepare and execute interceptor
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		interceptor.setAuthenticationManager(new MockPortletAuthenticationManager());
+		interceptor.afterPropertiesSet();
+		interceptor.preHandleAction(request, response, null);
+
+		// Verify that authentication is empty
+		assertNull(SecurityContextHolder.getContext().getAuthentication());
+
+		// Verify that proper exception was thrown
+		assertTrue(request.getPortletSession().getAttribute(
+					AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
+					PortletSession.APPLICATION_SCOPE)
+					instanceof BadCredentialsException);
+	}
+
+	public void testExistingAuthenticationIsLeftAlone() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = PortletTestUtils.createActionRequest();
+		MockActionResponse response = PortletTestUtils.createActionResponse();
+
+		// Prepare interceptor
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		interceptor.setAuthenticationManager(new MockPortletAuthenticationManager());
+		interceptor.afterPropertiesSet();
+
+		UsernamePasswordAuthenticationToken testingToken = new UsernamePasswordAuthenticationToken("dummy", "dummy", null);
+		UsernamePasswordAuthenticationToken baselineToken = new UsernamePasswordAuthenticationToken("dummy", "dummy", null);
+		SecurityContextHolder.getContext().setAuthentication(testingToken);
+
+		// Execute preHandlerAction phase and verify results
+		interceptor.preHandleAction(request, response, null);
+		assertTrue(SecurityContextHolder.getContext().getAuthentication() == testingToken);
+		assertEquals(baselineToken, SecurityContextHolder.getContext().getAuthentication());
+
+		// Execute afterActionCompletion phase and verify nothing changed
+		interceptor.afterActionCompletion(request, response, null, null);
+		assertTrue(SecurityContextHolder.getContext().getAuthentication() == testingToken);
+		assertEquals(baselineToken, SecurityContextHolder.getContext().getAuthentication());
+	}
+
+	public void testUsernameFromRemoteUser() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = new MockActionRequest();
+		MockActionResponse response = new MockActionResponse();
+		request.setRemoteUser(PortletTestUtils.TESTUSER);
+		request.setAuthType(PortletRequest.FORM_AUTH);
+
+		// Prepare and execute interceptor
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		interceptor.setAuthenticationManager(new MockPortletAuthenticationManager());
+		interceptor.afterPropertiesSet();
+		interceptor.preHandleAction(request, response, null);
+
+		// Verify username
+		assertEquals(PortletTestUtils.TESTUSER,
+				SecurityContextHolder.getContext().getAuthentication().getName());
+	}
+
+	public void testUsernameFromPrincipal() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = new MockActionRequest();
+		MockActionResponse response = new MockActionResponse();
+		request.setUserPrincipal(new TestingAuthenticationToken(PortletTestUtils.TESTUSER, PortletTestUtils.TESTCRED, null));
+		request.setAuthType(PortletRequest.FORM_AUTH);
+
+		// Prepare and execute interceptor
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		interceptor.setAuthenticationManager(new MockPortletAuthenticationManager());
+		interceptor.afterPropertiesSet();
+		interceptor.preHandleAction(request, response, null);
+
+		// Verify username
+		assertEquals(PortletTestUtils.TESTUSER,
+				SecurityContextHolder.getContext().getAuthentication().getName());
+	}
+
+	public void testUsernameFromUserInfo() throws Exception {
+
+		// Build mock request and response
+		MockActionRequest request = new MockActionRequest();
+		MockActionResponse response = new MockActionResponse();
+		HashMap userInfo = new HashMap();
+		userInfo.put("user.name.given", "Test");
+		userInfo.put("user.name.family", "User");
+		userInfo.put("user.id", "mytestuser");
+		request.setAttribute(PortletRequest.USER_INFO, userInfo);
+		request.setAuthType(PortletRequest.FORM_AUTH);
+
+		// Prepare and execute interceptor
+		PortletProcessingInterceptor interceptor = new PortletProcessingInterceptor();
+		interceptor.setAuthenticationManager(new MockPortletAuthenticationManager());
+		ArrayList userNameAttributes = new ArrayList();
+		userNameAttributes.add("user.name");
+		userNameAttributes.add("user.id");
+		interceptor.setUserNameAttributes(userNameAttributes);
+		interceptor.afterPropertiesSet();
+		interceptor.preHandleAction(request, response, null);
+
+		// Verify username
+		assertEquals("mytestuser", SecurityContextHolder.getContext().getAuthentication().getName());
+	}
+
+	//~ Inner Classes ==================================================================================================
+
+	private static class MockPortletAuthenticationManager implements AuthenticationManager {
+
+		public Authentication authenticate(Authentication token) {
+
+			// Make sure we got a valid token
+			if (!(token instanceof PortletAuthenticationToken)) {
+				TestCase.fail("Expected PortletAuthentication object-- got: " + token);
+			}
+
+			// Make sure the token details are the PortletRequest
+			if (!(token.getDetails() instanceof PortletRequest)) {
+				TestCase.fail("Expected Authentication.getDetails to be a PortletRequest object -- got: " + token.getDetails());
+			}
+
+			// Make sure it's got a principal
+			if (token.getPrincipal() == null) {
+				throw new BadCredentialsException("Mock authentication manager rejecting null principal");
+			}
+
+			// Make sure it's got credentials
+			if (token.getCredentials() == null) {
+				throw new BadCredentialsException("Mock authentication manager rejecting null credentials");
+			}
+
+			// create resulting Authentication object
+			User user = new User(token.getName(), token.getCredentials().toString(), true, true, true, true,
+					new GrantedAuthority[] {new GrantedAuthorityImpl(PortletTestUtils.TESTROLE1), new GrantedAuthorityImpl(PortletTestUtils.TESTROLE2)});
+			PortletAuthenticationToken result = new PortletAuthenticationToken(
+					user, user.getPassword(), user.getAuthorities());
+			result.setAuthenticated(true);
+			return result;
+		}
+
+	}
+
+}