diff --git a/core/pom.xml b/core/pom.xml index d290407e7a..313b8a910b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -82,6 +82,12 @@ 1.2 true + + jaxen + jaxen + 1.1.1 + true + javax.servlet jsp-api diff --git a/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProvider.java b/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProvider.java new file mode 100755 index 0000000000..5f25d3c8c8 --- /dev/null +++ b/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; + +/** + *

+ * Processes a pre-authenticated authentication request. The request will + * typically originate from a {@link AbstractPreAuthenticatedProcessingFilter} + * subclass. + *

+ * + *

+ * 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. + *

+ */ +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; + } +} diff --git a/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationToken.java b/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationToken.java new file mode 100755 index 0000000000..4bffbedf63 --- /dev/null +++ b/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 + * false. + * + * @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 + * true. + * + * @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; + } + +} diff --git a/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesRetriever.java b/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesRetriever.java new file mode 100755 index 0000000000..4410dda924 --- /dev/null +++ b/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(); +} diff --git a/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesSetter.java b/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesSetter.java new file mode 100755 index 0000000000..b889ccfc6a --- /dev/null +++ b/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); +} diff --git a/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsService.java b/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsService.java new file mode 100755 index 0000000000..293c6b6c24 --- /dev/null +++ b/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; + +/** + *

+ * 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(). + *

+ * + *

+ * The details object as returned by + * PreAuthenticatedAuthenticationToken.getDetails() must implement the + * PreAuthenticatedGrantedAuthoritiesRetriever interface for this implementation + * to work. + *

+ */ +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; + } +} diff --git a/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedUserDetailsService.java b/core/src/main/java/org/springframework/security/providers/preauth/PreAuthenticatedUserDetailsService.java new file mode 100755 index 0000000000..4c8a2167ce --- /dev/null +++ b/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; +} diff --git a/core/src/main/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapper.java b/core/src/main/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapper.java new file mode 100755 index 0000000000..c9b23be98a --- /dev/null +++ b/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; + } +} diff --git a/core/src/main/java/org/springframework/security/rolemapping/MappableRolesRetriever.java b/core/src/main/java/org/springframework/security/rolemapping/MappableRolesRetriever.java new file mode 100755 index 0000000000..c243881983 --- /dev/null +++ b/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(); +} diff --git a/core/src/main/java/org/springframework/security/rolemapping/Roles2GrantedAuthoritiesMapper.java b/core/src/main/java/org/springframework/security/rolemapping/Roles2GrantedAuthoritiesMapper.java new file mode 100755 index 0000000000..958cfeecac --- /dev/null +++ b/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); +} diff --git a/core/src/main/java/org/springframework/security/rolemapping/SimpleMappableRolesRetriever.java b/core/src/main/java/org/springframework/security/rolemapping/SimpleMappableRolesRetriever.java new file mode 100755 index 0000000000..6b51f69c6f --- /dev/null +++ b/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); + } + +} diff --git a/core/src/main/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapper.java b/core/src/main/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapper.java new file mode 100755 index 0000000000..6619662c58 --- /dev/null +++ b/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; + +/** + *

+ * 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. + *

+ * + *

+ * By default, the role is prefixed with "ROLE_" unless it already starts with + * "ROLE_", and no case conversion is done. + *

+ */ +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; + } + +} diff --git a/core/src/main/java/org/springframework/security/rolemapping/XmlMappableRolesRetriever.java b/core/src/main/java/org/springframework/security/rolemapping/XmlMappableRolesRetriever.java new file mode 100755 index 0000000000..239dd31566 --- /dev/null +++ b/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 + } + } +} diff --git a/core/src/main/java/org/springframework/security/ui/preauth/AbstractPreAuthenticatedProcessingFilter.java b/core/src/main/java/org/springframework/security/ui/preauth/AbstractPreAuthenticatedProcessingFilter.java new file mode 100755 index 0000000000..fb6e114ada --- /dev/null +++ b/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. + *

+ * This code is partly based on + * {@link org.springframework.security.ui.x509.X509ProcessingFilter}. + *

+ */ +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 Authentication 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); +} diff --git a/core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.java b/core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.java new file mode 100755 index 0000000000..1827dd8c41 --- /dev/null +++ b/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); + } +} diff --git a/core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPoint.java b/core/src/main/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPoint.java new file mode 100755 index 0000000000..cafeb155ac --- /dev/null +++ b/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; + +/** + *

+ * 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. + *

+ *

+ * 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. + *

+ *

+ * The commence method will always return an + * HttpServletResponse.SC_FORBIDDEN (403 error). + *

+ *

+ * This code is based on + * {@link org.springframework.security.ui.x509.X509ProcessingFilterEntryPoint}. + *

+ * + * @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; + } + +} diff --git a/core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.java b/core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.java new file mode 100755 index 0000000000..1b6f97c624 --- /dev/null +++ b/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; + } + +} diff --git a/core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java b/core/src/main/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java new file mode 100755 index 0000000000..b85cddb22e --- /dev/null +++ b/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"; + } +} diff --git a/core/src/main/java/org/springframework/security/ui/preauth/j2ee/WebXmlMappableRolesRetriever.java b/core/src/main/java/org/springframework/security/ui/preauth/j2ee/WebXmlMappableRolesRetriever.java new file mode 100755 index 0000000000..1a2d9cb598 --- /dev/null +++ b/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; + +/** + *

+ * 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. + *

+ * + *

+ * Example on how to configure this MappableRolesRetriever in the Spring + * configuration file: + * + *

+ * 
+ *  
+ *   	<bean id="j2eeMappableRolesRetriever" class="org.springframework.security.ui.preauth.j2ee.WebXmlMappableRolesRetriever">
+ *  		<property name="webXmlInputStream"><bean factory-bean="webXmlResource" factory-method="getInputStream"/></property>
+ *  	</bean>
+ *  	<bean id="webXmlResource" class="org.springframework.web.context.support.ServletContextResource">
+ *  		<constructor-arg><ref local="servletContext"/></constructor-arg>
+ *  		<constructor-arg><value>/WEB-INF/web.xml</value></constructor-arg>
+ *  	</bean>
+ *  	<bean id="servletContext" class="org.springframework.web.context.support.ServletContextFactoryBean"/>
+ *   
+ *  
+ * 
+ * + *

+ */ +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); + } +} diff --git a/core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProviderTests.java b/core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationProviderTests.java new file mode 100755 index 0000000000..991dea30b4 --- /dev/null +++ b/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; + } + } + }; + } + +} diff --git a/core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationTokenTests.java b/core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedAuthenticationTokenTests.java new file mode 100755 index 0000000000..3af8f164fb --- /dev/null +++ b/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)); + + } + +} diff --git a/core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsServiceTests.java b/core/src/test/java/org/springframework/security/providers/preauth/PreAuthenticatedGrantedAuthoritiesUserDetailsServiceTests.java new file mode 100755 index 0000000000..a7e50f6bca --- /dev/null +++ b/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)); + } + +} diff --git a/core/src/test/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapperTests.java b/core/src/test/java/org/springframework/security/providers/preauth/UserDetailsByNameServiceWrapperTests.java new file mode 100755 index 0000000000..a8f1a033ca --- /dev/null +++ b/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); + } + +} diff --git a/core/src/test/java/org/springframework/security/rolemapping/SimpleMappableRolesRetrieverTests.java b/core/src/test/java/org/springframework/security/rolemapping/SimpleMappableRolesRetrieverTests.java new file mode 100755 index 0000000000..4223fcd872 --- /dev/null +++ b/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)); + } + +} diff --git a/core/src/test/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapperTests.java b/core/src/test/java/org/springframework/security/rolemapping/SimpleRoles2GrantedAuthoritiesMapperTests.java new file mode 100755 index 0000000000..b37eced405 --- /dev/null +++ b/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; + } + +} diff --git a/core/src/test/java/org/springframework/security/rolemapping/XmlMappableRolesRetrieverTests.java b/core/src/test/java/org/springframework/security/rolemapping/XmlMappableRolesRetrieverTests.java new file mode 100755 index 0000000000..684714a98e --- /dev/null +++ b/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 = "Role1Role2"; + + 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; + } + } +} diff --git a/core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetailsTests.java b/core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetailsTests.java new file mode 100755 index 0000000000..d75cc9e3b8 --- /dev/null +++ b/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; + } + +} diff --git a/core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPointTests.java b/core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcesingFilterEntryPointTests.java new file mode 100755 index 0000000000..d8e3275e5b --- /dev/null +++ b/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); + } + + } +} diff --git a/core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcessingFilterTests.java b/core/src/test/java/org/springframework/security/ui/preauth/PreAuthenticatedProcessingFilterTests.java new file mode 100755 index 0000000000..25a8760425 --- /dev/null +++ b/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"; + } + } +} diff --git a/core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSourceTests.java b/core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eeBasedPreAuthenticatedWebAuthenticationDetailsSourceTests.java new file mode 100755 index 0000000000..85112e3fa2 --- /dev/null +++ b/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; + } +} diff --git a/core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilterTests.java b/core/src/test/java/org/springframework/security/ui/preauth/j2ee/J2eePreAuthenticatedProcessingFilterTests.java new file mode 100755 index 0000000000..0dd6070f64 --- /dev/null +++ b/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; + } + +} diff --git a/core/src/test/java/org/springframework/security/ui/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java b/core/src/test/java/org/springframework/security/ui/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java new file mode 100755 index 0000000000..cd85acacf0 --- /dev/null +++ b/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); + } +}