diff --git a/core/src/main/java/org/acegisecurity/AccountExpiredException.java b/core/src/main/java/org/acegisecurity/AccountExpiredException.java
new file mode 100644
index 0000000000..b2dce386f9
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/AccountExpiredException.java
@@ -0,0 +1,49 @@
+/* Copyright 2004 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+/**
+ * Thrown if an authentication request is rejected because the account has
+ * expired. Makes no assertion as to whether or not the credentials were
+ * valid.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AccountExpiredException extends AuthenticationException {
+ //~ Constructors ===========================================================
+
+ /**
+ * Constructs a AccountExpiredException with the specified
+ * message.
+ *
+ * @param msg the detail message
+ */
+ public AccountExpiredException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a AccountExpiredException with the specified
+ * message and root cause.
+ *
+ * @param msg the detail message
+ * @param t root cause
+ */
+ public AccountExpiredException(String msg, Throwable t) {
+ super(msg, t);
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/CredentialsExpiredException.java b/core/src/main/java/org/acegisecurity/CredentialsExpiredException.java
new file mode 100644
index 0000000000..5cdba82878
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/CredentialsExpiredException.java
@@ -0,0 +1,49 @@
+/* Copyright 2004 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+/**
+ * Thrown if an authentication request is rejected because the account's
+ * credentials have expired. Makes no assertion as to whether or not the
+ * credentials were valid.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class CredentialsExpiredException extends AuthenticationException {
+ //~ Constructors ===========================================================
+
+ /**
+ * Constructs a CredentialsExpiredException with the specified
+ * message.
+ *
+ * @param msg the detail message
+ */
+ public CredentialsExpiredException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a CredentialsExpiredException with the specified
+ * message and root cause.
+ *
+ * @param msg the detail message
+ * @param t root cause
+ */
+ public CredentialsExpiredException(String msg, Throwable t) {
+ super(msg, t);
+ }
+}
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 581e3dd20d..c4b5802a2f 100644
--- a/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java
+++ b/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java
@@ -15,16 +15,20 @@
package net.sf.acegisecurity.providers.dao;
+import net.sf.acegisecurity.AccountExpiredException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.CredentialsExpiredException;
import net.sf.acegisecurity.DisabledException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.providers.AuthenticationProvider;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
+import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureAccountExpiredEvent;
+import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureCredentialsExpiredEvent;
import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureDisabledEvent;
import net.sf.acegisecurity.providers.dao.event.AuthenticationFailurePasswordEvent;
import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureUsernameNotFoundEvent;
@@ -228,7 +232,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
authentication,
new User("".equals(username)
? "EMPTY_STRING_PROVIDED" : username, "*****",
- false, new GrantedAuthority[0])));
+ false, false, false, new GrantedAuthority[0])));
}
throw ex;
@@ -244,6 +248,25 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
throw new DisabledException("User is disabled");
}
+ if (!user.isAccountNonExpired()) {
+ if (this.context != null) {
+ context.publishEvent(new AuthenticationFailureAccountExpiredEvent(
+ authentication, user));
+ }
+
+ throw new AccountExpiredException("User account has expired");
+ }
+
+ if (!user.isCredentialsNonExpired()) {
+ if (this.context != null) {
+ context.publishEvent(new AuthenticationFailureCredentialsExpiredEvent(
+ authentication, user));
+ }
+
+ throw new CredentialsExpiredException(
+ "User credentials have expired");
+ }
+
if (!isPasswordCorrect(authentication, user)) {
// Password incorrect, so ensure we're using most current password
if (cacheWasUsed) {
diff --git a/core/src/main/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProvider.java
index a1757b7389..943e96a07d 100644
--- a/core/src/main/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProvider.java
+++ b/core/src/main/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProvider.java
@@ -15,16 +15,20 @@
package net.sf.acegisecurity.providers.dao;
+import net.sf.acegisecurity.AccountExpiredException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.CredentialsExpiredException;
import net.sf.acegisecurity.DisabledException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.providers.AuthenticationProvider;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
+import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureAccountExpiredEvent;
+import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureCredentialsExpiredEvent;
import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureDisabledEvent;
import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureUsernameOrPasswordEvent;
import net.sf.acegisecurity.providers.dao.event.AuthenticationSuccessEvent;
@@ -179,7 +183,7 @@ public class PasswordDaoAuthenticationProvider implements AuthenticationProvider
context.publishEvent(new AuthenticationFailureUsernameOrPasswordEvent(
authentication,
- new User(username, "*****", false,
+ new User(username, "*****", false, false, false,
new GrantedAuthority[0])));
}
@@ -196,6 +200,25 @@ public class PasswordDaoAuthenticationProvider implements AuthenticationProvider
throw new DisabledException("User is disabled");
}
+ if (!user.isAccountNonExpired()) {
+ if (this.context != null) {
+ context.publishEvent(new AuthenticationFailureAccountExpiredEvent(
+ authentication, user));
+ }
+
+ throw new AccountExpiredException("User account has expired");
+ }
+
+ if (!user.isCredentialsNonExpired()) {
+ if (this.context != null) {
+ context.publishEvent(new AuthenticationFailureCredentialsExpiredEvent(
+ authentication, user));
+ }
+
+ throw new CredentialsExpiredException(
+ "User credentials have expired");
+ }
+
if (!cacheWasUsed) {
// Put into cache
this.userCache.putUserInCache(user);
diff --git a/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureAccountExpiredEvent.java b/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureAccountExpiredEvent.java
new file mode 100644
index 0000000000..8bc4bc8965
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureAccountExpiredEvent.java
@@ -0,0 +1,37 @@
+/* Copyright 2004 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao.event;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.UserDetails;
+
+
+/**
+ * Application event which indicates authentication failure due to the user's
+ * account having expired.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AuthenticationFailureAccountExpiredEvent
+ extends AuthenticationEvent {
+ //~ Constructors ===========================================================
+
+ public AuthenticationFailureAccountExpiredEvent(
+ Authentication authentication, UserDetails user) {
+ super(authentication, user);
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureCredentialsExpiredEvent.java b/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureCredentialsExpiredEvent.java
new file mode 100644
index 0000000000..ff2fb44c29
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureCredentialsExpiredEvent.java
@@ -0,0 +1,37 @@
+/* Copyright 2004 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao.event;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.UserDetails;
+
+
+/**
+ * Application event which indicates authentication failure due to the user's
+ * credentials having expired.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AuthenticationFailureCredentialsExpiredEvent
+ extends AuthenticationEvent {
+ //~ Constructors ===========================================================
+
+ public AuthenticationFailureCredentialsExpiredEvent(
+ Authentication authentication, UserDetails user) {
+ super(authentication, user);
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/userdetails/User.java b/core/src/main/java/org/acegisecurity/userdetails/User.java
index 7e353b8204..bc1eb2e384 100644
--- a/core/src/main/java/org/acegisecurity/userdetails/User.java
+++ b/core/src/main/java/org/acegisecurity/userdetails/User.java
@@ -37,6 +37,8 @@ public class User implements UserDetails {
private String password;
private String username;
private GrantedAuthority[] authorities;
+ private boolean accountNonExpired;
+ private boolean credentialsNonExpired;
private boolean enabled;
//~ Constructors ===========================================================
@@ -57,8 +59,38 @@ public class User implements UserDetails {
* @throws IllegalArgumentException if a null value was passed
* either as a parameter or as an element in the
* GrantedAuthority[] array
+ *
+ * @deprecated use new constructor with extended properties (this
+ * constructor will be removed from release 1.0.0)
*/
public User(String username, String password, boolean enabled,
+ GrantedAuthority[] authorities) throws IllegalArgumentException {
+ this(username, password, enabled, true, true, authorities);
+ }
+
+ /**
+ * Construct the User with the details required by {@link
+ * DaoAuthenticationProvider}.
+ *
+ * @param username the username presented to the
+ * DaoAuthenticationProvider
+ * @param password the password that should be presented to the
+ * DaoAuthenticationProvider
+ * @param enabled set to true if the user is enabled
+ * @param accountNonExpired set to true if the account has not
+ * expired
+ * @param credentialsNonExpired set to true if the credentials
+ * have not expired
+ * @param authorities the authorities that should be granted to the caller
+ * if they presented the correct username and password and the user
+ * is enabled
+ *
+ * @throws IllegalArgumentException if a null value was passed
+ * either as a parameter or as an element in the
+ * GrantedAuthority[] array
+ */
+ public User(String username, String password, boolean enabled,
+ boolean accountNonExpired, boolean credentialsNonExpired,
GrantedAuthority[] authorities) throws IllegalArgumentException {
if (((username == null) || "".equals(username)) || (password == null)
|| "".equals(password) || (authorities == null)) {
@@ -78,6 +110,8 @@ public class User implements UserDetails {
this.password = password;
this.enabled = enabled;
this.authorities = authorities;
+ this.accountNonExpired = accountNonExpired;
+ this.credentialsNonExpired = credentialsNonExpired;
}
protected User() {
@@ -86,10 +120,18 @@ public class User implements UserDetails {
//~ Methods ================================================================
+ public boolean isAccountNonExpired() {
+ return accountNonExpired;
+ }
+
public GrantedAuthority[] getAuthorities() {
return authorities;
}
+ public boolean isCredentialsNonExpired() {
+ return credentialsNonExpired;
+ }
+
public boolean isEnabled() {
return enabled;
}
diff --git a/core/src/main/java/org/acegisecurity/userdetails/UserDetails.java b/core/src/main/java/org/acegisecurity/userdetails/UserDetails.java
index c3d1daa7e5..93bfe58929 100644
--- a/core/src/main/java/org/acegisecurity/userdetails/UserDetails.java
+++ b/core/src/main/java/org/acegisecurity/userdetails/UserDetails.java
@@ -43,6 +43,16 @@ import java.io.Serializable;
public interface UserDetails extends Serializable {
//~ Methods ================================================================
+ /**
+ * Indicates whether the user's account has expired. An expired account
+ * cannot be authenticated.
+ *
+ * @return true if the user's account is valid (ie
+ * non-expired), false if no longer valid (ie
+ * expired)
+ */
+ public boolean isAccountNonExpired();
+
/**
* Returns the authorities granted to the user. Cannot return
* null.
@@ -51,6 +61,16 @@ public interface UserDetails extends Serializable {
*/
public GrantedAuthority[] getAuthorities();
+ /**
+ * Indicates whether the user's credentials (password) has expired. Expired
+ * credentials prevent authentication.
+ *
+ * @return true if the user's credentials are valid (ie
+ * non-expired), false if no longer valid (ie
+ * expired)
+ */
+ public boolean isCredentialsNonExpired();
+
/**
* Indicates whether the user is enabled or disabled. A disabled user
* cannot be authenticated.
diff --git a/core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java b/core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java
index f435b63228..0dc668bbad 100644
--- a/core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java
+++ b/core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java
@@ -58,6 +58,13 @@ import javax.sql.DataSource;
* the {@link MappingSqlQuery} instances used, via the {@link
* #initMappingSqlQueries()} extension point.
*
+ * In order to minimise backward compatibility issues, this DAO does not + * recognise the expiration of user accounts or the expiration of user + * credentials. However, it does recognise and honour the user + * enabled/disabled column. + *
* * @author Ben Alex * @author colin sampaleanu @@ -185,14 +192,14 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao { arrayAuths = (GrantedAuthority[]) dbAuths.toArray(arrayAuths); return new User(user.getUsername(), user.getPassword(), - user.isEnabled(), arrayAuths); + user.isEnabled(), true, true, arrayAuths); } /** * Allows subclasses to add their own granted authorities to the list to be * returned in theUser.
*
- * @param username the username, for use by finder methods
+ * @param username the username, for use by finder methods
* @param authorities the current granted authorities, as populated from
* the authoritiesByUsername mapping
*/
@@ -248,7 +255,8 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
String username = rs.getString(1);
String password = rs.getString(2);
boolean enabled = rs.getBoolean(3);
- UserDetails user = new User(username, password, enabled,
+ UserDetails user = new User(username, password, enabled, true,
+ true,
new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
return user;
diff --git a/core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java b/core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java
index a9eb6341d1..cc402f9924 100644
--- a/core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java
+++ b/core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java
@@ -56,6 +56,12 @@ import java.util.Properties;
* If the above requirements are not met, the invalid entry will be silently
* ignored.
*
+ *
+ * + * This editor always assumes each entry has a non-expired account and + * non-expired credentials. However, it does honour the user enabled/disabled + * flag as described above. + *
* * @author Ben Alex * @version $Id$ @@ -91,7 +97,7 @@ public class UserMapEditor extends PropertyEditorSupport { // Make a user object, assuming the properties were properly provided if (attr != null) { UserDetails user = new User(username, attr.getPassword(), - attr.isEnabled(), attr.getAuthorities()); + attr.isEnabled(), true, true, attr.getAuthorities()); userMap.addUser(user); } } diff --git a/core/src/test/java/org/acegisecurity/acl/basic/GrantedAuthorityEffectiveAclsResolverTests.java b/core/src/test/java/org/acegisecurity/acl/basic/GrantedAuthorityEffectiveAclsResolverTests.java index deada7925e..5e856f0eb9 100644 --- a/core/src/test/java/org/acegisecurity/acl/basic/GrantedAuthorityEffectiveAclsResolverTests.java +++ b/core/src/test/java/org/acegisecurity/acl/basic/GrantedAuthorityEffectiveAclsResolverTests.java @@ -55,7 +55,7 @@ public class GrantedAuthorityEffectiveAclsResolverTests extends TestCase { .getPrincipal(), new NamedEntityObjectIdentity("OBJECT", "100"), null, 2); private UsernamePasswordAuthenticationToken scottWithUserDetails = new UsernamePasswordAuthenticationToken(new User( - "scott", "NOT_USED", true, + "scott", "NOT_USED", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl( "ROLE_EVERYBODY")}), "not used", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_EVERYBODY"), new GrantedAuthorityImpl("ROLE_TWO")}); 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 091af44471..3a3dcaa6e1 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.java @@ -327,7 +327,7 @@ public class CasAuthenticationProviderTests extends TestCase { } private UserDetails makeUserDetails() { - return new User("user", "password", true, + return new User("user", "password", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } @@ -337,7 +337,7 @@ public class CasAuthenticationProviderTests extends TestCase { private class MockAuthoritiesPopulator implements CasAuthoritiesPopulator { public UserDetails getUserDetails(String casUserId) throws AuthenticationException { - return new User("user", "password", true, + return new User("user", "password", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl( "ROLE_B")}); } diff --git a/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationTokenTests.java b/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationTokenTests.java index 38ac1f06df..f1af3dc848 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationTokenTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationTokenTests.java @@ -319,7 +319,7 @@ public class CasAuthenticationTokenTests extends TestCase { } private UserDetails makeUserDetails() { - return new User("user", "password", true, + return new User("user", "password", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } diff --git a/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java b/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java index 660ba7931a..57a797252e 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java @@ -102,7 +102,7 @@ public class EhCacheBasedTicketCacheTests extends TestCase { List proxyList = new Vector(); proxyList.add("https://localhost/newPortal/j_acegi_cas_security_check"); - User user = new User("marissa", "password", true, + User user = new User("marissa", "password", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); diff --git a/core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.java b/core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.java index e697984459..304e2397d1 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.java @@ -139,7 +139,7 @@ public class DaoCasAuthoritiesPopulatorTests extends TestCase { public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { if ("marissa".equals(username)) { - return new User("marissa", "koala", true, + return new User("marissa", "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } else { 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 5a624a89a1..3f818b2960 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java @@ -17,9 +17,11 @@ package net.sf.acegisecurity.providers.dao; import junit.framework.TestCase; +import net.sf.acegisecurity.AccountExpiredException; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.AuthenticationServiceException; import net.sf.acegisecurity.BadCredentialsException; +import net.sf.acegisecurity.CredentialsExpiredException; import net.sf.acegisecurity.DisabledException; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; @@ -73,6 +75,38 @@ public class DaoAuthenticationProviderTests extends TestCase { } } + public void testAuthenticateFailsIfAccountExpired() { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", + "opal"); + + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setAuthenticationDao(new MockAuthenticationDaoUserPeterAccountExpired()); + provider.setUserCache(new MockUserCache()); + + try { + provider.authenticate(token); + fail("Should have thrown AccountExpiredException"); + } catch (AccountExpiredException expected) { + assertTrue(true); + } + } + + public void testAuthenticateFailsIfCredentialsExpired() { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", + "opal"); + + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setAuthenticationDao(new MockAuthenticationDaoUserPeterCredentialsExpired()); + provider.setUserCache(new MockUserCache()); + + try { + provider.authenticate(token); + fail("Should have thrown CredentialsExpiredException"); + } catch (CredentialsExpiredException expected) { + assertTrue(true); + } + } + public void testAuthenticateFailsIfUserDisabled() { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal"); @@ -426,7 +460,7 @@ public class DaoAuthenticationProviderTests extends TestCase { public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { if ("marissa".equals(username)) { - return new User("marissa", password, true, + return new User("marissa", password, true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } else { @@ -442,6 +476,7 @@ public class DaoAuthenticationProviderTests extends TestCase { throws UsernameNotFoundException, DataAccessException { if ("marissa".equals(username)) { return new User("marissa", "koala{SYSTEM_SALT_VALUE}", true, + true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } else { @@ -455,7 +490,37 @@ public class DaoAuthenticationProviderTests extends TestCase { public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { if ("peter".equals(username)) { - return new User("peter", "opal", false, + return new User("peter", "opal", false, true, true, + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( + "ROLE_TWO")}); + } else { + throw new UsernameNotFoundException("Could not find: " + + username); + } + } + } + + private class MockAuthenticationDaoUserPeterAccountExpired + implements AuthenticationDao { + public UserDetails loadUserByUsername(String username) + throws UsernameNotFoundException, DataAccessException { + if ("peter".equals(username)) { + return new User("peter", "opal", true, false, true, + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( + "ROLE_TWO")}); + } else { + throw new UsernameNotFoundException("Could not find: " + + username); + } + } + } + + private class MockAuthenticationDaoUserPeterCredentialsExpired + implements AuthenticationDao { + public UserDetails loadUserByUsername(String username) + throws UsernameNotFoundException, DataAccessException { + if ("peter".equals(username)) { + return new User("peter", "opal", true, true, false, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } else { diff --git a/core/src/test/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProviderTests.java b/core/src/test/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProviderTests.java index 12521b00c3..18a71cca8b 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProviderTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProviderTests.java @@ -17,9 +17,11 @@ package net.sf.acegisecurity.providers.dao; import junit.framework.TestCase; +import net.sf.acegisecurity.AccountExpiredException; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.AuthenticationServiceException; import net.sf.acegisecurity.BadCredentialsException; +import net.sf.acegisecurity.CredentialsExpiredException; import net.sf.acegisecurity.DisabledException; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; @@ -68,6 +70,38 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase { } } + public void testAuthenticateFailsIfAccountExpired() { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", + "opal"); + + PasswordDaoAuthenticationProvider provider = new PasswordDaoAuthenticationProvider(); + provider.setPasswordAuthenticationDao(new MockAuthenticationDaoUserPeterAccountExpired()); + provider.setUserCache(new MockUserCache()); + + try { + provider.authenticate(token); + fail("Should have thrown AccountExpiredException"); + } catch (AccountExpiredException expected) { + assertTrue(true); + } + } + + public void testAuthenticateFailsIfCredentialsExpired() { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", + "opal"); + + PasswordDaoAuthenticationProvider provider = new PasswordDaoAuthenticationProvider(); + provider.setPasswordAuthenticationDao(new MockAuthenticationDaoUserPeterCredentialsExpired()); + provider.setUserCache(new MockUserCache()); + + try { + provider.authenticate(token); + fail("Should have thrown CredentialsExpiredException"); + } catch (CredentialsExpiredException expected) { + assertTrue(true); + } + } + public void testAuthenticateFailsIfUserDisabled() { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal"); @@ -290,7 +324,7 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase { String password) throws BadCredentialsException, DataAccessException { if ("marissa".equals(username) && "koala".equals(password)) { - return new User("marissa", "koala", true, + return new User("marissa", "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } else { @@ -305,7 +339,7 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase { String password) throws BadCredentialsException, DataAccessException { if ("peter".equals(username) && "opal".equals(password)) { - return new User("peter", "opal", false, + return new User("peter", "opal", false, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } else { @@ -314,6 +348,38 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase { } } + private class MockAuthenticationDaoUserPeterAccountExpired + implements PasswordAuthenticationDao { + public UserDetails loadUserByUsernameAndPassword(String username, + String password) + throws UsernameNotFoundException, DataAccessException { + if ("peter".equals(username)) { + return new User("peter", "opal", true, false, true, + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( + "ROLE_TWO")}); + } else { + throw new UsernameNotFoundException("Could not find: " + + username); + } + } + } + + private class MockAuthenticationDaoUserPeterCredentialsExpired + implements PasswordAuthenticationDao { + public UserDetails loadUserByUsernameAndPassword(String username, + String password) + throws UsernameNotFoundException, DataAccessException { + if ("peter".equals(username)) { + return new User("peter", "opal", true, true, false, + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( + "ROLE_TWO")}); + } else { + throw new UsernameNotFoundException("Could not find: " + + username); + } + } + } + private class MockUserCache implements UserCache { private Map cache = new HashMap(); diff --git a/core/src/test/java/org/acegisecurity/providers/dao/UserTests.java b/core/src/test/java/org/acegisecurity/providers/dao/UserTests.java index 881d6829d5..0a4744508e 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/UserTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/UserTests.java @@ -60,7 +60,7 @@ public class UserTests extends TestCase { public void testNullValuesRejected() throws Exception { try { - UserDetails user = new User(null, "koala", true, + UserDetails user = new User(null, "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); fail("Should have thrown IllegalArgumentException"); @@ -69,7 +69,7 @@ public class UserTests extends TestCase { } try { - UserDetails user = new User("marissa", null, true, + UserDetails user = new User("marissa", null, true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); fail("Should have thrown IllegalArgumentException"); @@ -78,14 +78,15 @@ public class UserTests extends TestCase { } try { - UserDetails user = new User("marissa", "koala", true, null); + UserDetails user = new User("marissa", "koala", true, true, true, + null); fail("Should have thrown IllegalArgumentException"); } catch (IllegalArgumentException expected) { assertTrue(true); } try { - UserDetails user = new User("marissa", "koala", true, + UserDetails user = new User("marissa", "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), null}); fail("Should have thrown IllegalArgumentException"); } catch (IllegalArgumentException expected) { @@ -96,7 +97,7 @@ public class UserTests extends TestCase { public void testNullWithinGrantedAuthorityElementIsRejected() throws Exception { try { - UserDetails user = new User(null, "koala", true, + UserDetails user = new User(null, "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO"), null, new GrantedAuthorityImpl( "ROLE_THREE")}); @@ -107,7 +108,7 @@ public class UserTests extends TestCase { } public void testUserGettersSetter() throws Exception { - UserDetails user = new User("marissa", "koala", true, + UserDetails user = new User("marissa", "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); assertEquals("marissa", user.getUsername()); @@ -120,7 +121,7 @@ public class UserTests extends TestCase { } public void testUserIsEnabled() throws Exception { - UserDetails user = new User("marissa", "koala", false, + UserDetails user = new User("marissa", "koala", false, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); assertTrue(!user.isEnabled()); diff --git a/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java b/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java index 80ffe11137..3367a9e1b0 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java @@ -95,7 +95,7 @@ public class EhCacheBasedUserCacheTests extends TestCase { } private User getUser() { - return new User("john", "password", true, + return new User("john", "password", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } diff --git a/core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.java b/core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.java index 9c5df76a05..920b31a35f 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.java @@ -57,7 +57,7 @@ public class NullUserCacheTests extends TestCase { } private User getUser() { - return new User("john", "password", true, + return new User("john", "password", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); } diff --git a/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java b/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java index e8963c76df..6cdc804226 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java @@ -97,7 +97,7 @@ public class AuthenticationEventTests extends TestCase { } private User getUser() { - User user = new User("foo", "bar", true, + User user = new User("foo", "bar", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_FOOBAR")}); return user; diff --git a/core/src/test/java/org/acegisecurity/providers/dao/event/LoggerListenerTests.java b/core/src/test/java/org/acegisecurity/providers/dao/event/LoggerListenerTests.java index 434e303637..323c180f29 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/event/LoggerListenerTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/event/LoggerListenerTests.java @@ -90,7 +90,7 @@ public class LoggerListenerTests extends TestCase { } private User getUser() { - User user = new User("foo", "bar", true, + User user = new User("foo", "bar", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_FOOBAR")}); return user; diff --git a/core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java b/core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java index 54039e15e0..06150601d5 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java @@ -52,13 +52,13 @@ public class UserMapTests extends TestCase { } public void testAddAndRetrieveUser() { - UserDetails marissa = new User("marissa", "koala", true, + UserDetails marissa = new User("marissa", "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); - UserDetails scott = new User("scott", "wombat", true, + UserDetails scott = new User("scott", "wombat", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_THREE")}); - UserDetails peter = new User("peter", "opal", true, + UserDetails peter = new User("peter", "opal", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_FOUR")}); UserMap map = new UserMap(); @@ -85,7 +85,7 @@ public class UserMapTests extends TestCase { } public void testUnknownUserIsNotRetrieved() { - UserDetails marissa = new User("marissa", "koala", true, + UserDetails marissa = new User("marissa", "koala", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( "ROLE_TWO")}); UserMap map = new UserMap(); diff --git a/core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.java b/core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.java index b646c93ac4..febd64af75 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.java @@ -67,7 +67,7 @@ public class ReflectionSaltSourceTests extends TestCase { ReflectionSaltSource saltSource = new ReflectionSaltSource(); saltSource.setUserPropertyToUse("getDoesNotExist"); - UserDetails user = new User("scott", "wombat", true, + UserDetails user = new User("scott", "wombat", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")}); try { @@ -89,7 +89,7 @@ public class ReflectionSaltSourceTests extends TestCase { saltSource.setUserPropertyToUse("getUsername"); saltSource.afterPropertiesSet(); - UserDetails user = new User("scott", "wombat", true, + UserDetails user = new User("scott", "wombat", true, true, true, new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")}); assertEquals("scott", saltSource.getSalt(user)); } diff --git a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java index 52f0efa428..717c667515 100644 --- a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java +++ b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java @@ -77,7 +77,7 @@ public class AuthenticationTagTests extends TestCase { public void testOperationWhenPrincipalIsAUserDetailsInstance() throws JspException { Authentication auth = new TestingAuthenticationToken(new User( - "marissaUserDetails", "koala", true, + "marissaUserDetails", "koala", true, true, true, new GrantedAuthority[] {}), "koala", new GrantedAuthority[] {}); SecureContext sc = new SecureContextImpl(); diff --git a/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapperTests.java b/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapperTests.java index 13aa9a8505..59b2011be8 100644 --- a/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapperTests.java +++ b/core/src/test/java/org/acegisecurity/ui/wrapper/ContextHolderAwareRequestWrapperTests.java @@ -78,7 +78,7 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase { throws Exception { SecureContext sc = new SecureContextImpl(); Authentication auth = new TestingAuthenticationToken(new User( - "marissaAsUserDetails", "koala", true, + "marissaAsUserDetails", "koala", true, true, true, new GrantedAuthority[] {}), "koala", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_HELLO"), new GrantedAuthorityImpl( "ROLE_FOOBAR")}); diff --git a/doc/docbook/index.xml b/doc/docbook/index.xml index f71c342fe5..01e516ac3a 100644 --- a/doc/docbook/index.xml +++ b/doc/docbook/index.xml @@ -1042,7 +1042,11 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { authentication is denied. An