Browse Source

implemented unit tests for portlet support

John Lewis 18 năm trước cách đây
mục cha
commit
8396f04ae6
15 tập tin đã thay đổi với 1410 bổ sung54 xóa
  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;
+		}
+
+	}
+
+}