Selaa lähdekoodia

UserDetails now indicates locked accounts.

Ben Alex 20 vuotta sitten
vanhempi
commit
6f31ecb04b
31 muutettua tiedostoa jossa 399 lisäystä ja 157 poistoa
  1. 13 1
      core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java
  2. 13 2
      core/src/main/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProvider.java
  3. 36 0
      core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureAccountLockedEvent.java
  4. 12 1
      core/src/main/java/org/acegisecurity/providers/dao/event/LoggerListener.java
  5. 40 0
      core/src/main/java/org/acegisecurity/userdetails/User.java
  6. 10 1
      core/src/main/java/org/acegisecurity/userdetails/UserDetails.java
  7. 3 3
      core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java
  8. 2 1
      core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java
  9. 2 2
      core/src/test/java/org/acegisecurity/acl/basic/GrantedAuthorityEffectiveAclsResolverTests.java
  10. 36 29
      core/src/test/java/org/acegisecurity/providers/ConcurrentSessionControllerImplTests.java
  11. 3 3
      core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.java
  12. 2 2
      core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationTokenTests.java
  13. 2 2
      core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java
  14. 2 2
      core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.java
  15. 48 6
      core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java
  16. 48 5
      core/src/test/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProviderTests.java
  17. 8 5
      core/src/test/java/org/acegisecurity/providers/dao/UserTests.java
  18. 2 2
      core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java
  19. 2 2
      core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.java
  20. 2 2
      core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java
  21. 2 2
      core/src/test/java/org/acegisecurity/providers/dao/event/LoggerListenerTests.java
  22. 5 3
      core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java
  23. 3 3
      core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.java
  24. 36 31
      core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationProviderTests.java
  25. 6 6
      core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationTokenTests.java
  26. 48 36
      core/src/test/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulatorTests.java
  27. 1 1
      core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java
  28. 7 0
      core/src/test/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServicesTests.java
  29. 1 1
      core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapperTests.java
  30. 3 2
      doc/xdocs/changes.xml
  31. 1 1
      sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/LdapPasswordAuthenticationDao.java

+ 13 - 1
core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java

@@ -23,11 +23,13 @@ import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.CredentialsExpiredException;
 import net.sf.acegisecurity.DisabledException;
 import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.LockedException;
 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.AuthenticationFailureAccountLockedEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureCredentialsExpiredEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureDisabledEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailurePasswordEvent;
@@ -232,7 +234,8 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
                             authentication,
                             new User("".equals(username)
                                 ? "EMPTY_STRING_PROVIDED" : username, "*****",
-                                false, false, false, new GrantedAuthority[0])));
+                                false, false, false, false,
+                                new GrantedAuthority[0])));
                 }
 
                 throw ex;
@@ -257,6 +260,15 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
             throw new AccountExpiredException("User account has expired");
         }
 
+        if (!user.isAccountNonLocked()) {
+            if (this.context != null) {
+                context.publishEvent(new AuthenticationFailureAccountLockedEvent(
+                        authentication, user));
+            }
+
+            throw new LockedException("User account is locked");
+        }
+
         if (!user.isCredentialsNonExpired()) {
             if (this.context != null) {
                 context.publishEvent(new AuthenticationFailureCredentialsExpiredEvent(

+ 13 - 2
core/src/main/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProvider.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.
@@ -23,11 +23,13 @@ import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.CredentialsExpiredException;
 import net.sf.acegisecurity.DisabledException;
 import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.LockedException;
 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.AuthenticationFailureAccountLockedEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureCredentialsExpiredEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureDisabledEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureUsernameOrPasswordEvent;
@@ -184,7 +186,7 @@ public class PasswordDaoAuthenticationProvider implements AuthenticationProvider
                     context.publishEvent(new AuthenticationFailureUsernameOrPasswordEvent(
                             authentication,
                             new User(username, "*****", false, false, false,
-                                new GrantedAuthority[0])));
+                                false, new GrantedAuthority[0])));
                 }
 
                 throw ex;
@@ -209,6 +211,15 @@ public class PasswordDaoAuthenticationProvider implements AuthenticationProvider
             throw new AccountExpiredException("User account has expired");
         }
 
+        if (!user.isAccountNonLocked()) {
+            if (this.context != null) {
+                context.publishEvent(new AuthenticationFailureAccountLockedEvent(
+                        authentication, user));
+            }
+
+            throw new LockedException("User account is locked");
+        }
+
         if (!user.isCredentialsNonExpired()) {
             if (this.context != null) {
                 context.publishEvent(new AuthenticationFailureCredentialsExpiredEvent(

+ 36 - 0
core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureAccountLockedEvent.java

@@ -0,0 +1,36 @@
+/* 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.
+ * 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 been locked.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AuthenticationFailureAccountLockedEvent extends AuthenticationEvent {
+    //~ Constructors ===========================================================
+
+    public AuthenticationFailureAccountLockedEvent(
+        Authentication authentication, UserDetails user) {
+        super(authentication, user);
+    }
+}

+ 12 - 1
core/src/main/java/org/acegisecurity/providers/dao/event/LoggerListener.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.
@@ -63,6 +63,17 @@ public class LoggerListener implements ApplicationListener {
             }
         }
 
+        if (event instanceof AuthenticationFailureAccountLockedEvent) {
+            AuthenticationFailureAccountLockedEvent authEvent = (AuthenticationFailureAccountLockedEvent) event;
+
+            if (logger.isWarnEnabled()) {
+                logger.warn(
+                    "Authentication failed due to account being locked for user: "
+                    + authEvent.getUser().getUsername() + "; details: "
+                    + authEvent.getAuthentication().getDetails());
+            }
+        }
+
         if (event instanceof AuthenticationFailureCredentialsExpiredEvent) {
             AuthenticationFailureCredentialsExpiredEvent authEvent = (AuthenticationFailureCredentialsExpiredEvent) event;
 

+ 40 - 0
core/src/main/java/org/acegisecurity/userdetails/User.java

@@ -38,6 +38,7 @@ public class User implements UserDetails {
     private String username;
     private GrantedAuthority[] authorities;
     private boolean accountNonExpired;
+    private boolean accountNonLocked;
     private boolean credentialsNonExpired;
     private boolean enabled;
 
@@ -88,10 +89,44 @@ public class User implements UserDetails {
      * @throws IllegalArgumentException if a <code>null</code> value was passed
      *         either as a parameter or as an element in the
      *         <code>GrantedAuthority[]</code> 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,
         boolean accountNonExpired, boolean credentialsNonExpired,
         GrantedAuthority[] authorities) throws IllegalArgumentException {
+        this(username, password, enabled, accountNonExpired,
+            credentialsNonExpired, true, authorities);
+    }
+
+    /**
+     * Construct the <code>User</code> with the details required by {@link
+     * DaoAuthenticationProvider}.
+     *
+     * @param username the username presented to the
+     *        <code>DaoAuthenticationProvider</code>
+     * @param password the password that should be presented to the
+     *        <code>DaoAuthenticationProvider</code>
+     * @param enabled set to <code>true</code> if the user is enabled
+     * @param accountNonExpired set to <code>true</code> if the account has not
+     *        expired
+     * @param credentialsNonExpired set to <code>true</code> if the credentials
+     *        have not expired
+     * @param accountNonLocked set to <code>true</code> if the account is not
+     *        locked
+     * @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 <code>null</code> value was passed
+     *         either as a parameter or as an element in the
+     *         <code>GrantedAuthority[]</code> array
+     */
+    public User(String username, String password, boolean enabled,
+        boolean accountNonExpired, boolean credentialsNonExpired,
+        boolean accountNonLocked, GrantedAuthority[] authorities)
+        throws IllegalArgumentException {
         if (((username == null) || "".equals(username)) || (password == null)
             || (authorities == null)) {
             throw new IllegalArgumentException(
@@ -112,6 +147,7 @@ public class User implements UserDetails {
         this.authorities = authorities;
         this.accountNonExpired = accountNonExpired;
         this.credentialsNonExpired = credentialsNonExpired;
+        this.accountNonLocked = accountNonLocked;
     }
 
     protected User() {
@@ -124,6 +160,10 @@ public class User implements UserDetails {
         return accountNonExpired;
     }
 
+    public boolean isAccountNonLocked() {
+        return this.accountNonLocked;
+    }
+
     public GrantedAuthority[] getAuthorities() {
         return authorities;
     }

+ 10 - 1
core/src/main/java/org/acegisecurity/userdetails/UserDetails.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.
@@ -53,6 +53,15 @@ public interface UserDetails extends Serializable {
      */
     public boolean isAccountNonExpired();
 
+    /**
+     * Indicates whether the user is locked or unlocked. A locked user cannot
+     * be authenticated.
+     *
+     * @return <code>true</code> if the user is not locked, <code>false</code>
+     *         otherwise
+     */
+    public boolean isAccountNonLocked();
+
     /**
      * Returns the authorities granted to the user. Cannot return
      * <code>null</code>.

+ 3 - 3
core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.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.
@@ -192,7 +192,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
         arrayAuths = (GrantedAuthority[]) dbAuths.toArray(arrayAuths);
 
         return new User(user.getUsername(), user.getPassword(),
-            user.isEnabled(), true, true, arrayAuths);
+            user.isEnabled(), true, true, true, arrayAuths);
     }
 
     /**
@@ -256,7 +256,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
             String password = rs.getString(2);
             boolean enabled = rs.getBoolean(3);
             UserDetails user = new User(username, password, enabled, true,
-                    true,
+                    true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
 
             return user;

+ 2 - 1
core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java

@@ -96,7 +96,8 @@ 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(), true, true, attr.getAuthorities());
+                            attr.isEnabled(), true, true, true,
+                            attr.getAuthorities());
                     userMap.addUser(user);
                 }
             }

+ 2 - 2
core/src/test/java/org/acegisecurity/acl/basic/GrantedAuthorityEffectiveAclsResolverTests.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.
@@ -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, true, true,
+                "scott", "NOT_USED", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl(
                         "ROLE_EVERYBODY")}), "not used",
             new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_EVERYBODY"), new GrantedAuthorityImpl("ROLE_TWO")});

+ 36 - 29
core/src/test/java/org/acegisecurity/providers/ConcurrentSessionControllerImplTests.java

@@ -16,12 +16,14 @@
 package net.sf.acegisecurity.providers;
 
 import junit.framework.TestCase;
+
 import net.sf.acegisecurity.*;
 import net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.ui.WebAuthenticationDetails;
 import net.sf.acegisecurity.ui.session.HttpSessionCreatedEvent;
 import net.sf.acegisecurity.ui.session.HttpSessionDestroyedEvent;
+
 import org.springframework.context.ApplicationListener;
 
 import java.security.Principal;
@@ -39,8 +41,17 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
 
     //~ Methods ================================================================
 
+    public void testAnonymous() throws Exception {
+        AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken("blah",
+                "anon",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ANON")});
+        target.beforeAuthentication(auth);
+        target.afterAuthentication(auth, auth);
+    }
+
     public void testBumpCoverage() throws Exception {
-        target.onApplicationEvent(new HttpSessionCreatedEvent(new MockHttpSession()));
+        target.onApplicationEvent(new HttpSessionCreatedEvent(
+                new MockHttpSession()));
     }
 
     public void testEnforcementKnownGood() throws Exception {
@@ -63,7 +74,8 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
         try {
             auth = createAuthentication("user", "password", "lastsession");
             target.beforeAuthentication(auth);
-            fail("Only allowed 5 sessions, this should have thrown a ConcurrentLoginException");
+            fail(
+                "Only allowed 5 sessions, this should have thrown a ConcurrentLoginException");
         } catch (ConcurrentLoginException e) {
             assertTrue(e.getMessage().startsWith(auth.getPrincipal().toString()));
         }
@@ -81,9 +93,9 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
         try {
             target.beforeAuthentication(createAuthentication("user",
                     "password", "session2"));
-            fail("Only allowed 1 session, this should have thrown a ConcurrentLoginException");
-        } catch (ConcurrentLoginException e) {
-        }
+            fail(
+                "Only allowed 1 session, this should have thrown a ConcurrentLoginException");
+        } catch (ConcurrentLoginException e) {}
     }
 
     public void testEnforcementUnlimitedSameSession() throws Exception {
@@ -129,6 +141,11 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
         target.afterAuthentication(different, different);
     }
 
+    public void testImplementsApplicationListener() throws Exception {
+        assertTrue("This class must implement ApplicationListener, and at one point it didn't.",
+            target instanceof ApplicationListener);
+    }
+
     public void testNonWebDetails() throws Exception {
         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("asdf",
                 "asdf");
@@ -141,7 +158,7 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
         target.setMaxSessions(1);
 
         final UserDetails user = new User("user", "password", true, true, true,
-                new GrantedAuthority[0]);
+                true, new GrantedAuthority[0]);
         final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
                 "password", user.getAuthorities());
         auth.setDetails(createWebDetails(auth, "session1"));
@@ -151,20 +168,20 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
 
         try {
             UsernamePasswordAuthenticationToken otherAuth = new UsernamePasswordAuthenticationToken(new Principal() {
-                public String getName() {
-                    return "user";
-                }
+                        public String getName() {
+                            return "user";
+                        }
 
-                public String toString() {
-                    return getName();
-                }
-            }, "password");
+                        public String toString() {
+                            return getName();
+                        }
+                    }, "password");
 
             otherAuth.setDetails(createWebDetails(otherAuth, "session2"));
             target.beforeAuthentication(otherAuth);
-            fail("Same principal, different principal type, different session should have thrown ConcurrentLoginException");
-        } catch (ConcurrentLoginException e) {
-        }
+            fail(
+                "Same principal, different principal type, different session should have thrown ConcurrentLoginException");
+        } catch (ConcurrentLoginException e) {}
     }
 
     public void testSetMax() throws Exception {
@@ -177,7 +194,7 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
 
     public void testSetTrustManager() throws Exception {
         assertNotNull("There is supposed to be a default AuthenticationTrustResolver",
-                target.getTrustResolver());
+            target.getTrustResolver());
 
         AuthenticationTrustResolverImpl impl = new AuthenticationTrustResolverImpl();
         target.setTrustResolver(impl);
@@ -220,7 +237,7 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
     }
 
     private Authentication createAuthentication(String user, String password,
-                                                String sessionId) {
+        String sessionId) {
         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user,
                 password);
         auth.setDetails(createWebDetails(auth, sessionId));
@@ -229,21 +246,11 @@ public class ConcurrentSessionControllerImplTests extends TestCase {
     }
 
     private WebAuthenticationDetails createWebDetails(Authentication auth,
-                                                      String sessionId) {
+        String sessionId) {
         MockHttpSession session = new MockHttpSession(sessionId);
         MockHttpServletRequest request = new MockHttpServletRequest(auth,
                 session);
 
         return new WebAuthenticationDetails(request);
     }
-
-    public void testAnonymous() throws Exception {
-        AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken("blah", "anon", new GrantedAuthority[]{new GrantedAuthorityImpl("ROLE_ANON")});
-        target.beforeAuthentication(auth);
-        target.afterAuthentication(auth, auth);
-    }
-
-    public void testImplementsApplicationListener() throws Exception {
-        assertTrue("This class must implement ApplicationListener, and at one point it didn't.", target instanceof ApplicationListener);
-    }
 }

+ 3 - 3
core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationProviderTests.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.
@@ -327,7 +327,7 @@ public class CasAuthenticationProviderTests extends TestCase {
     }
 
     private UserDetails makeUserDetails() {
-        return new User("user", "password", true, true, true,
+        return new User("user", "password", true, 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, true, true,
+            return new User("user", "password", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl(
                         "ROLE_B")});
         }

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/cas/CasAuthenticationTokenTests.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.
@@ -319,7 +319,7 @@ public class CasAuthenticationTokenTests extends TestCase {
     }
 
     private UserDetails makeUserDetails() {
-        return new User("user", "password", true, true, true,
+        return new User("user", "password", true, true, true, true,
             new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                     "ROLE_TWO")});
     }

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.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.
@@ -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, true, true,
+        User user = new User("marissa", "password", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
 

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.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.
@@ -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, true, true,
+                return new User("marissa", "koala", true, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {

+ 48 - 6
core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.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.
@@ -25,6 +25,7 @@ import net.sf.acegisecurity.CredentialsExpiredException;
 import net.sf.acegisecurity.DisabledException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.LockedException;
 import net.sf.acegisecurity.UserDetails;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
@@ -103,6 +104,32 @@ public class DaoAuthenticationProviderTests extends TestCase {
         }
     }
 
+    public void testAuthenticateFailsIfAccountLocked() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter",
+                "opal");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserPeterAccountLocked());
+        provider.setUserCache(new MockUserCache());
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown LockedException");
+        } catch (LockedException expected) {
+            assertTrue(true);
+        }
+
+        provider.setApplicationContext(new ClassPathXmlApplicationContext(
+                "net/sf/acegisecurity/util/filtertest-valid.xml"));
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown CredentialsExpiredException");
+        } catch (LockedException expected) {
+            assertTrue(true);
+        }
+    }
+
     public void testAuthenticateFailsIfCredentialsExpired() {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter",
                 "opal");
@@ -492,7 +519,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
         public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             if ("marissa".equals(username)) {
-                return new User("marissa", password, true, true, true,
+                return new User("marissa", password, true, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {
@@ -508,7 +535,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
             throws UsernameNotFoundException, DataAccessException {
             if ("marissa".equals(username)) {
                 return new User("marissa", "koala{SYSTEM_SALT_VALUE}", true,
-                    true, true,
+                    true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {
@@ -522,7 +549,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
         public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             if ("peter".equals(username)) {
-                return new User("peter", "opal", false, true, true,
+                return new User("peter", "opal", false, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {
@@ -537,7 +564,22 @@ public class DaoAuthenticationProviderTests extends TestCase {
         public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             if ("peter".equals(username)) {
-                return new User("peter", "opal", true, false, true,
+                return new User("peter", "opal", true, false, true, true,
+                    new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                            "ROLE_TWO")});
+            } else {
+                throw new UsernameNotFoundException("Could not find: "
+                    + username);
+            }
+        }
+    }
+
+    private class MockAuthenticationDaoUserPeterAccountLocked
+        implements AuthenticationDao {
+        public UserDetails loadUserByUsername(String username)
+            throws UsernameNotFoundException, DataAccessException {
+            if ("peter".equals(username)) {
+                return new User("peter", "opal", true, true, true, false,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {
@@ -552,7 +594,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
         public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             if ("peter".equals(username)) {
-                return new User("peter", "opal", true, true, false,
+                return new User("peter", "opal", true, true, false, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {

+ 48 - 5
core/src/test/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProviderTests.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.
@@ -25,6 +25,7 @@ import net.sf.acegisecurity.CredentialsExpiredException;
 import net.sf.acegisecurity.DisabledException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.LockedException;
 import net.sf.acegisecurity.UserDetails;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
@@ -98,6 +99,32 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase {
         }
     }
 
+    public void testAuthenticateFailsIfAccountLocked() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter",
+                "opal");
+
+        PasswordDaoAuthenticationProvider provider = new PasswordDaoAuthenticationProvider();
+        provider.setPasswordAuthenticationDao(new MockAuthenticationDaoUserPeterAccountLocked());
+        provider.setUserCache(new MockUserCache());
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown AccountExpiredException");
+        } catch (LockedException expected) {
+            assertTrue(true);
+        }
+
+        provider.setApplicationContext(new ClassPathXmlApplicationContext(
+                "net/sf/acegisecurity/util/filtertest-valid.xml"));
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown AccountExpiredException");
+        } catch (LockedException expected) {
+            assertTrue(true);
+        }
+    }
+
     public void testAuthenticateFailsIfCredentialsExpired() {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter",
                 "opal");
@@ -346,7 +373,7 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase {
             String password)
             throws BadCredentialsException, DataAccessException {
             if ("marissa".equals(username) && "koala".equals(password)) {
-                return new User("marissa", "koala", true, true, true,
+                return new User("marissa", "koala", true, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {
@@ -361,7 +388,7 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase {
             String password)
             throws BadCredentialsException, DataAccessException {
             if ("peter".equals(username) && "opal".equals(password)) {
-                return new User("peter", "opal", false, true, true,
+                return new User("peter", "opal", false, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {
@@ -376,7 +403,23 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase {
             String password)
             throws UsernameNotFoundException, DataAccessException {
             if ("peter".equals(username)) {
-                return new User("peter", "opal", true, false, true,
+                return new User("peter", "opal", true, false, true, true,
+                    new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                            "ROLE_TWO")});
+            } else {
+                throw new UsernameNotFoundException("Could not find: "
+                    + username);
+            }
+        }
+    }
+
+    private class MockAuthenticationDaoUserPeterAccountLocked
+        implements PasswordAuthenticationDao {
+        public UserDetails loadUserByUsernameAndPassword(String username,
+            String password)
+            throws UsernameNotFoundException, DataAccessException {
+            if ("peter".equals(username)) {
+                return new User("peter", "opal", true, true, true, false,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {
@@ -392,7 +435,7 @@ public class PasswordDaoAuthenticationProviderTests extends TestCase {
             String password)
             throws UsernameNotFoundException, DataAccessException {
             if ("peter".equals(username)) {
-                return new User("peter", "opal", true, true, false,
+                return new User("peter", "opal", true, true, false, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             } else {

+ 8 - 5
core/src/test/java/org/acegisecurity/providers/dao/UserTests.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.
@@ -60,7 +60,7 @@ public class UserTests extends TestCase {
 
     public void testNullValuesRejected() throws Exception {
         try {
-            UserDetails user = new User(null, "koala", true, true, true,
+            UserDetails user = new User(null, "koala", true, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             fail("Should have thrown IllegalArgumentException");
@@ -70,6 +70,7 @@ public class UserTests extends TestCase {
 
         try {
             UserDetails user = new User("marissa", null, true, true, true,
+                    true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
             fail("Should have thrown IllegalArgumentException");
@@ -79,7 +80,7 @@ public class UserTests extends TestCase {
 
         try {
             UserDetails user = new User("marissa", "koala", true, true, true,
-                    null);
+                    true, null);
             fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
             assertTrue(true);
@@ -87,6 +88,7 @@ public class UserTests extends TestCase {
 
         try {
             UserDetails user = new User("marissa", "koala", true, true, true,
+                    true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), null});
             fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
@@ -97,7 +99,7 @@ public class UserTests extends TestCase {
     public void testNullWithinGrantedAuthorityElementIsRejected()
         throws Exception {
         try {
-            UserDetails user = new User(null, "koala", true, true, true,
+            UserDetails user = new User(null, "koala", true, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO"), null, new GrantedAuthorityImpl(
                             "ROLE_THREE")});
@@ -108,7 +110,7 @@ public class UserTests extends TestCase {
     }
 
     public void testUserGettersSetter() throws Exception {
-        UserDetails user = new User("marissa", "koala", true, true, true,
+        UserDetails user = new User("marissa", "koala", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
         assertEquals("marissa", user.getUsername());
@@ -122,6 +124,7 @@ public class UserTests extends TestCase {
 
     public void testUserIsEnabled() throws Exception {
         UserDetails user = new User("marissa", "koala", false, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
         assertTrue(!user.isEnabled());

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.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.
@@ -95,7 +95,7 @@ public class EhCacheBasedUserCacheTests extends TestCase {
     }
 
     private User getUser() {
-        return new User("john", "password", true, true, true,
+        return new User("john", "password", true, true, true, true,
             new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                     "ROLE_TWO")});
     }

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.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.
@@ -57,7 +57,7 @@ public class NullUserCacheTests extends TestCase {
     }
 
     private User getUser() {
-        return new User("john", "password", true, true, true,
+        return new User("john", "password", true, true, true, true,
             new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                     "ROLE_TWO")});
     }

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.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.
@@ -97,7 +97,7 @@ public class AuthenticationEventTests extends TestCase {
     }
 
     private User getUser() {
-        User user = new User("foo", "bar", true, true, true,
+        User user = new User("foo", "bar", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_FOOBAR")});
 
         return user;

+ 2 - 2
core/src/test/java/org/acegisecurity/providers/dao/event/LoggerListenerTests.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.
@@ -90,7 +90,7 @@ public class LoggerListenerTests extends TestCase {
     }
 
     private User getUser() {
-        User user = new User("foo", "bar", true, true, true,
+        User user = new User("foo", "bar", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_FOOBAR")});
 
         return user;

+ 5 - 3
core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.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.
@@ -53,12 +53,13 @@ public class UserMapTests extends TestCase {
 
     public void testAddAndRetrieveUser() {
         UserDetails marissa = new User("marissa", "koala", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
-        UserDetails scott = new User("scott", "wombat", true, true, true,
+        UserDetails scott = new User("scott", "wombat", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_THREE")});
-        UserDetails peter = new User("peter", "opal", true, true, true,
+        UserDetails peter = new User("peter", "opal", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_FOUR")});
         UserMap map = new UserMap();
@@ -86,6 +87,7 @@ public class UserMapTests extends TestCase {
 
     public void testUnknownUserIsNotRetrieved() {
         UserDetails marissa = new User("marissa", "koala", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
         UserMap map = new UserMap();

+ 3 - 3
core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.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.
@@ -67,7 +67,7 @@ public class ReflectionSaltSourceTests extends TestCase {
         ReflectionSaltSource saltSource = new ReflectionSaltSource();
         saltSource.setUserPropertyToUse("getDoesNotExist");
 
-        UserDetails user = new User("scott", "wombat", true, true, true,
+        UserDetails user = new User("scott", "wombat", true, 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, true, true,
+        UserDetails user = new User("scott", "wombat", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
         assertEquals("scott", saltSource.getSalt(user));
     }

+ 36 - 31
core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationProviderTests.java

@@ -16,12 +16,14 @@
 package net.sf.acegisecurity.providers.x509;
 
 import junit.framework.TestCase;
+
 import net.sf.acegisecurity.*;
-import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+import net.sf.acegisecurity.providers.dao.User;
 
 import java.security.cert.X509Certificate;
 
+
 /**
  * Tests {@link net.sf.acegisecurity.providers.x509.X509AuthenticationProvider}
  *
@@ -45,17 +47,28 @@ public class X509AuthenticationProviderTests extends TestCase {
         super.setUp();
     }
 
-    public void testRequiresPopulator() throws Exception {
+    public void testAuthenticationIsNullWithUnsupportedToken() {
+        X509AuthenticationProvider provider = new X509AuthenticationProvider();
+        Authentication request = new UsernamePasswordAuthenticationToken("dummy",
+                "dummy");
+        Authentication result = provider.authenticate(request);
+        assertNull(result);
+    }
+
+    public void testFailsWithNullCertificate() {
         X509AuthenticationProvider provider = new X509AuthenticationProvider();
+
+        provider.setX509AuthoritiesPopulator(new MockAuthoritiesPopulator(false));
+
         try {
-            provider.afterPropertiesSet();
-            fail("Should have thrown IllegalArgumentException");
-        } catch (IllegalArgumentException failed) {
-            //ignored
+            provider.authenticate(new X509AuthenticationToken(null));
+            fail("Should have thrown BadCredentialsException");
+        } catch (BadCredentialsException e) {
+            //ignore
         }
     }
 
-    public void testNormalOperation () throws Exception {
+    public void testNormalOperation() throws Exception {
         X509AuthenticationProvider provider = new X509AuthenticationProvider();
 
         provider.setX509AuthoritiesPopulator(new MockAuthoritiesPopulator(false));
@@ -67,56 +80,48 @@ public class X509AuthenticationProviderTests extends TestCase {
         assertNotNull(result.getAuthorities());
     }
 
-    public void testFailsWithNullCertificate() {
-        X509AuthenticationProvider provider = new X509AuthenticationProvider();
-
-        provider.setX509AuthoritiesPopulator(new MockAuthoritiesPopulator(false));
-        try {
-            provider.authenticate(new X509AuthenticationToken(null));
-            fail("Should have thrown BadCredentialsException");
-        } catch(BadCredentialsException e) {
-            //ignore
-        }
-    }
-
     public void testPopulatorRejectionCausesFailure() throws Exception {
         X509AuthenticationProvider provider = new X509AuthenticationProvider();
         provider.setX509AuthoritiesPopulator(new MockAuthoritiesPopulator(true));
+
         try {
             provider.authenticate(X509TestUtils.createToken());
             fail("Should have thrown BadCredentialsException");
-        } catch(BadCredentialsException e) {
+        } catch (BadCredentialsException e) {
             //ignore
         }
     }
 
-    public void testAuthenticationIsNullWithUnsupportedToken() {
+    public void testRequiresPopulator() throws Exception {
         X509AuthenticationProvider provider = new X509AuthenticationProvider();
-        Authentication request = new UsernamePasswordAuthenticationToken("dummy","dummy");
-        Authentication result = provider.authenticate(request);
-        assertNull(result);
+
+        try {
+            provider.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException failed) {
+            //ignored
+        }
     }
 
     //~ Inner Classes ==========================================================
 
-    public static class MockAuthoritiesPopulator implements X509AuthoritiesPopulator {
+    public static class MockAuthoritiesPopulator
+        implements X509AuthoritiesPopulator {
         private boolean rejectCertificate;
 
         public MockAuthoritiesPopulator(boolean rejectCertificate) {
             this.rejectCertificate = rejectCertificate;
         }
 
-        public UserDetails getUserDetails(X509Certificate userCertificate) throws AuthenticationException {
-            if(rejectCertificate) {
+        public UserDetails getUserDetails(X509Certificate userCertificate)
+            throws AuthenticationException {
+            if (rejectCertificate) {
                 throw new BadCredentialsException("Invalid Certificate");
             }
 
-            return new User ("user", "password", true, true, true,
+            return new User("user", "password", true, true, true, true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl(
                         "ROLE_B")});
         }
     }
-
-
-
 }

+ 6 - 6
core/src/test/java/org/acegisecurity/providers/x509/X509AuthenticationTokenTests.java

@@ -17,22 +17,23 @@ package net.sf.acegisecurity.providers.x509;
 
 import junit.framework.TestCase;
 
-import java.security.cert.X509Certificate;
-import java.security.cert.CertificateFactory;
-import java.io.ByteArrayInputStream;
 
 /**
+ * DOCUMENT ME!
+ *
  * @author Luke Taylor
  */
 public class X509AuthenticationTokenTests extends TestCase {
+    //~ Constructors ===========================================================
 
-    public X509AuthenticationTokenTests() {
-    }
+    public X509AuthenticationTokenTests() {}
 
     public X509AuthenticationTokenTests(String s) {
         super(s);
     }
 
+    //~ Methods ================================================================
+
     public void setUp() throws Exception {
         super.setUp();
     }
@@ -44,4 +45,3 @@ public class X509AuthenticationTokenTests extends TestCase {
         assertTrue(token.isAuthenticated());
     }
 }
-

+ 48 - 36
core/src/test/java/org/acegisecurity/providers/x509/populator/DaoX509AuthoritiesPopulatorTests.java

@@ -16,19 +16,24 @@
 package net.sf.acegisecurity.providers.x509.populator;
 
 import junit.framework.TestCase;
+
+import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.UserDetails;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
-import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.x509.X509TestUtils;
-import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.GrantedAuthority;
-import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.BadCredentialsException;
+
 import org.springframework.dao.DataAccessException;
 
 import java.security.cert.X509Certificate;
 
+
 /**
+ * DOCUMENT ME!
+ *
  * @author Luke Taylor
  */
 public class DaoX509AuthoritiesPopulatorTests extends TestCase {
@@ -48,45 +53,52 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase {
         super.setUp();
     }
 
-    public void testRequiresDao() throws Exception {
+    public void testDefaultCNPatternMatch() throws Exception {
+        X509Certificate cert = X509TestUtils.buildTestCertificate();
         DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator();
-        try {
-            populator.afterPropertiesSet();
-            fail("Should have thrown IllegalArgumentException");
-        } catch(IllegalArgumentException failed) {
-            // ignored
-        }
+
+        populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail());
+        populator.afterPropertiesSet();
+        populator.getUserDetails(cert);
+    }
+
+    public void testEmailPatternMatch() throws Exception {
+        X509Certificate cert = X509TestUtils.buildTestCertificate();
+        DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator();
+
+        populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail());
+        populator.setSubjectDNRegex("emailAddress=(.*?),");
+        populator.afterPropertiesSet();
+        populator.getUserDetails(cert);
     }
 
     public void testInvalidRegexFails() throws Exception {
         DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator();
         populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail());
         populator.setSubjectDNRegex("CN=(.*?,"); // missing closing bracket on group
+
         try {
             populator.afterPropertiesSet();
             fail("Should have thrown IllegalArgumentException");
-        } catch(IllegalArgumentException failed) {
+        } catch (IllegalArgumentException failed) {
             // ignored
         }
     }
 
-    public void testDefaultCNPatternMatch() throws Exception{
+    public void testMatchOnShoeSizeFieldInDNFails() throws Exception {
         X509Certificate cert = X509TestUtils.buildTestCertificate();
         DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator();
 
         populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail());
+        populator.setSubjectDNRegex("shoeSize=(.*?),");
         populator.afterPropertiesSet();
-        populator.getUserDetails(cert);
-    }
-
-    public void testEmailPatternMatch() throws Exception{
-        X509Certificate cert = X509TestUtils.buildTestCertificate();
-        DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator();
 
-        populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail());
-        populator.setSubjectDNRegex("emailAddress=(.*?),");
-        populator.afterPropertiesSet();
-        populator.getUserDetails(cert);
+        try {
+            populator.getUserDetails(cert);
+            fail("Should have thrown BadCredentialsException.");
+        } catch (BadCredentialsException failed) {
+            // ignored
+        }
     }
 
     public void testPatternWithNoGroupFails() throws Exception {
@@ -96,36 +108,36 @@ public class DaoX509AuthoritiesPopulatorTests extends TestCase {
         populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail());
         populator.setSubjectDNRegex("CN=.*?,");
         populator.afterPropertiesSet();
+
         try {
             populator.getUserDetails(cert);
-            fail("Should have thrown IllegalArgumentException for regexp without group");
+            fail(
+                "Should have thrown IllegalArgumentException for regexp without group");
         } catch (IllegalArgumentException e) {
             // ignored
         }
     }
 
-    public void testMatchOnShoeSizeFieldInDNFails() throws Exception {
-        X509Certificate cert = X509TestUtils.buildTestCertificate();
+    public void testRequiresDao() throws Exception {
         DaoX509AuthoritiesPopulator populator = new DaoX509AuthoritiesPopulator();
 
-        populator.setAuthenticationDao(new MockAuthenticationDaoMatchesNameOrEmail());
-        populator.setSubjectDNRegex("shoeSize=(.*?),");
-        populator.afterPropertiesSet();
         try {
-            populator.getUserDetails(cert);
-            fail("Should have thrown BadCredentialsException.");
-        } catch (BadCredentialsException failed) {
+            populator.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException failed) {
             // ignored
         }
     }
 
     //~ Inner Classes ==========================================================
-    private class MockAuthenticationDaoMatchesNameOrEmail implements AuthenticationDao {
 
+    private class MockAuthenticationDaoMatchesNameOrEmail
+        implements AuthenticationDao {
         public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
-            if ("Luke Taylor".equals(username) || "luke@monkeymachine".equals(username)) {
-                return new User("luke", "monkey", true, true, true,
+            if ("Luke Taylor".equals(username)
+                || "luke@monkeymachine".equals(username)) {
+                return new User("luke", "monkey", true, true, true, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE")});
             } else {
                 throw new UsernameNotFoundException("Could not find: "

+ 1 - 1
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, true, true,
+                    "marissaUserDetails", "koala", true, true, true, true,
                     new GrantedAuthority[] {}), "koala",
                 new GrantedAuthority[] {});
         SecureContext sc = new SecureContextImpl();

+ 7 - 0
core/src/test/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServicesTests.java

@@ -104,6 +104,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
 
     public void testAutoLoginIfExpired() throws Exception {
         UserDetails user = new User("someone", "password", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
 
         TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
@@ -130,6 +131,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
     public void testAutoLoginIfMissingThreeTokensInCookieValue()
         throws Exception {
         UserDetails user = new User("someone", "password", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
 
         TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
@@ -154,6 +156,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
 
     public void testAutoLoginIfNotBase64Encoded() throws Exception {
         UserDetails user = new User("someone", "password", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
 
         TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
@@ -179,6 +182,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
     public void testAutoLoginIfSignatureBlocksDoesNotMatchExpectedValue()
         throws Exception {
         UserDetails user = new User("someone", "password", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
 
         TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
@@ -205,6 +209,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
     public void testAutoLoginIfTokenDoesNotContainANumberInCookieValue()
         throws Exception {
         UserDetails user = new User("someone", "password", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
 
         TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
@@ -252,6 +257,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
 
     public void testAutoLoginWithValidToken() throws Exception {
         UserDetails user = new User("someone", "password", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
 
         TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
@@ -346,6 +352,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
 
         MockHttpServletResponse response = new MockHttpServletResponse();
         UserDetails user = new User("someone", "password", true, true, true,
+                true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
         services.loginSuccess(request, response,
             new TestingAuthenticationToken(user, "ignored",

+ 1 - 1
core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapperTests.java

@@ -80,7 +80,7 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase {
         throws Exception {
         SecureContext sc = new SecureContextImpl();
         Authentication auth = new TestingAuthenticationToken(new User(
-                    "marissaAsUserDetails", "koala", true, true, true,
+                    "marissaAsUserDetails", "koala", true, true, true, true,
                     new GrantedAuthority[] {}), "koala",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_HELLO"), new GrantedAuthorityImpl(
                         "ROLE_FOOBAR")});

+ 3 - 2
doc/xdocs/changes.xml

@@ -26,12 +26,13 @@
   </properties>
   <body>
     <release version="0.8.1" date="In CVS">
-      <action dev="benalex" type="add">X509 (certificate-based) authentication support</action>
+      <action dev="luke_t" type="add">X509 (certificate-based) authentication support</action>
+      <action dev="benalex" type="update">UserDetails now advises locked accounts, with corresponding DaoAuthenticationProvider events and enforcement</action>
       <action dev="benalex" type="update">ContextHolderAwareRequestWrapper methods returns null if user is anonymous</action>
       <action dev="benalex" type="update">AbstractBasicAclEntry improved compatibility with Hibernate</action>
       <action dev="benalex" type="fix">SecurityEnforcementFilter caused NullPointerException when anonymous authentication used with BasicProcessingFilterEntryPoint</action>
       <action dev="benalex" type="fix">FilterChainProxy now supports replacement of ServletRequest and ServetResponse by Filter beans</action>
-      <action dev="benalex" type="fix">Corrected Authz parsing of whitespace in GrantedAuthoritys</action>
+      <action dev="fbos" type="fix">Corrected Authz parsing of whitespace in GrantedAuthoritys</action>
       <action dev="benalex" type="fix">TokenBasedRememberMeServices now respects expired users, expired credentials and disabled users</action>
       <action dev="benalex" type="fix">HttpSessionContextIntegrationFilter now handles HttpSession invalidation without redirection</action>
     </release>

+ 1 - 1
sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/LdapPasswordAuthenticationDao.java

@@ -721,7 +721,7 @@ public class LdapPasswordAuthenticationDao implements PasswordAuthenticationDao
 
            String[] ldapRoles = (String[]) roles.toArray(new String[] {});
            
-           return new User(username, password, true, true, true,
+           return new User(username, password, true, true, true, true,
                    getGrantedAuthorities(ldapRoles));
        } catch (AuthenticationException ex) {
            throw new BadCredentialsException(