From fddcd6112ee7dca2c1fd9f6d49af2d124a14ecdc Mon Sep 17 00:00:00 2001 From: Ben Alex Date: Sat, 26 Nov 2005 05:11:53 +0000 Subject: [PATCH] SEC-56: Add localisation support. --- .../acl/basic/jdbc/JdbcDaoImpl.java | 639 ++++++++-------- .../adapters/AuthByAdapterProvider.java | 43 +- .../BasicAclEntryAfterInvocationProvider.java | 105 +-- .../ConcurrentSessionControllerImpl.java | 208 +++--- .../AbstractSecurityInterceptor.java | 629 ++++++++-------- .../org/acegisecurity/messages.properties | 39 + .../providers/ProviderManager.java | 183 ++--- .../AnonymousAuthenticationProvider.java | 39 +- .../cas/CasAuthenticationProvider.java | 145 ++-- .../cas/proxy/NamedCasProxyDecider.java | 41 +- .../cas/proxy/RejectProxyTickets.java | 32 +- ...ractUserDetailsAuthenticationProvider.java | 271 +++---- .../dao/DaoAuthenticationProvider.java | 150 ++-- .../RememberMeAuthenticationProvider.java | 37 +- .../x509/X509AuthenticationProvider.java | 119 +-- .../DaoX509AuthoritiesPopulator.java | 105 +-- .../RunAsImplAuthenticationProvider.java | 42 +- .../ui/AbstractProcessingFilter.java | 245 +++--- .../ui/digestauth/DigestProcessingFilter.java | 202 ++--- .../SwitchUserProcessingFilter.java | 707 ++++++++++-------- .../vote/AbstractAccessDecisionManager.java | 51 +- .../acegisecurity/vote/AffirmativeBased.java | 13 +- .../acegisecurity/vote/ConsensusBased.java | 35 +- .../acegisecurity/vote/UnanimousBased.java | 13 +- .../adapters/AuthByAdapterTests.java | 4 + ...cAclEntryAfterInvocationProviderTests.java | 10 + .../ConcurrentSessionControllerImplTests.java | 2 + .../MethodSecurityInterceptorTests.java | 13 + .../AspectJSecurityInterceptorTests.java | 3 + .../web/FilterSecurityInterceptorTests.java | 6 + .../providers/ProviderManagerTests.java | 3 +- .../AnonymousAuthenticationProviderTests.java | 7 + .../cas/CasAuthenticationProviderTests.java | 14 + .../cas/proxy/NamedCasProxyDeciderTests.java | 22 +- .../cas/proxy/RejectProxyTicketsTests.java | 2 + .../dao/DaoAuthenticationProviderTests.java | 23 + ...RememberMeAuthenticationProviderTests.java | 6 + .../x509/X509AuthenticationProviderTests.java | 6 + .../DaoX509AuthoritiesPopulatorTests.java | 7 + .../RunAsImplAuthenticationProviderTests.java | 17 +- .../SwitchUserProcessingFilterTests.java | 13 + .../vote/AffirmativeBasedTests.java | 2 + .../vote/ConsensusBasedTests.java | 2 + .../vote/UnanimousBasedTests.java | 10 + 44 files changed, 2403 insertions(+), 1862 deletions(-) create mode 100644 core/src/main/java/org/acegisecurity/messages.properties diff --git a/core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcDaoImpl.java b/core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcDaoImpl.java index a25e73071a..068d6030c8 100644 --- a/core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcDaoImpl.java +++ b/core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcDaoImpl.java @@ -29,6 +29,8 @@ import org.springframework.jdbc.core.SqlParameter; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.object.MappingSqlQuery; +import org.springframework.util.Assert; + import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; @@ -51,9 +53,6 @@ import javax.sql.DataSource; * the {@link MappingSqlQuery} instance used, via the {@link * #initMappingSqlQueries()} extension point. *

- * - * @author Ben Alex - * @version $Id$ */ public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao { //~ Static fields/initializers ============================================= @@ -79,113 +78,6 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao { //~ Methods ================================================================ - /** - * Returns the ACLs associated with the requested - * AclObjectIdentity. - * - *

- * The {@link BasicAclEntry}s returned by this method will have - * String-based recipients. This will not be a problem if you - * are using the GrantedAuthorityEffectiveAclsResolver, which - * is the default configured against BasicAclProvider. - *

- * - *

- * This method will only return ACLs for requests where the - * AclObjectIdentity is of type {@link - * NamedEntityObjectIdentity}. Of course, you can subclass or replace this - * class and support your own custom AclObjectIdentity types. - *

- * - * @param aclObjectIdentity for which ACL information is required (cannot - * be null and must be an instance of - * NamedEntityObjectIdentity) - * - * @return the ACLs that apply (without any nulls inside the - * array), or null if not found or if an incompatible - * AclObjectIdentity was requested - */ - public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity) { - String aclObjectIdentityString; - - try { - aclObjectIdentityString = convertAclObjectIdentityToString(aclObjectIdentity); - } catch (IllegalArgumentException unsupported) { - return null; // pursuant to contract described in JavaDocs above - } - - // Lookup the object's main properties from the RDBMS (guaranteed no nulls) - List objects = objectProperties.execute(aclObjectIdentityString); - - if (objects.size() == 0) { - // this is an unknown object identity string - return null; - } - - // Cast to an object properties holder (there should only be one record) - AclDetailsHolder propertiesInformation = (AclDetailsHolder) objects.get(0); - - // Lookup the object's ACLs from RDBMS (guaranteed no nulls) - List acls = aclsByObjectIdentity.execute(propertiesInformation - .getForeignKeyId()); - - if (acls.size() == 0) { - // return merely an inheritence marker (as we know about the object but it has no related ACLs) - return new BasicAclEntry[] {createBasicAclEntry(propertiesInformation, - null)}; - } else { - // return the individual ACL instances - AclDetailsHolder[] aclHolders = (AclDetailsHolder[]) acls.toArray(new AclDetailsHolder[] {}); - List toReturnAcls = new Vector(); - - for (int i = 0; i < aclHolders.length; i++) { - toReturnAcls.add(createBasicAclEntry(propertiesInformation, - aclHolders[i])); - } - - return (BasicAclEntry[]) toReturnAcls.toArray(new BasicAclEntry[] {}); - } - } - - public void setAclsByObjectIdentity( - MappingSqlQuery aclsByObjectIdentityQuery) { - this.aclsByObjectIdentity = aclsByObjectIdentityQuery; - } - - public MappingSqlQuery getAclsByObjectIdentity() { - return aclsByObjectIdentity; - } - - /** - * Allows the default query string used to retrieve ACLs based on object - * identity to be overriden, if default table or column names need to be - * changed. The default query is {@link - * #DEF_ACLS_BY_OBJECT_IDENTITY_QUERY}; when modifying this query, ensure - * that all returned columns are mapped back to the same column names as - * in the default query. - * - * @param queryString The query string to set - */ - public void setAclsByObjectIdentityQuery(String queryString) { - aclsByObjectIdentityQuery = queryString; - } - - public String getAclsByObjectIdentityQuery() { - return aclsByObjectIdentityQuery; - } - - public void setObjectProperties(MappingSqlQuery objectPropertiesQuery) { - this.objectProperties = objectPropertiesQuery; - } - - public void setObjectPropertiesQuery(String queryString) { - objectPropertiesQuery = queryString; - } - - public String getObjectPropertiesQuery() { - return objectPropertiesQuery; - } - /** * Responsible for covering a AclObjectIdentity to a * String that can be located in the RDBMS. @@ -193,17 +85,13 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao { * @param aclObjectIdentity to locate * * @return the object identity as a String - * - * @throws IllegalArgumentException DOCUMENT ME! */ protected String convertAclObjectIdentityToString( AclObjectIdentity aclObjectIdentity) { // Ensure we can process this type of AclObjectIdentity - if (!(aclObjectIdentity instanceof NamedEntityObjectIdentity)) { - throw new IllegalArgumentException( - "Only aclObjectIdentity of type NamedEntityObjectIdentity supported (was passed: " - + aclObjectIdentity + ")"); - } + Assert.isInstanceOf(NamedEntityObjectIdentity.class, aclObjectIdentity, + "Only aclObjectIdentity of type NamedEntityObjectIdentity supported (was passed: " + + aclObjectIdentity + ")"); NamedEntityObjectIdentity neoi = (NamedEntityObjectIdentity) aclObjectIdentity; @@ -211,19 +99,6 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao { return neoi.getClassname() + ":" + neoi.getId(); } - protected void initDao() throws ApplicationContextException { - initMappingSqlQueries(); - } - - /** - * Extension point to allow other MappingSqlQuery objects to be substituted - * in a subclass - */ - protected void initMappingSqlQueries() { - setAclsByObjectIdentity(new AclsByObjectIdentityMapping(getDataSource())); - setObjectProperties(new ObjectPropertiesMapping(getDataSource())); - } - /** * Constructs an individual BasicAclEntry from the passed * AclDetailsHolders. @@ -263,206 +138,336 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements BasicAclDao { entry.setAclObjectIdentity(propertiesInformation.getAclObjectIdentity()); entry.setAclObjectParentIdentity(propertiesInformation - .getAclObjectParentIdentity()); + .getAclObjectParentIdentity()); - if (aclInformation == null) { - // this is an inheritence marker instance only - entry.setMask(0); - entry.setRecipient(RECIPIENT_USED_FOR_INHERITENCE_MARKER); - } else { - // this is an individual ACL entry - entry.setMask(aclInformation.getMask()); - entry.setRecipient(aclInformation.getRecipient()); - } + if (aclInformation == null) { + // this is an inheritence marker instance only + entry.setMask(0); + entry.setRecipient(RECIPIENT_USED_FOR_INHERITENCE_MARKER); + } else { + // this is an individual ACL entry + entry.setMask(aclInformation.getMask()); + entry.setRecipient(aclInformation.getRecipient()); + } - return entry; - } - - //~ Inner Classes ========================================================== - - /** - * Used to hold details of a domain object instance's properties, or an - * individual ACL entry. - * - *

- * Not all properties will be set. The actual properties set will depend on - * which MappingSqlQuery creates the object. - *

- * - *

- * Does not enforce nulls or empty Strings as - * this is performed by the MappingSqlQuery objects (or - * preferably the backend RDBMS via schema constraints). - *

- */ - protected final class AclDetailsHolder { - private AclObjectIdentity aclObjectIdentity; - private AclObjectIdentity aclObjectParentIdentity; - private Class aclClass; - private Object recipient; - private int mask; - private long foreignKeyId; - - /** - * Record details of an individual ACL entry (usually from the - * ACL_PERMISSION table) - * - * @param recipient the recipient - * @param mask the integer to be masked - */ - public AclDetailsHolder(Object recipient, int mask) { - this.recipient = recipient; - this.mask = mask; + return entry; } /** - * Record details of a domain object instance's properties (usually - * from the ACL_OBJECT_IDENTITY table) + * Returns the ACLs associated with the requested + * AclObjectIdentity. + * + *

+ * The {@link BasicAclEntry}s returned by this method will have + * String-based recipients. This will not be a problem if + * you are using the + * GrantedAuthorityEffectiveAclsResolver, which is the + * default configured against BasicAclProvider. + *

+ * + *

+ * This method will only return ACLs for requests where the + * AclObjectIdentity is of type {@link + * NamedEntityObjectIdentity}. Of course, you can subclass or replace + * this class and support your own custom + * AclObjectIdentity types. + *

* - * @param foreignKeyId used by the - * AclsByObjectIdentityMapping to locate the - * individual ACL entries - * @param aclObjectIdentity the object identity of the domain object - * instance - * @param aclObjectParentIdentity the object identity of the domain - * object instance's parent - * @param aclClass the class of which a new instance which should be - * created for each individual ACL entry (or an inheritence - * "holder" class if there are no ACL entries) + * @param aclObjectIdentity for which ACL information is required + * (cannot be null and must be an instance of + * NamedEntityObjectIdentity) + * + * @return the ACLs that apply (without any nulls inside + * the array), or null if not found or if an + * incompatible AclObjectIdentity was requested */ - public AclDetailsHolder(long foreignKeyId, - AclObjectIdentity aclObjectIdentity, - AclObjectIdentity aclObjectParentIdentity, Class aclClass) { - this.foreignKeyId = foreignKeyId; - this.aclObjectIdentity = aclObjectIdentity; - this.aclObjectParentIdentity = aclObjectParentIdentity; - this.aclClass = aclClass; - } - - public Class getAclClass() { - return aclClass; - } - - public AclObjectIdentity getAclObjectIdentity() { - return aclObjectIdentity; - } - - public AclObjectIdentity getAclObjectParentIdentity() { - return aclObjectParentIdentity; - } - - public long getForeignKeyId() { - return foreignKeyId; - } - - public int getMask() { - return mask; - } - - public Object getRecipient() { - return recipient; - } - } - - /** - * Query object to look up individual ACL entries. - * - *

- * Returns the generic AclDetailsHolder object. - *

- * - *

- * Guarantees to never return null (exceptions are thrown in - * the event of any issues). - *

- * - *

- * The executed SQL requires the following information be made available - * from the indicated placeholders: 1. RECIPIENT, 2. MASK. - *

- */ - protected class AclsByObjectIdentityMapping extends MappingSqlQuery { - protected AclsByObjectIdentityMapping(DataSource ds) { - super(ds, aclsByObjectIdentityQuery); - declareParameter(new SqlParameter(Types.BIGINT)); - compile(); - } - - protected Object mapRow(ResultSet rs, int rownum) - throws SQLException { - String recipient = rs.getString(1); - int mask = rs.getInt(2); - - if ((recipient == null) || "".equals(recipient)) { - throw new IllegalArgumentException("recipient required"); - } - - return new AclDetailsHolder(recipient, mask); - } - } - - /** - * Query object to look up properties for an object identity. - * - *

- * Returns the generic AclDetailsHolder object. - *

- * - *

- * Guarantees to never return null (exceptions are thrown in - * the event of any issues). - *

- * - *

- * The executed SQL requires the following information be made available - * from the indicated placeholders: 1. ID, 2. OBJECT_IDENTITY, 3. - * ACL_CLASS and 4. PARENT_OBJECT_IDENTITY. - *

- */ - protected class ObjectPropertiesMapping extends MappingSqlQuery { - protected ObjectPropertiesMapping(DataSource ds) { - super(ds, objectPropertiesQuery); - declareParameter(new SqlParameter(Types.VARCHAR)); - compile(); - } - - protected Object mapRow(ResultSet rs, int rownum) - throws SQLException { - long id = rs.getLong(1); // required - String objectIdentity = rs.getString(2); // required - String aclClass = rs.getString(3); // required - String parentObjectIdentity = rs.getString(4); // optional - - if ((objectIdentity == null) || "".equals(objectIdentity) - || (aclClass == null) || "".equals(aclClass)) { - // shouldn't happen if DB schema defined NOT NULL columns - throw new IllegalArgumentException( - "required DEF_OBJECT_PROPERTIES_QUERY value returned null or empty"); - } - - Class aclClazz; + public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity) { + String aclObjectIdentityString; try { - aclClazz = this.getClass().getClassLoader().loadClass(aclClass); - } catch (ClassNotFoundException cnf) { - throw new IllegalArgumentException(cnf.getMessage()); + aclObjectIdentityString = convertAclObjectIdentityToString(aclObjectIdentity); + } catch (IllegalArgumentException unsupported) { + return null; // pursuant to contract described in JavaDocs above } - return new AclDetailsHolder(id, buildIdentity(objectIdentity), - buildIdentity(parentObjectIdentity), aclClazz); - } + // Lookup the object's main properties from the RDBMS (guaranteed no nulls) + List objects = objectProperties.execute(aclObjectIdentityString); - private AclObjectIdentity buildIdentity(String identity) { - if (identity == null) { - // Must be an empty parent, so return null + if (objects.size() == 0) { + // this is an unknown object identity string return null; } - int delim = identity.lastIndexOf(":"); - String classname = identity.substring(0, delim); - String id = identity.substring(delim + 1); + // Cast to an object properties holder (there should only be one record) + AclDetailsHolder propertiesInformation = (AclDetailsHolder) objects + .get(0); - return new NamedEntityObjectIdentity(classname, id); - } - } -} + // Lookup the object's ACLs from RDBMS (guaranteed no nulls) + List acls = aclsByObjectIdentity.execute(propertiesInformation + .getForeignKeyId()); + + if (acls.size() == 0) { + // return merely an inheritence marker (as we know about the object but it has no related ACLs) + return new BasicAclEntry[] {createBasicAclEntry(propertiesInformation, + null)}; + } else { + // return the individual ACL instances + AclDetailsHolder[] aclHolders = (AclDetailsHolder[]) acls + .toArray(new AclDetailsHolder[] {}); + List toReturnAcls = new Vector(); + + for (int i = 0; i < aclHolders.length; i++) { + toReturnAcls.add(createBasicAclEntry( + propertiesInformation, aclHolders[i])); + } + + return (BasicAclEntry[]) toReturnAcls.toArray(new BasicAclEntry[] {}); + } + } + + public MappingSqlQuery getAclsByObjectIdentity() { + return aclsByObjectIdentity; + } + + public String getAclsByObjectIdentityQuery() { + return aclsByObjectIdentityQuery; + } + + public String getObjectPropertiesQuery() { + return objectPropertiesQuery; + } + + protected void initDao() throws ApplicationContextException { + initMappingSqlQueries(); + } + + /** + * Extension point to allow other MappingSqlQuery objects to be + * substituted in a subclass + */ + protected void initMappingSqlQueries() { + setAclsByObjectIdentity(new AclsByObjectIdentityMapping( + getDataSource())); + setObjectProperties(new ObjectPropertiesMapping( + getDataSource())); + } + + public void setAclsByObjectIdentity( + MappingSqlQuery aclsByObjectIdentityQuery) { + this.aclsByObjectIdentity = aclsByObjectIdentityQuery; + } + + /** + * Allows the default query string used to retrieve ACLs based + * on object identity to be overriden, if default table or + * column names need to be changed. The default query is + * {@link #DEF_ACLS_BY_OBJECT_IDENTITY_QUERY}; when modifying + * this query, ensure that all returned columns are mapped + * back to the same column names as in the default query. + * + * @param queryString The query string to set + */ + public void setAclsByObjectIdentityQuery(String queryString) { + aclsByObjectIdentityQuery = queryString; + } + + public void setObjectProperties( + MappingSqlQuery objectPropertiesQuery) { + this.objectProperties = objectPropertiesQuery; + } + + public void setObjectPropertiesQuery(String queryString) { + objectPropertiesQuery = queryString; + } + + //~ Inner Classes ========================================================== + + /** + * Used to hold details of a domain object instance's + * properties, or an individual ACL entry. + * + *

+ * Not all properties will be set. The actual properties set + * will depend on which MappingSqlQuery creates + * the object. + *

+ * + *

+ * Does not enforce nulls or empty + * Strings as this is performed by the + * MappingSqlQuery objects (or preferably the + * backend RDBMS via schema constraints). + *

+ */ + protected final class AclDetailsHolder { + private AclObjectIdentity aclObjectIdentity; + private AclObjectIdentity aclObjectParentIdentity; + private Class aclClass; + private Object recipient; + private int mask; + private long foreignKeyId; + + /** + * Record details of an individual ACL entry (usually from + * the ACL_PERMISSION table) + * + * @param recipient the recipient + * @param mask the integer to be masked + */ + public AclDetailsHolder(Object recipient, int mask) { + this.recipient = recipient; + this.mask = mask; + } + + /** + * Record details of a domain object instance's properties + * (usually from the ACL_OBJECT_IDENTITY table) + * + * @param foreignKeyId used by the + * AclsByObjectIdentityMapping to + * locate the individual ACL entries + * @param aclObjectIdentity the object identity of the + * domain object instance + * @param aclObjectParentIdentity the object identity of + * the domain object instance's parent + * @param aclClass the class of which a new instance which + * should be created for each individual ACL entry + * (or an inheritence "holder" class if there are + * no ACL entries) + */ + public AclDetailsHolder(long foreignKeyId, + AclObjectIdentity aclObjectIdentity, + AclObjectIdentity aclObjectParentIdentity, + Class aclClass) { + this.foreignKeyId = foreignKeyId; + this.aclObjectIdentity = aclObjectIdentity; + this.aclObjectParentIdentity = aclObjectParentIdentity; + this.aclClass = aclClass; + } + + public Class getAclClass() { + return aclClass; + } + + public AclObjectIdentity getAclObjectIdentity() { + return aclObjectIdentity; + } + + public AclObjectIdentity getAclObjectParentIdentity() { + return aclObjectParentIdentity; + } + + public long getForeignKeyId() { + return foreignKeyId; + } + + public int getMask() { + return mask; + } + + public Object getRecipient() { + return recipient; + } + } + + /** + * Query object to look up individual ACL entries. + * + *

+ * Returns the generic AclDetailsHolder object. + *

+ * + *

+ * Guarantees to never return null (exceptions are + * thrown in the event of any issues). + *

+ * + *

+ * The executed SQL requires the following information be made + * available from the indicated placeholders: 1. RECIPIENT, 2. + * MASK. + *

+ */ + protected class AclsByObjectIdentityMapping + extends MappingSqlQuery { + protected AclsByObjectIdentityMapping(DataSource ds) { + super(ds, aclsByObjectIdentityQuery); + declareParameter(new SqlParameter(Types.BIGINT)); + compile(); + } + + protected Object mapRow(ResultSet rs, int rownum) + throws SQLException { + String recipient = rs.getString(1); + int mask = rs.getInt(2); + Assert.hasText(recipient, "recipient required"); + + return new AclDetailsHolder(recipient, mask); + } + } + + /** + * Query object to look up properties for an object identity. + * + *

+ * Returns the generic AclDetailsHolder object. + *

+ * + *

+ * Guarantees to never return null (exceptions are + * thrown in the event of any issues). + *

+ * + *

+ * The executed SQL requires the following information be made + * available from the indicated placeholders: 1. ID, 2. + * OBJECT_IDENTITY, 3. ACL_CLASS and 4. + * PARENT_OBJECT_IDENTITY. + *

+ */ + protected class ObjectPropertiesMapping extends MappingSqlQuery { + protected ObjectPropertiesMapping(DataSource ds) { + super(ds, objectPropertiesQuery); + declareParameter(new SqlParameter(Types.VARCHAR)); + compile(); + } + + private AclObjectIdentity buildIdentity(String identity) { + if (identity == null) { + // Must be an empty parent, so return null + return null; + } + + int delim = identity.lastIndexOf(":"); + String classname = identity.substring(0, delim); + String id = identity.substring(delim + 1); + + return new NamedEntityObjectIdentity(classname, id); + } + + protected Object mapRow(ResultSet rs, int rownum) + throws SQLException { + long id = rs.getLong(1); // required + String objectIdentity = rs.getString(2); // required + String aclClass = rs.getString(3); // required + String parentObjectIdentity = rs.getString(4); // optional + Assert.hasText(objectIdentity, + "required DEF_OBJECT_PROPERTIES_QUERY value (objectIdentity) returned null or empty"); + Assert.hasText(aclClass, + "required DEF_OBJECT_PROPERTIES_QUERY value (aclClass) returned null or empty"); + + Class aclClazz; + + try { + aclClazz = this.getClass().getClassLoader() + .loadClass(aclClass); + } catch (ClassNotFoundException cnf) { + throw new IllegalArgumentException(cnf.getMessage()); + } + + return new AclDetailsHolder(id, + buildIdentity(objectIdentity), + buildIdentity(parentObjectIdentity), aclClazz); + } + } + } diff --git a/core/src/main/java/org/acegisecurity/adapters/AuthByAdapterProvider.java b/core/src/main/java/org/acegisecurity/adapters/AuthByAdapterProvider.java index e10fcaec2a..8232131258 100644 --- a/core/src/main/java/org/acegisecurity/adapters/AuthByAdapterProvider.java +++ b/core/src/main/java/org/acegisecurity/adapters/AuthByAdapterProvider.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,15 @@ package org.acegisecurity.adapters; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.acegisecurity.BadCredentialsException; + import org.acegisecurity.providers.AuthenticationProvider; import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; @@ -38,28 +44,20 @@ import org.springframework.util.Assert; *

* If the key does not match, a BadCredentialsException is thrown. *

- * - * @author Ben Alex - * @version $Id$ */ public class AuthByAdapterProvider implements InitializingBean, - AuthenticationProvider { + AuthenticationProvider, MessageSourceAware { //~ Instance fields ======================================================== + protected MessageSourceAccessor messages; private String key; //~ Methods ================================================================ - public void setKey(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - public void afterPropertiesSet() throws Exception { - Assert.notNull(key, "A Key is required and should match that configured for the adapters"); + Assert.notNull(key, + "A Key is required and should match that configured for the adapters"); + Assert.notNull(messages, "A message source must be set"); } public Authentication authenticate(Authentication authentication) @@ -69,11 +67,24 @@ public class AuthByAdapterProvider implements InitializingBean, if (token.getKeyHash() == key.hashCode()) { return authentication; } else { - throw new BadCredentialsException( - "The presented AuthByAdapter implementation does not contain the expected key"); + throw new BadCredentialsException(messages.getMessage( + "AuthByAdapterProvider.incorrectKey", + "The presented AuthByAdapter implementation does not contain the expected key")); } } + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + public boolean supports(Class authentication) { if (AuthByAdapter.class.isAssignableFrom(authentication)) { return true; diff --git a/core/src/main/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProvider.java b/core/src/main/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProvider.java index f250c03efa..58fb86320f 100644 --- a/core/src/main/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProvider.java +++ b/core/src/main/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProvider.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; import org.acegisecurity.ConfigAttribute; import org.acegisecurity.ConfigAttributeDefinition; + import org.acegisecurity.acl.AclEntry; import org.acegisecurity.acl.AclManager; import org.acegisecurity.acl.basic.BasicAclEntry; @@ -28,6 +29,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; import java.util.Iterator; @@ -45,9 +51,8 @@ import java.util.Iterator; * (ACL) permissions associated with a domain object instance for the current * Authentication object. This class is designed to process * {@link AclEntry}s that are subclasses of {@link - * org.acegisecurity.acl.basic.BasicAclEntry} only. Generally these - * are obtained by using the {@link - * org.acegisecurity.acl.basic.BasicAclProvider}. + * org.acegisecurity.acl.basic.BasicAclEntry} only. Generally these are + * obtained by using the {@link org.acegisecurity.acl.basic.BasicAclProvider}. *

* *

@@ -55,8 +60,8 @@ import java.util.Iterator; * ConfigAttribute#getAttribute()} matches the {@link * #processConfigAttribute}. The provider will then lookup the ACLs from the * AclManager and ensure the principal is {@link - * org.acegisecurity.acl.basic.BasicAclEntry#isPermitted(int)} for - * at least one of the {@link #requirePermission}s. + * org.acegisecurity.acl.basic.BasicAclEntry#isPermitted(int)} for at least + * one of the {@link #requirePermission}s. *

* *

@@ -74,9 +79,8 @@ import java.util.Iterator; *

* The AclManager is allowed to return any implementations of * AclEntry it wishes. However, this provider will only be able - * to validate against BasicAclEntrys, and thus access - * will be denied if no AclEntry is of type - * BasicAclEntry. + * to validate against BasicAclEntrys, and thus access will be + * denied if no AclEntry is of type BasicAclEntry. *

* *

@@ -87,12 +91,9 @@ import java.util.Iterator; *

* All comparisons and prefixes are case sensitive. *

- * - * @author Ben Alex - * @version $Id$ */ public class BasicAclEntryAfterInvocationProvider - implements AfterInvocationProvider, InitializingBean { + implements AfterInvocationProvider, InitializingBean, MessageSourceAware { //~ Static fields/initializers ============================================= protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationProvider.class); @@ -100,41 +101,21 @@ public class BasicAclEntryAfterInvocationProvider //~ Instance fields ======================================================== private AclManager aclManager; + protected MessageSourceAccessor messages; private String processConfigAttribute = "AFTER_ACL_READ"; private int[] requirePermission = {SimpleAclEntry.READ}; //~ Methods ================================================================ - public void setAclManager(AclManager aclManager) { - this.aclManager = aclManager; - } - - public AclManager getAclManager() { - return aclManager; - } - - public void setProcessConfigAttribute(String processConfigAttribute) { - this.processConfigAttribute = processConfigAttribute; - } - - public String getProcessConfigAttribute() { - return processConfigAttribute; - } - - public void setRequirePermission(int[] requirePermission) { - this.requirePermission = requirePermission; - } - - public int[] getRequirePermission() { - return requirePermission; - } - public void afterPropertiesSet() throws Exception { - Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory"); + Assert.notNull(processConfigAttribute, + "A processConfigAttribute is mandatory"); Assert.notNull(aclManager, "An aclManager is mandatory"); + Assert.notNull(messages, "A message source must be set"); if ((requirePermission == null) || (requirePermission.length == 0)) { - throw new IllegalArgumentException("One or more requirePermission entries is mandatory"); + throw new IllegalArgumentException( + "One or more requirePermission entries is mandatory"); } } @@ -162,16 +143,16 @@ public class BasicAclEntryAfterInvocationProvider authentication); if ((acls == null) || (acls.length == 0)) { - throw new AccessDeniedException("Authentication: " - + authentication.toString() - + " has NO permissions at all to the domain object: " - + returnedObject); + throw new AccessDeniedException(messages.getMessage( + "BasicAclEntryAfterInvocationProvider.noPermission", + new Object[] {authentication.getName(), returnedObject}, + "Authentication {0} has NO permissions at all to the domain object {1}")); } for (int i = 0; i < acls.length; i++) { // Locate processable AclEntrys if (acls[i] instanceof BasicAclEntry) { - BasicAclEntry processableAcl = (BasicAclEntry) acls[i]; + BasicAclEntry processableAcl = (BasicAclEntry) acls[i]; // See if principal has any of the required permissions for (int y = 0; y < requirePermission.length; y++) { @@ -190,16 +171,44 @@ public class BasicAclEntryAfterInvocationProvider } // No permissions match - throw new AccessDeniedException("Authentication: " - + authentication.toString() - + " has ACL permissions to the domain object, but not the required ACL permission to the domain object: " - + returnedObject); + throw new AccessDeniedException(messages.getMessage( + "BasicAclEntryAfterInvocationProvider.insufficientPermission", + new Object[] {authentication.getName(), returnedObject}, + "Authentication {0} has ACL permissions to the domain object, but not the required ACL permission to the domain object {1}")); } } return returnedObject; } + public AclManager getAclManager() { + return aclManager; + } + + public String getProcessConfigAttribute() { + return processConfigAttribute; + } + + public int[] getRequirePermission() { + return requirePermission; + } + + public void setAclManager(AclManager aclManager) { + this.aclManager = aclManager; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + public void setProcessConfigAttribute(String processConfigAttribute) { + this.processConfigAttribute = processConfigAttribute; + } + + public void setRequirePermission(int[] requirePermission) { + this.requirePermission = requirePermission; + } + public boolean supports(ConfigAttribute attribute) { if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) { diff --git a/core/src/main/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImpl.java b/core/src/main/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImpl.java index f487fbee25..284d54d31f 100644 --- a/core/src/main/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImpl.java +++ b/core/src/main/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImpl.java @@ -19,6 +19,11 @@ import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; @@ -30,36 +35,61 @@ import org.springframework.util.Assert; * By default uses {@link org.acegisecurity.concurrent.SessionRegistryImpl}, * although any SessionRegistry may be used. *

- * - * @author Ben Alex - * @version $Id$ */ public class ConcurrentSessionControllerImpl - implements ConcurrentSessionController, InitializingBean { + implements ConcurrentSessionController, InitializingBean, + MessageSourceAware { //~ Instance fields ======================================================== + protected MessageSourceAccessor messages; private SessionRegistry sessionRegistry = new SessionRegistryImpl(); - private int maximumSessions = 1; private boolean exceptionIfMaximumExceeded = false; + private int maximumSessions = 1; //~ Methods ================================================================ - public void setMaximumSessions(int maximumSessions) { - this.maximumSessions = maximumSessions; - } - - public void setSessionRegistry(SessionRegistry sessionRegistry) { - this.sessionRegistry = sessionRegistry; - } - - public void setExceptionIfMaximumExceeded(boolean exceptionIfMaximumExceeded) { - this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded; - } - - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() throws Exception { Assert.notNull(sessionRegistry, "SessionRegistry required"); Assert.isTrue(maximumSessions != 0, "MaximumLogins must be either -1 to allow unlimited logins, or a positive integer to specify a maximum"); + Assert.notNull(this.messages, "A message source must be set"); + } + + /** + * Allows subclasses to customise behaviour when too many sessions are + * detected. + * + * @param sessionId the session ID of the present request + * @param sessions either null or all unexpired sessions + * associated with the principal + * @param allowableSessions DOCUMENT ME! + * @param registry an instance of the SessionRegistry for + * subclass use + * + * @throws ConcurrentLoginException DOCUMENT ME! + */ + protected void allowableSessionsExceeded(String sessionId, + SessionInformation[] sessions, int allowableSessions, + SessionRegistry registry) { + if (exceptionIfMaximumExceeded || (sessions == null)) { + throw new ConcurrentLoginException(messages.getMessage( + "ConcurrentSessionControllerImpl.exceededAllowed", + new Object[] {new Integer(allowableSessions)}, + "Maximum sessions of {0} for this principal exceeded")); + } + + // Determine least recently used session, and mark it for invalidation + SessionInformation leastRecentlyUsed = null; + + for (int i = 0; i < sessions.length; i++) { + if ((leastRecentlyUsed == null) + || sessions[i].getLastRequest() + .before(leastRecentlyUsed.getLastRequest())) { + leastRecentlyUsed = sessions[i]; + } + } + + leastRecentlyUsed.expireNow(); } public void checkAuthenticationAllowed(Authentication request) @@ -68,86 +98,82 @@ public class ConcurrentSessionControllerImpl "Authentication request cannot be null (violation of interface contract)"); Object principal = SessionRegistryUtils - .obtainPrincipalFromAuthentication(request); - String sessionId = SessionRegistryUtils - .obtainSessionIdFromAuthentication(request); + .obtainPrincipalFromAuthentication(request); + String sessionId = SessionRegistryUtils + .obtainSessionIdFromAuthentication(request); - SessionInformation[] sessions = sessionRegistry.getAllSessions(principal); + SessionInformation[] sessions = sessionRegistry.getAllSessions(principal); - int sessionCount = 0; + int sessionCount = 0; - if (sessions != null) { - sessionCount = sessions.length; - } - - int allowableSessions = getMaximumSessionsForThisUser(request); - Assert.isTrue(allowableSessions != 0, - "getMaximumSessionsForThisUser() must return either -1 to allow unlimited logins, or a positive integer to specify a maximum"); - - if (sessionCount < allowableSessions) { - return; - } else if (sessionCount == allowableSessions) { - // Only permit it though if this request is associated with one of the sessions - for (int i = 0; i < sessionCount; i++) { - if (sessions[i].getSessionId().equals(sessionId)) { - return; + if (sessions != null) { + sessionCount = sessions.length; } + + int allowableSessions = getMaximumSessionsForThisUser(request); + Assert.isTrue(allowableSessions != 0, + "getMaximumSessionsForThisUser() must return either -1 to allow unlimited logins, or a positive integer to specify a maximum"); + + if (sessionCount < allowableSessions) { + return; + } else if (sessionCount == allowableSessions) { + // Only permit it though if this request is associated with one of the sessions + for (int i = 0; i < sessionCount; i++) { + if (sessions[i].getSessionId().equals(sessionId)) { + return; + } + } + } + + allowableSessionsExceeded(sessionId, sessions, + allowableSessions, sessionRegistry); } - } - allowableSessionsExceeded(sessionId, sessions, allowableSessions, sessionRegistry); - } - - /** - * Allows subclasses to customise behaviour when too many sessions are - * detected. - * - * @param sessionId the session ID of the present request - * @param sessions either null or all unexpired sessions associated with the principal - * @param registry an instance of the SessionRegistry for subclass use - */ - protected void allowableSessionsExceeded(String sessionId, SessionInformation[] sessions, int allowableSessions, SessionRegistry registry) { - if (exceptionIfMaximumExceeded || sessions == null) { - throw new ConcurrentLoginException("Maximum sessions of " - + allowableSessions + " for this principal exceeded"); - } - - // Determine least recently used session, and mark it for invalidation - SessionInformation leastRecentlyUsed = null; - for (int i = 0; i < sessions.length; i++) { - if (leastRecentlyUsed == null || sessions[i].getLastRequest().before(leastRecentlyUsed.getLastRequest())) { - leastRecentlyUsed = sessions[i]; - } - } - - leastRecentlyUsed.expireNow(); - } + /** + * Method intended for use by subclasses to override the maximum + * number of sessions that are permitted for a particular + * authentication. The default implementation simply returns the + * maximumSessions value for the bean. + * + * @param authentication to determine the maximum sessions for + * + * @return either -1 meaning unlimited, or a positive integer to + * limit (never zero) + */ + protected int getMaximumSessionsForThisUser( + Authentication authentication) { + return maximumSessions; + } - public void registerSuccessfulAuthentication(Authentication authentication) { - Assert.notNull(authentication, - "Authentication cannot be null (violation of interface contract)"); + public void registerSuccessfulAuthentication( + Authentication authentication) { + Assert.notNull(authentication, + "Authentication cannot be null (violation of interface contract)"); - Object principal = SessionRegistryUtils - .obtainPrincipalFromAuthentication(authentication); - String sessionId = SessionRegistryUtils - .obtainSessionIdFromAuthentication(authentication); + Object principal = SessionRegistryUtils + .obtainPrincipalFromAuthentication(authentication); + String sessionId = SessionRegistryUtils + .obtainSessionIdFromAuthentication(authentication); - sessionRegistry.removeSessionInformation(sessionId); - sessionRegistry.registerNewSession(sessionId, principal); - } + sessionRegistry.removeSessionInformation(sessionId); + sessionRegistry.registerNewSession(sessionId, principal); + } - /** - * Method intended for use by subclasses to override the maximum number of - * sessions that are permitted for a particular authentication. The - * default implementation simply returns the maximumSessions - * value for the bean. - * - * @param authentication to determine the maximum sessions for - * - * @return either -1 meaning unlimited, or a positive integer to limit - * (never zero) - */ - protected int getMaximumSessionsForThisUser(Authentication authentication) { - return maximumSessions; - } -} + public void setExceptionIfMaximumExceeded( + boolean exceptionIfMaximumExceeded) { + this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded; + } + + public void setMaximumSessions(int maximumSessions) { + this.maximumSessions = maximumSessions; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + public void setSessionRegistry( + SessionRegistry sessionRegistry) { + this.sessionRegistry = sessionRegistry; + } + } diff --git a/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java b/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java index 3cd7d9fa6e..4e873d893d 100644 --- a/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java +++ b/core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java @@ -42,6 +42,9 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; import org.springframework.util.Assert; @@ -135,12 +138,9 @@ import java.util.Set; * * *

- * - * @author Ben Alex - * @version $Id$ */ public abstract class AbstractSecurityInterceptor implements InitializingBean, - ApplicationEventPublisherAware { + ApplicationEventPublisherAware, MessageSourceAware { //~ Static fields/initializers ============================================= protected static final Log logger = LogFactory.getLog(AbstractSecurityInterceptor.class); @@ -151,6 +151,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, private AfterInvocationManager afterInvocationManager; private ApplicationEventPublisher eventPublisher; private AuthenticationManager authenticationManager; + protected MessageSourceAccessor messages; private RunAsManager runAsManager = new NullRunAsManager(); private boolean alwaysReauthenticate = false; private boolean rejectPublicInvocations = false; @@ -158,194 +159,6 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, //~ Methods ================================================================ - public void setAfterInvocationManager( - AfterInvocationManager afterInvocationManager) { - this.afterInvocationManager = afterInvocationManager; - } - - public AfterInvocationManager getAfterInvocationManager() { - return afterInvocationManager; - } - - /** - * Indicates whether the AbstractSecurityInterceptor should - * ignore the {@link Authentication#isAuthenticated()} property. Defaults - * to false, meaning by default the - * Authentication.isAuthenticated() property is trusted and - * re-authentication will not occur if the principal has already been - * authenticated. - * - * @param alwaysReauthenticate true to force - * AbstractSecurityInterceptor to disregard the value - * of Authentication.isAuthenticated() and always - * re-authenticate the request (defaults to false). - */ - public void setAlwaysReauthenticate(boolean alwaysReauthenticate) { - this.alwaysReauthenticate = alwaysReauthenticate; - } - - public boolean isAlwaysReauthenticate() { - return alwaysReauthenticate; - } - - public void setApplicationEventPublisher( - ApplicationEventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; - } - - /** - * Indicates the type of secure objects the subclass will be presenting to - * the abstract parent for processing. This is used to ensure - * collaborators wired to the AbstractSecurityInterceptor all - * support the indicated secure object class. - * - * @return the type of secure object the subclass provides services for - */ - public abstract Class getSecureObjectClass(); - - public abstract ObjectDefinitionSource obtainObjectDefinitionSource(); - - public void setAccessDecisionManager( - AccessDecisionManager accessDecisionManager) { - this.accessDecisionManager = accessDecisionManager; - } - - public AccessDecisionManager getAccessDecisionManager() { - return accessDecisionManager; - } - - public void setAuthenticationManager(AuthenticationManager newManager) { - this.authenticationManager = newManager; - } - - public AuthenticationManager getAuthenticationManager() { - return this.authenticationManager; - } - - /** - * By rejecting public invocations (and setting this property to - * true), essentially you are ensuring that every secure - * object invocation advised by AbstractSecurityInterceptor - * has a configuration attribute defined. This is useful to ensure a "fail - * safe" mode where undeclared secure objects will be rejected and - * configuration omissions detected early. An - * IllegalArgumentException will be thrown by the - * AbstractSecurityInterceptor if you set this property to - * true and an attempt is made to invoke a secure object that - * has no configuration attributes. - * - * @param rejectPublicInvocations set to true to reject - * invocations of secure objects that have no configuration - * attributes (by default it is true which treats - * undeclared secure objects as "public" or unauthorized) - */ - public void setRejectPublicInvocations(boolean rejectPublicInvocations) { - this.rejectPublicInvocations = rejectPublicInvocations; - } - - public boolean isRejectPublicInvocations() { - return rejectPublicInvocations; - } - - public void setRunAsManager(RunAsManager runAsManager) { - this.runAsManager = runAsManager; - } - - public RunAsManager getRunAsManager() { - return runAsManager; - } - - public void setValidateConfigAttributes(boolean validateConfigAttributes) { - this.validateConfigAttributes = validateConfigAttributes; - } - - public boolean isValidateConfigAttributes() { - return validateConfigAttributes; - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(getSecureObjectClass(), - "Subclass must provide a non-null response to getSecureObjectClass()"); - - Assert.notNull(this.authenticationManager, - "An AuthenticationManager is required"); - - Assert.notNull(this.accessDecisionManager, - "An AccessDecisionManager is required"); - - Assert.notNull(this.runAsManager, "A RunAsManager is required"); - - Assert.notNull(this.obtainObjectDefinitionSource(), - "An ObjectDefinitionSource is required"); - - if (!this.obtainObjectDefinitionSource().supports(getSecureObjectClass())) { - throw new IllegalArgumentException( - "ObjectDefinitionSource does not support secure object class: " - + getSecureObjectClass()); - } - - if (!this.runAsManager.supports(getSecureObjectClass())) { - throw new IllegalArgumentException( - "RunAsManager does not support secure object class: " - + getSecureObjectClass()); - } - - if (!this.accessDecisionManager.supports(getSecureObjectClass())) { - throw new IllegalArgumentException( - "AccessDecisionManager does not support secure object class: " - + getSecureObjectClass()); - } - - if ((this.afterInvocationManager != null) - && !this.afterInvocationManager.supports(getSecureObjectClass())) { - throw new IllegalArgumentException( - "AfterInvocationManager does not support secure object class: " - + getSecureObjectClass()); - } - - if (this.validateConfigAttributes) { - Iterator iter = this.obtainObjectDefinitionSource() - .getConfigAttributeDefinitions(); - - if (iter == null) { - if (logger.isWarnEnabled()) { - logger.warn( - "Could not validate configuration attributes as the MethodDefinitionSource did not return a ConfigAttributeDefinition Iterator"); - } - } else { - Set set = new HashSet(); - - while (iter.hasNext()) { - ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter - .next(); - Iterator attributes = def.getConfigAttributes(); - - while (attributes.hasNext()) { - ConfigAttribute attr = (ConfigAttribute) attributes - .next(); - - if (!this.runAsManager.supports(attr) - && !this.accessDecisionManager.supports(attr) - && ((this.afterInvocationManager == null) - || !this.afterInvocationManager.supports(attr))) { - set.add(attr); - } - } - } - - if (set.size() == 0) { - if (logger.isInfoEnabled()) { - logger.info("Validated configuration attributes"); - } - } else { - throw new IllegalArgumentException( - "Unsupported configuration attributes: " - + set.toString()); - } - } - } - } - /** * Completes the work of the AbstractSecurityInterceptor after * the secure object invocation has been complete @@ -371,151 +184,353 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, + token.getAuthentication().toString()); } - SecurityContextHolder.getContext().setAuthentication(token - .getAuthentication()); + SecurityContextHolder.getContext() + .setAuthentication(token.getAuthentication()); } if (afterInvocationManager != null) { returnedObject = afterInvocationManager.decide(token - .getAuthentication(), token.getSecureObject(), - token.getAttr(), returnedObject); - } - - return returnedObject; - } - - protected InterceptorStatusToken beforeInvocation(Object object) { - Assert.notNull(object, "Object was null"); - Assert.isTrue(getSecureObjectClass().isAssignableFrom(object.getClass()), - "Security invocation attempted for object " - + object.getClass().getName() - + " but AbstractSecurityInterceptor only configured to support secure objects of type: " - + getSecureObjectClass()); - - ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource() - .getAttributes(object); - - if ((attr == null) && rejectPublicInvocations) { - throw new IllegalArgumentException( - "No public invocations are allowed via this AbstractSecurityInterceptor. This indicates a configuration error because the AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'"); - } - - if (attr != null) { - if (logger.isDebugEnabled()) { - logger.debug("Secure object: " + object.toString() - + "; ConfigAttributes: " + attr.toString()); + .getAuthentication(), token.getSecureObject(), + token.getAttr(), returnedObject); } - // We check for just the property we're interested in (we do - // not call Context.validate() like the ContextInterceptor) - if (SecurityContextHolder.getContext().getAuthentication() == null) { - credentialsNotFound("Authentication credentials were not found in the SecurityContext", - object, attr); + return returnedObject; + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(getSecureObjectClass(), + "Subclass must provide a non-null response to getSecureObjectClass()"); + + Assert.notNull(this.messages, "A message source must be set"); + Assert.notNull(this.authenticationManager, + "An AuthenticationManager is required"); + + Assert.notNull(this.accessDecisionManager, + "An AccessDecisionManager is required"); + + Assert.notNull(this.runAsManager, "A RunAsManager is required"); + + Assert.notNull(this.obtainObjectDefinitionSource(), + "An ObjectDefinitionSource is required"); + + if (!this.obtainObjectDefinitionSource() + .supports(getSecureObjectClass())) { + throw new IllegalArgumentException( + "ObjectDefinitionSource does not support secure object class: " + + getSecureObjectClass()); } - // Attempt authentication if not already authenticated, or user always wants reauthentication - Authentication authenticated; + if (!this.runAsManager.supports(getSecureObjectClass())) { + throw new IllegalArgumentException( + "RunAsManager does not support secure object class: " + + getSecureObjectClass()); + } - if (!SecurityContextHolder.getContext().getAuthentication() - .isAuthenticated() - || alwaysReauthenticate) { + if (!this.accessDecisionManager.supports(getSecureObjectClass())) { + throw new IllegalArgumentException( + "AccessDecisionManager does not support secure object class: " + + getSecureObjectClass()); + } + + if ((this.afterInvocationManager != null) + && !this.afterInvocationManager.supports(getSecureObjectClass())) { + throw new IllegalArgumentException( + "AfterInvocationManager does not support secure object class: " + + getSecureObjectClass()); + } + + if (this.validateConfigAttributes) { + Iterator iter = this.obtainObjectDefinitionSource() + .getConfigAttributeDefinitions(); + + if (iter == null) { + if (logger.isWarnEnabled()) { + logger.warn( + "Could not validate configuration attributes as the MethodDefinitionSource did not return a ConfigAttributeDefinition Iterator"); + } + } else { + Set set = new HashSet(); + + while (iter.hasNext()) { + ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter + .next(); + Iterator attributes = def.getConfigAttributes(); + + while (attributes.hasNext()) { + ConfigAttribute attr = (ConfigAttribute) attributes + .next(); + + if (!this.runAsManager.supports(attr) + && !this.accessDecisionManager.supports(attr) + && ((this.afterInvocationManager == null) + || !this.afterInvocationManager.supports(attr))) { + set.add(attr); + } + } + } + + if (set.size() == 0) { + if (logger.isInfoEnabled()) { + logger.info("Validated configuration attributes"); + } + } else { + throw new IllegalArgumentException( + "Unsupported configuration attributes: " + + set.toString()); + } + } + } + } + + protected InterceptorStatusToken beforeInvocation(Object object) { + Assert.notNull(object, "Object was null"); + Assert.isTrue(getSecureObjectClass() + .isAssignableFrom(object.getClass()), + "Security invocation attempted for object " + + object.getClass().getName() + + " but AbstractSecurityInterceptor only configured to support secure objects of type: " + + getSecureObjectClass()); + + ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource() + .getAttributes(object); + + if ((attr == null) && rejectPublicInvocations) { + throw new IllegalArgumentException( + "No public invocations are allowed via this AbstractSecurityInterceptor. This indicates a configuration error because the AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'"); + } + + if (attr != null) { + if (logger.isDebugEnabled()) { + logger.debug("Secure object: " + object.toString() + + "; ConfigAttributes: " + attr.toString()); + } + + // We check for just the property we're interested in (we do + // not call Context.validate() like the ContextInterceptor) + if (SecurityContextHolder.getContext().getAuthentication() == null) { + credentialsNotFound(messages.getMessage( + "AbstractSecurityInterceptor.authenticationNotFound", + "An Authentication object was not found in the SecurityContext"), + object, attr); + } + + // Attempt authentication if not already authenticated, or user always wants reauthentication + Authentication authenticated; + + if (!SecurityContextHolder.getContext().getAuthentication() + .isAuthenticated() + || alwaysReauthenticate) { + try { + authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext() + .getAuthentication()); + } catch (AuthenticationException authenticationException) { + throw authenticationException; + } + + // We don't authenticated.setAuthentication(true), because each provider should do that + if (logger.isDebugEnabled()) { + logger.debug("Successfully Authenticated: " + + authenticated.toString()); + } + + SecurityContextHolder.getContext() + .setAuthentication(authenticated); + } else { + authenticated = SecurityContextHolder.getContext() + .getAuthentication(); + + if (logger.isDebugEnabled()) { + logger.debug("Previously Authenticated: " + + authenticated.toString()); + } + } + + // Attempt authorization try { - authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext() - .getAuthentication()); - } catch (AuthenticationException authenticationException) { - throw authenticationException; - } + this.accessDecisionManager.decide(authenticated, object, + attr); + } catch (AccessDeniedException accessDeniedException) { + AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, + attr, authenticated, accessDeniedException); + this.eventPublisher.publishEvent(event); - // We don't authenticated.setAuthentication(true), because each provider should do that - if (logger.isDebugEnabled()) { - logger.debug("Successfully Authenticated: " - + authenticated.toString()); + throw accessDeniedException; } - SecurityContextHolder.getContext().setAuthentication(authenticated); - } else { - authenticated = SecurityContextHolder.getContext() - .getAuthentication(); - if (logger.isDebugEnabled()) { - logger.debug("Previously Authenticated: " - + authenticated.toString()); + logger.debug("Authorization successful"); } - } - // Attempt authorization - try { - this.accessDecisionManager.decide(authenticated, object, attr); - } catch (AccessDeniedException accessDeniedException) { - AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, - attr, authenticated, accessDeniedException); + AuthorizedEvent event = new AuthorizedEvent(object, attr, + authenticated); this.eventPublisher.publishEvent(event); - throw accessDeniedException; - } + // Attempt to run as a different user + Authentication runAs = this.runAsManager.buildRunAs(authenticated, + object, attr); - if (logger.isDebugEnabled()) { - logger.debug("Authorization successful"); - } + if (runAs == null) { + if (logger.isDebugEnabled()) { + logger.debug( + "RunAsManager did not change Authentication object"); + } - AuthorizedEvent event = new AuthorizedEvent(object, attr, - authenticated); - this.eventPublisher.publishEvent(event); + return new InterceptorStatusToken(authenticated, false, + attr, object); // no further work post-invocation + } else { + if (logger.isDebugEnabled()) { + logger.debug("Switching to RunAs Authentication: " + + runAs.toString()); + } - // Attempt to run as a different user - Authentication runAs = this.runAsManager.buildRunAs(authenticated, - object, attr); + SecurityContextHolder.getContext().setAuthentication(runAs); - if (runAs == null) { - if (logger.isDebugEnabled()) { - logger.debug( - "RunAsManager did not change Authentication object"); + return new InterceptorStatusToken(authenticated, true, + attr, object); // revert to token.Authenticated post-invocation } - - return new InterceptorStatusToken(authenticated, false, attr, - object); // no further work post-invocation } else { if (logger.isDebugEnabled()) { - logger.debug("Switching to RunAs Authentication: " - + runAs.toString()); + logger.debug("Public object - authentication not attempted"); } - SecurityContextHolder.getContext().setAuthentication(runAs); + this.eventPublisher.publishEvent(new PublicInvocationEvent( + object)); - return new InterceptorStatusToken(authenticated, true, attr, - object); // revert to token.Authenticated post-invocation - } - } else { - if (logger.isDebugEnabled()) { - logger.debug("Public object - authentication not attempted"); + return null; // no further work post-invocation } + } - this.eventPublisher.publishEvent(new PublicInvocationEvent(object)); + /** + * Helper method which generates an exception containing the passed + * reason, and publishes an event to the application context. + * + *

+ * Always throws an exception. + *

+ * + * @param reason to be provided in the exception detail + * @param secureObject that was being called + * @param configAttribs that were defined for the secureObject + */ + private void credentialsNotFound(String reason, Object secureObject, + ConfigAttributeDefinition configAttribs) { + AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(reason); - return null; // no further work post-invocation + AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject, + configAttribs, exception); + this.eventPublisher.publishEvent(event); + + throw exception; + } + + public AccessDecisionManager getAccessDecisionManager() { + return accessDecisionManager; + } + + public AfterInvocationManager getAfterInvocationManager() { + return afterInvocationManager; + } + + public AuthenticationManager getAuthenticationManager() { + return this.authenticationManager; + } + + public RunAsManager getRunAsManager() { + return runAsManager; + } + + /** + * Indicates the type of secure objects the subclass will be presenting + * to the abstract parent for processing. This is used to ensure + * collaborators wired to the AbstractSecurityInterceptor + * all support the indicated secure object class. + * + * @return the type of secure object the subclass provides services for + */ + public abstract Class getSecureObjectClass(); + + public boolean isAlwaysReauthenticate() { + return alwaysReauthenticate; + } + + public boolean isRejectPublicInvocations() { + return rejectPublicInvocations; + } + + public boolean isValidateConfigAttributes() { + return validateConfigAttributes; + } + + public abstract ObjectDefinitionSource obtainObjectDefinitionSource(); + + public void setAccessDecisionManager( + AccessDecisionManager accessDecisionManager) { + this.accessDecisionManager = accessDecisionManager; + } + + public void setAfterInvocationManager( + AfterInvocationManager afterInvocationManager) { + this.afterInvocationManager = afterInvocationManager; + } + + /** + * Indicates whether the AbstractSecurityInterceptor + * should ignore the {@link Authentication#isAuthenticated()} + * property. Defaults to false, meaning by default the + * Authentication.isAuthenticated() property is trusted + * and re-authentication will not occur if the principal has already + * been authenticated. + * + * @param alwaysReauthenticate true to force + * AbstractSecurityInterceptor to disregard the + * value of Authentication.isAuthenticated() and + * always re-authenticate the request (defaults to + * false). + */ + public void setAlwaysReauthenticate(boolean alwaysReauthenticate) { + this.alwaysReauthenticate = alwaysReauthenticate; + } + + public void setApplicationEventPublisher( + ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } + + public void setAuthenticationManager(AuthenticationManager newManager) { + this.authenticationManager = newManager; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + /** + * By rejecting public invocations (and setting this property to + * true), essentially you are ensuring that every secure + * object invocation advised by + * AbstractSecurityInterceptor has a configuration + * attribute defined. This is useful to ensure a "fail safe" mode + * where undeclared secure objects will be rejected and configuration + * omissions detected early. An IllegalArgumentException + * will be thrown by the AbstractSecurityInterceptor if + * you set this property to true and an attempt is made + * to invoke a secure object that has no configuration attributes. + * + * @param rejectPublicInvocations set to true to reject + * invocations of secure objects that have no configuration + * attributes (by default it is true which treats + * undeclared secure objects as "public" or unauthorized) + */ + public void setRejectPublicInvocations(boolean rejectPublicInvocations) { + this.rejectPublicInvocations = rejectPublicInvocations; + } + + public void setRunAsManager(RunAsManager runAsManager) { + this.runAsManager = runAsManager; + } + + public void setValidateConfigAttributes( + boolean validateConfigAttributes) { + this.validateConfigAttributes = validateConfigAttributes; } } - - /** - * Helper method which generates an exception containing the passed reason, - * and publishes an event to the application context. - * - *

- * Always throws an exception. - *

- * - * @param reason to be provided in the exception detail - * @param secureObject that was being called - * @param configAttribs that were defined for the secureObject - */ - private void credentialsNotFound(String reason, Object secureObject, - ConfigAttributeDefinition configAttribs) { - AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(reason); - - AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject, - configAttribs, exception); - this.eventPublisher.publishEvent(event); - - throw exception; - } -} diff --git a/core/src/main/java/org/acegisecurity/messages.properties b/core/src/main/java/org/acegisecurity/messages.properties new file mode 100644 index 0000000000..7b70e0c659 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/messages.properties @@ -0,0 +1,39 @@ +AuthByAdapterProvider.incorrectKey=The presented AuthByAdapter implementation does not contain the expected key +BasicAclEntryAfterInvocationProvider.noPermission=Authentication {0} has NO permissions at all to the domain object {1} +BasicAclEntryAfterInvocationProvider.insufficientPermission=Authentication {0} has ACL permissions to the domain object, but not the required ACL permission to the domain object {1} +ConcurrentSessionControllerImpl.exceededAllowed=Maximum sessions of {0} for this principal exceeded +ProviderManager.providerNotFound=No AuthenticationProvider found for {0} +AnonymousAuthenticationProvider.incorrectKey=The presented AnonymousAuthenticationToken does not contain the expected key +CasAuthenticationProvider.incorrectKey=The presented CasAuthenticationToken does not contain the expected key +CasAuthenticationProvider.noServiceTicket=Failed to provide a CAS service ticket to validate +NamedCasProxyDecider.untrusted=Nearest proxy {0} is untrusted +RejectProxyTickets.reject=Proxy tickets are rejected +AbstractSecurityInterceptor.authenticationNotFound=An Authentication object was not found in the SecurityContext +AbstractUserDetailsAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported +AbstractUserDetailsAuthenticationProvider.locked=User account is locked +AbstractUserDetailsAuthenticationProvider.disabled=User is disabled +AbstractUserDetailsAuthenticationProvider.expired=User account has expired +AbstractUserDetailsAuthenticationProvider.credentialsExpired=User credentials have expired +AbstractUserDetailsAuthenticationProvider.badCredentials=Bad credentials +X509AuthenticationProvider.certificateNull=Certificate is null +DaoX509AuthoritiesPopulator.noMatching=No matching pattern was found in subjectDN: {0} +RememberMeAuthenticationProvider.incorrectKey=The presented RememberMeAuthenticationToken does not contain the expected key +RunAsImplAuthenticationProvider.incorrectKey=The presented RunAsUserToken does not contain the expected key +DigestProcessingFilter.missingMandatory=Missing mandatory digest value; received header {0} +DigestProcessingFilter.missingAuth=Missing mandatory digest value for 'auth' QOP; received header {0} +DigestProcessingFilter.incorrectRealm=Response realm name {0} does not match system realm name of {1} +DigestProcessingFilter.nonceExpired=Nonce has expired/timed out +DigestProcessingFilter.nonceEncoding=Nonce is not encoded in Base64; received nonce {0} +DigestProcessingFilter.nonceNotTwoTokens=Nonce should have yielded two tokens but was {0} +DigestProcessingFilter.nonceNotNumeric=Nonce token should have yielded a numeric first token, but was {0} +DigestProcessingFilter.nonceCompromised=Nonce token compromised {0} +DigestProcessingFilter.usernameNotFound=Username {0} not found +DigestProcessingFilter.incorrectResponse=Incorrect response +SwitchUserProcessingFilter.noCurrentUser=No current user associated with this request +SwitchUserProcessingFilter.noOriginalAuthentication=Could not find original Authentication object +SwitchUserProcessingFilter.usernameNotFound=Username {0} not found +SwitchUserProcessingFilter.locked=User account is locked +SwitchUserProcessingFilter.disabled=User is disabled +SwitchUserProcessingFilter.expired=User account has expired +SwitchUserProcessingFilter.credentialsExpired=User credentials have expired +AbstractAccessDecisionManager.accessDenied=Access is denied diff --git a/core/src/main/java/org/acegisecurity/providers/ProviderManager.java b/core/src/main/java/org/acegisecurity/providers/ProviderManager.java index 9ef142acd2..77b321ac8b 100644 --- a/core/src/main/java/org/acegisecurity/providers/ProviderManager.java +++ b/core/src/main/java/org/acegisecurity/providers/ProviderManager.java @@ -24,9 +24,11 @@ import org.acegisecurity.BadCredentialsException; import org.acegisecurity.CredentialsExpiredException; import org.acegisecurity.DisabledException; import org.acegisecurity.LockedException; + import org.acegisecurity.concurrent.ConcurrentLoginException; import org.acegisecurity.concurrent.ConcurrentSessionController; import org.acegisecurity.concurrent.NullConcurrentSessionController; + import org.acegisecurity.event.authentication.AbstractAuthenticationEvent; import org.acegisecurity.event.authentication.AuthenticationFailureBadCredentialsEvent; import org.acegisecurity.event.authentication.AuthenticationFailureConcurrentLoginEvent; @@ -38,6 +40,7 @@ import org.acegisecurity.event.authentication.AuthenticationFailureProviderNotFo import org.acegisecurity.event.authentication.AuthenticationFailureProxyUntrustedEvent; import org.acegisecurity.event.authentication.AuthenticationFailureServiceExceptionEvent; import org.acegisecurity.event.authentication.AuthenticationSuccessEvent; + import org.acegisecurity.providers.cas.ProxyUntrustedException; import org.acegisecurity.providers.dao.UsernameNotFoundException; @@ -48,6 +51,9 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; import org.springframework.util.Assert; @@ -85,8 +91,8 @@ import java.util.Properties; * If a valid Authentication is returned by an * AuthenticationProvider, the ProviderManager will * publish an {@link - * org.acegisecurity.event.authentication.AuthenticationSuccessEvent}. If - * an AuthenticationException is detected, the final + * org.acegisecurity.event.authentication.AuthenticationSuccessEvent}. If an + * AuthenticationException is detected, the final * AuthenticationException thrown will be used to publish an * appropriate failure event. By default ProviderManager maps * common exceptions to events, but this can be fine-tuned by providing a new @@ -98,15 +104,11 @@ import java.util.Properties; * and provides its constructor. *

* - * @author Ben Alex - * @author Wesley Hall - * @author Ray Krueger - * @version $Id$ - * * @see ConcurrentSessionController */ public class ProviderManager extends AbstractAuthenticationManager - implements InitializingBean, ApplicationEventPublisherAware { + implements InitializingBean, ApplicationEventPublisherAware, + MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(ProviderManager.class); @@ -116,74 +118,14 @@ public class ProviderManager extends AbstractAuthenticationManager private ApplicationEventPublisher applicationEventPublisher; private ConcurrentSessionController sessionController = new NullConcurrentSessionController(); private List providers; + protected MessageSourceAccessor messages; private Properties exceptionMappings; //~ Methods ================================================================ - public void setApplicationEventPublisher( - ApplicationEventPublisher applicationEventPublisher) { - this.applicationEventPublisher = applicationEventPublisher; - } - - /** - * Sets the {@link AuthenticationProvider} objects to be used for - * authentication. - * - * @param newList - * - * @throws IllegalArgumentException DOCUMENT ME! - */ - public void setProviders(List newList) { - checkIfValidList(newList); - - Iterator iter = newList.iterator(); - - while (iter.hasNext()) { - Object currentObject = null; - - try { - currentObject = iter.next(); - - AuthenticationProvider attemptToCast = (AuthenticationProvider) currentObject; - } catch (ClassCastException cce) { - throw new IllegalArgumentException("AuthenticationProvider " - + currentObject.getClass().getName() - + " must implement AuthenticationProvider"); - } - } - - this.providers = newList; - } - - public List getProviders() { - return this.providers; - } - - /** - * Set the {@link ConcurrentSessionController} to be used for limiting - * user's sessions. The {@link NullConcurrentSessionController} is used - * by default - * - * @param sessionController {@link ConcurrentSessionController} - */ - public void setSessionController( - ConcurrentSessionController sessionController) { - this.sessionController = sessionController; - } - - /** - * The configured {@link ConcurrentSessionController} is returned or the - * {@link NullConcurrentSessionController} if a specific one has not been - * set. - * - * @return {@link ConcurrentSessionController} instance - */ - public ConcurrentSessionController getSessionController() { - return sessionController; - } - public void afterPropertiesSet() throws Exception { checkIfValidList(this.providers); + Assert.notNull(this.messages, "A message source must be set"); if (exceptionMappings == null) { exceptionMappings = new Properties(); @@ -211,6 +153,23 @@ public class ProviderManager extends AbstractAuthenticationManager } } + private void checkIfValidList(List listToCheck) { + if ((listToCheck == null) || (listToCheck.size() == 0)) { + throw new IllegalArgumentException( + "A list of AuthenticationManagers is required"); + } + } + + /** + * Provided so subclasses can add extra exception mappings during startup + * if no exception mappings are injected by the IoC container. + * + * @param exceptionMappings the properties object, which already has + * entries in it + */ + protected void doAddExtraDefaultExceptionMappings( + Properties exceptionMappings) {} + /** * Attempts to authenticate the passed {@link Authentication} object. * @@ -244,8 +203,7 @@ public class ProviderManager extends AbstractAuthenticationManager AuthenticationException lastException = null; while (iter.hasNext()) { - AuthenticationProvider provider = (AuthenticationProvider) iter - .next(); + AuthenticationProvider provider = (AuthenticationProvider) iter.next(); if (provider.supports(toTest)) { logger.debug("Authentication attempt using " @@ -272,8 +230,10 @@ public class ProviderManager extends AbstractAuthenticationManager } if (lastException == null) { - lastException = new ProviderNotFoundException( - "No authentication provider for " + toTest.getName()); + lastException = new ProviderNotFoundException(messages.getMessage( + "ProviderManager.providerNotFound", + new Object[] {toTest.getName()}, + "No AuthenticationProvider found for {0}")); } // Publish the event @@ -309,20 +269,69 @@ public class ProviderManager extends AbstractAuthenticationManager throw lastException; } - /** - * Provided so subclasses can add extra exception mappings during startup - * if no exception mappings are injected by the IoC container. - * - * @param exceptionMappings the properties object, which already has - * entries in it - */ - protected void doAddExtraDefaultExceptionMappings( - Properties exceptionMappings) {} + public List getProviders() { + return this.providers; + } - private void checkIfValidList(List listToCheck) { - if ((listToCheck == null) || (listToCheck.size() == 0)) { - throw new IllegalArgumentException( - "A list of AuthenticationManagers is required"); + /** + * The configured {@link ConcurrentSessionController} is returned or the + * {@link NullConcurrentSessionController} if a specific one has not been + * set. + * + * @return {@link ConcurrentSessionController} instance + */ + public ConcurrentSessionController getSessionController() { + return sessionController; + } + + public void setApplicationEventPublisher( + ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + /** + * Sets the {@link AuthenticationProvider} objects to be used for + * authentication. + * + * @param newList + * + * @throws IllegalArgumentException DOCUMENT ME! + */ + public void setProviders(List newList) { + checkIfValidList(newList); + + Iterator iter = newList.iterator(); + + while (iter.hasNext()) { + Object currentObject = null; + + try { + currentObject = iter.next(); + + AuthenticationProvider attemptToCast = (AuthenticationProvider) currentObject; + } catch (ClassCastException cce) { + throw new IllegalArgumentException("AuthenticationProvider " + + currentObject.getClass().getName() + + " must implement AuthenticationProvider"); + } } + + this.providers = newList; + } + + /** + * Set the {@link ConcurrentSessionController} to be used for limiting + * user's sessions. The {@link NullConcurrentSessionController} is used + * by default + * + * @param sessionController {@link ConcurrentSessionController} + */ + public void setSessionController( + ConcurrentSessionController sessionController) { + this.sessionController = sessionController; } } diff --git a/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProvider.java index c69f85a5a8..8858c96918 100644 --- a/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProvider.java @@ -18,6 +18,7 @@ package org.acegisecurity.providers.anonymous; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.acegisecurity.BadCredentialsException; + import org.acegisecurity.providers.AuthenticationProvider; import org.apache.commons.logging.Log; @@ -25,6 +26,10 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; @@ -37,32 +42,23 @@ import org.springframework.util.Assert; * org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken#getKeyHash()} * must match this class' {@link #getKey()}. *

- * - * @author Ben Alex - * @version $Id$ */ public class AnonymousAuthenticationProvider implements AuthenticationProvider, - InitializingBean { + InitializingBean, MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(AnonymousAuthenticationProvider.class); //~ Instance fields ======================================================== + protected MessageSourceAccessor messages; private String key; //~ Methods ================================================================ - public void setKey(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - public void afterPropertiesSet() throws Exception { - Assert.hasLength(key); + Assert.hasLength(key, "A Key is required"); + Assert.notNull(this.messages, "A message source must be set"); } public Authentication authenticate(Authentication authentication) @@ -73,13 +69,26 @@ public class AnonymousAuthenticationProvider implements AuthenticationProvider, if (this.key.hashCode() != ((AnonymousAuthenticationToken) authentication) .getKeyHash()) { - throw new BadCredentialsException( - "The presented AnonymousAuthenticationToken does not contain the expected key"); + throw new BadCredentialsException(messages.getMessage( + "AnonymousAuthenticationProvider.incorrectKey", + "The presented AnonymousAuthenticationToken does not contain the expected key")); } return authentication; } + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + public boolean supports(Class authentication) { return (AnonymousAuthenticationToken.class.isAssignableFrom(authentication)); } diff --git a/core/src/main/java/org/acegisecurity/providers/cas/CasAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/cas/CasAuthenticationProvider.java index 503407bc0a..6d03891a21 100644 --- a/core/src/main/java/org/acegisecurity/providers/cas/CasAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/cas/CasAuthenticationProvider.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,14 +19,21 @@ import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.acegisecurity.BadCredentialsException; import org.acegisecurity.UserDetails; + import org.acegisecurity.providers.AuthenticationProvider; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; + import org.acegisecurity.ui.cas.CasProcessingFilter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; @@ -42,12 +49,9 @@ import org.springframework.util.Assert; * CasProcessingFilter#CAS_STATELESS_IDENTIFIER}. It can also validate a * previously created {@link CasAuthenticationToken}. *

- * - * @author Ben Alex - * @version $Id$ */ public class CasAuthenticationProvider implements AuthenticationProvider, - InitializingBean { + InitializingBean, MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class); @@ -56,60 +60,23 @@ public class CasAuthenticationProvider implements AuthenticationProvider, private CasAuthoritiesPopulator casAuthoritiesPopulator; private CasProxyDecider casProxyDecider; + protected MessageSourceAccessor messages; private StatelessTicketCache statelessTicketCache; private String key; private TicketValidator ticketValidator; //~ Methods ================================================================ - public void setCasAuthoritiesPopulator( - CasAuthoritiesPopulator casAuthoritiesPopulator) { - this.casAuthoritiesPopulator = casAuthoritiesPopulator; - } - - public CasAuthoritiesPopulator getCasAuthoritiesPopulator() { - return casAuthoritiesPopulator; - } - - public void setCasProxyDecider(CasProxyDecider casProxyDecider) { - this.casProxyDecider = casProxyDecider; - } - - public CasProxyDecider getCasProxyDecider() { - return casProxyDecider; - } - - public void setKey(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - - public void setStatelessTicketCache( - StatelessTicketCache statelessTicketCache) { - this.statelessTicketCache = statelessTicketCache; - } - - public StatelessTicketCache getStatelessTicketCache() { - return statelessTicketCache; - } - - public void setTicketValidator(TicketValidator ticketValidator) { - this.ticketValidator = ticketValidator; - } - - public TicketValidator getTicketValidator() { - return ticketValidator; - } - public void afterPropertiesSet() throws Exception { - Assert.notNull(this.casAuthoritiesPopulator, "A casAuthoritiesPopulator must be set"); + Assert.notNull(this.casAuthoritiesPopulator, + "A casAuthoritiesPopulator must be set"); Assert.notNull(this.ticketValidator, "A ticketValidator must be set"); Assert.notNull(this.casProxyDecider, "A casProxyDecider must be set"); - Assert.notNull(this.statelessTicketCache, "A statelessTicketCache must be set"); - Assert.notNull(key, "A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated"); + Assert.notNull(this.statelessTicketCache, + "A statelessTicketCache must be set"); + Assert.notNull(key, + "A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated"); + Assert.notNull(this.messages, "A message source must be set"); } public Authentication authenticate(Authentication authentication) @@ -133,16 +100,18 @@ public class CasAuthenticationProvider implements AuthenticationProvider, .getKeyHash()) { return authentication; } else { - throw new BadCredentialsException( - "The presented CasAuthenticationToken does not contain the expected key"); + throw new BadCredentialsException(messages.getMessage( + "CasAuthenticationProvider.incorrectKey", + "The presented CasAuthenticationToken does not contain the expected key")); } } // Ensure credentials are presented if ((authentication.getCredentials() == null) || "".equals(authentication.getCredentials())) { - throw new BadCredentialsException( - "Failed to provide a CAS service ticket to validate"); + throw new BadCredentialsException(messages.getMessage( + "CasAuthenticationProvider.noServiceTicket", + "Failed to provide a CAS service ticket to validate")); } boolean stateless = false; @@ -173,17 +142,6 @@ public class CasAuthenticationProvider implements AuthenticationProvider, return result; } - public boolean supports(Class authentication) { - if (UsernamePasswordAuthenticationToken.class.isAssignableFrom( - authentication)) { - return true; - } else if (CasAuthenticationToken.class.isAssignableFrom(authentication)) { - return true; - } else { - return false; - } - } - private CasAuthenticationToken authenticateNow( Authentication authentication) throws AuthenticationException { // Validate @@ -203,4 +161,61 @@ public class CasAuthenticationProvider implements AuthenticationProvider, userDetails, response.getProxyList(), response.getProxyGrantingTicketIou()); } + + public CasAuthoritiesPopulator getCasAuthoritiesPopulator() { + return casAuthoritiesPopulator; + } + + public CasProxyDecider getCasProxyDecider() { + return casProxyDecider; + } + + public String getKey() { + return key; + } + + public StatelessTicketCache getStatelessTicketCache() { + return statelessTicketCache; + } + + public TicketValidator getTicketValidator() { + return ticketValidator; + } + + public void setCasAuthoritiesPopulator( + CasAuthoritiesPopulator casAuthoritiesPopulator) { + this.casAuthoritiesPopulator = casAuthoritiesPopulator; + } + + public void setCasProxyDecider(CasProxyDecider casProxyDecider) { + this.casProxyDecider = casProxyDecider; + } + + public void setKey(String key) { + this.key = key; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + public void setStatelessTicketCache( + StatelessTicketCache statelessTicketCache) { + this.statelessTicketCache = statelessTicketCache; + } + + public void setTicketValidator(TicketValidator ticketValidator) { + this.ticketValidator = ticketValidator; + } + + public boolean supports(Class authentication) { + if (UsernamePasswordAuthenticationToken.class.isAssignableFrom( + authentication)) { + return true; + } else if (CasAuthenticationToken.class.isAssignableFrom(authentication)) { + return true; + } else { + return false; + } + } } diff --git a/core/src/main/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDecider.java b/core/src/main/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDecider.java index 19867f7014..d7af3b6bb0 100644 --- a/core/src/main/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDecider.java +++ b/core/src/main/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDecider.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; import java.util.List; @@ -35,11 +40,9 @@ import java.util.List; * Also accepts the request if there was no proxy (ie the user directly * authenticated against this service). *

- * - * @author Ben Alex - * @version $Id$ */ -public class NamedCasProxyDecider implements CasProxyDecider, InitializingBean { +public class NamedCasProxyDecider implements CasProxyDecider, InitializingBean, + MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(NamedCasProxyDecider.class); @@ -47,19 +50,13 @@ public class NamedCasProxyDecider implements CasProxyDecider, InitializingBean { //~ Instance fields ======================================================== private List validProxies; + protected MessageSourceAccessor messages; //~ Methods ================================================================ - public void setValidProxies(List validProxies) { - this.validProxies = validProxies; - } - - public List getValidProxies() { - return validProxies; - } - public void afterPropertiesSet() throws Exception { Assert.notNull(this.validProxies, "A validProxies list must be set"); + Assert.notNull(this.messages, "A message source must be set"); } public void confirmProxyListTrusted(List proxyList) @@ -76,8 +73,22 @@ public class NamedCasProxyDecider implements CasProxyDecider, InitializingBean { } if (!validProxies.contains(proxyList.get(0))) { - throw new ProxyUntrustedException("Nearest proxy '" - + proxyList.get(0) + "' is untrusted"); + throw new ProxyUntrustedException(messages.getMessage( + "NamedCasProxyDecider.untrusted", + new Object[] {proxyList.get(0)}, + "Nearest proxy {0} is untrusted")); } } + + public List getValidProxies() { + return validProxies; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + public void setValidProxies(List validProxies) { + this.validProxies = validProxies; + } } diff --git a/core/src/main/java/org/acegisecurity/providers/cas/proxy/RejectProxyTickets.java b/core/src/main/java/org/acegisecurity/providers/cas/proxy/RejectProxyTickets.java index 5cbf957fb1..be5fdafe9d 100644 --- a/core/src/main/java/org/acegisecurity/providers/cas/proxy/RejectProxyTickets.java +++ b/core/src/main/java/org/acegisecurity/providers/cas/proxy/RejectProxyTickets.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,13 @@ import org.acegisecurity.providers.cas.ProxyUntrustedException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; import java.util.List; @@ -32,17 +39,23 @@ import java.util.List; * This class should be used if only service tickets wish to be accepted (ie no * proxy tickets at all). *

- * - * @author Ben Alex - * @version $Id$ */ -public class RejectProxyTickets implements CasProxyDecider { +public class RejectProxyTickets implements CasProxyDecider, MessageSourceAware, + InitializingBean { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(RejectProxyTickets.class); + //~ Instance fields ======================================================== + + protected MessageSourceAccessor messages; + //~ Methods ================================================================ + public void afterPropertiesSet() throws Exception { + Assert.notNull(this.messages, "A message source must be set"); + } + public void confirmProxyListTrusted(List proxyList) throws ProxyUntrustedException { Assert.notNull(proxyList, "proxyList cannot be null"); @@ -54,9 +67,14 @@ public class RejectProxyTickets implements CasProxyDecider { if (logger.isDebugEnabled()) { logger.debug("Proxies are unacceptable; proxy list provided: " - + proxyList.toString()); + + proxyList.toString()); } - throw new ProxyUntrustedException("Proxy tickets are rejected"); + throw new ProxyUntrustedException(messages.getMessage( + "RejectProxyTickets.reject", "Proxy tickets are rejected")); + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); } } diff --git a/core/src/main/java/org/acegisecurity/providers/dao/AbstractUserDetailsAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/dao/AbstractUserDetailsAuthenticationProvider.java index 7e593a47bb..3deb9d3ecb 100644 --- a/core/src/main/java/org/acegisecurity/providers/dao/AbstractUserDetailsAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/dao/AbstractUserDetailsAuthenticationProvider.java @@ -22,12 +22,17 @@ import org.acegisecurity.CredentialsExpiredException; import org.acegisecurity.DisabledException; import org.acegisecurity.LockedException; import org.acegisecurity.UserDetails; + import org.acegisecurity.providers.AuthenticationProvider; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.providers.dao.cache.NullUserCache; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; @@ -62,110 +67,17 @@ import org.springframework.util.Assert; * incorrect password, the {@link AuthenticationDao} will be queried to * confirm the most up-to-date password was used for comparison. *

- * - * @author Ben Alex - * @version $Id$ */ public abstract class AbstractUserDetailsAuthenticationProvider - implements AuthenticationProvider, InitializingBean { + implements AuthenticationProvider, InitializingBean, MessageSourceAware { //~ Instance fields ======================================================== + protected MessageSourceAccessor messages; private UserCache userCache = new NullUserCache(); private boolean forcePrincipalAsString = false; //~ Methods ================================================================ - public void setForcePrincipalAsString(boolean forcePrincipalAsString) { - this.forcePrincipalAsString = forcePrincipalAsString; - } - - public boolean isForcePrincipalAsString() { - return forcePrincipalAsString; - } - - public void setUserCache(UserCache userCache) { - this.userCache = userCache; - } - - public UserCache getUserCache() { - return userCache; - } - - public final void afterPropertiesSet() throws Exception { - Assert.notNull(this.userCache, "A user cache must be set"); - doAfterPropertiesSet(); - } - - public Authentication authenticate(Authentication authentication) - throws AuthenticationException { - Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, - authentication, - "Only UsernamePasswordAuthenticationToken is supported"); - - // Determine username - String username = (authentication.getPrincipal() == null) - ? "NONE_PROVIDED" : authentication.getName(); - - boolean cacheWasUsed = true; - UserDetails user = this.userCache.getUserFromCache(username); - - if (user == null) { - cacheWasUsed = false; - user = retrieveUser(username, - (UsernamePasswordAuthenticationToken) authentication); - Assert.notNull(user, - "retrieveUser returned null - a violation of the interface contract"); - } - - if (!user.isAccountNonLocked()) { - throw new LockedException("User account is locked"); - } - - if (!user.isEnabled()) { - throw new DisabledException("User is disabled"); - } - - if (!user.isAccountNonExpired()) { - throw new AccountExpiredException("User account has expired"); - } - - // This check must come here, as we don't want to tell users - // about account status unless they presented the correct credentials - try { - additionalAuthenticationChecks(user, - (UsernamePasswordAuthenticationToken) authentication); - } catch (AuthenticationException exception) { - // There was a problem, so try again after checking we're using latest data - cacheWasUsed = false; - user = retrieveUser(username, - (UsernamePasswordAuthenticationToken) authentication); - additionalAuthenticationChecks(user, - (UsernamePasswordAuthenticationToken) authentication); - } - - if (!user.isCredentialsNonExpired()) { - throw new CredentialsExpiredException( - "User credentials have expired"); - } - - if (!cacheWasUsed) { - this.userCache.putUserInCache(user); - } - - Object principalToReturn = user; - - if (forcePrincipalAsString) { - principalToReturn = user.getUsername(); - } - - return createSuccessAuthentication(principalToReturn, authentication, - user); - } - - public boolean supports(Class authentication) { - return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); - } - /** * Allows subclasses to perform any additional checks of a returned (or * cached) UserDetails for a given authentication request. @@ -190,8 +102,132 @@ public abstract class AbstractUserDetailsAuthenticationProvider UsernamePasswordAuthenticationToken authentication) throws AuthenticationException; + public final void afterPropertiesSet() throws Exception { + Assert.notNull(this.userCache, "A user cache must be set"); + Assert.notNull(this.messages, "A message source must be set"); + doAfterPropertiesSet(); + } + + public Authentication authenticate(Authentication authentication) + throws AuthenticationException { + Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, + authentication, + messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.onlySupports", + "Only UsernamePasswordAuthenticationToken is supported")); + + // Determine username + String username = (authentication.getPrincipal() == null) + ? "NONE_PROVIDED" : authentication.getName(); + + boolean cacheWasUsed = true; + UserDetails user = this.userCache.getUserFromCache(username); + + if (user == null) { + cacheWasUsed = false; + user = retrieveUser(username, + (UsernamePasswordAuthenticationToken) authentication); + Assert.notNull(user, + "retrieveUser returned null - a violation of the interface contract"); + } + + if (!user.isAccountNonLocked()) { + throw new LockedException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.locked", + "User account is locked")); + } + + if (!user.isEnabled()) { + throw new DisabledException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.disabled", + "User is disabled")); + } + + if (!user.isAccountNonExpired()) { + throw new AccountExpiredException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.expired", + "User account has expired")); + } + + // This check must come here, as we don't want to tell users + // about account status unless they presented the correct credentials + try { + additionalAuthenticationChecks(user, + (UsernamePasswordAuthenticationToken) authentication); + } catch (AuthenticationException exception) { + // There was a problem, so try again after checking we're using latest data + cacheWasUsed = false; + user = retrieveUser(username, + (UsernamePasswordAuthenticationToken) authentication); + additionalAuthenticationChecks(user, + (UsernamePasswordAuthenticationToken) authentication); + } + + if (!user.isCredentialsNonExpired()) { + throw new CredentialsExpiredException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.credentialsExpired", + "User credentials have expired")); + } + + if (!cacheWasUsed) { + this.userCache.putUserInCache(user); + } + + Object principalToReturn = user; + + if (forcePrincipalAsString) { + principalToReturn = user.getUsername(); + } + + return createSuccessAuthentication(principalToReturn, authentication, + user); + } + + /** + * Creates a successful {@link Authentication} object. + * + *

+ * Protected so subclasses can override. + *

+ * + *

+ * Subclasses will usually store the original credentials the user supplied + * (not salted or encoded passwords) in the returned + * Authentication object. + *

+ * + * @param principal that should be the principal in the returned object + * (defined by the {@link #isForcePrincipalAsString()} method) + * @param authentication that was presented to the + * DaoAuthenticationProvider for validation + * @param user that was loaded by the AuthenticationDao + * + * @return the successful authentication token + */ + protected Authentication createSuccessAuthentication(Object principal, + Authentication authentication, UserDetails user) { + // Ensure we return the original credentials the user supplied, + // so subsequent attempts are successful even with encoded passwords. + // Also ensure we return the original getDetails(), so that future + // authentication events after cache expiry contain the details + UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, + authentication.getCredentials(), user.getAuthorities()); + result.setDetails((authentication.getDetails() != null) + ? authentication.getDetails() : null); + + return result; + } + protected void doAfterPropertiesSet() throws Exception {} + public UserCache getUserCache() { + return userCache; + } + + public boolean isForcePrincipalAsString() { + return forcePrincipalAsString; + } + /** * Allows subclasses to actually retrieve the UserDetails from * an implementation-specific location, with the option of throwing an @@ -243,38 +279,19 @@ public abstract class AbstractUserDetailsAuthenticationProvider UsernamePasswordAuthenticationToken authentication) throws AuthenticationException; - /** - * Creates a successful {@link Authentication} object. - * - *

- * Protected so subclasses can override. - *

- * - *

- * Subclasses will usually store the original credentials the user supplied - * (not salted or encoded passwords) in the returned - * Authentication object. - *

- * - * @param principal that should be the principal in the returned object - * (defined by the {@link #isForcePrincipalAsString()} method) - * @param authentication that was presented to the - * DaoAuthenticationProvider for validation - * @param user that was loaded by the AuthenticationDao - * - * @return the successful authentication token - */ - protected Authentication createSuccessAuthentication(Object principal, - Authentication authentication, UserDetails user) { - // Ensure we return the original credentials the user supplied, - // so subsequent attempts are successful even with encoded passwords. - // Also ensure we return the original getDetails(), so that future - // authentication events after cache expiry contain the details - UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, - authentication.getCredentials(), user.getAuthorities()); - result.setDetails((authentication.getDetails() != null) - ? authentication.getDetails() : null); + public void setForcePrincipalAsString(boolean forcePrincipalAsString) { + this.forcePrincipalAsString = forcePrincipalAsString; + } - return result; + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + public void setUserCache(UserCache userCache) { + this.userCache = userCache; + } + + public boolean supports(Class authentication) { + return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } } diff --git a/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java index f54f926108..9ad3a04a23 100644 --- a/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java @@ -19,6 +19,7 @@ import org.acegisecurity.AuthenticationException; import org.acegisecurity.AuthenticationServiceException; import org.acegisecurity.BadCredentialsException; import org.acegisecurity.UserDetails; + import org.acegisecurity.providers.AuthenticationProvider; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.providers.encoding.PasswordEncoder; @@ -32,9 +33,6 @@ import org.springframework.util.Assert; /** * An {@link AuthenticationProvider} implementation that retrieves user details * from an {@link AuthenticationDao}. - * - * @author Ben Alex - * @version $Id$ */ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @@ -47,68 +45,6 @@ public class DaoAuthenticationProvider //~ Methods ================================================================ - public void setAuthenticationDao(AuthenticationDao authenticationDao) { - this.authenticationDao = authenticationDao; - } - - public AuthenticationDao getAuthenticationDao() { - return authenticationDao; - } - - /** - * By default the DaoAuthenticationProvider throws a - * BadCredentialsException if a username is not found or the - * password is incorrect. Setting this property to false will - * cause UsernameNotFoundExceptions to be thrown instead for - * the former. Note this is considered less secure than throwing - * BadCredentialsException for both exceptions. - * - * @param hideUserNotFoundExceptions set to false if you wish - * UsernameNotFoundExceptions to be thrown instead of - * the non-specific BadCredentialsException (defaults - * to true) - */ - public void setHideUserNotFoundExceptions( - boolean hideUserNotFoundExceptions) { - this.hideUserNotFoundExceptions = hideUserNotFoundExceptions; - } - - public boolean isHideUserNotFoundExceptions() { - return hideUserNotFoundExceptions; - } - - /** - * Sets the PasswordEncoder instance to be used to encode and validate - * passwords. If not set, {@link PlaintextPasswordEncoder} will be used by - * default. - * - * @param passwordEncoder The passwordEncoder to use - */ - public void setPasswordEncoder(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - public PasswordEncoder getPasswordEncoder() { - return passwordEncoder; - } - - /** - * The source of salts to use when decoding passwords. null - * is a valid value, meaning the DaoAuthenticationProvider - * will present null to the relevant - * PasswordEncoder. - * - * @param saltSource to use when attempting to decode passwords via the - * PasswordEncoder - */ - public void setSaltSource(SaltSource saltSource) { - this.saltSource = saltSource; - } - - public SaltSource getSaltSource() { - return saltSource; - } - protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { @@ -120,7 +56,9 @@ public class DaoAuthenticationProvider if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), authentication.getCredentials().toString(), salt)) { - throw new BadCredentialsException("Bad credentials", userDetails); + throw new BadCredentialsException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.badCredentials", + "Bad credentials"), userDetails); } } @@ -129,6 +67,22 @@ public class DaoAuthenticationProvider "An Authentication DAO must be set"); } + public AuthenticationDao getAuthenticationDao() { + return authenticationDao; + } + + public PasswordEncoder getPasswordEncoder() { + return passwordEncoder; + } + + public SaltSource getSaltSource() { + return saltSource; + } + + public boolean isHideUserNotFoundExceptions() { + return hideUserNotFoundExceptions; + } + protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { @@ -138,20 +92,70 @@ public class DaoAuthenticationProvider loadedUser = this.authenticationDao.loadUserByUsername(username); } catch (UsernameNotFoundException notFound) { if (hideUserNotFoundExceptions) { - throw new BadCredentialsException("Bad credentials presented"); + throw new BadCredentialsException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.badCredentials", + "Bad credentials")); } else { throw notFound; } } catch (DataAccessException repositoryProblem) { throw new AuthenticationServiceException(repositoryProblem - .getMessage(), repositoryProblem); + .getMessage(), repositoryProblem); + } + + if (loadedUser == null) { + throw new AuthenticationServiceException( + "AuthenticationDao returned null, which is an interface contract violation"); + } + + return loadedUser; } - if (loadedUser == null) { - throw new AuthenticationServiceException( - "AuthenticationDao returned null, which is an interface contract violation"); + public void setAuthenticationDao(AuthenticationDao authenticationDao) { + this.authenticationDao = authenticationDao; } - return loadedUser; + /** + * By default the DaoAuthenticationProvider throws a + * BadCredentialsException if a username is not found or + * the password is incorrect. Setting this property to + * false will cause + * UsernameNotFoundExceptions to be thrown instead for + * the former. Note this is considered less secure than throwing + * BadCredentialsException for both exceptions. + * + * @param hideUserNotFoundExceptions set to false if you + * wish UsernameNotFoundExceptions to be thrown + * instead of the non-specific + * BadCredentialsException (defaults to + * true) + */ + public void setHideUserNotFoundExceptions( + boolean hideUserNotFoundExceptions) { + this.hideUserNotFoundExceptions = hideUserNotFoundExceptions; + } + + /** + * Sets the PasswordEncoder instance to be used to encode and validate + * passwords. If not set, {@link PlaintextPasswordEncoder} will be + * used by default. + * + * @param passwordEncoder The passwordEncoder to use + */ + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + /** + * The source of salts to use when decoding passwords. + * null is a valid value, meaning the + * DaoAuthenticationProvider will present + * null to the relevant PasswordEncoder. + * + * @param saltSource to use when attempting to decode passwords via the + * PasswordEncoder + */ + public void setSaltSource(SaltSource saltSource) { + this.saltSource = saltSource; + } } -} diff --git a/core/src/main/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProvider.java index f49f53e0d3..c397e061bc 100644 --- a/core/src/main/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProvider.java @@ -18,6 +18,7 @@ package org.acegisecurity.providers.rememberme; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.acegisecurity.BadCredentialsException; + import org.acegisecurity.providers.AuthenticationProvider; import org.apache.commons.logging.Log; @@ -25,6 +26,10 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; @@ -37,32 +42,23 @@ import org.springframework.util.Assert; * org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken#getKeyHash()} * must match this class' {@link #getKey()}. *

- * - * @author Ben Alex - * @version $Id$ */ public class RememberMeAuthenticationProvider implements AuthenticationProvider, - InitializingBean { + InitializingBean, MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(RememberMeAuthenticationProvider.class); //~ Instance fields ======================================================== + protected MessageSourceAccessor messages; private String key; //~ Methods ================================================================ - public void setKey(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - public void afterPropertiesSet() throws Exception { Assert.hasLength(key); + Assert.notNull(this.messages, "A message source must be set"); } public Authentication authenticate(Authentication authentication) @@ -73,13 +69,26 @@ public class RememberMeAuthenticationProvider implements AuthenticationProvider, if (this.key.hashCode() != ((RememberMeAuthenticationToken) authentication) .getKeyHash()) { - throw new BadCredentialsException( - "The presented RememberMeAuthenticationToken does not contain the expected key"); + throw new BadCredentialsException(messages.getMessage( + "RememberMeAuthenticationProvider.incorrectKey", + "The presented RememberMeAuthenticationToken does not contain the expected key")); } return authentication; } + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + public boolean supports(Class authentication) { return (RememberMeAuthenticationToken.class.isAssignableFrom(authentication)); } diff --git a/core/src/main/java/org/acegisecurity/providers/x509/X509AuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/x509/X509AuthenticationProvider.java index 360ae5b630..d5f03891e3 100644 --- a/core/src/main/java/org/acegisecurity/providers/x509/X509AuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/x509/X509AuthenticationProvider.java @@ -15,71 +15,81 @@ package org.acegisecurity.providers.x509; -import org.acegisecurity.providers.AuthenticationProvider; -import org.acegisecurity.providers.x509.cache.NullX509UserCache; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; -import org.acegisecurity.UserDetails; import org.acegisecurity.BadCredentialsException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; +import org.acegisecurity.UserDetails; + +import org.acegisecurity.providers.AuthenticationProvider; +import org.acegisecurity.providers.x509.cache.NullX509UserCache; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + +import org.springframework.util.Assert; + import java.security.cert.X509Certificate; + /** * Processes an X.509 authentication request. + * *

- * The request will typically originate from - * {@link org.acegisecurity.ui.x509.X509ProcessingFilter}). + * The request will typically originate from {@link + * org.acegisecurity.ui.x509.X509ProcessingFilter}). *

- * - * @author Luke Taylor - * @version $Id$ */ public class X509AuthenticationProvider implements AuthenticationProvider, - InitializingBean { + InitializingBean, MessageSourceAware { //~ Static fields/initializers ============================================= - + private static final Log logger = LogFactory.getLog(X509AuthenticationProvider.class); //~ Instance fields ======================================================== + protected MessageSourceAccessor messages; private X509AuthoritiesPopulator x509AuthoritiesPopulator; private X509UserCache userCache = new NullX509UserCache(); //~ Methods ================================================================ - public void setX509AuthoritiesPopulator(X509AuthoritiesPopulator x509AuthoritiesPopulator) { - this.x509AuthoritiesPopulator = x509AuthoritiesPopulator; - } - - public void setX509UserCache(X509UserCache cache) { - this.userCache = cache; - } - public void afterPropertiesSet() throws Exception { Assert.notNull(userCache, "An x509UserCache must be set"); - Assert.notNull(x509AuthoritiesPopulator, "An X509AuthoritiesPopulator must be set"); + Assert.notNull(x509AuthoritiesPopulator, + "An X509AuthoritiesPopulator must be set"); + Assert.notNull(this.messages, "A message source must be set"); } /** - * If the supplied authentication token contains a certificate then this will be passed - * to the configured {@link X509AuthoritiesPopulator} - * to obtain the user details and authorities for the user identified by the certificate. + * If the supplied authentication token contains a certificate then this + * will be passed to the configured {@link X509AuthoritiesPopulator} to + * obtain the user details and authorities for the user identified by the + * certificate. + * *

- * If no certificate is present (for example, if the filter is applied to an HttpRequest for which - * client authentication hasn't been configured in the container) then a BadCredentialsException will be raised. + * If no certificate is present (for example, if the filter is applied to + * an HttpRequest for which client authentication hasn't been configured + * in the container) then a BadCredentialsException will be raised. *

* * @param authentication the authentication request. - * @return an X509AuthenticationToken containing the authorities of the principal represented by the - * certificate. - * @throws AuthenticationException if the {@link X509AuthoritiesPopulator} rejects the certficate. - * @throws BadCredentialsException if no certificate was presented in the authentication request. + * + * @return an X509AuthenticationToken containing the authorities of the + * principal represented by the certificate. + * + * @throws AuthenticationException if the {@link X509AuthoritiesPopulator} + * rejects the certficate. + * @throws BadCredentialsException if no certificate was presented in the + * authentication request. */ - public Authentication authenticate(Authentication authentication) throws AuthenticationException { + public Authentication authenticate(Authentication authentication) + throws AuthenticationException { if (!supports(authentication.getClass())) { return null; } @@ -88,25 +98,42 @@ public class X509AuthenticationProvider implements AuthenticationProvider, logger.debug("X509 authentication request: " + authentication); } - X509Certificate clientCertificate = (X509Certificate)authentication.getCredentials(); + X509Certificate clientCertificate = (X509Certificate) authentication + .getCredentials(); - if(clientCertificate == null) { - throw new BadCredentialsException("Certificate is null."); + if (clientCertificate == null) { + throw new BadCredentialsException(messages.getMessage( + "X509AuthenticationProvider.certificateNull", + "Certificate is null")); + } + + UserDetails user = userCache.getUserFromCache(clientCertificate); + + if (user == null) { + logger.debug("Authenticating with certificate " + + clientCertificate); + user = x509AuthoritiesPopulator.getUserDetails(clientCertificate); + userCache.putUserInCache(clientCertificate, user); + } + + return new X509AuthenticationToken(user, clientCertificate, + user.getAuthorities()); } - UserDetails user = userCache.getUserFromCache(clientCertificate); - - if(user == null) { - logger.debug("Authenticating with certificate " + clientCertificate); - user = x509AuthoritiesPopulator.getUserDetails(clientCertificate); - userCache.putUserInCache(clientCertificate, user); + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); } - return new X509AuthenticationToken(user, clientCertificate, user.getAuthorities()); - } + public void setX509AuthoritiesPopulator( + X509AuthoritiesPopulator x509AuthoritiesPopulator) { + this.x509AuthoritiesPopulator = x509AuthoritiesPopulator; + } - public boolean supports(Class authentication) { - return X509AuthenticationToken.class.isAssignableFrom(authentication); - } + public void setX509UserCache(X509UserCache cache) { + this.userCache = cache; + } -} + public boolean supports(Class authentication) { + return X509AuthenticationToken.class.isAssignableFrom(authentication); + } + } diff --git a/core/src/main/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulator.java b/core/src/main/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulator.java index d5d9269dbc..89492549fc 100644 --- a/core/src/main/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulator.java +++ b/core/src/main/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulator.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,29 +16,34 @@ package org.acegisecurity.providers.x509.populator; import org.acegisecurity.AuthenticationException; -import org.acegisecurity.UserDetails; import org.acegisecurity.BadCredentialsException; +import org.acegisecurity.UserDetails; + import org.acegisecurity.providers.dao.AuthenticationDao; import org.acegisecurity.providers.x509.X509AuthoritiesPopulator; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.oro.text.regex.*; +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + +import org.springframework.util.Assert; + import java.security.cert.X509Certificate; - /** - * Populates the X509 authorities via an {@link org.acegisecurity.providers.dao.AuthenticationDao}. - * - * @author Luke Taylor - * @version $Id$ + * Populates the X509 authorities via an {@link + * org.acegisecurity.providers.dao.AuthenticationDao}. */ public class DaoX509AuthoritiesPopulator implements X509AuthoritiesPopulator, - InitializingBean { + InitializingBean, MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(DaoX509AuthoritiesPopulator.class); @@ -46,18 +51,64 @@ public class DaoX509AuthoritiesPopulator implements X509AuthoritiesPopulator, //~ Instance fields ======================================================== private AuthenticationDao authenticationDao; - private String subjectDNRegex = "CN=(.*?),"; + protected MessageSourceAccessor messages; private Pattern subjectDNPattern; + private String subjectDNRegex = "CN=(.*?),"; //~ Methods ================================================================ + public void afterPropertiesSet() throws Exception { + Assert.notNull(authenticationDao, "An authenticationDao must be set"); + Assert.notNull(this.messages, "A message source must be set"); + + Perl5Compiler compiler = new Perl5Compiler(); + + try { + subjectDNPattern = compiler.compile(subjectDNRegex, + Perl5Compiler.READ_ONLY_MASK + | Perl5Compiler.CASE_INSENSITIVE_MASK); + } catch (MalformedPatternException mpe) { + throw new IllegalArgumentException("Malformed regular expression: " + + subjectDNRegex); + } + } + + public UserDetails getUserDetails(X509Certificate clientCert) + throws AuthenticationException { + String subjectDN = clientCert.getSubjectDN().getName(); + PatternMatcher matcher = new Perl5Matcher(); + + if (!matcher.contains(subjectDN, subjectDNPattern)) { + throw new BadCredentialsException(messages.getMessage( + "DaoX509AuthoritiesPopulator.noMatching", + new Object[] {subjectDN}, + "No matching pattern was found in subjectDN: {0}")); + } + + MatchResult match = matcher.getMatch(); + + if (match.groups() != 2) { // 2 = 1 + the entire match + throw new IllegalArgumentException( + "Regular expression must contain a single group "); + } + + String userName = match.group(1); + + return this.authenticationDao.loadUserByUsername(userName); + } + public void setAuthenticationDao(AuthenticationDao authenticationDao) { this.authenticationDao = authenticationDao; } + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + /** * Sets the regular expression which will by used to extract the user name * from the certificate's Subject DN. + * *

* It should contain a single group; for example the default expression * "CN=(.*?)," matches the common name field. So "CN=Jimi Hendrix, OU=..." @@ -73,36 +124,4 @@ public class DaoX509AuthoritiesPopulator implements X509AuthoritiesPopulator, public void setSubjectDNRegex(String subjectDNRegex) { this.subjectDNRegex = subjectDNRegex; } - - public UserDetails getUserDetails(X509Certificate clientCert) - throws AuthenticationException { - - String subjectDN = clientCert.getSubjectDN().getName(); - PatternMatcher matcher = new Perl5Matcher(); - - if(!matcher.contains(subjectDN , subjectDNPattern)) { - throw new BadCredentialsException("No matching pattern was found in subjectDN: " + subjectDN); - } - - MatchResult match = matcher.getMatch(); - if(match.groups() != 2) { // 2 = 1 + the entire match - throw new IllegalArgumentException("Regular expression must contain a single group "); - } - String userName = match.group(1); - - return this.authenticationDao.loadUserByUsername(userName); - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(authenticationDao, "An authenticationDao must be set"); - - Perl5Compiler compiler = new Perl5Compiler(); - - try { - subjectDNPattern = compiler.compile(subjectDNRegex, - Perl5Compiler.READ_ONLY_MASK | Perl5Compiler.CASE_INSENSITIVE_MASK); - } catch (MalformedPatternException mpe) { - throw new IllegalArgumentException("Malformed regular expression: " + subjectDNRegex); - } - } } diff --git a/core/src/main/java/org/acegisecurity/runas/RunAsImplAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/runas/RunAsImplAuthenticationProvider.java index 3101983023..290bc9b04f 100644 --- a/core/src/main/java/org/acegisecurity/runas/RunAsImplAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/runas/RunAsImplAuthenticationProvider.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,15 @@ package org.acegisecurity.runas; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.acegisecurity.BadCredentialsException; + import org.acegisecurity.providers.AuthenticationProvider; import org.springframework.beans.factory.InitializingBean; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; @@ -38,28 +44,19 @@ import org.springframework.util.Assert; *

* If the key does not match, a BadCredentialsException is thrown. *

- * - * @author Ben Alex - * @version $Id$ */ public class RunAsImplAuthenticationProvider implements InitializingBean, - AuthenticationProvider { + AuthenticationProvider, MessageSourceAware { //~ Instance fields ======================================================== + protected MessageSourceAccessor messages; private String key; //~ Methods ================================================================ - public void setKey(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - public void afterPropertiesSet() throws Exception { - Assert.notNull(key, "A Key is required and should match that configured for the RunAsManagerImpl"); + Assert.notNull(key, + "A Key is required and should match that configured for the RunAsManagerImpl"); } public Authentication authenticate(Authentication authentication) @@ -69,11 +66,24 @@ public class RunAsImplAuthenticationProvider implements InitializingBean, if (token.getKeyHash() == key.hashCode()) { return authentication; } else { - throw new BadCredentialsException( - "The presented RunAsUserToken does not contain the expected key"); + throw new BadCredentialsException(messages.getMessage( + "RunAsImplAuthenticationProvider.incorrectKey", + "The presented RunAsUserToken does not contain the expected key")); } } + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + public boolean supports(Class authentication) { if (RunAsUserToken.class.isAssignableFrom(authentication)) { return true; diff --git a/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java index 46957b0251..ca5a8197f7 100644 --- a/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java @@ -15,7 +15,32 @@ package org.acegisecurity.ui; +import org.acegisecurity.Authentication; +import org.acegisecurity.AuthenticationException; +import org.acegisecurity.AuthenticationManager; + +import org.acegisecurity.context.SecurityContextHolder; + +import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent; + +import org.acegisecurity.ui.rememberme.NullRememberMeServices; +import org.acegisecurity.ui.rememberme.RememberMeServices; + +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.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + +import org.springframework.util.Assert; + import java.io.IOException; + import java.util.Properties; import javax.servlet.Filter; @@ -27,21 +52,6 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.acegisecurity.Authentication; -import org.acegisecurity.AuthenticationException; -import org.acegisecurity.AuthenticationManager; -import org.acegisecurity.context.SecurityContextHolder; -import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent; -import org.acegisecurity.ui.rememberme.NullRememberMeServices; -import org.acegisecurity.ui.rememberme.RememberMeServices; - -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; - /** * Abstract processor of browser-based HTTP-based authentication requests. @@ -115,20 +125,16 @@ import org.springframework.util.Assert; * *

* If authentication is successful, an {@link - * org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent} will be - * published to the application context. No events will be published if - * authentication was unsuccessful, because this would generally be recorded - * via an AuthenticationManager-specific application event. + * org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent} + * will be published to the application context. No events will be published + * if authentication was unsuccessful, because this would generally be + * recorded via an AuthenticationManager-specific application + * event. *

- * - * @author Ben Alex - * @author colin sampaleanu - * @author Ray Krueger - * @version $Id$ */ public abstract class AbstractProcessingFilter implements Filter, - InitializingBean, ApplicationEventPublisherAware { - //~ Static fields/initializersApplicationContextAware ============================================= + InitializingBean, ApplicationEventPublisherAware, MessageSourceAware { + //~ Static fields/initializers ============================================= public static final String ACEGI_SECURITY_TARGET_URL_KEY = "ACEGI_SECURITY_TARGET_URL"; public static final String ACEGI_SECURITY_LAST_EXCEPTION_KEY = "ACEGI_SECURITY_LAST_EXCEPTION"; @@ -138,6 +144,7 @@ public abstract class AbstractProcessingFilter implements Filter, private ApplicationEventPublisher eventPublisher; private AuthenticationManager authenticationManager; + protected MessageSourceAccessor messages; private Properties exceptionMappings = new Properties(); private RememberMeServices rememberMeServices = new NullRememberMeServices(); @@ -173,65 +180,15 @@ public abstract class AbstractProcessingFilter implements Filter, //~ Methods ================================================================ - public void setAlwaysUseDefaultTargetUrl(boolean alwaysUseDefaultTargetUrl) { - this.alwaysUseDefaultTargetUrl = alwaysUseDefaultTargetUrl; - } - - public boolean isAlwaysUseDefaultTargetUrl() { - return alwaysUseDefaultTargetUrl; - } - - public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; - } - - public void setContinueChainBeforeSuccessfulAuthentication( - boolean continueChainBeforeSuccessfulAuthentication) { - this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication; - } - - public boolean isContinueChainBeforeSuccessfulAuthentication() { - return continueChainBeforeSuccessfulAuthentication; - } - - /** - * Specifies the default filterProcessesUrl for the - * implementation. - * - * @return the default filterProcessesUrl - */ - public abstract String getDefaultFilterProcessesUrl(); - - public void setDefaultTargetUrl(String defaultTargetUrl) { - this.defaultTargetUrl = defaultTargetUrl; - } - - public String getDefaultTargetUrl() { - return defaultTargetUrl; - } - - public void setExceptionMappings(Properties exceptionMappings) { - this.exceptionMappings = exceptionMappings; - } - - public Properties getExceptionMappings() { - return new Properties(exceptionMappings); - } - - public void setFilterProcessesUrl(String filterProcessesUrl) { - this.filterProcessesUrl = filterProcessesUrl; - } - - public String getFilterProcessesUrl() { - return filterProcessesUrl; - } - - public void setRememberMeServices(RememberMeServices rememberMeServices) { - this.rememberMeServices = rememberMeServices; - } - - public RememberMeServices getRememberMeServices() { - return rememberMeServices; + public void afterPropertiesSet() throws Exception { + Assert.hasLength(filterProcessesUrl, + "filterProcessesUrl must be specified"); + Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified"); + Assert.hasLength(authenticationFailureUrl, + "authenticationFailureUrl must be specified"); + Assert.notNull(authenticationManager, + "authenticationManager must be specified"); + Assert.notNull(this.rememberMeServices); } /** @@ -247,34 +204,6 @@ public abstract class AbstractProcessingFilter implements Filter, public abstract Authentication attemptAuthentication( HttpServletRequest request) throws AuthenticationException; - public void setAuthenticationFailureUrl(String authenticationFailureUrl) { - this.authenticationFailureUrl = authenticationFailureUrl; - } - - public String getAuthenticationFailureUrl() { - return authenticationFailureUrl; - } - - public void setAuthenticationManager( - AuthenticationManager authenticationManager) { - this.authenticationManager = authenticationManager; - } - - public AuthenticationManager getAuthenticationManager() { - return authenticationManager; - } - - public void afterPropertiesSet() throws Exception { - Assert.hasLength(filterProcessesUrl, - "filterProcessesUrl must be specified"); - Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified"); - Assert.hasLength(authenticationFailureUrl, - "authenticationFailureUrl must be specified"); - Assert.notNull(authenticationManager, - "authenticationManager must be specified"); - Assert.notNull(this.rememberMeServices); - } - /** * Does nothing. We use IoC container lifecycle services instead. */ @@ -324,6 +253,38 @@ public abstract class AbstractProcessingFilter implements Filter, chain.doFilter(request, response); } + public String getAuthenticationFailureUrl() { + return authenticationFailureUrl; + } + + public AuthenticationManager getAuthenticationManager() { + return authenticationManager; + } + + /** + * Specifies the default filterProcessesUrl for the + * implementation. + * + * @return the default filterProcessesUrl + */ + public abstract String getDefaultFilterProcessesUrl(); + + public String getDefaultTargetUrl() { + return defaultTargetUrl; + } + + public Properties getExceptionMappings() { + return new Properties(exceptionMappings); + } + + public String getFilterProcessesUrl() { + return filterProcessesUrl; + } + + public RememberMeServices getRememberMeServices() { + return rememberMeServices; + } + /** * Does nothing. We use IoC container lifecycle services instead. * @@ -333,6 +294,14 @@ public abstract class AbstractProcessingFilter implements Filter, */ public void init(FilterConfig arg0) throws ServletException {} + public boolean isAlwaysUseDefaultTargetUrl() { + return alwaysUseDefaultTargetUrl; + } + + public boolean isContinueChainBeforeSuccessfulAuthentication() { + return continueChainBeforeSuccessfulAuthentication; + } + protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {} @@ -380,6 +349,49 @@ public abstract class AbstractProcessingFilter implements Filter, return uri.endsWith(request.getContextPath() + filterProcessesUrl); } + public void setAlwaysUseDefaultTargetUrl(boolean alwaysUseDefaultTargetUrl) { + this.alwaysUseDefaultTargetUrl = alwaysUseDefaultTargetUrl; + } + + public void setApplicationEventPublisher( + ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } + + public void setAuthenticationFailureUrl(String authenticationFailureUrl) { + this.authenticationFailureUrl = authenticationFailureUrl; + } + + public void setAuthenticationManager( + AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } + + public void setContinueChainBeforeSuccessfulAuthentication( + boolean continueChainBeforeSuccessfulAuthentication) { + this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication; + } + + public void setDefaultTargetUrl(String defaultTargetUrl) { + this.defaultTargetUrl = defaultTargetUrl; + } + + public void setExceptionMappings(Properties exceptionMappings) { + this.exceptionMappings = exceptionMappings; + } + + public void setFilterProcessesUrl(String filterProcessesUrl) { + this.filterProcessesUrl = filterProcessesUrl; + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + public void setRememberMeServices(RememberMeServices rememberMeServices) { + this.rememberMeServices = rememberMeServices; + } + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException { @@ -395,7 +407,8 @@ public abstract class AbstractProcessingFilter implements Filter, + authResult + "'"); } - String targetUrl = (String) request.getSession().getAttribute(ACEGI_SECURITY_TARGET_URL_KEY); + String targetUrl = (String) request.getSession() + .getAttribute(ACEGI_SECURITY_TARGET_URL_KEY); request.getSession().removeAttribute(ACEGI_SECURITY_TARGET_URL_KEY); if (alwaysUseDefaultTargetUrl == true) { @@ -444,8 +457,8 @@ public abstract class AbstractProcessingFilter implements Filter, } try { - request.getSession().setAttribute(ACEGI_SECURITY_LAST_EXCEPTION_KEY, - failed); + request.getSession() + .setAttribute(ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed); } catch (Exception ignored) {} onUnsuccessfulAuthentication(request, response); diff --git a/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java index 013dcd2cfc..b35c00ee8d 100644 --- a/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java @@ -19,13 +19,17 @@ import org.acegisecurity.AuthenticationException; import org.acegisecurity.AuthenticationServiceException; import org.acegisecurity.BadCredentialsException; import org.acegisecurity.UserDetails; + import org.acegisecurity.context.SecurityContextHolder; + import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.providers.dao.AuthenticationDao; import org.acegisecurity.providers.dao.UserCache; import org.acegisecurity.providers.dao.UsernameNotFoundException; import org.acegisecurity.providers.dao.cache.NullUserCache; + import org.acegisecurity.ui.WebAuthenticationDetails; + import org.acegisecurity.util.StringSplitUtils; import org.apache.commons.codec.binary.Base64; @@ -35,6 +39,10 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -72,19 +80,22 @@ import javax.servlet.http.HttpServletResponse; *

* This Digest implementation has been designed to avoid needing to store * session state between invocations. All session management information is - * stored in the "nonce" that is sent to the client by the {@link DigestProcessingFilterEntryPoint}. + * stored in the "nonce" that is sent to the client by the {@link + * DigestProcessingFilterEntryPoint}. *

* *

- * If authentication is successful, the resulting {@link org.acegisecurity.Authentication Authentication} - * object will be placed into the SecurityContextHolder. + * If authentication is successful, the resulting {@link + * org.acegisecurity.Authentication Authentication} object will be placed into + * the SecurityContextHolder. *

* *

- * If authentication fails, an - * {@link org.acegisecurity.intercept.web.AuthenticationEntryPoint AuthenticationEntryPoint} - * implementation is called. This must always be {@link DigestProcessingFilterEntryPoint}, - * which will prompt the user to authenticate again via Digest authentication. + * If authentication fails, an {@link + * org.acegisecurity.intercept.web.AuthenticationEntryPoint + * AuthenticationEntryPoint} implementation is called. This must always be + * {@link DigestProcessingFilterEntryPoint}, which will prompt the user to + * authenticate again via Digest authentication. *

* *

@@ -100,11 +111,9 @@ import javax.servlet.http.HttpServletResponse; * web.xml to use the {@link * org.acegisecurity.util.FilterToBeanProxy}. *

- * - * @author Ben Alex - * @version $Id$ */ -public class DigestProcessingFilter implements Filter, InitializingBean { +public class DigestProcessingFilter implements Filter, InitializingBean, + MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(DigestProcessingFilter.class); @@ -113,32 +122,12 @@ public class DigestProcessingFilter implements Filter, InitializingBean { private AuthenticationDao authenticationDao; private DigestProcessingFilterEntryPoint authenticationEntryPoint; + protected MessageSourceAccessor messages; private UserCache userCache = new NullUserCache(); private boolean passwordAlreadyEncoded = false; //~ Methods ================================================================ - public void setPasswordAlreadyEncoded(boolean passwordAlreadyEncoded) { - this.passwordAlreadyEncoded = passwordAlreadyEncoded; - } - - public void setAuthenticationDao(AuthenticationDao authenticationDao) { - this.authenticationDao = authenticationDao; - } - - public AuthenticationDao getAuthenticationDao() { - return authenticationDao; - } - - public void setAuthenticationEntryPoint( - DigestProcessingFilterEntryPoint authenticationEntryPoint) { - this.authenticationEntryPoint = authenticationEntryPoint; - } - - public DigestProcessingFilterEntryPoint getAuthenticationEntryPoint() { - return authenticationEntryPoint; - } - public void afterPropertiesSet() throws Exception { Assert.notNull(authenticationDao, "An AuthenticationDao is required"); Assert.notNull(authenticationEntryPoint, @@ -169,8 +158,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean { if ((header != null) && header.startsWith("Digest ")) { String section212response = header.substring(7); - String[] headerEntries = StringUtils - .commaDelimitedListToStringArray(section212response); + String[] headerEntries = StringUtils.commaDelimitedListToStringArray(section212response); Map headerMap = StringSplitUtils.splitEachArrayElementAndCreateMap(headerEntries, "=", "\""); @@ -194,9 +182,10 @@ public class DigestProcessingFilter implements Filter, InitializingBean { } fail(request, response, - new BadCredentialsException( - "Missing mandatory digest value; received header '" - + section212response + "'")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.missingMandatory", + new Object[] {section212response}, + "Missing mandatory digest value; received header {0}"))); return; } @@ -210,9 +199,10 @@ public class DigestProcessingFilter implements Filter, InitializingBean { } fail(request, response, - new BadCredentialsException( - "Missing mandatory digest value for 'auth' QOP; received header '" - + section212response + "'")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.missingAuth", + new Object[] {section212response}, + "Missing mandatory digest value; received header {0}"))); return; } @@ -221,10 +211,11 @@ public class DigestProcessingFilter implements Filter, InitializingBean { // Check realm name equals what we expected if (!this.getAuthenticationEntryPoint().getRealmName().equals(realm)) { fail(request, response, - new BadCredentialsException("Response realm name '" + realm - + "' does not match system realm name of '" - + this.getAuthenticationEntryPoint().getRealmName() - + "'")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.incorrectRealm", + new Object[] {realm, this.getAuthenticationEntryPoint() + .getRealmName()}, + "Response realm name '{0}' does not match system realm name of '{1}'"))); return; } @@ -232,9 +223,10 @@ public class DigestProcessingFilter implements Filter, InitializingBean { // Check nonce was a Base64 encoded (as sent by DigestProcessingFilterEntryPoint) if (!Base64.isArrayByteBase64(nonce.getBytes())) { fail(request, response, - new BadCredentialsException( - "Nonce is not encoded in Base64; received nonce: '" - + nonce + "'")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.nonceEncoding", + new Object[] {nonce}, + "Nonce is not encoded in Base64; received nonce {0}"))); return; } @@ -249,9 +241,10 @@ public class DigestProcessingFilter implements Filter, InitializingBean { if (nonceTokens.length != 2) { fail(request, response, - new BadCredentialsException( - "Nonce should have yielded two tokens but was: '" - + nonceAsPlainText + "'")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.nonceNotTwoTokens", + new Object[] {nonceAsPlainText}, + "Nonce should have yielded two tokens but was {0}"))); return; } @@ -263,9 +256,10 @@ public class DigestProcessingFilter implements Filter, InitializingBean { nonceExpiryTime = new Long(nonceTokens[0]).longValue(); } catch (NumberFormatException nfe) { fail(request, response, - new BadCredentialsException( - "Nonce token should have yielded a numeric first token, but was: '" - + nonceAsPlainText + "'")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.nonceNotNumeric", + new Object[] {nonceAsPlainText}, + "Nonce token should have yielded a numeric first token, but was {0}"))); return; } @@ -276,14 +270,17 @@ public class DigestProcessingFilter implements Filter, InitializingBean { if (!expectedNonceSignature.equals(nonceTokens[1])) { fail(request, response, - new BadCredentialsException("Nonce token compromised: '" - + nonceAsPlainText + "'")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.nonceCompromised", + new Object[] {nonceAsPlainText}, + "Nonce token compromised {0}"))); return; } // Lookup password for presented username // NB: DAO-provided password MUST be clear text - not encoded/salted + // (unless this instance's passwordAlreadyEncoded property is 'false') boolean loadedFromDao = false; UserDetails user = userCache.getUserFromCache(username); @@ -294,8 +291,10 @@ public class DigestProcessingFilter implements Filter, InitializingBean { user = authenticationDao.loadUserByUsername(username); } catch (UsernameNotFoundException notFound) { fail(request, response, - new BadCredentialsException("Username '" + username - + "' not known")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.usernameNotFound", + new Object[] {username}, + "Username {0} not found"))); return; } @@ -312,8 +311,8 @@ public class DigestProcessingFilter implements Filter, InitializingBean { String serverDigestMd5; // Don't catch IllegalArgumentException (already checked validity) - serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm, - user.getPassword(), + serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, + realm, user.getPassword(), ((HttpServletRequest) request).getMethod(), uri, qop, nonce, nc, cnonce); @@ -329,15 +328,17 @@ public class DigestProcessingFilter implements Filter, InitializingBean { } catch (UsernameNotFoundException notFound) { // Would very rarely happen, as user existed earlier fail(request, response, - new BadCredentialsException("Username '" + username - + "' not known")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.usernameNotFound", + new Object[] {username}, + "Username {0} not found"))); } userCache.putUserInCache(user); // Don't catch IllegalArgumentException (already checked validity) - serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm, - user.getPassword(), + serverDigestMd5 = generateDigest(passwordAlreadyEncoded, + username, realm, user.getPassword(), ((HttpServletRequest) request).getMethod(), uri, qop, nonce, nc, cnonce); } @@ -351,7 +352,9 @@ public class DigestProcessingFilter implements Filter, InitializingBean { } fail(request, response, - new BadCredentialsException("Incorrect response")); + new BadCredentialsException(messages.getMessage( + "DigestProcessingFilter.incorrectResponse", + "Incorrect response"))); return; } @@ -362,7 +365,9 @@ public class DigestProcessingFilter implements Filter, InitializingBean { // but the request was otherwise appearing to be valid if (nonceExpiryTime < System.currentTimeMillis()) { fail(request, response, - new NonceExpiredException("Nonce has expired/timed out")); + new NonceExpiredException(messages.getMessage( + "DigestProcessingFilter.nonceExpired", + "Nonce has expired/timed out"))); return; } @@ -382,18 +387,32 @@ public class DigestProcessingFilter implements Filter, InitializingBean { chain.doFilter(request, response); } - public static String encodePasswordInA1Format(String username, String realm, String password) { + public static String encodePasswordInA1Format(String username, + String realm, String password) { String a1 = username + ":" + realm + ":" + password; String a1Md5 = new String(DigestUtils.md5Hex(a1)); - return a1Md5; + + return a1Md5; } - + + private void fail(ServletRequest request, ServletResponse response, + AuthenticationException failed) throws IOException, ServletException { + SecurityContextHolder.getContext().setAuthentication(null); + + if (logger.isDebugEnabled()) { + logger.debug(failed); + } + + authenticationEntryPoint.commence(request, response, failed); + } + /** * Computes the response portion of a Digest authentication * header. Both the server and user agent should compute the * response independently. Provided as a static method to * simplify the coding of user agents. * + * @param passwordAlreadyEncoded DOCUMENT ME! * @param username DOCUMENT ME! * @param realm DOCUMENT ME! * @param password DOCUMENT ME! @@ -408,19 +427,20 @@ public class DigestProcessingFilter implements Filter, InitializingBean { * * @throws IllegalArgumentException DOCUMENT ME! */ - public static String generateDigest(boolean passwordAlreadyEncoded, String username, String realm, - String password, String httpMethod, String uri, String qop, - String nonce, String nc, String cnonce) throws IllegalArgumentException { + public static String generateDigest(boolean passwordAlreadyEncoded, + String username, String realm, String password, String httpMethod, + String uri, String qop, String nonce, String nc, String cnonce) + throws IllegalArgumentException { String a1Md5 = null; String a2 = httpMethod + ":" + uri; String a2Md5 = new String(DigestUtils.md5Hex(a2)); - + if (passwordAlreadyEncoded) { - a1Md5 = password; + a1Md5 = password; } else { - a1Md5 = encodePasswordInA1Format(username, realm, password); + a1Md5 = encodePasswordInA1Format(username, realm, password); } - + String digest; if (qop == null) { @@ -440,8 +460,12 @@ public class DigestProcessingFilter implements Filter, InitializingBean { return digestMd5; } - public void setUserCache(UserCache userCache) { - this.userCache = userCache; + public AuthenticationDao getAuthenticationDao() { + return authenticationDao; + } + + public DigestProcessingFilterEntryPoint getAuthenticationEntryPoint() { + return authenticationEntryPoint; } public UserCache getUserCache() { @@ -450,14 +474,24 @@ public class DigestProcessingFilter implements Filter, InitializingBean { public void init(FilterConfig ignored) throws ServletException {} - private void fail(ServletRequest request, ServletResponse response, - AuthenticationException failed) throws IOException, ServletException { - SecurityContextHolder.getContext().setAuthentication(null); + public void setAuthenticationDao(AuthenticationDao authenticationDao) { + this.authenticationDao = authenticationDao; + } - if (logger.isDebugEnabled()) { - logger.debug(failed); - } + public void setAuthenticationEntryPoint( + DigestProcessingFilterEntryPoint authenticationEntryPoint) { + this.authenticationEntryPoint = authenticationEntryPoint; + } - authenticationEntryPoint.commence(request, response, failed); + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + public void setPasswordAlreadyEncoded(boolean passwordAlreadyEncoded) { + this.passwordAlreadyEncoded = passwordAlreadyEncoded; + } + + public void setUserCache(UserCache userCache) { + this.userCache = userCache; } } diff --git a/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java index d26f8cd2d1..9d96b0513c 100644 --- a/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java @@ -22,12 +22,17 @@ import org.acegisecurity.AuthenticationException; import org.acegisecurity.CredentialsExpiredException; import org.acegisecurity.DisabledException; import org.acegisecurity.GrantedAuthority; +import org.acegisecurity.LockedException; import org.acegisecurity.UserDetails; + import org.acegisecurity.context.SecurityContextHolder; + import org.acegisecurity.event.authentication.AuthenticationSwitchUserEvent; + import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.providers.dao.AuthenticationDao; import org.acegisecurity.providers.dao.UsernameNotFoundException; + import org.acegisecurity.ui.WebAuthenticationDetails; import org.apache.commons.logging.Log; @@ -36,8 +41,11 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; import org.springframework.util.Assert; @@ -80,8 +88,8 @@ import javax.servlet.http.HttpServletResponse; *

* On successful switch, the user's SecurityContextHolder will be * updated to reflect the specified user and will also contain an additinal - * {@link org.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority } - * which contains the original user. + * {@link org.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority } which + * contains the original user. *

* *

@@ -104,13 +112,10 @@ import javax.servlet.http.HttpServletResponse; * *

* - * @author Mark St.Godard - * @version $Id$ - * * @see org.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority */ public class SwitchUserProcessingFilter implements Filter, InitializingBean, - ApplicationEventPublisherAware { + ApplicationEventPublisherAware, MessageSourceAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(SwitchUserProcessingFilter.class); @@ -127,105 +132,21 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean, // ~ Instance fields // ======================================================== private AuthenticationDao authenticationDao; + protected MessageSourceAccessor messages; private String exitUserUrl = "/j_acegi_exit_user"; private String switchUserUrl = "/j_acegi_switch_user"; private String targetUrl; //~ Methods ================================================================ - public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) - throws BeansException { - this.eventPublisher = eventPublisher; - } - - /** - * Sets the authentication data access object. - * - * @param authenticationDao The authentication dao - */ - public void setAuthenticationDao(AuthenticationDao authenticationDao) { - this.authenticationDao = authenticationDao; - } - - /** - * Set the URL to respond to exit user processing. - * - * @param exitUserUrl The exit user URL. - */ - public void setExitUserUrl(String exitUserUrl) { - this.exitUserUrl = exitUserUrl; - } - - /** - * Set the URL to respond to switch user processing. - * - * @param switchUserUrl The switch user URL. - */ - public void setSwitchUserUrl(String switchUserUrl) { - this.switchUserUrl = switchUserUrl; - } - - /** - * Sets the URL to go to after a successful switch / exit user request. - * - * @param targetUrl The target url. - */ - public void setTargetUrl(String targetUrl) { - this.targetUrl = targetUrl; - } - public void afterPropertiesSet() throws Exception { Assert.hasLength(switchUserUrl, "switchUserUrl must be specified"); Assert.hasLength(exitUserUrl, "exitUserUrl must be specified"); Assert.hasLength(targetUrl, "targetUrl must be specified"); Assert.notNull(authenticationDao, "authenticationDao must be specified"); + Assert.notNull(messages, "A message source must be set"); } - public void destroy() {} - - /** - * @see javax.servlet.Filter#doFilter - */ - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - Assert.isInstanceOf(HttpServletRequest.class, request); - Assert.isInstanceOf(HttpServletResponse.class, response); - - HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpServletResponse httpResponse = (HttpServletResponse) response; - - // check for switch or exit request - if (requiresSwitchUser(httpRequest)) { - // if set, attempt switch and store original - Authentication targetUser = attemptSwitchUser(httpRequest); - - // update the current context to the new target user - SecurityContextHolder.getContext().setAuthentication(targetUser); - - // redirect to target url - httpResponse.sendRedirect(httpResponse.encodeRedirectURL(httpRequest - .getContextPath() + targetUrl)); - - return; - } else if (requiresExitUser(httpRequest)) { - // get the original authentication object (if exists) - Authentication originalUser = attemptExitUser(httpRequest); - - // update the current context back to the original user - SecurityContextHolder.getContext().setAuthentication(originalUser); - - // redirect to target url - httpResponse.sendRedirect(httpResponse.encodeRedirectURL(httpRequest - .getContextPath() + targetUrl)); - - return; - } - - chain.doFilter(request, response); - } - - public void init(FilterConfig ignored) throws ServletException {} - /** * Attempt to exit from an already switched user. * @@ -244,229 +165,397 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean, .getAuthentication(); if (null == current) { - throw new AuthenticationCredentialsNotFoundException( - "No current user associated with this request!"); - } - - // check to see if the current user did actual switch to another user - // if so, get the original source user so we can switch back - Authentication original = getSourceAuthentication(current); - - if (original == null) { - logger.error("Could not find original user Authentication object!"); - throw new AuthenticationCredentialsNotFoundException( - "Could not find original Authentication object!"); - } - - // get the source user details - UserDetails originalUser = null; - Object obj = original.getPrincipal(); - - if ((obj != null) && obj instanceof UserDetails) { - originalUser = (UserDetails) obj; - } - - // publish event - if (this.eventPublisher != null) { - eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(current, - originalUser)); - } - - return original; - } - - /** - * Attempt to switch to another user. If the user does not exist or is not - * active, return null. - * - * @param request The http request - * - * @return The new Authentication request if successfully - * switched to another user, null otherwise. - * - * @throws AuthenticationException - * @throws UsernameNotFoundException If the target user is not found. - * @throws DisabledException If the target user is disabled. - * @throws AccountExpiredException If the target user account is expired. - * @throws CredentialsExpiredException If the target user credentials are - * expired. - */ - protected Authentication attemptSwitchUser(HttpServletRequest request) - throws AuthenticationException { - UsernamePasswordAuthenticationToken targetUserRequest = null; - - String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY); - - if (username == null) { - username = ""; - } - - if (logger.isDebugEnabled()) { - logger.debug("Attempt to switch to user [" + username + "]"); - } - - // load the user by name - UserDetails targetUser = this.authenticationDao.loadUserByUsername(username); - - // user not found - if (targetUser == null) { - throw new UsernameNotFoundException("User [" + username - + "] cannot be found!"); - } - - // user is disabled - if (!targetUser.isEnabled()) { - throw new DisabledException("User is disabled"); - } - - // account is expired - if (!targetUser.isAccountNonExpired()) { - throw new AccountExpiredException("User account has expired"); - } - - // credentials expired - if (!targetUser.isCredentialsNonExpired()) { - throw new CredentialsExpiredException("User credentials expired"); - } - - // ok, create the switch user token - targetUserRequest = createSwitchUserToken(request, username, targetUser); - - if (logger.isDebugEnabled()) { - logger.debug("Switch User Token [" + targetUserRequest + "]"); - } - - // publish event - if (this.eventPublisher != null) { - eventPublisher.publishEvent(new AuthenticationSwitchUserEvent( - SecurityContextHolder.getContext().getAuthentication(), - targetUser)); - } - - return targetUserRequest; - } - - /** - * Checks the request URI for the presence of exitUserUrl. - * - * @param request The http servlet request - * - * @return true if the request requires a exit user, - * false otherwise. - * - * @see SwitchUserProcessingFilter#exitUserUrl - */ - protected boolean requiresExitUser(HttpServletRequest request) { - String uri = stripUri(request); - - return uri.endsWith(request.getContextPath() + exitUserUrl); - } - - /** - * Checks the request URI for the presence of switchUserUrl. - * - * @param request The http servlet request - * - * @return true if the request requires a switch, - * false otherwise. - * - * @see SwitchUserProcessingFilter#switchUserUrl - */ - protected boolean requiresSwitchUser(HttpServletRequest request) { - String uri = stripUri(request); - - return uri.endsWith(request.getContextPath() + switchUserUrl); - } - - /** - * Strips any content after the ';' in the request URI - * - * @param request The http request - * - * @return The stripped uri - */ - private static String stripUri(HttpServletRequest request) { - String uri = request.getRequestURI(); - int idx = uri.indexOf(';'); - - if (idx > 0) { - uri = uri.substring(0, idx); - } - - return uri; - } - - /** - * Find the original Authentication object from the current - * user's granted authorities. A successfully switched user should have a - * SwitchUserGrantedAuthority that contains the original - * source user Authentication object. - * - * @param current The current Authentication object - * - * @return The source user Authentication object or - * null otherwise. - */ - private Authentication getSourceAuthentication(Authentication current) { - Authentication original = null; - - // iterate over granted authorities and find the 'switch user' authority - GrantedAuthority[] authorities = current.getAuthorities(); - - for (int i = 0; i < authorities.length; i++) { - // check for switch user type of authority - if (authorities[i] instanceof SwitchUserGrantedAuthority) { - original = ((SwitchUserGrantedAuthority) authorities[i]) - .getSource(); - logger.debug("Found original switch user granted authority [" - + original + "]"); + throw new AuthenticationCredentialsNotFoundException(messages + .getMessage("SwitchUserProcessingFilter.noCurrentUser", + "No current user associated with this request")); } - } - return original; - } + // check to see if the current user did actual switch to another user + // if so, get the original source user so we can switch back + Authentication original = getSourceAuthentication(current); - /** - * Create a switch user token that contains an additional - * GrantedAuthority that contains the original - * Authentication object. - * - * @param request The http servlet request. - * @param username The username of target user - * @param targetUser The target user - * - * @return The authentication token - * - * @see SwitchUserGrantedAuthority - */ - private UsernamePasswordAuthenticationToken createSwitchUserToken( - HttpServletRequest request, String username, UserDetails targetUser) { - UsernamePasswordAuthenticationToken targetUserRequest; + if (original == null) { + logger.error( + "Could not find original user Authentication object!"); + throw new AuthenticationCredentialsNotFoundException(messages + .getMessage( + "SwitchUserProcessingFilter.noOriginalAuthentication", + "Could not find original Authentication object")); + } - // grant an additional authority that contains the original Authentication object - // which will be used to 'exit' from the current switched user. - Authentication currentAuth = SecurityContextHolder.getContext() - .getAuthentication(); - GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR, - currentAuth); + // get the source user details + UserDetails originalUser = null; + Object obj = original.getPrincipal(); - // get the original authorities - List orig = Arrays.asList(targetUser.getAuthorities()); + if ((obj != null) && obj instanceof UserDetails) { + originalUser = (UserDetails) obj; + } - // add the new switch user authority - List newAuths = new ArrayList(orig); - newAuths.add(switchAuthority); + // publish event + if (this.eventPublisher != null) { + eventPublisher.publishEvent(new AuthenticationSwitchUserEvent( + current, originalUser)); + } - GrantedAuthority[] authorities = {}; - authorities = (GrantedAuthority[]) newAuths.toArray(authorities); + return original; + } - // create the new authentication token - targetUserRequest = new UsernamePasswordAuthenticationToken(targetUser, - targetUser.getPassword(), authorities); + /** + * Attempt to switch to another user. If the user does not exist or + * is not active, return null. + * + * @param request The http request + * + * @return The new Authentication request if + * successfully switched to another user, + * null otherwise. + * + * @throws AuthenticationException + * @throws UsernameNotFoundException If the target user is not + * found. + * @throws LockedException DOCUMENT ME! + * @throws DisabledException If the target user is disabled. + * @throws AccountExpiredException If the target user account is + * expired. + * @throws CredentialsExpiredException If the target user + * credentials are expired. + */ + protected Authentication attemptSwitchUser( + HttpServletRequest request) throws AuthenticationException { + UsernamePasswordAuthenticationToken targetUserRequest = null; - // set details - targetUserRequest.setDetails(new WebAuthenticationDetails(request)); + String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY); - return targetUserRequest; - } -} + if (username == null) { + username = ""; + } + + if (logger.isDebugEnabled()) { + logger.debug("Attempt to switch to user [" + username + "]"); + } + + // load the user by name + UserDetails targetUser = this.authenticationDao + .loadUserByUsername(username); + + // user not found + if (targetUser == null) { + throw new UsernameNotFoundException(messages.getMessage( + "SwitchUserProcessingFilter.usernameNotFound", + new Object[] {username}, + "Username {0} not found")); + } + + // account is expired + if (!targetUser.isAccountNonLocked()) { + throw new LockedException(messages.getMessage( + "SwitchUserProcessingFilter.locked", + "User account is locked")); + } + + // user is disabled + if (!targetUser.isEnabled()) { + throw new DisabledException(messages.getMessage( + "SwitchUserProcessingFilter.disabled", + "User is disabled")); + } + + // account is expired + if (!targetUser.isAccountNonExpired()) { + throw new AccountExpiredException(messages.getMessage( + "SwitchUserProcessingFilter.expired", + "User account has expired")); + } + + // credentials expired + if (!targetUser.isCredentialsNonExpired()) { + throw new CredentialsExpiredException(messages + .getMessage( + "SwitchUserProcessingFilter.credentialsExpired", + "User credentials have expired")); + } + + // ok, create the switch user token + targetUserRequest = createSwitchUserToken(request, + username, targetUser); + + if (logger.isDebugEnabled()) { + logger.debug("Switch User Token [" + + targetUserRequest + "]"); + } + + // publish event + if (this.eventPublisher != null) { + eventPublisher.publishEvent(new AuthenticationSwitchUserEvent( + SecurityContextHolder.getContext() + .getAuthentication(), + targetUser)); + } + + return targetUserRequest; + } + + /** + * Create a switch user token that contains an additional + * GrantedAuthority that contains the original + * Authentication object. + * + * @param request The http servlet request. + * @param username The username of target user + * @param targetUser The target user + * + * @return The authentication token + * + * @see SwitchUserGrantedAuthority + */ + private UsernamePasswordAuthenticationToken createSwitchUserToken( + HttpServletRequest request, String username, + UserDetails targetUser) { + UsernamePasswordAuthenticationToken targetUserRequest; + + // grant an additional authority that contains the original Authentication object + // which will be used to 'exit' from the current switched user. + Authentication currentAuth = SecurityContextHolder.getContext() + .getAuthentication(); + GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR, + currentAuth); + + // get the original authorities + List orig = Arrays.asList(targetUser.getAuthorities()); + + // add the new switch user authority + List newAuths = new ArrayList(orig); + newAuths.add(switchAuthority); + + GrantedAuthority[] authorities = {}; + authorities = (GrantedAuthority[]) newAuths.toArray(authorities); + + // create the new authentication token + targetUserRequest = new UsernamePasswordAuthenticationToken(targetUser, + targetUser.getPassword(), authorities); + + // set details + targetUserRequest.setDetails(new WebAuthenticationDetails( + request)); + + return targetUserRequest; + } + + public void destroy() {} + + /** + * @see javax.servlet.Filter#doFilter + */ + public void doFilter(ServletRequest request, + ServletResponse response, FilterChain chain) + throws IOException, ServletException { + Assert.isInstanceOf(HttpServletRequest.class, request); + Assert.isInstanceOf(HttpServletResponse.class, response); + + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + // check for switch or exit request + if (requiresSwitchUser(httpRequest)) { + // if set, attempt switch and store original + Authentication targetUser = attemptSwitchUser(httpRequest); + + // update the current context to the new target user + SecurityContextHolder.getContext() + .setAuthentication(targetUser); + + // redirect to target url + httpResponse.sendRedirect(httpResponse + .encodeRedirectURL(httpRequest + .getContextPath() + targetUrl)); + + return; + } else if (requiresExitUser(httpRequest)) { + // get the original authentication object (if exists) + Authentication originalUser = attemptExitUser(httpRequest); + + // update the current context back to the original user + SecurityContextHolder.getContext() + .setAuthentication(originalUser); + + // redirect to target url + httpResponse.sendRedirect(httpResponse + .encodeRedirectURL(httpRequest + .getContextPath() + + targetUrl)); + + return; + } + + chain.doFilter(request, response); + } + + /** + * Find the original + * Authentication object from + * the current user's granted authorities. + * A successfully switched user should + * have a + * SwitchUserGrantedAuthority + * that contains the original source user + * Authentication object. + * + * @param current The current + * Authentication + * object + * + * @return The source user + * Authentication + * object or null + * otherwise. + */ + private Authentication getSourceAuthentication( + Authentication current) { + Authentication original = null; + + // iterate over granted authorities and find the 'switch user' authority + GrantedAuthority[] authorities = current + .getAuthorities(); + + for (int i = 0; i < authorities.length; + i++) { + // check for switch user type of authority + if (authorities[i] instanceof SwitchUserGrantedAuthority) { + original = ((SwitchUserGrantedAuthority) authorities[i]) + .getSource(); + logger.debug( + "Found original switch user granted authority [" + + original + "]"); + } + } + + return original; + } + + public void init(FilterConfig ignored) + throws ServletException {} + + /** + * Checks the request URI for the presence + * of exitUserUrl. + * + * @param request The http servlet request + * + * @return true if the request + * requires a exit user, + * false otherwise. + * + * @see SwitchUserProcessingFilter#exitUserUrl + */ + protected boolean requiresExitUser( + HttpServletRequest request) { + String uri = stripUri(request); + + return uri.endsWith(request + .getContextPath() + exitUserUrl); + } + + /** + * Checks the request URI for the + * presence of switchUserUrl. + * + * @param request The http servlet + * request + * + * @return true if the + * request requires a switch, + * false + * otherwise. + * + * @see SwitchUserProcessingFilter#switchUserUrl + */ + protected boolean requiresSwitchUser( + HttpServletRequest request) { + String uri = stripUri(request); + + return uri.endsWith(request + .getContextPath() + + switchUserUrl); + } + + public void setApplicationEventPublisher( + ApplicationEventPublisher eventPublisher) + throws BeansException { + this.eventPublisher = eventPublisher; + } + + /** + * Sets the authentication data + * access object. + * + * @param authenticationDao The + * authentication dao + */ + public void setAuthenticationDao( + AuthenticationDao authenticationDao) { + this.authenticationDao = authenticationDao; + } + + /** + * Set the URL to respond to exit + * user processing. + * + * @param exitUserUrl The exit user + * URL. + */ + public void setExitUserUrl( + String exitUserUrl) { + this.exitUserUrl = exitUserUrl; + } + + public void setMessageSource( + MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + + /** + * Set the URL to respond to switch + * user processing. + * + * @param switchUserUrl The switch + * user URL. + */ + public void setSwitchUserUrl( + String switchUserUrl) { + this.switchUserUrl = switchUserUrl; + } + + /** + * Sets the URL to go to after a + * successful switch / exit user + * request. + * + * @param targetUrl The target url. + */ + public void setTargetUrl( + String targetUrl) { + this.targetUrl = targetUrl; + } + + /** + * Strips any content after the ';' + * in the request URI + * + * @param request The http request + * + * @return The stripped uri + */ + private static String stripUri( + HttpServletRequest request) { + String uri = request + .getRequestURI(); + int idx = uri.indexOf(';'); + + if (idx > 0) { + uri = uri.substring(0, + idx); + } + + return uri; + } + } diff --git a/core/src/main/java/org/acegisecurity/vote/AbstractAccessDecisionManager.java b/core/src/main/java/org/acegisecurity/vote/AbstractAccessDecisionManager.java index 268b2020ec..82734f0702 100644 --- a/core/src/main/java/org/acegisecurity/vote/AbstractAccessDecisionManager.java +++ b/core/src/main/java/org/acegisecurity/vote/AbstractAccessDecisionManager.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,12 @@ import org.acegisecurity.ConfigAttribute; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; + +import org.springframework.util.Assert; + import java.util.Iterator; import java.util.List; @@ -32,28 +38,42 @@ import java.util.List; * AccessDecisionVoter}s and the access control behaviour if all voters * abstain from voting (defaults to deny access). *

- * - * @author Ben Alex - * @version $Id$ */ public abstract class AbstractAccessDecisionManager - implements AccessDecisionManager, InitializingBean { + implements AccessDecisionManager, InitializingBean, MessageSourceAware { //~ Instance fields ======================================================== private List decisionVoters; + protected MessageSourceAccessor messages; private boolean allowIfAllAbstainDecisions = false; //~ Methods ================================================================ - public void setAllowIfAllAbstainDecisions( - boolean allowIfAllAbstainDecisions) { - this.allowIfAllAbstainDecisions = allowIfAllAbstainDecisions; + public void afterPropertiesSet() throws Exception { + checkIfValidList(this.decisionVoters); + Assert.notNull(this.messages, "A message source must be set"); + } + + private void checkIfValidList(List listToCheck) { + if ((listToCheck == null) || (listToCheck.size() == 0)) { + throw new IllegalArgumentException( + "A list of AccessDecisionVoters is required"); + } + } + + public List getDecisionVoters() { + return this.decisionVoters; } public boolean isAllowIfAllAbstainDecisions() { return allowIfAllAbstainDecisions; } + public void setAllowIfAllAbstainDecisions( + boolean allowIfAllAbstainDecisions) { + this.allowIfAllAbstainDecisions = allowIfAllAbstainDecisions; + } + public void setDecisionVoters(List newList) { checkIfValidList(newList); @@ -76,12 +96,8 @@ public abstract class AbstractAccessDecisionManager this.decisionVoters = newList; } - public List getDecisionVoters() { - return this.decisionVoters; - } - - public void afterPropertiesSet() throws Exception { - checkIfValidList(this.decisionVoters); + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); } public boolean supports(ConfigAttribute attribute) { @@ -124,11 +140,4 @@ public abstract class AbstractAccessDecisionManager return true; } - - private void checkIfValidList(List listToCheck) { - if ((listToCheck == null) || (listToCheck.size() == 0)) { - throw new IllegalArgumentException( - "A list of AccessDecisionVoters is required"); - } - } } diff --git a/core/src/main/java/org/acegisecurity/vote/AffirmativeBased.java b/core/src/main/java/org/acegisecurity/vote/AffirmativeBased.java index c686b8d3a8..1418cd9dd8 100644 --- a/core/src/main/java/org/acegisecurity/vote/AffirmativeBased.java +++ b/core/src/main/java/org/acegisecurity/vote/AffirmativeBased.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,9 +29,6 @@ import java.util.Iterator; * Simple concrete implementation of {@link * org.acegisecurity.AccessDecisionManager} that grants access if any * AccessDecisionVoter returns an affirmative response. - * - * @author Ben Alex - * @version $Id$ */ public class AffirmativeBased extends AbstractAccessDecisionManager { //~ Static fields/initializers ============================================= @@ -83,14 +80,18 @@ public class AffirmativeBased extends AbstractAccessDecisionManager { } if (deny > 0) { - throw new AccessDeniedException("Access is denied."); + throw new AccessDeniedException(messages.getMessage( + "AbstractAccessDecisionManager.accessDenied", + "Access is denied")); } // To get this far, every AccessDecisionVoter abstained if (this.isAllowIfAllAbstainDecisions()) { return; } else { - throw new AccessDeniedException("Access is denied."); + throw new AccessDeniedException(messages.getMessage( + "AbstractAccessDecisionManager.accessDenied", + "Access is denied")); } } } diff --git a/core/src/main/java/org/acegisecurity/vote/ConsensusBased.java b/core/src/main/java/org/acegisecurity/vote/ConsensusBased.java index 3339f64b90..059e5a6c1f 100644 --- a/core/src/main/java/org/acegisecurity/vote/ConsensusBased.java +++ b/core/src/main/java/org/acegisecurity/vote/ConsensusBased.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,9 +29,6 @@ import java.util.Iterator; * Simple concrete implementation of {@link * org.acegisecurity.AccessDecisionManager} that uses a consensus-based * approach. - * - * @author Ben Alex - * @version $Id$ */ public class ConsensusBased extends AbstractAccessDecisionManager { //~ Static fields/initializers ============================================= @@ -44,15 +41,6 @@ public class ConsensusBased extends AbstractAccessDecisionManager { //~ Methods ================================================================ - public void setAllowIfEqualGrantedDeniedDecisions( - boolean allowIfEqualGrantedDeniedDecisions) { - this.allowIfEqualGrantedDeniedDecisions = allowIfEqualGrantedDeniedDecisions; - } - - public boolean isAllowIfEqualGrantedDeniedDecisions() { - return allowIfEqualGrantedDeniedDecisions; - } - /** * This concrete implementation simply polls all configured {@link * AccessDecisionVoter}s and upon completion determines the consensus of @@ -111,14 +99,18 @@ public class ConsensusBased extends AbstractAccessDecisionManager { } if (deny > grant) { - throw new AccessDeniedException("Access is denied."); + throw new AccessDeniedException(messages.getMessage( + "AbstractAccessDecisionManager.accessDenied", + "Access is denied")); } if ((grant == deny) && (grant != 0)) { if (this.allowIfEqualGrantedDeniedDecisions) { return; } else { - throw new AccessDeniedException("Access is denied."); + throw new AccessDeniedException(messages.getMessage( + "AbstractAccessDecisionManager.accessDenied", + "Access is denied")); } } @@ -126,7 +118,18 @@ public class ConsensusBased extends AbstractAccessDecisionManager { if (this.isAllowIfAllAbstainDecisions()) { return; } else { - throw new AccessDeniedException("Access is denied."); + throw new AccessDeniedException(messages.getMessage( + "AbstractAccessDecisionManager.accessDenied", + "Access is denied")); } } + + public boolean isAllowIfEqualGrantedDeniedDecisions() { + return allowIfEqualGrantedDeniedDecisions; + } + + public void setAllowIfEqualGrantedDeniedDecisions( + boolean allowIfEqualGrantedDeniedDecisions) { + this.allowIfEqualGrantedDeniedDecisions = allowIfEqualGrantedDeniedDecisions; + } } diff --git a/core/src/main/java/org/acegisecurity/vote/UnanimousBased.java b/core/src/main/java/org/acegisecurity/vote/UnanimousBased.java index 642c537a5b..9f362d06ed 100644 --- a/core/src/main/java/org/acegisecurity/vote/UnanimousBased.java +++ b/core/src/main/java/org/acegisecurity/vote/UnanimousBased.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,9 +30,6 @@ import java.util.Iterator; * Simple concrete implementation of {@link * org.acegisecurity.AccessDecisionManager} that requires all voters to * abstain or grant access. - * - * @author Ben Alex - * @version $Id$ */ public class UnanimousBased extends AbstractAccessDecisionManager { //~ Static fields/initializers ============================================= @@ -105,7 +102,9 @@ public class UnanimousBased extends AbstractAccessDecisionManager { } if (deny > 0) { - throw new AccessDeniedException("Access is denied."); + throw new AccessDeniedException(messages.getMessage( + "AbstractAccessDecisionManager.accessDenied", + "Access is denied")); } // To get this far, there were no deny votes @@ -117,7 +116,9 @@ public class UnanimousBased extends AbstractAccessDecisionManager { if (this.isAllowIfAllAbstainDecisions()) { return; } else { - throw new AccessDeniedException("Access is denied."); + throw new AccessDeniedException(messages.getMessage( + "AbstractAccessDecisionManager.accessDenied", + "Access is denied")); } } } diff --git a/core/src/test/java/org/acegisecurity/adapters/AuthByAdapterTests.java b/core/src/test/java/org/acegisecurity/adapters/AuthByAdapterTests.java index ddcbe26451..19ac5a7485 100644 --- a/core/src/test/java/org/acegisecurity/adapters/AuthByAdapterTests.java +++ b/core/src/test/java/org/acegisecurity/adapters/AuthByAdapterTests.java @@ -23,6 +23,7 @@ import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; /** @@ -81,6 +82,7 @@ public class AuthByAdapterTests extends TestCase { public void testAuthByAdapterProviderNonAuthenticationMethods() throws Exception { AuthByAdapterProvider provider = new AuthByAdapterProvider(); + provider.setMessageSource(new StaticMessageSource()); try { provider.afterPropertiesSet(); @@ -99,6 +101,7 @@ public class AuthByAdapterTests extends TestCase { public void testAuthByAdapterProviderOnlyAcceptsAuthByAdapterImplementations() throws Exception { AuthByAdapterProvider provider = new AuthByAdapterProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setKey("my_password"); // Should fail as UsernamePassword is not interface of AuthByAdapter @@ -119,6 +122,7 @@ public class AuthByAdapterTests extends TestCase { public void testAuthByAdapterProviderRequiresCorrectKey() throws Exception { AuthByAdapterProvider provider = new AuthByAdapterProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setKey("my_password"); // Should fail as PrincipalAcegiUserToken has different key diff --git a/core/src/test/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProviderTests.java b/core/src/test/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProviderTests.java index 1bb23cf69c..cca7f77036 100644 --- a/core/src/test/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/afterinvocation/BasicAclEntryAfterInvocationProviderTests.java @@ -27,6 +27,7 @@ import org.acegisecurity.acl.basic.MockAclObjectIdentity; import org.acegisecurity.acl.basic.SimpleAclEntry; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.util.SimpleMethodInvocation; +import org.springframework.context.support.StaticMessageSource; /** @@ -65,6 +66,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { SimpleAclEntry.ADMINISTRATION)}); BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAclManager(aclManager); provider.afterPropertiesSet(); @@ -94,6 +96,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE)}); BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAclManager(aclManager); provider.afterPropertiesSet(); @@ -123,6 +126,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE)}); BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAclManager(aclManager); assertEquals(aclManager, provider.getAclManager()); provider.afterPropertiesSet(); @@ -150,6 +154,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { new MockAclObjectIdentity(), null, SimpleAclEntry.DELETE), new MockAclEntry()}); BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAclManager(aclManager); provider.afterPropertiesSet(); @@ -171,6 +176,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { new MockAclObjectIdentity(), null, SimpleAclEntry.READ), new MockAclEntry()}); BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAclManager(aclManager); assertEquals("AFTER_ACL_READ", provider.getProcessConfigAttribute()); provider.setProcessConfigAttribute("AFTER_ACL_ADMIN"); @@ -202,6 +208,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { SimpleAclEntry.ADMINISTRATION), new MockAclEntry()}); BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAclManager(aclManager); assertEquals(SimpleAclEntry.READ, provider.getRequirePermission()[0]); provider.setRequirePermission(new int[] {SimpleAclEntry.ADMINISTRATION}); @@ -222,6 +229,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { public void testStartupDetectsMissingAclManager() throws Exception { BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); try { provider.afterPropertiesSet(); @@ -234,6 +242,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { public void testStartupDetectsMissingProcessConfigAttribute() throws Exception { BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); AclManager aclManager = new MockAclManager("sydney", "marissa", new AclEntry[] {new SimpleAclEntry("marissa", new MockAclObjectIdentity(), null, @@ -254,6 +263,7 @@ public class BasicAclEntryAfterInvocationProviderTests extends TestCase { public void testStartupDetectsMissingRequirePermission() throws Exception { BasicAclEntryAfterInvocationProvider provider = new BasicAclEntryAfterInvocationProvider(); + provider.setMessageSource(new StaticMessageSource()); AclManager aclManager = new MockAclManager("sydney", "marissa", new AclEntry[] {new SimpleAclEntry("marissa", new MockAclObjectIdentity(), null, diff --git a/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java b/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java index 58caed15c3..7c42310eac 100644 --- a/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java +++ b/core/src/test/java/org/acegisecurity/concurrent/ConcurrentSessionControllerImplTests.java @@ -21,6 +21,7 @@ import org.acegisecurity.Authentication; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.ui.WebAuthenticationDetails; +import org.springframework.context.support.StaticMessageSource; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpSession; @@ -39,6 +40,7 @@ public class ConcurrentSessionControllerImplTests extends TestCase { ConcurrentSessionControllerImpl sc = new ConcurrentSessionControllerImpl(); SessionRegistry registry = new SessionRegistryImpl(); sc.setSessionRegistry(registry); + sc.setMessageSource(new StaticMessageSource()); // Attempt to authenticate - it should be successful Authentication auth = createAuthentication("bob", "1212"); diff --git a/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java b/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java index 504c8178ac..a1e1c55bef 100644 --- a/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java +++ b/core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java @@ -41,6 +41,7 @@ import org.acegisecurity.runas.RunAsManagerImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.StaticMessageSource; import java.lang.reflect.Method; @@ -177,6 +178,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testRejectsAccessDecisionManagersThatDoNotSupportMethodInvocation() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManagerWhichOnlySupportsStrings()); si.setAuthenticationManager(new MockAuthenticationManager()); si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true)); @@ -212,6 +214,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testRejectsCallsWhenObjectDefinitionSourceDoesNotSupportObject() throws Throwable { MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor(); + interceptor.setMessageSource(new StaticMessageSource()); interceptor.setObjectDefinitionSource(new MockObjectDefinitionSourceWhichOnlySupportsStrings()); interceptor.setAccessDecisionManager(new MockAccessDecisionManager()); interceptor.setAuthenticationManager(new MockAuthenticationManager()); @@ -228,6 +231,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testRejectsCallsWhenObjectIsNull() throws Throwable { MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor(); + interceptor.setMessageSource(new StaticMessageSource()); try { interceptor.invoke(null); @@ -240,6 +244,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testRejectsRunAsManagersThatDoNotSupportMethodInvocation() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setAuthenticationManager(new MockAuthenticationManager()); si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true)); @@ -258,6 +263,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testStartupCheckForAccessDecisionManager() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setRunAsManager(new MockRunAsManager()); si.setAuthenticationManager(new MockAuthenticationManager()); si.setAfterInvocationManager(new MockAfterInvocationManager()); @@ -276,6 +282,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testStartupCheckForAuthenticationManager() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setRunAsManager(new MockRunAsManager()); si.setAfterInvocationManager(new MockAfterInvocationManager()); @@ -294,6 +301,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testStartupCheckForMethodDefinitionSource() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setAuthenticationManager(new MockAuthenticationManager()); @@ -308,6 +316,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testStartupCheckForRunAsManager() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setAuthenticationManager(new MockAuthenticationManager()); si.setRunAsManager(null); // Overriding the default @@ -325,6 +334,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testStartupCheckForValidAfterInvocationManager() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setRunAsManager(new MockRunAsManager()); si.setAuthenticationManager(new MockAuthenticationManager()); si.setAfterInvocationManager(new MockAfterInvocationManagerWhichOnlySupportsStrings()); @@ -342,6 +352,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testValidationFailsIfInvalidAttributePresented() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setAuthenticationManager(new MockAuthenticationManager()); si.setRunAsManager(new RunAsManagerImpl()); @@ -361,6 +372,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testValidationNotAttemptedIfIsValidateConfigAttributesSetToFalse() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setAuthenticationManager(new MockAuthenticationManager()); @@ -376,6 +388,7 @@ public class MethodSecurityInterceptorTests extends TestCase { public void testValidationNotAttemptedIfMethodDefinitionSourceCannotReturnIterator() throws Exception { MethodSecurityInterceptor si = new MethodSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setRunAsManager(new MockRunAsManager()); si.setAuthenticationManager(new MockAuthenticationManager()); diff --git a/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java b/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java index 543a9caa95..803d9bd127 100644 --- a/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java +++ b/core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java @@ -30,6 +30,7 @@ import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.intercept.method.MethodDefinitionMap; import org.acegisecurity.intercept.method.MethodDefinitionSourceEditor; import org.acegisecurity.providers.TestingAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; import java.lang.reflect.Method; @@ -64,6 +65,7 @@ public class AspectJSecurityInterceptorTests extends TestCase { public void testCallbackIsInvokedWhenPermissionGranted() throws Exception { AspectJSecurityInterceptor si = new AspectJSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setApplicationEventPublisher(MockApplicationContext.getContext()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setAuthenticationManager(new MockAuthenticationManager()); @@ -100,6 +102,7 @@ public class AspectJSecurityInterceptorTests extends TestCase { public void testCallbackIsNotInvokedWhenPermissionDenied() throws Exception { AspectJSecurityInterceptor si = new AspectJSecurityInterceptor(); + si.setMessageSource(new StaticMessageSource()); si.setApplicationEventPublisher(MockApplicationContext.getContext()); si.setAccessDecisionManager(new MockAccessDecisionManager()); si.setAuthenticationManager(new MockAuthenticationManager()); diff --git a/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java b/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java index 69f3b6421f..a31a85c798 100644 --- a/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java +++ b/core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java @@ -34,6 +34,7 @@ import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.context.SecurityContextImpl; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -77,6 +78,7 @@ public class FilterSecurityInterceptorTests extends TestCase { public void testEnsuresAccessDecisionManagerSupportsFilterInvocationClass() throws Exception { FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor(); + interceptor.setMessageSource(new StaticMessageSource()); interceptor.setAuthenticationManager(new MockAuthenticationManager()); interceptor.setObjectDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); interceptor.setRunAsManager(new MockRunAsManager()); @@ -110,6 +112,7 @@ public class FilterSecurityInterceptorTests extends TestCase { public void testEnsuresRunAsManagerSupportsFilterInvocationClass() throws Exception { FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor(); + interceptor.setMessageSource(new StaticMessageSource()); interceptor.setAccessDecisionManager(new MockAccessDecisionManager()); interceptor.setAuthenticationManager(new MockAuthenticationManager()); interceptor.setObjectDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); @@ -144,6 +147,7 @@ public class FilterSecurityInterceptorTests extends TestCase { throws Throwable { // Setup the FilterSecurityInterceptor FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor(); + interceptor.setMessageSource(new StaticMessageSource()); interceptor.setAccessDecisionManager(new MockAccessDecisionManager()); interceptor.setAuthenticationManager(new MockAuthenticationManager()); interceptor.setRunAsManager(new MockRunAsManager()); @@ -183,6 +187,7 @@ public class FilterSecurityInterceptorTests extends TestCase { public void testNormalStartupAndGetter() throws Exception { FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor(); + interceptor.setMessageSource(new StaticMessageSource()); interceptor.setAccessDecisionManager(new MockAccessDecisionManager()); interceptor.setAuthenticationManager(new MockAuthenticationManager()); @@ -203,6 +208,7 @@ public class FilterSecurityInterceptorTests extends TestCase { public void testSuccessfulInvocation() throws Throwable { // Setup the FilterSecurityInterceptor FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor(); + interceptor.setMessageSource(new StaticMessageSource()); interceptor.setAccessDecisionManager(new MockAccessDecisionManager()); interceptor.setAuthenticationManager(new MockAuthenticationManager()); interceptor.setRunAsManager(new MockRunAsManager()); diff --git a/core/src/test/java/org/acegisecurity/providers/ProviderManagerTests.java b/core/src/test/java/org/acegisecurity/providers/ProviderManagerTests.java index d1356cd264..c780a76aa4 100644 --- a/core/src/test/java/org/acegisecurity/providers/ProviderManagerTests.java +++ b/core/src/test/java/org/acegisecurity/providers/ProviderManagerTests.java @@ -29,6 +29,7 @@ import org.acegisecurity.concurrent.NullConcurrentSessionController; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.support.StaticMessageSource; /** @@ -182,8 +183,8 @@ public class ProviderManagerTests extends TestCase { ProviderManager mgr = new ProviderManager(); mgr.setProviders(providers); + mgr.setMessageSource(new StaticMessageSource()); - mgr.afterPropertiesSet(); return mgr; } diff --git a/core/src/test/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProviderTests.java index 22e8257f48..c06777dd3f 100644 --- a/core/src/test/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/anonymous/AnonymousAuthenticationProviderTests.java @@ -22,6 +22,7 @@ import org.acegisecurity.BadCredentialsException; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.providers.TestingAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; /** @@ -53,6 +54,7 @@ public class AnonymousAuthenticationProviderTests extends TestCase { public void testDetectsAnInvalidKey() throws Exception { AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); aap.setKey("qwerty"); AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("WRONG_KEY", @@ -71,6 +73,7 @@ public class AnonymousAuthenticationProviderTests extends TestCase { public void testDetectsMissingKey() throws Exception { AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); try { aap.afterPropertiesSet(); @@ -82,6 +85,7 @@ public class AnonymousAuthenticationProviderTests extends TestCase { public void testGettersSetters() throws Exception { AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); aap.setKey("qwerty"); aap.afterPropertiesSet(); assertEquals("qwerty", aap.getKey()); @@ -89,6 +93,7 @@ public class AnonymousAuthenticationProviderTests extends TestCase { public void testIgnoresClassesItDoesNotSupport() throws Exception { AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); aap.setKey("qwerty"); TestingAuthenticationToken token = new TestingAuthenticationToken("user", @@ -102,6 +107,7 @@ public class AnonymousAuthenticationProviderTests extends TestCase { public void testNormalOperation() throws Exception { AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); aap.setKey("qwerty"); AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("qwerty", @@ -116,6 +122,7 @@ public class AnonymousAuthenticationProviderTests extends TestCase { public void testSupports() { AnonymousAuthenticationProvider aap = new AnonymousAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); assertTrue(aap.supports(AnonymousAuthenticationToken.class)); assertFalse(aap.supports(TestingAuthenticationToken.class)); } diff --git a/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.java index 85ce5cdb60..cc0cac2930 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.java @@ -28,6 +28,7 @@ import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.providers.cas.ticketvalidator.AbstractTicketValidator; import org.acegisecurity.providers.dao.User; import org.acegisecurity.ui.cas.CasProcessingFilter; +import org.springframework.context.support.StaticMessageSource; import java.util.HashMap; import java.util.List; @@ -64,6 +65,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testAuthenticateStateful() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider(true)); cap.setKey("qwerty"); @@ -108,6 +110,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testAuthenticateStateless() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider(true)); cap.setKey("qwerty"); @@ -144,6 +147,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testDetectsAMissingTicketId() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider(true)); cap.setKey("qwerty"); @@ -167,6 +171,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testDetectsAnInvalidKey() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider(true)); cap.setKey("qwerty"); @@ -193,6 +198,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testDetectsMissingAuthoritiesPopulator() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasProxyDecider(new MockProxyDecider()); cap.setKey("qwerty"); cap.setStatelessTicketCache(new MockStatelessTicketCache()); @@ -209,6 +215,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testDetectsMissingKey() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider()); cap.setStatelessTicketCache(new MockStatelessTicketCache()); @@ -225,6 +232,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testDetectsMissingProxyDecider() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setKey("qwerty"); cap.setStatelessTicketCache(new MockStatelessTicketCache()); @@ -241,6 +249,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testDetectsMissingStatelessTicketCache() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider()); cap.setKey("qwerty"); @@ -257,6 +266,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testDetectsMissingTicketValidator() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider(true)); cap.setKey("qwerty"); @@ -272,6 +282,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testGettersSetters() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider()); cap.setKey("qwerty"); @@ -288,6 +299,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testIgnoresClassesItDoesNotSupport() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider()); cap.setKey("qwerty"); @@ -307,6 +319,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testIgnoresUsernamePasswordAuthenticationTokensWithoutCasIdentifiersAsPrincipal() throws Exception { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator()); cap.setCasProxyDecider(new MockProxyDecider()); cap.setKey("qwerty"); @@ -322,6 +335,7 @@ public class CasAuthenticationProviderTests extends TestCase { public void testSupports() { CasAuthenticationProvider cap = new CasAuthenticationProvider(); + cap.setMessageSource(new StaticMessageSource()); assertTrue(cap.supports(UsernamePasswordAuthenticationToken.class)); assertTrue(cap.supports(CasAuthenticationToken.class)); } diff --git a/core/src/test/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDeciderTests.java b/core/src/test/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDeciderTests.java index 5680933a8b..8cf2eb41a2 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDeciderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/proxy/NamedCasProxyDeciderTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,14 @@ import junit.framework.TestCase; import org.acegisecurity.providers.cas.ProxyUntrustedException; +import org.springframework.context.support.StaticMessageSource; + import java.util.List; import java.util.Vector; /** * Tests {@link NamedCasProxyDecider}. - * - * @author Ben Alex - * @version $Id$ */ public class NamedCasProxyDeciderTests extends TestCase { //~ Constructors =========================================================== @@ -42,17 +41,18 @@ public class NamedCasProxyDeciderTests extends TestCase { //~ Methods ================================================================ - public final void setUp() throws Exception { - super.setUp(); - } - public static void main(String[] args) { junit.textui.TestRunner.run(NamedCasProxyDeciderTests.class); } + public final void setUp() throws Exception { + super.setUp(); + } + public void testAcceptsIfNearestProxyIsAuthorized() throws Exception { NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider(); + proxyDecider.setMessageSource(new StaticMessageSource()); // Build the ticket returned from CAS List proxyList = new Vector(); @@ -72,6 +72,8 @@ public class NamedCasProxyDeciderTests extends TestCase { public void testAcceptsIfNoProxiesInTicket() { NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider(); + proxyDecider.setMessageSource(new StaticMessageSource()); + List proxyList = new Vector(); // no proxies in list proxyDecider.confirmProxyListTrusted(proxyList); @@ -80,6 +82,7 @@ public class NamedCasProxyDeciderTests extends TestCase { public void testDetectsMissingValidProxiesList() throws Exception { NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider(); + proxyDecider.setMessageSource(new StaticMessageSource()); try { proxyDecider.afterPropertiesSet(); @@ -92,6 +95,7 @@ public class NamedCasProxyDeciderTests extends TestCase { public void testDoesNotAcceptNull() { NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider(); + proxyDecider.setMessageSource(new StaticMessageSource()); try { proxyDecider.confirmProxyListTrusted(null); @@ -103,6 +107,7 @@ public class NamedCasProxyDeciderTests extends TestCase { public void testGettersSetters() { NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider(); + proxyDecider.setMessageSource(new StaticMessageSource()); // Build the list of valid nearest proxies List validProxies = new Vector(); @@ -117,6 +122,7 @@ public class NamedCasProxyDeciderTests extends TestCase { public void testRejectsIfNearestProxyIsNotAuthorized() throws Exception { NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider(); + proxyDecider.setMessageSource(new StaticMessageSource()); // Build the ticket returned from CAS List proxyList = new Vector(); diff --git a/core/src/test/java/org/acegisecurity/providers/cas/proxy/RejectProxyTicketsTests.java b/core/src/test/java/org/acegisecurity/providers/cas/proxy/RejectProxyTicketsTests.java index e971943ae0..d477fff22c 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/proxy/RejectProxyTicketsTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/proxy/RejectProxyTicketsTests.java @@ -18,6 +18,7 @@ package org.acegisecurity.providers.cas.proxy; import junit.framework.TestCase; import org.acegisecurity.providers.cas.ProxyUntrustedException; +import org.springframework.context.support.StaticMessageSource; import java.util.List; import java.util.Vector; @@ -71,6 +72,7 @@ public class RejectProxyTicketsTests extends TestCase { public void testRejectsIfAnyProxyInList() { RejectProxyTickets proxyDecider = new RejectProxyTickets(); + proxyDecider.setMessageSource(new StaticMessageSource()); List proxyList = new Vector(); proxyList.add("https://localhost/webApp/j_acegi_cas_security_check"); diff --git a/core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java index d634b16dde..cd0edbc904 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java @@ -34,6 +34,7 @@ import org.acegisecurity.providers.dao.cache.NullUserCache; import org.acegisecurity.providers.dao.salt.SystemWideSaltSource; import org.acegisecurity.providers.encoding.ShaPasswordEncoder; +import org.springframework.context.support.StaticMessageSource; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataRetrievalFailureException; @@ -63,6 +64,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "KOala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -79,6 +81,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "opal"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserPeterAccountExpired()); provider.setUserCache(new MockUserCache()); @@ -95,6 +98,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "opal"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserPeterAccountLocked()); provider.setUserCache(new MockUserCache()); @@ -111,6 +115,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "opal"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserPeterCredentialsExpired()); provider.setUserCache(new MockUserCache()); @@ -138,6 +143,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "opal"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserPeter()); provider.setUserCache(new MockUserCache()); @@ -154,6 +160,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoSimulateBackendError()); provider.setUserCache(new MockUserCache()); @@ -170,6 +177,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -186,6 +194,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "INVALID_PASSWORD"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -202,6 +211,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setHideUserNotFoundExceptions(false); // we want UsernameNotFoundExceptions provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -219,6 +229,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); assertTrue(provider.isHideUserNotFoundExceptions()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -236,6 +247,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -253,6 +265,7 @@ public class DaoAuthenticationProviderTests extends TestCase { token.setDetails("192.168.0.1"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -276,6 +289,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); @@ -305,6 +319,7 @@ public class DaoAuthenticationProviderTests extends TestCase { salt.setSystemWideSalt("SYSTEM_SALT_VALUE"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissaWithSalt()); provider.setSaltSource(salt); provider.setUserCache(new MockUserCache()); @@ -330,6 +345,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); provider.setUserCache(new MockUserCache()); provider.setForcePrincipalAsString(true); @@ -351,6 +367,7 @@ public class DaoAuthenticationProviderTests extends TestCase { "koala"); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoReturnsNull()); try { @@ -364,6 +381,7 @@ public class DaoAuthenticationProviderTests extends TestCase { public void testGettersSetters() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setPasswordEncoder(new ShaPasswordEncoder()); assertEquals(ShaPasswordEncoder.class, provider.getPasswordEncoder().getClass()); @@ -388,6 +406,7 @@ public class DaoAuthenticationProviderTests extends TestCase { MockAuthenticationDaoUserMarissa authenticationDao = new MockAuthenticationDaoUserMarissa(); MockUserCache cache = new MockUserCache(); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(authenticationDao); provider.setUserCache(cache); @@ -414,6 +433,7 @@ public class DaoAuthenticationProviderTests extends TestCase { public void testStartupFailsIfNoAuthenticationDao() throws Exception { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); try { provider.afterPropertiesSet(); @@ -425,6 +445,7 @@ public class DaoAuthenticationProviderTests extends TestCase { public void testStartupFailsIfNoUserCacheSet() throws Exception { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa()); assertEquals(NullUserCache.class, provider.getUserCache().getClass()); provider.setUserCache(null); @@ -439,6 +460,7 @@ public class DaoAuthenticationProviderTests extends TestCase { public void testStartupSuccess() throws Exception { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); AuthenticationDao dao = new MockAuthenticationDaoUserMarissa(); provider.setAuthenticationDao(dao); provider.setUserCache(new MockUserCache()); @@ -449,6 +471,7 @@ public class DaoAuthenticationProviderTests extends TestCase { public void testSupports() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class)); assertTrue(!provider.supports(TestingAuthenticationToken.class)); } diff --git a/core/src/test/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProviderTests.java index 0d5acb6166..224391e60b 100644 --- a/core/src/test/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/rememberme/RememberMeAuthenticationProviderTests.java @@ -22,6 +22,7 @@ import org.acegisecurity.BadCredentialsException; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.providers.TestingAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; /** @@ -53,6 +54,7 @@ public class RememberMeAuthenticationProviderTests extends TestCase { public void testDetectsAnInvalidKey() throws Exception { RememberMeAuthenticationProvider aap = new RememberMeAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); aap.setKey("qwerty"); RememberMeAuthenticationToken token = new RememberMeAuthenticationToken("WRONG_KEY", @@ -71,6 +73,7 @@ public class RememberMeAuthenticationProviderTests extends TestCase { public void testDetectsMissingKey() throws Exception { RememberMeAuthenticationProvider aap = new RememberMeAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); try { aap.afterPropertiesSet(); @@ -82,6 +85,7 @@ public class RememberMeAuthenticationProviderTests extends TestCase { public void testGettersSetters() throws Exception { RememberMeAuthenticationProvider aap = new RememberMeAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); aap.setKey("qwerty"); aap.afterPropertiesSet(); assertEquals("qwerty", aap.getKey()); @@ -102,6 +106,7 @@ public class RememberMeAuthenticationProviderTests extends TestCase { public void testNormalOperation() throws Exception { RememberMeAuthenticationProvider aap = new RememberMeAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); aap.setKey("qwerty"); RememberMeAuthenticationToken token = new RememberMeAuthenticationToken("qwerty", @@ -116,6 +121,7 @@ public class RememberMeAuthenticationProviderTests extends TestCase { public void testSupports() { RememberMeAuthenticationProvider aap = new RememberMeAuthenticationProvider(); + aap.setMessageSource(new StaticMessageSource()); assertTrue(aap.supports(RememberMeAuthenticationToken.class)); assertFalse(aap.supports(TestingAuthenticationToken.class)); } diff --git a/core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationProviderTests.java index 371ebba15e..e962e2e158 100644 --- a/core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationProviderTests.java @@ -20,6 +20,7 @@ import junit.framework.TestCase; import org.acegisecurity.*; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.providers.dao.User; +import org.springframework.context.support.StaticMessageSource; import java.security.cert.X509Certificate; @@ -49,6 +50,7 @@ public class X509AuthenticationProviderTests extends TestCase { public void testAuthenticationIsNullWithUnsupportedToken() { X509AuthenticationProvider provider = new X509AuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); Authentication request = new UsernamePasswordAuthenticationToken("dummy", "dummy"); Authentication result = provider.authenticate(request); @@ -57,6 +59,7 @@ public class X509AuthenticationProviderTests extends TestCase { public void testFailsWithNullCertificate() { X509AuthenticationProvider provider = new X509AuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setX509AuthoritiesPopulator(new MockAuthoritiesPopulator(false)); @@ -70,6 +73,7 @@ public class X509AuthenticationProviderTests extends TestCase { public void testNormalOperation() throws Exception { X509AuthenticationProvider provider = new X509AuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setX509AuthoritiesPopulator(new MockAuthoritiesPopulator(false)); provider.afterPropertiesSet(); @@ -82,6 +86,7 @@ public class X509AuthenticationProviderTests extends TestCase { public void testPopulatorRejectionCausesFailure() throws Exception { X509AuthenticationProvider provider = new X509AuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); provider.setX509AuthoritiesPopulator(new MockAuthoritiesPopulator(true)); try { @@ -94,6 +99,7 @@ public class X509AuthenticationProviderTests extends TestCase { public void testRequiresPopulator() throws Exception { X509AuthenticationProvider provider = new X509AuthenticationProvider(); + provider.setMessageSource(new StaticMessageSource()); try { provider.afterPropertiesSet(); diff --git a/core/src/test/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulatorTests.java b/core/src/test/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulatorTests.java index e43fa85ec6..a240a7113f 100644 --- a/core/src/test/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulatorTests.java +++ b/core/src/test/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulatorTests.java @@ -26,6 +26,7 @@ import org.acegisecurity.providers.dao.User; import org.acegisecurity.providers.dao.UsernameNotFoundException; import org.acegisecurity.providers.x509.X509TestUtils; +import org.springframework.context.support.StaticMessageSource; import org.springframework.dao.DataAccessException; import java.security.cert.X509Certificate; @@ -56,6 +57,7 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase { public void testDefaultCNPatternMatch() throws Exception { X509Certificate cert = X509TestUtils.buildTestCertificate(); DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator(); + populator.setMessageSource(new StaticMessageSource()); populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail()); populator.afterPropertiesSet(); @@ -65,6 +67,7 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase { public void testEmailPatternMatch() throws Exception { X509Certificate cert = X509TestUtils.buildTestCertificate(); DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator(); + populator.setMessageSource(new StaticMessageSource()); populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail()); populator.setSubjectDNRegex("emailAddress=(.*?),"); @@ -74,6 +77,7 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase { public void testInvalidRegexFails() throws Exception { DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator(); + populator.setMessageSource(new StaticMessageSource()); populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail()); populator.setSubjectDNRegex("CN=(.*?,"); // missing closing bracket on group @@ -88,6 +92,7 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase { public void testMatchOnShoeSizeFieldInDNFails() throws Exception { X509Certificate cert = X509TestUtils.buildTestCertificate(); DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator(); + populator.setMessageSource(new StaticMessageSource()); populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail()); populator.setSubjectDNRegex("shoeSize=(.*?),"); @@ -104,6 +109,7 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase { public void testPatternWithNoGroupFails() throws Exception { X509Certificate cert = X509TestUtils.buildTestCertificate(); DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator(); + populator.setMessageSource(new StaticMessageSource()); populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail()); populator.setSubjectDNRegex("CN=.*?,"); @@ -120,6 +126,7 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase { public void testRequiresDao() throws Exception { DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator(); + populator.setMessageSource(new StaticMessageSource()); try { populator.afterPropertiesSet(); diff --git a/core/src/test/java/org/acegisecurity/runas/RunAsImplAuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/runas/RunAsImplAuthenticationProviderTests.java index 6ecd1106cf..6bc476eef9 100644 --- a/core/src/test/java/org/acegisecurity/runas/RunAsImplAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/runas/RunAsImplAuthenticationProviderTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,15 +21,15 @@ import org.acegisecurity.Authentication; import org.acegisecurity.BadCredentialsException; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; + import org.acegisecurity.providers.TestingAuthenticationToken; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; + /** * Tests {@link RunAsImplAuthenticationProvider}. - * - * @author Ben Alex - * @version $Id$ */ public class RunAsImplAuthenticationProviderTests extends TestCase { //~ Constructors =========================================================== @@ -44,14 +44,14 @@ public class RunAsImplAuthenticationProviderTests extends TestCase { //~ Methods ================================================================ - public final void setUp() throws Exception { - super.setUp(); - } - public static void main(String[] args) { junit.textui.TestRunner.run(RunAsImplAuthenticationProviderTests.class); } + public final void setUp() throws Exception { + super.setUp(); + } + public void testAuthenticationFailDueToWrongKey() { RunAsUserToken token = new RunAsUserToken("WRONG_PASSWORD", "Test", "Password", @@ -59,6 +59,7 @@ public class RunAsImplAuthenticationProviderTests extends TestCase { "ROLE_TWO")}, UsernamePasswordAuthenticationToken.class); RunAsImplAuthenticationProvider provider = new RunAsImplAuthenticationProvider(); provider.setKey("hello_world"); + provider.setMessageSource(new StaticMessageSource()); try { provider.authenticate(token); diff --git a/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java index d43e3f3a83..2bc7fadec0 100644 --- a/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java +++ b/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java @@ -31,6 +31,7 @@ import org.acegisecurity.providers.dao.User; import org.acegisecurity.providers.dao.UsernameNotFoundException; import org.acegisecurity.util.MockFilterChain; +import org.springframework.context.support.StaticMessageSource; import org.springframework.dao.DataAccessException; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -74,6 +75,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { "user-that-doesnt-exist"); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); try { @@ -97,6 +99,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { "mcgarrett"); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); try { @@ -122,6 +125,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { "wofat"); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); try { @@ -147,6 +151,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { "steve"); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); try { @@ -169,6 +174,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { "jacklord"); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); Authentication result = filter.attemptSwitchUser(request); @@ -177,6 +183,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { public void testBadConfigMissingAuthenticationDao() { SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setSwitchUserUrl("/j_acegi_switch_user"); filter.setExitUserUrl("/j_acegi_exit_user"); filter.setTargetUrl("/main.jsp"); @@ -191,6 +198,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { public void testBadConfigMissingTargetUrl() { SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); filter.setSwitchUserUrl("/j_acegi_switch_user"); filter.setExitUserUrl("/j_acegi_exit_user"); @@ -206,6 +214,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { public void testDefaultProcessesFilterUrlWithPathParameter() { MockHttpServletRequest request = createMockSwitchRequest(); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setSwitchUserUrl("/j_acegi_switch_user"); request.setRequestURI( @@ -238,6 +247,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { // setup filter SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); filter.setExitUserUrl("/j_acegi_exit_user"); @@ -266,6 +276,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { // setup filter SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); filter.setExitUserUrl("/j_acegi_exit_user"); @@ -294,6 +305,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { MockFilterChain chain = new MockFilterChain(true); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setSwitchUserUrl("/j_acegi_switch_user"); filter.setTargetUrl("/webapp/someOtherUrl"); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); @@ -343,6 +355,7 @@ public class SwitchUserProcessingFilterTests extends TestCase { // setup filter SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); + filter.setMessageSource(new StaticMessageSource()); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); filter.setSwitchUserUrl("/j_acegi_switch_user"); diff --git a/core/src/test/java/org/acegisecurity/vote/AffirmativeBasedTests.java b/core/src/test/java/org/acegisecurity/vote/AffirmativeBasedTests.java index a4f2e64803..f40d48f8dd 100644 --- a/core/src/test/java/org/acegisecurity/vote/AffirmativeBasedTests.java +++ b/core/src/test/java/org/acegisecurity/vote/AffirmativeBasedTests.java @@ -23,6 +23,7 @@ import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.SecurityConfig; import org.acegisecurity.providers.TestingAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; import java.util.List; import java.util.Vector; @@ -143,6 +144,7 @@ public class AffirmativeBasedTests extends TestCase { private AffirmativeBased makeDecisionManager() { AffirmativeBased decisionManager = new AffirmativeBased(); + decisionManager.setMessageSource(new StaticMessageSource()); RoleVoter roleVoter = new RoleVoter(); DenyVoter denyForSureVoter = new DenyVoter(); DenyAgainVoter denyAgainForSureVoter = new DenyAgainVoter(); diff --git a/core/src/test/java/org/acegisecurity/vote/ConsensusBasedTests.java b/core/src/test/java/org/acegisecurity/vote/ConsensusBasedTests.java index 57bdaf4f8a..4e47159713 100644 --- a/core/src/test/java/org/acegisecurity/vote/ConsensusBasedTests.java +++ b/core/src/test/java/org/acegisecurity/vote/ConsensusBasedTests.java @@ -23,6 +23,7 @@ import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.SecurityConfig; import org.acegisecurity.providers.TestingAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; import java.util.List; import java.util.Vector; @@ -164,6 +165,7 @@ public class ConsensusBasedTests extends TestCase { private ConsensusBased makeDecisionManager() { ConsensusBased decisionManager = new ConsensusBased(); + decisionManager.setMessageSource(new StaticMessageSource()); RoleVoter roleVoter = new RoleVoter(); DenyVoter denyForSureVoter = new DenyVoter(); DenyAgainVoter denyAgainForSureVoter = new DenyAgainVoter(); diff --git a/core/src/test/java/org/acegisecurity/vote/UnanimousBasedTests.java b/core/src/test/java/org/acegisecurity/vote/UnanimousBasedTests.java index a1c986bde5..5274533048 100644 --- a/core/src/test/java/org/acegisecurity/vote/UnanimousBasedTests.java +++ b/core/src/test/java/org/acegisecurity/vote/UnanimousBasedTests.java @@ -23,6 +23,7 @@ import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.SecurityConfig; import org.acegisecurity.providers.TestingAuthenticationToken; +import org.springframework.context.support.StaticMessageSource; import java.util.List; import java.util.Vector; @@ -59,6 +60,7 @@ public class UnanimousBasedTests extends TestCase { throws Exception { TestingAuthenticationToken auth = makeTestToken(); UnanimousBased mgr = makeDecisionManager(); + mgr.setMessageSource(new StaticMessageSource()); ConfigAttributeDefinition config = new ConfigAttributeDefinition(); config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant @@ -76,6 +78,7 @@ public class UnanimousBasedTests extends TestCase { throws Exception { TestingAuthenticationToken auth = makeTestToken(); UnanimousBased mgr = makeDecisionManager(); + mgr.setMessageSource(new StaticMessageSource()); ConfigAttributeDefinition config = new ConfigAttributeDefinition(); config.addConfigAttribute(new SecurityConfig("ROLE_2")); // grant @@ -88,6 +91,7 @@ public class UnanimousBasedTests extends TestCase { throws Exception { TestingAuthenticationToken auth = makeTestToken(); UnanimousBased mgr = makeDecisionManager(); + mgr.setMessageSource(new StaticMessageSource()); ConfigAttributeDefinition config = new ConfigAttributeDefinition(); config.addConfigAttribute(new SecurityConfig("ROLE_WE_DO_NOT_HAVE")); // deny @@ -103,6 +107,7 @@ public class UnanimousBasedTests extends TestCase { public void testRoleVoterPrefixObserved() throws Exception { TestingAuthenticationToken auth = makeTestTokenWithFooBarPrefix(); UnanimousBased mgr = makeDecisionManagerWithFooBarPrefix(); + mgr.setMessageSource(new StaticMessageSource()); ConfigAttributeDefinition config = new ConfigAttributeDefinition(); config.addConfigAttribute(new SecurityConfig("FOOBAR_1")); // grant @@ -116,6 +121,7 @@ public class UnanimousBasedTests extends TestCase { throws Exception { TestingAuthenticationToken auth = makeTestToken(); UnanimousBased mgr = makeDecisionManager(); + mgr.setMessageSource(new StaticMessageSource()); assertTrue(!mgr.isAllowIfAllAbstainDecisions()); // check default @@ -135,6 +141,7 @@ public class UnanimousBasedTests extends TestCase { TestingAuthenticationToken auth = makeTestToken(); UnanimousBased mgr = makeDecisionManager(); mgr.setAllowIfAllAbstainDecisions(true); + mgr.setMessageSource(new StaticMessageSource()); assertTrue(mgr.isAllowIfAllAbstainDecisions()); // check changed ConfigAttributeDefinition config = new ConfigAttributeDefinition(); @@ -148,6 +155,7 @@ public class UnanimousBasedTests extends TestCase { throws Exception { TestingAuthenticationToken auth = makeTestToken(); UnanimousBased mgr = makeDecisionManager(); + mgr.setMessageSource(new StaticMessageSource()); ConfigAttributeDefinition config = new ConfigAttributeDefinition(); config.addConfigAttribute(new SecurityConfig("ROLE_1")); // grant @@ -159,6 +167,7 @@ public class UnanimousBasedTests extends TestCase { private UnanimousBased makeDecisionManager() { UnanimousBased decisionManager = new UnanimousBased(); + decisionManager.setMessageSource(new StaticMessageSource()); RoleVoter roleVoter = new RoleVoter(); DenyVoter denyForSureVoter = new DenyVoter(); DenyAgainVoter denyAgainForSureVoter = new DenyAgainVoter(); @@ -173,6 +182,7 @@ public class UnanimousBasedTests extends TestCase { private UnanimousBased makeDecisionManagerWithFooBarPrefix() { UnanimousBased decisionManager = new UnanimousBased(); + decisionManager.setMessageSource(new StaticMessageSource()); RoleVoter roleVoter = new RoleVoter(); roleVoter.setRolePrefix("FOOBAR_");