Browse Source

SEC-576: Committed pre-autheticated contribution. Still has to be more thoroughly reviewed.

Luke Taylor 17 năm trước cách đây
mục cha
commit
c8b9f24038
32 tập tin đã thay đổi với 2116 bổ sung0 xóa
  1. 6 0
      core/pom.xml
  2. 90 0
      core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProvider.java
  3. 70 0
      core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationToken.java
  4. 15 0
      core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesRetriever.java
  5. 18 0
      core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesSetter.java
  6. 44 0
      core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsService.java
  7. 24 0
      core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedUserDetailsService.java
  8. 45 0
      core/src/main/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapper.java
  9. 16 0
      core/src/main/java/org/springframework/security/rolemapping/MappableRolesRetriever.java
  10. 22 0
      core/src/main/java/org/springframework/security/rolemapping/Roles2GrantedAuthoritiesMapper.java
  11. 30 0
      core/src/main/java/org/springframework/security/rolemapping/SimpleMappableRolesRetriever.java
  12. 105 0
      core/src/main/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapper.java
  13. 181 0
      core/src/main/java/org/springframework/security/rolemapping/XmlMappableRolesRetriever.java
  14. 176 0
      core/src/main/java/org/springframework/security/ui/preauth/AbstractPreAuthenticatedProcessingFilter.java
  15. 58 0
      core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.java
  16. 66 0
      core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPoint.java
  17. 101 0
      core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.java
  18. 36 0
      core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java
  19. 52 0
      core/src/main/java/org/springframework/security/ui/preauth/j2ee/WebXmlMappableRolesRetriever.java
  20. 102 0
      core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProviderTests.java
  21. 57 0
      core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationTokenTests.java
  22. 79 0
      core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsServiceTests.java
  23. 51 0
      core/src/test/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapperTests.java
  24. 26 0
      core/src/test/java/org/springframework/security/rolemapping/SimpleMappableRolesRetrieverTests.java
  25. 121 0
      core/src/test/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapperTests.java
  26. 100 0
      core/src/test/java/org/springframework/security/rolemapping/XmlMappableRolesRetrieverTests.java
  27. 72 0
      core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetailsTests.java
  28. 42 0
      core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPointTests.java
  29. 79 0
      core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcessingFilterTests.java
  30. 149 0
      core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSourceTests.java
  31. 49 0
      core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilterTests.java
  32. 34 0
      core/src/test/java/org/springframework/security/ui/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java

+ 6 - 0
core/pom.xml

@@ -82,6 +82,12 @@
             <version>1.2</version>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>jaxen</groupId>
+            <artifactId>jaxen</artifactId>
+            <version>1.1.1</version>
+            <optional>true</optional>
+        </dependency>        
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>jsp-api</artifactId>

+ 90 - 0
core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProvider.java

@@ -0,0 +1,90 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.providers.AuthenticationProvider;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.userdetails.UserDetails;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.Ordered;
+import org.springframework.util.Assert;
+
+/**
+ * <p>
+ * Processes a pre-authenticated authentication request. The request will
+ * typically originate from a {@link AbstractPreAuthenticatedProcessingFilter}
+ * subclass.
+ * </p>
+ * 
+ * <p>
+ * This authentication provider will not perform any checks on authentication
+ * requests, as they should already be pre- authenticated. However, the
+ * PreAuthenticatedUserDetailsService implementation may still throw for exampe
+ * a UsernameNotFoundException.
+ * </p>
+ */
+public class PreAuthenticatedAuthenticationProvider implements AuthenticationProvider, InitializingBean, Ordered {
+	private static final Log LOG = LogFactory.getLog(PreAuthenticatedAuthenticationProvider.class);
+
+	private PreAuthenticatedUserDetailsService preAuthenticatedUserDetailsService = null;
+
+	private int order = -1; // default: same as non-ordered
+
+	/**
+	 * Check whether all required properties have been set.
+	 */
+	public void afterPropertiesSet() {
+		Assert.notNull(preAuthenticatedUserDetailsService, "A PreAuthenticatedUserDetailsService must be set");
+	}
+
+	/**
+	 * Authenticate the given PreAuthenticatedAuthenticationToken.
+	 */
+	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+		if (!supports(authentication.getClass())) {
+			return null;
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("PreAuthenticated authentication request: " + authentication);
+		}
+
+		UserDetails ud = preAuthenticatedUserDetailsService.getUserDetails((PreAuthenticatedAuthenticationToken) authentication);
+		if (ud == null) {
+			return null;
+		}
+		PreAuthenticatedAuthenticationToken result = new PreAuthenticatedAuthenticationToken(ud, authentication.getCredentials(), ud
+				.getAuthorities());
+		result.setDetails(authentication.getDetails());
+
+		return result;
+
+	}
+
+	/**
+	 * Indicate that this provider only supports
+	 * PreAuthenticatedAuthenticationToken (sub)classes.
+	 */
+	public boolean supports(Class authentication) {
+		return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
+	}
+
+	/**
+	 * Set the PreAuthenticatedUserDetailsServices to be used.
+	 * 
+	 * @param aPreAuthenticatedUserDetailsService
+	 */
+	public void setPreAuthenticatedUserDetailsService(PreAuthenticatedUserDetailsService aPreAuthenticatedUserDetailsService) {
+		this.preAuthenticatedUserDetailsService = aPreAuthenticatedUserDetailsService;
+	}
+
+	public int getOrder() {
+		return order;
+	}
+
+	public void setOrder(int i) {
+		order = i;
+	}
+}

+ 70 - 0
core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationToken.java

@@ -0,0 +1,70 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.providers.AbstractAuthenticationToken;
+import org.springframework.security.GrantedAuthority;
+
+
+/**
+ * {@link org.springframework.security.Authentication} implementation for pre-authenticated
+ * authentication.
+ */
+public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationToken {
+	private static final long serialVersionUID = 1L;
+
+	private Object principal;
+
+	private Object credentials;
+
+	/**
+	 * Constructor used for an authentication request. The {@link
+	 * org.springframework.security.Authentication#isAuthenticated()} will return
+	 * <code>false</code>.
+	 * 
+	 * @TODO Should we have only a single credentials parameter here? For
+	 *       example for X509 the certificate is used as credentials, while
+	 *       currently a J2EE username is specified as a principal but could as
+	 *       well be set as credentials.
+	 * 
+	 * @param aPrincipal
+	 *            The pre-authenticated principal
+	 * @param aCredentials
+	 *            The pre-authenticated credentials
+	 */
+	public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials) {
+		super(null);
+		this.principal = aPrincipal;
+		this.credentials = aCredentials;
+	}
+
+	/**
+	 * Constructor used for an authentication response. The {@link
+	 * org.springframework.security.Authentication#isAuthenticated()} will return
+	 * <code>true</code>.
+	 * 
+	 * @param aPrincipal
+	 *            The authenticated principal
+	 * @param anAuthorities
+	 *            The granted authorities
+	 */
+	public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials, GrantedAuthority[] anAuthorities) {
+		super(anAuthorities);
+		this.principal = aPrincipal;
+		this.credentials = aCredentials;
+		setAuthenticated(true);
+	}
+
+	/**
+	 * Get the credentials
+	 */
+	public Object getCredentials() {
+		return this.credentials;
+	}
+
+	/**
+	 * Get the principal
+	 */
+	public Object getPrincipal() {
+		return this.principal;
+	}
+
+}

+ 15 - 0
core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesRetriever.java

@@ -0,0 +1,15 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.GrantedAuthority;
+
+
+/**
+ * Interface that allows for retrieval of a list of pre-authenticated Granted
+ * Authorities.
+ */
+public interface PreAuthenticatedGrantedAuthoritiesRetriever {
+	/**
+	 * @return GrantedAuthority[] List of pre-authenticated GrantedAuthorities
+	 */
+	public GrantedAuthority[] getPreAuthenticatedGrantedAuthorities();
+}

+ 18 - 0
core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesSetter.java

@@ -0,0 +1,18 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.GrantedAuthority;
+
+/**
+ * Counterpart of PreAuthenticatedGrantedAuthoritiesRetriever that allows
+ * setting a list of pre-authenticated GrantedAuthorities. This interface is not
+ * actually being used by the PreAuthenticatedAuthenticationProvider or one of
+ * its related classes, but may be useful for classes that also implement
+ * PreAuthenticatedGrantedAuthoritiesRetriever.
+ */
+public interface PreAuthenticatedGrantedAuthoritiesSetter {
+	/**
+	 * @param aPreAuthenticatedGrantedAuthorities
+	 *            The pre-authenticated GrantedAuthority[] to set
+	 */
+	public void setPreAuthenticatedGrantedAuthorities(GrantedAuthority[] aPreAuthenticatedGrantedAuthorities);
+}

+ 44 - 0
core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsService.java

@@ -0,0 +1,44 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.User;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.AuthenticationException;
+
+import org.springframework.util.Assert;
+
+/**
+ * <p>
+ * This PreAuthenticatedUserDetailsService implementation creates a UserDetails
+ * object based solely on the information contained in the given
+ * PreAuthenticatedAuthenticationToken. The user name is set to the name as
+ * returned by PreAuthenticatedAuthenticationToken.getName(), the password is
+ * set to a fixed dummy value (it will not be used by the
+ * PreAuthenticatedAuthenticationProvider anyway), and the Granted Authorities
+ * are retrieved from the details object as returned by
+ * PreAuthenticatedAuthenticationToken.getDetails().
+ * </p>
+ * 
+ * <p>
+ * The details object as returned by
+ * PreAuthenticatedAuthenticationToken.getDetails() must implement the
+ * PreAuthenticatedGrantedAuthoritiesRetriever interface for this implementation
+ * to work.
+ * </p>
+ */
+public class PreAuthenticatedGrantedAuthoritiesUserDetailsService implements PreAuthenticatedUserDetailsService {
+	/**
+	 * Get a UserDetails object based on the user name contained in the given
+	 * token, and the GrantedAuthorities as returned by the
+	 * PreAuthenticatedGrantedAuthoritiesRetriever implementation as returned by
+	 * the token.getDetails() method.
+	 */
+	public UserDetails getUserDetails(PreAuthenticatedAuthenticationToken token) throws AuthenticationException {
+		Assert.notNull(token.getDetails());
+		Assert.isInstanceOf(PreAuthenticatedGrantedAuthoritiesRetriever.class, token.getDetails());
+		GrantedAuthority[] preAuthenticatedGrantedAuthorities = ((PreAuthenticatedGrantedAuthoritiesRetriever) token.getDetails())
+				.getPreAuthenticatedGrantedAuthorities();
+		UserDetails ud = new User(token.getName(), "N/A", true, true, true, true, preAuthenticatedGrantedAuthorities);
+		return ud;
+	}
+}

+ 24 - 0
core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedUserDetailsService.java

@@ -0,0 +1,24 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.userdetails.UsernameNotFoundException;
+import org.springframework.security.userdetails.UserDetails;
+
+
+/**
+ * Interface that allows for retrieving a UserDetails object based on a
+ * PreAuthenticatedAuthenticationToken object.
+ */
+public interface PreAuthenticatedUserDetailsService {
+
+	/**
+	 * 
+	 * @param aPreAuthenticatedAuthenticationToken
+	 *            The pre-authenticated authentication token
+	 * @return UserDetails for the given authentication token.
+	 * @throws UsernameNotFoundException
+	 *             if no user details can be found for the given authentication
+	 *             token
+	 */
+	public UserDetails getUserDetails(PreAuthenticatedAuthenticationToken aPreAuthenticatedAuthenticationToken)
+			throws UsernameNotFoundException;
+}

+ 45 - 0
core/src/main/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapper.java

@@ -0,0 +1,45 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UserDetailsService;
+import org.springframework.security.userdetails.UsernameNotFoundException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.util.Assert;
+
+/**
+ * This implementation for PreAuthenticatedUserDetailsService wraps a regular
+ * Acegi UserDetailsService implementation, to retrieve a UserDetails object
+ * based on the user name contained in a PreAuthenticatedAuthenticationToken.
+ */
+public class UserDetailsByNameServiceWrapper implements PreAuthenticatedUserDetailsService, InitializingBean {
+	private UserDetailsService userDetailsService = null;
+
+	/**
+	 * Check whether all required properties have been set.
+	 * 
+	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+	 */
+	public void afterPropertiesSet() throws Exception {
+		Assert.notNull(userDetailsService, "UserDetailsService must be set");
+	}
+
+	/**
+	 * Get the UserDetails object from the wrapped UserDetailsService
+	 * implementation
+	 */
+	public UserDetails getUserDetails(PreAuthenticatedAuthenticationToken aJ2eeAuthenticationToken) throws UsernameNotFoundException,
+			DataAccessException {
+		return userDetailsService.loadUserByUsername(aJ2eeAuthenticationToken.getName());
+	}
+
+	/**
+	 * Set the wrapped UserDetailsService implementation
+	 * 
+	 * @param aUserDetailsService
+	 *            The wrapped UserDetailsService to set
+	 */
+	public void setUserDetailsService(UserDetailsService aUserDetailsService) {
+		userDetailsService = aUserDetailsService;
+	}
+}

+ 16 - 0
core/src/main/java/org/springframework/security/rolemapping/MappableRolesRetriever.java

@@ -0,0 +1,16 @@
+package org.springframework.security.rolemapping;
+
+/**
+ * Interface to be implemented by classes that can retrieve a list of mappable
+ * roles (for example the list of all available J2EE roles in a web or EJB
+ * application).
+ */
+public interface MappableRolesRetriever {
+	/**
+	 * Implementations of this method should return a list of all mappable
+	 * roles.
+	 * 
+	 * @return String[] containg list of all mappable roles
+	 */
+	public String[] getMappableRoles();
+}

+ 22 - 0
core/src/main/java/org/springframework/security/rolemapping/Roles2GrantedAuthoritiesMapper.java

@@ -0,0 +1,22 @@
+package org.springframework.security.rolemapping;
+
+import org.springframework.security.GrantedAuthority;
+
+/**
+ * Interface to be implemented by classes that can map a list of roles to a list
+ * of Acegi GrantedAuthorities.
+ */
+public interface Roles2GrantedAuthoritiesMapper {
+	/**
+	 * Implementations of this method should map the given list of roles to a
+	 * list of Acegi GrantedAuthorities. There are no restrictions for the
+	 * mapping process; a single role can be mapped to multiple Acegi
+	 * GrantedAuthorities, all roles can be mapped to a single Acegi
+	 * GrantedAuthority, some roles may not be mapped, etc.
+	 * 
+	 * @param String[]
+	 *            containing list of roles
+	 * @return GrantedAuthority[] containing list of mapped GrantedAuthorities
+	 */
+	public GrantedAuthority[] getGrantedAuthorities(String[] roles);
+}

+ 30 - 0
core/src/main/java/org/springframework/security/rolemapping/SimpleMappableRolesRetriever.java

@@ -0,0 +1,30 @@
+package org.springframework.security.rolemapping;
+
+import org.springframework.util.Assert;
+
+/**
+ * This class implements the MappableRolesRetriever interface by just returning
+ * a list of mappable roles as previously set using the corresponding setter
+ * method.
+ */
+public class SimpleMappableRolesRetriever implements MappableRolesRetriever {
+	private String[] mappableRoles = null;
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.springframework.security.rolemapping.MappableRolesRetriever#getMappableRoles()
+	 */
+	public String[] getMappableRoles() {
+		Assert.notNull(mappableRoles, "No mappable roles have been set");
+		String[] copy = new String[mappableRoles.length];
+		System.arraycopy(mappableRoles, 0, copy, 0, copy.length);
+		return copy;
+	}
+
+	public void setMappableRoles(String[] aMappableRoles) {
+		this.mappableRoles = new String[aMappableRoles.length];
+		System.arraycopy(aMappableRoles, 0, mappableRoles, 0, mappableRoles.length);
+	}
+
+}

+ 105 - 0
core/src/main/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapper.java

@@ -0,0 +1,105 @@
+package org.springframework.security.rolemapping;
+
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+
+import java.util.Locale;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+
+/**
+ * <p>
+ * This class implements the Roles2GrantedAuthoritiesMapper interface by doing a
+ * one-on-one mapping from roles to Acegi GrantedAuthorities. Optionally a
+ * prefix can be added, and the role name can be converted to upper or lower
+ * case.
+ * </p>
+ * 
+ * <p>
+ * By default, the role is prefixed with "ROLE_" unless it already starts with
+ * "ROLE_", and no case conversion is done.
+ * </p>
+ */
+public class SimpleRoles2GrantedAuthoritiesMapper implements Roles2GrantedAuthoritiesMapper, InitializingBean {
+	private String rolePrefix = "ROLE_";
+
+	private boolean convertRoleToUpperCase = false;
+
+	private boolean convertRoleToLowerCase = false;
+
+	private boolean addPrefixIfAlreadyExisting = false;
+
+	/**
+	 * Check whether all properties have been set to correct values.
+	 */
+	public void afterPropertiesSet() throws Exception {
+		Assert.isTrue(!(isConvertRoleToUpperCase() && isConvertRoleToLowerCase()),
+				"Either convertRoleToUpperCase or convertRoleToLowerCase can be set to true, but not both");
+	}
+
+	/**
+	 * Map the given list of roles one-on-one to Acegi GrantedAuthorities.
+	 */
+	public GrantedAuthority[] getGrantedAuthorities(String[] roles) {
+		GrantedAuthority[] result = new GrantedAuthority[roles.length];
+		for (int i = 0; i < roles.length; i++) {
+			result[i] = getGrantedAuthority(roles[i]);
+		}
+		return result;
+	}
+
+	/**
+	 * Map the given role ono-on-one to an Acegi GrantedAuthority, optionally
+	 * doing case conversion and/or adding a prefix.
+	 * 
+	 * @param role
+	 *            The role for which to get a GrantedAuthority
+	 * @return GrantedAuthority representing the given role.
+	 */
+	private GrantedAuthority getGrantedAuthority(String role) {
+		if (isConvertRoleToLowerCase()) {
+			role = role.toLowerCase(Locale.getDefault());
+		} else if (isConvertRoleToUpperCase()) {
+			role = role.toUpperCase(Locale.getDefault());
+		}
+		if (isAddPrefixIfAlreadyExisting() || !role.startsWith(getRolePrefix())) {
+			return new GrantedAuthorityImpl(getRolePrefix() + role);
+		} else {
+			return new GrantedAuthorityImpl(role);
+		}
+	}
+
+	private boolean isConvertRoleToLowerCase() {
+		return convertRoleToLowerCase;
+	}
+
+	public void setConvertRoleToLowerCase(boolean b) {
+		convertRoleToLowerCase = b;
+	}
+
+	private boolean isConvertRoleToUpperCase() {
+		return convertRoleToUpperCase;
+	}
+
+	public void setConvertRoleToUpperCase(boolean b) {
+		convertRoleToUpperCase = b;
+	}
+
+	private String getRolePrefix() {
+		return rolePrefix == null ? "" : rolePrefix;
+	}
+
+	public void setRolePrefix(String string) {
+		rolePrefix = string;
+	}
+
+	private boolean isAddPrefixIfAlreadyExisting() {
+		return addPrefixIfAlreadyExisting;
+	}
+
+	public void setAddPrefixIfAlreadyExisting(boolean b) {
+		addPrefixIfAlreadyExisting = b;
+	}
+
+}

+ 181 - 0
core/src/main/java/org/springframework/security/rolemapping/XmlMappableRolesRetriever.java

@@ -0,0 +1,181 @@
+package org.springframework.security.rolemapping;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jaxen.JaxenException;
+import org.jaxen.dom.DOMXPath;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * This implementation for the MappableRolesRetriever interface retrieves the
+ * list of mappable roles from an XML file.
+ * 
+ * This class is defined as abstract because it is too generic to be used
+ * directly. As this class is usually used to read very specific XML files (e.g.
+ * web.xml, ejb-jar.xml), subclasses should usually define the actual
+ * XPath-expression to use, and define a more specifically named setter for the
+ * XML InputStream (e.g. setWebXmlInputStream).
+ */
+public abstract class XmlMappableRolesRetriever implements MappableRolesRetriever, InitializingBean {
+	private static final Log LOG = LogFactory.getLog(XmlMappableRolesRetriever.class);
+
+	private String[] mappableRoles = null;
+
+	private InputStream xmlInputStream = null;
+
+	private String xpathExpression = null;
+
+	private boolean closeInputStream = true;
+
+	/**
+	 * Check whether all required properties have been set.
+	 */
+	public void afterPropertiesSet() throws Exception {
+		Assert.notNull(xmlInputStream, "An XML InputStream must be set");
+		Assert.notNull(xpathExpression, "An XPath expression must be set");
+		mappableRoles = getMappableRoles(xmlInputStream);
+	}
+
+	public String[] getMappableRoles() {
+		String[] copy = new String[mappableRoles.length];
+		System.arraycopy(mappableRoles, 0, copy, 0, copy.length);
+		return copy;
+	}
+
+	/**
+	 * Get the mappable roles from the specified XML document.
+	 */
+	private String[] getMappableRoles(InputStream aStream) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Reading mappable roles from XML document");
+		}
+		try {
+			Document doc = getDocument(aStream);
+			String[] roles = getMappableRoles(doc);
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("Mappable roles from XML document: " + ArrayUtils.toString(roles));
+			}
+			return roles;
+		} finally {
+			if (closeInputStream) {
+				try {
+					aStream.close();
+				} catch (Exception e) {
+					LOG.debug("Input stream could not be closed", e);
+				}
+			}
+		}
+
+	}
+
+	/**
+	 * @return Document for the specified InputStream
+	 */
+	private Document getDocument(InputStream aStream) {
+		Document doc;
+		try {
+			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+			factory.setValidating(false);
+			DocumentBuilder db = factory.newDocumentBuilder();
+			db.setEntityResolver(new MyEntityResolver());
+			doc = db.parse(new IgnoreCloseInputStream(aStream));
+			return doc;
+		} catch (FactoryConfigurationError e) {
+			throw new RuntimeException("Unable to parse document object", e);
+		} catch (ParserConfigurationException e) {
+			throw new RuntimeException("Unable to parse document object", e);
+		} catch (SAXException e) {
+			throw new RuntimeException("Unable to parse document object", e);
+		} catch (IOException e) {
+			throw new RuntimeException("Unable to parse document object", e);
+		}
+	}
+
+	/**
+	 * @param doc
+	 *            The Document from which to read the list of roles
+	 * @return String[] the list of roles.
+	 * @throws JaxenException
+	 */
+	private String[] getMappableRoles(Document doc) {
+		try {
+			DOMXPath xpath = new DOMXPath(xpathExpression);
+			List roleElements = xpath.selectNodes(doc);
+			String[] roles = new String[roleElements.size()];
+			for (int i = 0; i < roles.length; i++) {
+				roles[i] = ((Node) roleElements.get(i)).getNodeValue();
+			}
+			return roles;
+		} catch (JaxenException e) {
+			throw new RuntimeException("Unable to retrieve mappable roles", e);
+		} catch (DOMException e) {
+			throw new RuntimeException("Unable to retrieve mappable roles", e);
+		}
+	}
+
+	/**
+	 * Subclasses should provide this method with a more specific name (e.g.
+	 * indicating the type of XML file the subclass expects, like
+	 * setWebXmlInputStream).
+	 */
+	protected void setXmlInputStream(InputStream aStream) {
+		this.xmlInputStream = aStream;
+	}
+
+	/**
+	 * Subclasses usually want to set an XPath expression by themselves (e.g.
+	 * not user-configurable). However subclasses may provide configuration
+	 * options to for example choose from a list of predefined XPath expressions
+	 * (e.g. to support multiple versions of the same type of XML file), as such
+	 * we provide a setter instead of mandatory constructor argument.
+	 */
+	protected void setXpathExpression(String anXpathExpression) {
+		xpathExpression = anXpathExpression;
+	}
+
+	/**
+	 * Define whether the provided InputStream must be closed after reading it.
+	 */
+	public void setCloseInputStream(boolean b) {
+		closeInputStream = b;
+	}
+
+	/**
+	 * We do not need to resolve external entities, so just return an empty
+	 * String.
+	 */
+	private static final class MyEntityResolver implements EntityResolver {
+		public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+			return new InputSource(new StringReader(""));
+		}
+	}
+
+	public static final class IgnoreCloseInputStream extends FilterInputStream {
+		public IgnoreCloseInputStream(InputStream stream) {
+			super(stream);
+		}
+
+		public void close() throws IOException {
+			// do nothing
+		}
+	}
+}

+ 176 - 0
core/src/main/java/org/springframework/security/ui/preauth/AbstractPreAuthenticatedProcessingFilter.java

@@ -0,0 +1,176 @@
+package org.springframework.security.ui.preauth;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationToken;
+import org.springframework.security.AuthenticationManager;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.event.authentication.InteractiveAuthenticationSuccessEvent;
+import org.springframework.security.ui.AuthenticationDetailsSource;
+import org.springframework.security.ui.AuthenticationDetailsSourceImpl;
+import org.springframework.security.ui.AbstractProcessingFilter;
+import org.springframework.security.context.SecurityContextHolder;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+import org.springframework.util.Assert;
+
+/**
+ * Base class for processing filters that handle pre-authenticated
+ * authentication requests. Subclasses must implement the
+ * getPreAuthenticatedPrincipal() and getPreAuthenticatedCredentials() methods.
+ * <p>
+ * This code is partly based on
+ * {@link org.springframework.security.ui.x509.X509ProcessingFilter}.
+ * </p>
+ */
+public abstract class AbstractPreAuthenticatedProcessingFilter implements Filter, InitializingBean, ApplicationEventPublisherAware {
+	private static final Log LOG = LogFactory.getLog(AbstractPreAuthenticatedProcessingFilter.class);
+
+	private ApplicationEventPublisher eventPublisher = null;
+
+	private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
+
+	private AuthenticationManager authenticationManager = null;
+
+	/**
+	 * Check whether all required properties have been set.
+	 */
+	public void afterPropertiesSet() throws Exception {
+		Assert.notNull(authenticationManager, "An AuthenticationManager must be set");
+	}
+
+	/**
+	 * Try to authenticate a pre-authenticated user with Acegi if the user has
+	 * not yet been authenticated.
+	 */
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+		if (!(request instanceof HttpServletRequest)) {
+			throw new ServletException("Can only process HttpServletRequest");
+		}
+		if (!(response instanceof HttpServletResponse)) {
+			throw new ServletException("Can only process HttpServletResponse");
+		}
+
+		HttpServletRequest httpRequest = (HttpServletRequest) request;
+		HttpServletResponse httpResponse = (HttpServletResponse) response;
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Checking secure context token: " + SecurityContextHolder.getContext().getAuthentication());
+		}
+
+		if (SecurityContextHolder.getContext().getAuthentication() == null) {
+			doAuthenticate(httpRequest, httpResponse);
+		}
+		filterChain.doFilter(request, response);
+	}
+
+	/**
+	 * Do the actual authentication for a pre-authenticated user.
+	 * 
+	 * @param httpRequest
+	 *            The HttpServletRequest object
+	 * @param httpResponse
+	 *            The HttpServletResponse object
+	 */
+	private void doAuthenticate(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+		Authentication authResult = null;
+
+		Object principal = getPreAuthenticatedPrincipal(httpRequest);
+		Object credentials = getPreAuthenticatedCredentials(httpRequest);
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("AbstractPreAuthenticatedProcessingFilter: preAuthenticatedPrincipal=" + principal + ", trying to authenticate");
+		}
+
+		try {
+			PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken(principal, credentials);
+			authRequest.setDetails(authenticationDetailsSource.buildDetails(httpRequest));
+			authResult = authenticationManager.authenticate(authRequest);
+			successfulAuthentication(httpRequest, httpResponse, authResult);
+		} catch (AuthenticationException failed) {
+			unsuccessfulAuthentication(httpRequest, httpResponse, failed);
+		}
+	}
+
+	/**
+	 * Puts the <code>Authentication</code> instance returned by the
+	 * authentication manager into the secure context.
+	 */
+	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Authentication success: " + authResult);
+		}
+		SecurityContextHolder.getContext().setAuthentication(authResult);
+		// Fire event
+		if (this.eventPublisher != null) {
+			eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
+		}
+	}
+
+	/**
+	 * Ensures the authentication object in the secure context is set to null
+	 * when authentication fails.
+	 */
+	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
+		SecurityContextHolder.getContext().setAuthentication(null);
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Updated SecurityContextHolder to contain null Authentication due to exception", failed);
+		}
+		request.getSession().setAttribute(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, failed);
+	}
+
+	/**
+	 * @param anApplicationEventPublisher
+	 *            The ApplicationEventPublisher to use
+	 */
+	public void setApplicationEventPublisher(ApplicationEventPublisher anApplicationEventPublisher) {
+		this.eventPublisher = anApplicationEventPublisher;
+	}
+
+	/**
+	 * @param authenticationDetailsSource
+	 *            The AuthenticationDetailsSource to use
+	 */
+	public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
+		Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
+		this.authenticationDetailsSource = authenticationDetailsSource;
+	}
+
+	/**
+	 * @param authenticationManager
+	 *            The AuthenticationManager to use
+	 */
+	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
+		this.authenticationManager = authenticationManager;
+	}
+
+	/**
+	 * Required method, does nothing.
+	 */
+	public void init(FilterConfig filterConfig) {
+	}
+
+	/**
+	 * Required method, does nothing.
+	 */
+	public void destroy() {
+	}
+
+	protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest httpRequest);
+
+	protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest);
+}

+ 58 - 0
core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.java

@@ -0,0 +1,58 @@
+package org.springframework.security.ui.preauth;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.security.providers.preauth.PreAuthenticatedGrantedAuthoritiesRetriever;
+import org.springframework.security.providers.preauth.PreAuthenticatedGrantedAuthoritiesSetter;
+import org.springframework.security.ui.WebAuthenticationDetails;
+import org.springframework.security.GrantedAuthority;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.util.Assert;
+
+/**
+ * This WebAuthenticationDetails implementation allows for storing a list of
+ * pre-authenticated Granted Authorities.
+ */
+public class PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails extends WebAuthenticationDetails implements
+		PreAuthenticatedGrantedAuthoritiesRetriever, PreAuthenticatedGrantedAuthoritiesSetter {
+	public static final long serialVersionUID = 1L;
+
+	private GrantedAuthority[] preAuthenticatedGrantedAuthorities = null;
+
+	public PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails(HttpServletRequest request) {
+		super(request);
+	}
+
+	/**
+	 * @return The String representation of this object.
+	 */
+	public String toString() {
+		StringBuffer sb = new StringBuffer();
+		sb.append(super.toString() + "; ");
+		sb.append("preAuthenticatedGrantedAuthorities: " + StringUtils.join(preAuthenticatedGrantedAuthorities, ", "));
+		return sb.toString();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.springframework.security.providers.preauth.PreAuthenticatedGrantedAuthoritiesRetriever#getPreAuthenticatedGrantedAuthorities()
+	 */
+	public GrantedAuthority[] getPreAuthenticatedGrantedAuthorities() {
+		Assert.notNull(preAuthenticatedGrantedAuthorities, "Pre-authenticated granted authorities have not been set");
+		GrantedAuthority[] result = new GrantedAuthority[preAuthenticatedGrantedAuthorities.length];
+		System.arraycopy(preAuthenticatedGrantedAuthorities, 0, result, 0, result.length);
+		return result;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.springframework.security.providers.preauth.j2ee.PreAuthenticatedGrantedAuthoritiesSetter#setJ2eeBasedGrantedAuthorities()
+	 */
+	public void setPreAuthenticatedGrantedAuthorities(GrantedAuthority[] aJ2eeBasedGrantedAuthorities) {
+		this.preAuthenticatedGrantedAuthorities = new GrantedAuthority[aJ2eeBasedGrantedAuthorities.length];
+		System.arraycopy(aJ2eeBasedGrantedAuthorities, 0, preAuthenticatedGrantedAuthorities, 0, preAuthenticatedGrantedAuthorities.length);
+	}
+}

+ 66 - 0
core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPoint.java

@@ -0,0 +1,66 @@
+package org.springframework.security.ui.preauth;
+
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.ui.AuthenticationEntryPoint;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.core.Ordered;
+
+/**
+ * <p>
+ * In the pre-authenticated authentication case (unlike CAS, for example) the
+ * user will already have been identified through some external mechanism and a
+ * secure context established by the time the security-enforcement filter is
+ * invoked.
+ * </p>
+ * <p>
+ * Therefore this class isn't actually responsible for the commencement of
+ * authentication, as it is in the case of other providers. It will be called if
+ * the user is rejected by the AbstractPreAuthenticatedProcessingFilter,
+ * resulting in a null authentication.
+ * </p>
+ * <p>
+ * The <code>commence</code> method will always return an
+ * <code>HttpServletResponse.SC_FORBIDDEN</code> (403 error).
+ * </p>
+ * <p>
+ * This code is based on
+ * {@link org.springframework.security.ui.x509.X509ProcessingFilterEntryPoint}.
+ * </p>
+ * 
+ * @see org.springframework.security.ui.ExceptionTranslationFilter
+ */
+public class PreAuthenticatedProcesingFilterEntryPoint implements AuthenticationEntryPoint, Ordered {
+	private static final Log LOG = LogFactory.getLog(PreAuthenticatedProcesingFilterEntryPoint.class);
+
+	private int order = Integer.MAX_VALUE;
+
+	/**
+	 * Always returns a 403 error code to the client.
+	 */
+	public void commence(ServletRequest request, ServletResponse response, AuthenticationException arg2) throws IOException,
+			ServletException {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("J2EE entry point called. Rejecting access");
+		}
+		HttpServletResponse httpResponse = (HttpServletResponse) response;
+		httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
+	}
+
+	public int getOrder() {
+		return order;
+	}
+
+	public void setOrder(int i) {
+		order = i;
+	}
+
+}

+ 101 - 0
core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.java

@@ -0,0 +1,101 @@
+package org.springframework.security.ui.preauth.j2ee;
+
+import org.springframework.security.ui.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails;
+import org.springframework.security.ui.AuthenticationDetailsSourceImpl;
+import org.springframework.security.providers.preauth.PreAuthenticatedGrantedAuthoritiesSetter;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.rolemapping.Roles2GrantedAuthoritiesMapper;
+import org.springframework.security.rolemapping.MappableRolesRetriever;
+
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+
+public class J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource extends AuthenticationDetailsSourceImpl implements InitializingBean {
+	private static final Log LOG = LogFactory.getLog(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
+
+	private String[] j2eeMappableRoles;
+
+	private Roles2GrantedAuthoritiesMapper j2eeUserRoles2GrantedAuthoritiesMapper;
+
+	/**
+	 * Public constructor which overrides the default AuthenticationDetails
+	 * class to be used.
+	 */
+	public J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource() {
+		super.setClazz(PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.class);
+	}
+
+	/**
+	 * Check that all required properties have been set.
+	 */
+	public void afterPropertiesSet() throws Exception {
+		Assert.notNull(j2eeMappableRoles, "J2EE defined roles not available");
+		Assert.notNull(j2eeUserRoles2GrantedAuthoritiesMapper, "J2EE user roles to granted authorities mapper not set");
+	}
+
+	/**
+	 * Build the authentication details object. If the speficied authentication
+	 * details class implements the PreAuthenticatedGrantedAuthoritiesSetter, a
+	 * list of pre-authenticated Granted Authorities will be set based on the
+	 * J2EE roles for the current user.
+	 * 
+	 * @see org.springframework.security.ui.AuthenticationDetailsSource#buildDetails(javax.servlet.http.HttpServletRequest)
+	 */
+	public Object buildDetails(HttpServletRequest request) {
+		Object result = super.buildDetails(request);
+		if (result instanceof PreAuthenticatedGrantedAuthoritiesSetter) {
+			((PreAuthenticatedGrantedAuthoritiesSetter) result)
+					.setPreAuthenticatedGrantedAuthorities(getJ2eeBasedGrantedAuthorities(request));
+		}
+		return result;
+	}
+
+	/**
+	 * Get a list of Granted Authorities based on the current user's J2EE roles.
+	 * 
+	 * @param request
+	 *            The HttpServletRequest
+	 * @return GrantedAuthority[] mapped from the user's J2EE roles.
+	 */
+	private GrantedAuthority[] getJ2eeBasedGrantedAuthorities(HttpServletRequest request) {
+		ArrayList j2eeUserRolesList = new ArrayList();
+
+		for (int i = 0; i < j2eeMappableRoles.length; i++) {
+			if (request.isUserInRole(j2eeMappableRoles[i])) {
+				j2eeUserRolesList.add(j2eeMappableRoles[i]);
+			}
+		}
+		String[] j2eeUserRoles = new String[j2eeUserRolesList.size()];
+		j2eeUserRoles = (String[]) j2eeUserRolesList.toArray(j2eeUserRoles);
+		GrantedAuthority[] userGas = j2eeUserRoles2GrantedAuthoritiesMapper.getGrantedAuthorities(j2eeUserRoles);
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("J2EE user roles [" + StringUtils.join(j2eeUserRoles) + "] mapped to Granted Authorities: ["
+					+ StringUtils.join(userGas) + "]");
+		}
+		return userGas;
+	}
+
+	/**
+	 * @param aJ2eeMappableRolesRetriever
+	 *            The MappableRolesRetriever to use
+	 */
+	public void setJ2eeMappableRolesRetriever(MappableRolesRetriever aJ2eeMappableRolesRetriever) {
+		this.j2eeMappableRoles = aJ2eeMappableRolesRetriever.getMappableRoles();
+	}
+
+	/**
+	 * @param mapper
+	 *            The Roles2GrantedAuthoritiesMapper to use
+	 */
+	public void setJ2eeUserRoles2GrantedAuthoritiesMapper(Roles2GrantedAuthoritiesMapper mapper) {
+		j2eeUserRoles2GrantedAuthoritiesMapper = mapper;
+	}
+
+}

+ 36 - 0
core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java

@@ -0,0 +1,36 @@
+package org.springframework.security.ui.preauth.j2ee;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.security.ui.preauth.AbstractPreAuthenticatedProcessingFilter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This AbstractPreAuthenticatedProcessingFilter implementation is based on the
+ * J2EE container-based authentication mechanism. It will use the J2EE user
+ * principal name as the pre-authenticated principal.
+ */
+public class J2eePreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
+	private static final Log LOG = LogFactory.getLog(J2eePreAuthenticatedProcessingFilter.class);
+
+	/**
+	 * Return the J2EE user name.
+	 */
+	protected Object getPreAuthenticatedPrincipal(HttpServletRequest httpRequest) {
+		Object principal = httpRequest.getUserPrincipal() == null ? null : httpRequest.getUserPrincipal().getName();
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("PreAuthenticated J2EE principal: " + principal);
+		}
+		return principal;
+	}
+
+	/**
+	 * For J2EE container-based authentication there is no generic way to
+	 * retrieve the credentials, as such this method returns a fixed dummy
+	 * value.
+	 */
+	protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) {
+		return "N/A";
+	}
+}

+ 52 - 0
core/src/main/java/org/springframework/security/ui/preauth/j2ee/WebXmlMappableRolesRetriever.java

@@ -0,0 +1,52 @@
+package org.springframework.security.ui.preauth.j2ee;
+
+import java.io.InputStream;
+
+import org.springframework.security.rolemapping.XmlMappableRolesRetriever;
+
+/**
+ * <p>
+ * This MappableRolesRetriever implementation reads the list of defined J2EE
+ * roles from a web.xml file. It's functionality is based on the
+ * XmlMappableRolesRetriever base class.
+ * </p>
+ * 
+ * <p>
+ * Example on how to configure this MappableRolesRetriever in the Spring
+ * configuration file:
+ * 
+ * <pre>
+ * 
+ *  
+ *   	&lt;bean id=&quot;j2eeMappableRolesRetriever&quot; class=&quot;org.springframework.security.ui.preauth.j2ee.WebXmlMappableRolesRetriever&quot;&gt;
+ *  		&lt;property name=&quot;webXmlInputStream&quot;&gt;&lt;bean factory-bean=&quot;webXmlResource&quot; factory-method=&quot;getInputStream&quot;/&gt;&lt;/property&gt;
+ *  	&lt;/bean&gt;
+ *  	&lt;bean id=&quot;webXmlResource&quot; class=&quot;org.springframework.web.context.support.ServletContextResource&quot;&gt;
+ *  		&lt;constructor-arg&gt;&lt;ref local=&quot;servletContext&quot;/&gt;&lt;/constructor-arg&gt;
+ *  		&lt;constructor-arg&gt;&lt;value&gt;/WEB-INF/web.xml&lt;/value&gt;&lt;/constructor-arg&gt;
+ *  	&lt;/bean&gt;
+ *  	&lt;bean id=&quot;servletContext&quot; class=&quot;org.springframework.web.context.support.ServletContextFactoryBean&quot;/&gt;
+ *   
+ *  
+ * </pre>
+ * 
+ * </p>
+ */
+public class WebXmlMappableRolesRetriever extends XmlMappableRolesRetriever {
+	private static final String XPATH_EXPR = "/web-app/security-role/role-name/text()";
+
+	/**
+	 * Constructor setting the XPath expression to use
+	 */
+	public WebXmlMappableRolesRetriever() {
+		super.setXpathExpression(XPATH_EXPR);
+	}
+
+	/**
+	 * @param anInputStream
+	 *            The InputStream to read the XML data from
+	 */
+	public void setWebXmlInputStream(InputStream anInputStream) {
+		super.setXmlInputStream(anInputStream);
+	}
+}

+ 102 - 0
core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProviderTests.java

@@ -0,0 +1,102 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+import org.springframework.security.userdetails.User;
+import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UsernameNotFoundException;
+import org.springframework.security.Authentication;
+import org.springframework.security.GrantedAuthority;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class PreAuthenticatedAuthenticationProviderTests extends TestCase {
+	private static final String SUPPORTED_USERNAME = "dummyUser";
+
+	public final void testAfterPropertiesSet() {
+		PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
+		try {
+			provider.afterPropertiesSet();
+			fail("AfterPropertiesSet didn't throw expected exception");
+		} catch (IllegalArgumentException expected) {
+		} catch (Exception unexpected) {
+			fail("AfterPropertiesSet throws unexpected exception");
+		}
+	}
+
+	public final void testAuthenticateInvalidToken() throws Exception {
+		UserDetails ud = new User("dummyUser", "dummyPwd", true, true, true, true, new GrantedAuthority[] {});
+		PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
+		Authentication request = new UsernamePasswordAuthenticationToken("dummyUser", "dummyPwd");
+		Authentication result = provider.authenticate(request);
+		assertNull(result);
+	}
+
+	public final void testAuthenticateKnownUser() throws Exception {
+		UserDetails ud = new User("dummyUser", "dummyPwd", true, true, true, true, new GrantedAuthority[] {});
+		PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
+		Authentication request = new PreAuthenticatedAuthenticationToken("dummyUser", "dummyPwd");
+		Authentication result = provider.authenticate(request);
+		assertNotNull(result);
+		assertEquals(result.getPrincipal(), ud);
+		// @TODO: Add more asserts?
+	}
+
+	public final void testAuthenticateIgnoreCredentials() throws Exception {
+		UserDetails ud = new User("dummyUser1", "dummyPwd1", true, true, true, true, new GrantedAuthority[] {});
+		PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
+		Authentication request = new PreAuthenticatedAuthenticationToken("dummyUser1", "dummyPwd2");
+		Authentication result = provider.authenticate(request);
+		assertNotNull(result);
+		assertEquals(result.getPrincipal(), ud);
+		// @TODO: Add more asserts?
+	}
+
+	public final void testAuthenticateUnknownUser() throws Exception {
+		UserDetails ud = new User("dummyUser1", "dummyPwd", true, true, true, true, new GrantedAuthority[] {});
+		PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
+		Authentication request = new PreAuthenticatedAuthenticationToken("dummyUser2", "dummyPwd");
+		Authentication result = provider.authenticate(request);
+		assertNull(result);
+	}
+
+	public final void testSupportsArbitraryObject() throws Exception {
+		PreAuthenticatedAuthenticationProvider provider = getProvider(null);
+		assertFalse(provider.supports(Authentication.class));
+	}
+
+	public final void testSupportsPreAuthenticatedAuthenticationToken() throws Exception {
+		PreAuthenticatedAuthenticationProvider provider = getProvider(null);
+		assertTrue(provider.supports(PreAuthenticatedAuthenticationToken.class));
+	}
+
+	public void testGetSetOrder() throws Exception {
+		PreAuthenticatedAuthenticationProvider provider = getProvider(null);
+		provider.setOrder(333);
+		assertEquals(provider.getOrder(), 333);
+	}
+
+	private PreAuthenticatedAuthenticationProvider getProvider(UserDetails aUserDetails) throws Exception {
+		PreAuthenticatedAuthenticationProvider result = new PreAuthenticatedAuthenticationProvider();
+		result.setPreAuthenticatedUserDetailsService(getPreAuthenticatedUserDetailsService(aUserDetails));
+		result.afterPropertiesSet();
+		return result;
+	}
+
+	private PreAuthenticatedUserDetailsService getPreAuthenticatedUserDetailsService(final UserDetails aUserDetails) {
+		return new PreAuthenticatedUserDetailsService() {
+			public UserDetails getUserDetails(PreAuthenticatedAuthenticationToken token) throws UsernameNotFoundException {
+				if (aUserDetails != null && aUserDetails.getUsername().equals(token.getName())) {
+					return aUserDetails;
+				} else {
+					return null;
+				}
+			}
+		};
+	}
+
+}

+ 57 - 0
core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationTokenTests.java

@@ -0,0 +1,57 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.GrantedAuthority;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class PreAuthenticatedAuthenticationTokenTests extends TestCase {
+
+	public void testPreAuthenticatedAuthenticationTokenRequestWithDetails() {
+		Object principal = "dummyUser";
+		Object credentials = "dummyCredentials";
+		Object details = "dummyDetails";
+		PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal, credentials);
+		token.setDetails(details);
+		assertEquals(principal, token.getPrincipal());
+		assertEquals(credentials, token.getCredentials());
+		assertEquals(details, token.getDetails());
+		assertNull(token.getAuthorities());
+	}
+
+	public void testPreAuthenticatedAuthenticationTokenRequestWithoutDetails() {
+		Object principal = "dummyUser";
+		Object credentials = "dummyCredentials";
+		PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal, credentials);
+		assertEquals(principal, token.getPrincipal());
+		assertEquals(credentials, token.getCredentials());
+		assertNull(token.getDetails());
+		assertNull(token.getAuthorities());
+	}
+
+	public void testPreAuthenticatedAuthenticationTokenResponse() {
+		Object principal = "dummyUser";
+		Object credentials = "dummyCredentials";
+		GrantedAuthority[] gas = new GrantedAuthority[] { new GrantedAuthorityImpl("Role1") };
+		PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal, credentials, gas);
+		assertEquals(principal, token.getPrincipal());
+		assertEquals(credentials, token.getCredentials());
+		assertNull(token.getDetails());
+		assertNotNull(token.getAuthorities());
+		Collection expectedColl = Arrays.asList(gas);
+		Collection resultColl = Arrays.asList(token.getAuthorities());
+		assertTrue("GrantedAuthority collections do not match; result: " + resultColl + ", expected: " + expectedColl, expectedColl
+				.containsAll(resultColl)
+				&& resultColl.containsAll(expectedColl));
+
+	}
+
+}

+ 79 - 0
core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsServiceTests.java

@@ -0,0 +1,79 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.userdetails.UserDetails;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class PreAuthenticatedGrantedAuthoritiesUserDetailsServiceTests extends TestCase {
+
+	public final void testGetUserDetailsInvalidType() {
+		PreAuthenticatedGrantedAuthoritiesUserDetailsService svc = new PreAuthenticatedGrantedAuthoritiesUserDetailsService();
+		PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken("dummy", "dummy");
+		token.setDetails(new Object());
+		try {
+			svc.getUserDetails(token);
+			fail("Expected exception didn't occur");
+		} catch (IllegalArgumentException expected) {
+		}
+	}
+
+	public final void testGetUserDetailsNoDetails() {
+		PreAuthenticatedGrantedAuthoritiesUserDetailsService svc = new PreAuthenticatedGrantedAuthoritiesUserDetailsService();
+		PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken("dummy", "dummy");
+		token.setDetails(null);
+		try {
+			svc.getUserDetails(token);
+			fail("Expected exception didn't occur");
+		} catch (IllegalArgumentException expected) {
+		}
+	}
+
+	public final void testGetUserDetailsEmptyAuthorities() {
+		final String userName = "dummyUser";
+		final GrantedAuthority[] gas = new GrantedAuthority[] {};
+		testGetUserDetails(userName, gas);
+	}
+
+	public final void testGetUserDetailsWithAuthorities() {
+		final String userName = "dummyUser";
+		final GrantedAuthority[] gas = new GrantedAuthority[] { new GrantedAuthorityImpl("Role1"), new GrantedAuthorityImpl("Role2") };
+		testGetUserDetails(userName, gas);
+	}
+
+	private void testGetUserDetails(final String userName, final GrantedAuthority[] gas) {
+		PreAuthenticatedGrantedAuthoritiesUserDetailsService svc = new PreAuthenticatedGrantedAuthoritiesUserDetailsService();
+		PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(userName, "dummy");
+		token.setDetails(new PreAuthenticatedGrantedAuthoritiesRetriever() {
+			public GrantedAuthority[] getPreAuthenticatedGrantedAuthorities() {
+				return gas;
+			}
+		});
+		UserDetails ud = svc.getUserDetails(token);
+		assertTrue(ud.isAccountNonExpired());
+		assertTrue(ud.isAccountNonLocked());
+		assertTrue(ud.isCredentialsNonExpired());
+		assertTrue(ud.isEnabled());
+		assertEquals(ud.getUsername(), userName);
+
+		//Password is not saved by
+		// PreAuthenticatedGrantedAuthoritiesUserDetailsService
+		//assertEquals(ud.getPassword(),password);
+
+		Collection expectedColl = Arrays.asList(gas);
+		Collection resultColl = Arrays.asList(ud.getAuthorities());
+		assertTrue("GrantedAuthority collections do not match; result: " + resultColl + ", expected: " + expectedColl, expectedColl
+				.containsAll(resultColl)
+				&& resultColl.containsAll(expectedColl));
+	}
+
+}

+ 51 - 0
core/src/test/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapperTests.java

@@ -0,0 +1,51 @@
+package org.springframework.security.providers.preauth;
+
+import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UsernameNotFoundException;
+import org.springframework.security.userdetails.UserDetailsService;
+import org.springframework.security.userdetails.User;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.GrantedAuthority;
+
+import junit.framework.TestCase;
+
+import org.springframework.dao.DataAccessException;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class UserDetailsByNameServiceWrapperTests extends TestCase {
+
+	public final void testAfterPropertiesSet() {
+		UserDetailsByNameServiceWrapper svc = new UserDetailsByNameServiceWrapper();
+		try {
+			svc.afterPropertiesSet();
+			fail("AfterPropertiesSet didn't throw expected exception");
+		} catch (IllegalArgumentException expected) {
+		} catch (Exception unexpected) {
+			fail("AfterPropertiesSet throws unexpected exception");
+		}
+	}
+
+	public final void testGetUserDetails() throws Exception {
+		UserDetailsByNameServiceWrapper svc = new UserDetailsByNameServiceWrapper();
+		final User user = new User("dummy", "dummy", true, true, true, true, new GrantedAuthority[] { new GrantedAuthorityImpl("dummy") });
+		svc.setUserDetailsService(new UserDetailsService() {
+			public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException, DataAccessException {
+				if (user != null && user.getUsername().equals(name)) {
+					return user;
+				} else {
+					return null;
+				}
+			}
+		});
+		svc.afterPropertiesSet();
+		UserDetails result1 = svc.getUserDetails(new PreAuthenticatedAuthenticationToken("dummy", "dummy"));
+		assertEquals("Result doesn't match original user", user, result1);
+		UserDetails result2 = svc.getUserDetails(new PreAuthenticatedAuthenticationToken("dummy2", "dummy"));
+		assertNull("Result should have been null", result2);
+	}
+
+}

+ 26 - 0
core/src/test/java/org/springframework/security/rolemapping/SimpleMappableRolesRetrieverTests.java

@@ -0,0 +1,26 @@
+package org.springframework.security.rolemapping;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class SimpleMappableRolesRetrieverTests extends TestCase {
+
+	public final void testGetSetMappableRoles() {
+		String[] roles = new String[] { "Role1", "Role2" };
+		SimpleMappableRolesRetriever r = new SimpleMappableRolesRetriever();
+		r.setMappableRoles(roles);
+		String[] result = r.getMappableRoles();
+		Collection resultColl = Arrays.asList(result);
+		Collection rolesColl = Arrays.asList(roles);
+		assertTrue("Role collections do not match; result: " + resultColl + ", expected: " + rolesColl, rolesColl.containsAll(resultColl)
+				&& resultColl.containsAll(rolesColl));
+	}
+
+}

+ 121 - 0
core/src/test/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapperTests.java

@@ -0,0 +1,121 @@
+package org.springframework.security.rolemapping;
+
+import org.springframework.security.GrantedAuthority;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class SimpleRoles2GrantedAuthoritiesMapperTests extends TestCase {
+
+	public final void testAfterPropertiesSetConvertToUpperAndLowerCase() {
+		SimpleRoles2GrantedAuthoritiesMapper mapper = new SimpleRoles2GrantedAuthoritiesMapper();
+		mapper.setConvertRoleToLowerCase(true);
+		mapper.setConvertRoleToUpperCase(true);
+		try {
+			mapper.afterPropertiesSet();
+			fail("Expected exception not thrown");
+		} catch (IllegalArgumentException expected) {
+		} catch (Exception unexpected) {
+			fail("Unexpected exception: " + unexpected);
+		}
+	}
+
+	public final void testAfterPropertiesSet() {
+		SimpleRoles2GrantedAuthoritiesMapper mapper = new SimpleRoles2GrantedAuthoritiesMapper();
+		try {
+			mapper.afterPropertiesSet();
+		} catch (Exception unexpected) {
+			fail("Unexpected exception: " + unexpected);
+		}
+	}
+
+	public final void testGetGrantedAuthoritiesNoConversion() {
+		String[] roles = { "Role1", "Role2" };
+		String[] expectedGas = { "Role1", "Role2" };
+		SimpleRoles2GrantedAuthoritiesMapper mapper = getDefaultMapper();
+		testGetGrantedAuthorities(mapper, roles, expectedGas);
+	}
+
+	public final void testGetGrantedAuthoritiesToUpperCase() {
+		String[] roles = { "Role1", "Role2" };
+		String[] expectedGas = { "ROLE1", "ROLE2" };
+		SimpleRoles2GrantedAuthoritiesMapper mapper = getDefaultMapper();
+		mapper.setConvertRoleToUpperCase(true);
+		testGetGrantedAuthorities(mapper, roles, expectedGas);
+	}
+
+	public final void testGetGrantedAuthoritiesToLowerCase() {
+		String[] roles = { "Role1", "Role2" };
+		String[] expectedGas = { "role1", "role2" };
+		SimpleRoles2GrantedAuthoritiesMapper mapper = getDefaultMapper();
+		mapper.setConvertRoleToLowerCase(true);
+		testGetGrantedAuthorities(mapper, roles, expectedGas);
+	}
+
+	public final void testGetGrantedAuthoritiesAddPrefixIfAlreadyExisting() {
+		String[] roles = { "Role1", "Role2", "ROLE_Role3" };
+		String[] expectedGas = { "ROLE_Role1", "ROLE_Role2", "ROLE_ROLE_Role3" };
+		SimpleRoles2GrantedAuthoritiesMapper mapper = getDefaultMapper();
+		mapper.setAddPrefixIfAlreadyExisting(true);
+		mapper.setRolePrefix("ROLE_");
+		testGetGrantedAuthorities(mapper, roles, expectedGas);
+	}
+
+	public final void testGetGrantedAuthoritiesDontAddPrefixIfAlreadyExisting1() {
+		String[] roles = { "Role1", "Role2", "ROLE_Role3" };
+		String[] expectedGas = { "ROLE_Role1", "ROLE_Role2", "ROLE_Role3" };
+		SimpleRoles2GrantedAuthoritiesMapper mapper = getDefaultMapper();
+		mapper.setAddPrefixIfAlreadyExisting(false);
+		mapper.setRolePrefix("ROLE_");
+		testGetGrantedAuthorities(mapper, roles, expectedGas);
+	}
+
+	public final void testGetGrantedAuthoritiesDontAddPrefixIfAlreadyExisting2() {
+		String[] roles = { "Role1", "Role2", "role_Role3" };
+		String[] expectedGas = { "ROLE_Role1", "ROLE_Role2", "ROLE_role_Role3" };
+		SimpleRoles2GrantedAuthoritiesMapper mapper = getDefaultMapper();
+		mapper.setAddPrefixIfAlreadyExisting(false);
+		mapper.setRolePrefix("ROLE_");
+		testGetGrantedAuthorities(mapper, roles, expectedGas);
+	}
+
+	public final void testGetGrantedAuthoritiesCombination1() {
+		String[] roles = { "Role1", "Role2", "role_Role3" };
+		String[] expectedGas = { "ROLE_ROLE1", "ROLE_ROLE2", "ROLE_ROLE3" };
+		SimpleRoles2GrantedAuthoritiesMapper mapper = getDefaultMapper();
+		mapper.setAddPrefixIfAlreadyExisting(false);
+		mapper.setConvertRoleToUpperCase(true);
+		mapper.setRolePrefix("ROLE_");
+		testGetGrantedAuthorities(mapper, roles, expectedGas);
+	}
+
+	private void testGetGrantedAuthorities(SimpleRoles2GrantedAuthoritiesMapper mapper, String[] roles, String[] expectedGas) {
+		GrantedAuthority[] result = mapper.getGrantedAuthorities(roles);
+		Collection resultColl = new ArrayList(result.length);
+		for (int i = 0; i < result.length; i++) {
+			resultColl.add(result[i].getAuthority());
+		}
+		Collection expectedColl = Arrays.asList(expectedGas);
+		assertTrue("Role collections do not match; result: " + resultColl + ", expected: " + expectedColl, expectedColl
+				.containsAll(resultColl)
+				&& resultColl.containsAll(expectedColl));
+	}
+
+	private SimpleRoles2GrantedAuthoritiesMapper getDefaultMapper() {
+		SimpleRoles2GrantedAuthoritiesMapper mapper = new SimpleRoles2GrantedAuthoritiesMapper();
+		mapper.setRolePrefix("");
+		mapper.setConvertRoleToLowerCase(false);
+		mapper.setConvertRoleToUpperCase(false);
+		mapper.setAddPrefixIfAlreadyExisting(false);
+		return mapper;
+	}
+
+}

+ 100 - 0
core/src/test/java/org/springframework/security/rolemapping/XmlMappableRolesRetrieverTests.java

@@ -0,0 +1,100 @@
+package org.springframework.security.rolemapping;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class XmlMappableRolesRetrieverTests extends TestCase {
+	private static final String DEFAULT_XML = "<roles><role>Role1</role><role>Role2</role></roles>";
+
+	private static final String DEFAULT_XPATH = "/roles/role/text()";
+
+	private static final String[] DEFAULT_EXPECTED_ROLES = new String[] { "Role1", "Role2" };
+
+	public final void testAfterPropertiesSetException() {
+		TestXmlMappableRolesRetriever t = new TestXmlMappableRolesRetriever();
+		try {
+			t.afterPropertiesSet();
+			fail("AfterPropertiesSet didn't throw expected exception");
+		} catch (IllegalArgumentException expected) {
+		} catch (Exception unexpected) {
+			fail("AfterPropertiesSet throws unexpected exception");
+		}
+	}
+
+	public void testGetMappableRoles() {
+		XmlMappableRolesRetriever r = getXmlMappableRolesRetriever(true, getDefaultInputStream(), DEFAULT_XPATH);
+		String[] resultRoles = r.getMappableRoles();
+		assertNotNull("Result roles should not be null", resultRoles);
+		assertTrue("Number of result roles doesn't match expected number of roles", resultRoles.length == DEFAULT_EXPECTED_ROLES.length);
+		Collection resultRolesColl = Arrays.asList(resultRoles);
+		Collection expectedRolesColl = Arrays.asList(DEFAULT_EXPECTED_ROLES);
+		assertTrue("Role collections do not match", expectedRolesColl.containsAll(resultRolesColl)
+				&& resultRolesColl.containsAll(expectedRolesColl));
+	}
+
+	public void testCloseInputStream() {
+		testCloseInputStream(true);
+	}
+
+	public void testDontCloseInputStream() {
+		testCloseInputStream(false);
+	}
+
+	private void testCloseInputStream(boolean closeAfterRead) {
+		CloseableByteArrayInputStream is = getDefaultInputStream();
+		XmlMappableRolesRetriever r = getXmlMappableRolesRetriever(closeAfterRead, is, DEFAULT_XPATH);
+		r.getMappableRoles();
+		assertEquals(is.isClosed(), closeAfterRead);
+	}
+
+	private XmlMappableRolesRetriever getXmlMappableRolesRetriever(boolean closeInputStream, InputStream is, String xpath) {
+		XmlMappableRolesRetriever result = new TestXmlMappableRolesRetriever();
+		result.setCloseInputStream(closeInputStream);
+		result.setXmlInputStream(is);
+		result.setXpathExpression(xpath);
+		try {
+			result.afterPropertiesSet();
+		} catch (Exception e) {
+			fail("Unexpected exception" + e.toString());
+		}
+		return result;
+	}
+
+	private CloseableByteArrayInputStream getDefaultInputStream() {
+		return getInputStream(DEFAULT_XML);
+	}
+
+	private CloseableByteArrayInputStream getInputStream(String data) {
+		return new CloseableByteArrayInputStream(data.getBytes());
+	}
+
+	private static final class TestXmlMappableRolesRetriever extends XmlMappableRolesRetriever {
+	}
+
+	private static final class CloseableByteArrayInputStream extends ByteArrayInputStream {
+		private boolean closed = false;
+
+		public CloseableByteArrayInputStream(byte[] buf) {
+			super(buf);
+		}
+
+		public void close() throws IOException {
+			super.close();
+			closed = true;
+		}
+
+		public boolean isClosed() {
+			return closed;
+		}
+	}
+}

+ 72 - 0
core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetailsTests.java

@@ -0,0 +1,72 @@
+package org.springframework.security.ui.preauth;
+
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.GrantedAuthority;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetailsTests extends TestCase {
+
+    public final void testToString() {
+		PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails details = new PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails(
+				getRequest("testUser", new String[] {}));
+		GrantedAuthority[] gas = new GrantedAuthority[] { new GrantedAuthorityImpl("Role1"), new GrantedAuthorityImpl("Role2") };
+		details.setPreAuthenticatedGrantedAuthorities(gas);
+		String toString = details.toString();
+		assertTrue("toString doesn't contain Role1", StringUtils.contains(toString, "Role1"));
+		assertTrue("toString doesn't contain Role2", StringUtils.contains(toString, "Role2"));
+	}
+
+	public final void testGetSetPreAuthenticatedGrantedAuthorities() {
+		PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails details = new PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails(
+				getRequest("testUser", new String[] {}));
+		GrantedAuthority[] gas = new GrantedAuthority[] { new GrantedAuthorityImpl("Role1"), new GrantedAuthorityImpl("Role2") };
+		Collection expectedGas = Arrays.asList(gas);
+
+		details.setPreAuthenticatedGrantedAuthorities(gas);
+		Collection returnedGas = Arrays.asList(details.getPreAuthenticatedGrantedAuthorities());
+		assertTrue("Collections do not contain same elements; expected: " + expectedGas + ", returned: " + returnedGas, expectedGas
+				.containsAll(returnedGas)
+				&& returnedGas.containsAll(expectedGas));
+	}
+
+	public final void testGetWithoutSetPreAuthenticatedGrantedAuthorities() {
+		PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails details = new PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails(
+				getRequest("testUser", new String[] {}));
+		try {
+			GrantedAuthority[] gas = details.getPreAuthenticatedGrantedAuthorities();
+			fail("Expected exception didn't occur");
+		} catch (IllegalArgumentException expected) {
+		} catch (Exception unexpected) {
+			fail("Unexpected exception: " + unexpected.toString());
+		}
+	}
+	
+	private final HttpServletRequest getRequest(final String userName,final String[] aRoles)
+	{
+		MockHttpServletRequest req = new MockHttpServletRequest() {
+			private Set roles = new HashSet(Arrays.asList(aRoles));
+			public boolean isUserInRole(String arg0) {
+				return roles.contains(arg0);
+			}
+		};
+		req.setRemoteUser(userName);
+		return req;
+	}
+
+}

+ 42 - 0
core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPointTests.java

@@ -0,0 +1,42 @@
+package org.springframework.security.ui.preauth;
+
+import org.springframework.security.AuthenticationCredentialsNotFoundException;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class PreAuthenticatedProcesingFilterEntryPointTests extends TestCase {
+
+	public void testGetSetOrder() {
+		PreAuthenticatedProcesingFilterEntryPoint fep = new PreAuthenticatedProcesingFilterEntryPoint();
+		fep.setOrder(333);
+		assertEquals(fep.getOrder(), 333);
+	}
+	
+	public void testCommence() {
+		MockHttpServletRequest req = new MockHttpServletRequest();
+		MockHttpServletResponse resp = new MockHttpServletResponse();
+		PreAuthenticatedProcesingFilterEntryPoint fep = new PreAuthenticatedProcesingFilterEntryPoint();
+		try {
+			fep.commence(req,resp,new AuthenticationCredentialsNotFoundException("test"));
+			assertEquals("Incorrect status",resp.getStatus(),HttpServletResponse.SC_FORBIDDEN);
+		} catch (IOException e) {
+			fail("Unexpected exception thrown: "+e);
+		} catch (ServletException e) {
+			fail("Unexpected exception thrown: "+e);
+		}
+		
+	}
+}

+ 79 - 0
core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcessingFilterTests.java

@@ -0,0 +1,79 @@
+package org.springframework.security.ui.preauth;
+
+import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.MockAuthenticationManager;
+
+import javax.servlet.http.HttpServletRequest;
+
+import junit.framework.TestCase;
+
+import org.springframework.mock.web.MockFilterChain;
+import org.springframework.mock.web.MockFilterConfig;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+public class PreAuthenticatedProcessingFilterTests extends TestCase {
+	protected void setUp() throws Exception {
+		SecurityContextHolder.clearContext();
+	}
+	
+	public void testAfterPropertiesSet()
+	{
+		ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
+		try {
+			filter.afterPropertiesSet();
+			fail("AfterPropertiesSet didn't throw expected exception");
+		} catch (IllegalArgumentException expected) {
+		} catch (Exception unexpected) {
+			fail("AfterPropertiesSet throws unexpected exception");
+		}
+	}
+	
+	public void testInit() throws Exception
+	{
+		getFilter(true).init(new MockFilterConfig());
+		// Init doesn't do anything, so nothing to test
+	}
+	
+	public void testDestroy() throws Exception
+	{
+		getFilter(true).destroy();
+		// Destroy doesn't do anything, so nothing to test
+	}
+
+	public final void testDoFilterAuthenticated() throws Exception
+	{
+		testDoFilter(true);
+	}
+
+	public final void testDoFilterUnauthenticated() throws Exception
+	{
+		testDoFilter(false);
+	}
+	
+	private final void testDoFilter(boolean grantAccess) throws Exception
+	{
+		MockHttpServletRequest req = new MockHttpServletRequest();
+		MockHttpServletResponse res = new MockHttpServletResponse();
+		getFilter(grantAccess).doFilter(req,res,new MockFilterChain());
+		assertEquals(grantAccess,null!= SecurityContextHolder.getContext().getAuthentication());
+	}
+	
+	private static final ConcretePreAuthenticatedProcessingFilter getFilter(boolean grantAccess) throws Exception
+	{
+		ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
+		filter.setAuthenticationManager(new MockAuthenticationManager(grantAccess));
+		filter.afterPropertiesSet();
+		return filter;
+	}
+	
+	private static final class ConcretePreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter
+	{
+		protected Object getPreAuthenticatedPrincipal(HttpServletRequest httpRequest) {
+			return "testPrincipal";
+		}
+		protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) {
+			return "testCredentials";
+		}
+	}
+}

+ 149 - 0
core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSourceTests.java

@@ -0,0 +1,149 @@
+package org.springframework.security.ui.preauth.j2ee;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+
+import junit.framework.TestCase;
+
+import org.springframework.security.rolemapping.MappableRolesRetriever;
+import org.springframework.security.rolemapping.Roles2GrantedAuthoritiesMapper;
+import org.springframework.security.rolemapping.SimpleMappableRolesRetriever;
+import org.springframework.security.rolemapping.SimpleRoles2GrantedAuthoritiesMapper;
+import org.springframework.security.ui.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails;
+import org.springframework.security.GrantedAuthority;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class J2eeBasedPreAuthenticatedWebAuthenticationDetailsSourceTests extends TestCase {
+
+	public final void testAfterPropertiesSetException() {
+		J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource t = new J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource();
+		try {
+			t.afterPropertiesSet();
+			fail("AfterPropertiesSet didn't throw expected exception");
+		} catch (IllegalArgumentException expected) {
+		} catch (Exception unexpected) {
+			fail("AfterPropertiesSet throws unexpected exception");
+		}
+	}
+
+	public final void testBuildDetailsHttpServletRequestNoMappedNoUserRoles() {
+		String[] mappedRoles = new String[] {};
+		String[] roles = new String[] {};
+		String[] expectedRoles = new String[] {};
+		testDetails(mappedRoles, roles, expectedRoles);
+	}
+
+	public final void testBuildDetailsHttpServletRequestNoMappedUnmappedUserRoles() {
+		String[] mappedRoles = new String[] {};
+		String[] roles = new String[] { "Role1", "Role2" };
+		String[] expectedRoles = new String[] {};
+		testDetails(mappedRoles, roles, expectedRoles);
+	}
+
+	public final void testBuildDetailsHttpServletRequestNoUserRoles() {
+		String[] mappedRoles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		String[] roles = new String[] {};
+		String[] expectedRoles = new String[] {};
+		testDetails(mappedRoles, roles, expectedRoles);
+	}
+
+	public final void testBuildDetailsHttpServletRequestAllUserRoles() {
+		String[] mappedRoles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		String[] roles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		String[] expectedRoles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		testDetails(mappedRoles, roles, expectedRoles);
+	}
+
+	public final void testBuildDetailsHttpServletRequestUnmappedUserRoles() {
+		String[] mappedRoles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		String[] roles = new String[] { "Role1", "Role2", "Role3", "Role4", "Role5" };
+		String[] expectedRoles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		testDetails(mappedRoles, roles, expectedRoles);
+	}
+
+	public final void testBuildDetailsHttpServletRequestPartialUserRoles() {
+		String[] mappedRoles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		String[] roles = new String[] { "Role2", "Role3" };
+		String[] expectedRoles = new String[] { "Role2", "Role3" };
+		testDetails(mappedRoles, roles, expectedRoles);
+	}
+
+	public final void testBuildDetailsHttpServletRequestPartialAndUnmappedUserRoles() {
+		String[] mappedRoles = new String[] { "Role1", "Role2", "Role3", "Role4" };
+		String[] roles = new String[] { "Role2", "Role3", "Role5" };
+		String[] expectedRoles = new String[] { "Role2", "Role3" };
+		testDetails(mappedRoles, roles, expectedRoles);
+	}
+
+	private void testDetails(String[] mappedRoles, String[] userRoles, String[] expectedRoles) {
+		J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource src = getJ2eeBasedPreAuthenticatedWebAuthenticationDetailsSource(mappedRoles);
+		Object o = src.buildDetails(getRequest("testUser", userRoles));
+		assertNotNull(o);
+		assertTrue("Returned object not of type PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails, actual type: " + o.getClass(),
+				o instanceof PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails);
+		PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails details = (PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails) o;
+		GrantedAuthority[] gas = details.getPreAuthenticatedGrantedAuthorities();
+		assertNotNull("Granted authorities should not be null", gas);
+		assertTrue("Number of granted authorities should be " + expectedRoles.length, gas.length == expectedRoles.length);
+
+		Collection expectedRolesColl = Arrays.asList(expectedRoles);
+		Collection gasRolesSet = new HashSet();
+		for (int i = 0; i < gas.length; i++) {
+			gasRolesSet.add(gas[i].getAuthority());
+		}
+		assertTrue("Granted Authorities do not match expected roles", expectedRolesColl.containsAll(gasRolesSet)
+				&& gasRolesSet.containsAll(expectedRolesColl));
+	}
+
+	private final J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource getJ2eeBasedPreAuthenticatedWebAuthenticationDetailsSource(
+			String[] mappedRoles) {
+		J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource result = new J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource();
+		result.setJ2eeMappableRolesRetriever(getMappableRolesRetriever(mappedRoles));
+		result.setJ2eeUserRoles2GrantedAuthoritiesMapper(getJ2eeUserRoles2GrantedAuthoritiesMapper());
+		result.setClazz(PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.class);
+
+		try {
+			result.afterPropertiesSet();
+		} catch (Exception expected) {
+			fail("AfterPropertiesSet throws unexpected exception");
+		}
+		return result;
+	}
+
+	private MappableRolesRetriever getMappableRolesRetriever(String[] mappedRoles) {
+		SimpleMappableRolesRetriever result = new SimpleMappableRolesRetriever();
+		result.setMappableRoles(mappedRoles);
+		return result;
+	}
+
+	private Roles2GrantedAuthoritiesMapper getJ2eeUserRoles2GrantedAuthoritiesMapper() {
+		SimpleRoles2GrantedAuthoritiesMapper result = new SimpleRoles2GrantedAuthoritiesMapper();
+		result.setAddPrefixIfAlreadyExisting(false);
+		result.setConvertRoleToLowerCase(false);
+		result.setConvertRoleToUpperCase(false);
+		result.setRolePrefix("");
+		return result;
+	}
+	
+	private final HttpServletRequest getRequest(final String userName,final String[] aRoles)
+	{
+		MockHttpServletRequest req = new MockHttpServletRequest() {
+			private Set roles = new HashSet(Arrays.asList(aRoles));
+			public boolean isUserInRole(String arg0) {
+				return roles.contains(arg0);
+			}
+		};
+		req.setRemoteUser(userName);
+		return req;
+	}
+}

+ 49 - 0
core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilterTests.java

@@ -0,0 +1,49 @@
+package org.springframework.security.ui.preauth.j2ee;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+
+import junit.framework.TestCase;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+
+/**
+ * 
+ * @author TSARDD
+ * @since 18-okt-2007
+ */
+public class J2eePreAuthenticatedProcessingFilterTests extends TestCase {
+
+    public final void testGetPreAuthenticatedPrincipal() {
+		String user = "testUser";
+		assertEquals(user, new J2eePreAuthenticatedProcessingFilter().getPreAuthenticatedPrincipal(
+			getRequest(user,new String[] {})));
+	}
+
+	public final void testGetPreAuthenticatedCredentials() {
+		assertEquals("N/A", new J2eePreAuthenticatedProcessingFilter().getPreAuthenticatedCredentials(
+			getRequest("testUser", new String[] {})));
+	}
+	
+	private final HttpServletRequest getRequest(final String aUserName,final String[] aRoles)
+	{
+		MockHttpServletRequest req = new MockHttpServletRequest() {
+			private Set roles = new HashSet(Arrays.asList(aRoles));
+			public boolean isUserInRole(String arg0) {
+				return roles.contains(arg0);
+			}
+		};
+		req.setRemoteUser(aUserName);
+		req.setUserPrincipal(new Principal() {
+			public String getName() {
+				return aUserName;
+			}
+		});
+		return req;
+	}
+
+}

+ 34 - 0
core/src/test/java/org/springframework/security/ui/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java

@@ -0,0 +1,34 @@
+package org.springframework.security.ui.preauth.j2ee;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class WebXmlJ2eeDefinedRolesRetrieverTests extends TestCase {
+
+	public final void testRole1To4Roles() throws Exception {
+		final List ROLE1TO4_EXPECTED_ROLES = Arrays.asList(new String[] { "Role1", "Role2", "Role3", "Role4" });
+		InputStream role1to4InputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("webxml/Role1-4.web.xml");
+		WebXmlMappableRolesRetriever rolesRetriever = new WebXmlMappableRolesRetriever();
+		rolesRetriever.setWebXmlInputStream(role1to4InputStream);
+		rolesRetriever.afterPropertiesSet();
+		String[] j2eeRoles = rolesRetriever.getMappableRoles();
+		assertNotNull(j2eeRoles);
+		List j2eeRolesList = Arrays.asList(j2eeRoles);
+		assertTrue("J2eeRoles expected size: " + ROLE1TO4_EXPECTED_ROLES.size() + ", actual size: " + j2eeRolesList.size(), j2eeRolesList
+				.size() == ROLE1TO4_EXPECTED_ROLES.size());
+		assertTrue("J2eeRoles expected contents (arbitrary order): " + ROLE1TO4_EXPECTED_ROLES + ", actual content: " + j2eeRolesList,
+				j2eeRolesList.containsAll(ROLE1TO4_EXPECTED_ROLES));
+	}
+
+	public final void testGetZeroJ2eeRoles() throws Exception {
+		InputStream noRolesInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("webxml/NoRoles.web.xml");
+		WebXmlMappableRolesRetriever rolesRetriever = new WebXmlMappableRolesRetriever();
+		rolesRetriever.setWebXmlInputStream(noRolesInputStream);
+		rolesRetriever.afterPropertiesSet();
+		String[] j2eeRoles = rolesRetriever.getMappableRoles();
+		assertTrue("J2eeRoles expected size: 0, actual size: " + j2eeRoles.length, j2eeRoles.length == 0);
+	}
+}