Browse Source

UserDetails now indicates locked accounts.

Ben Alex 20 năm trước cách đây
mục cha
commit
6f31ecb04b
31 tập tin đã thay đổi với 399 bổ sung157 xóa
  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(