소스 검색

Initial commit.

Ben Alex 21 년 전
부모
커밋
fe379d9712
40개의 변경된 파일4914개의 추가작업 그리고 0개의 파일을 삭제
  1. 292 0
      adapters/catalina/src/test/java/org/acegisecurity/adapters/catalina/CatalinaAcegiUserRealmTests.java
  2. 378 0
      adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModuleTests.java
  3. 245 0
      adapters/jetty/src/test/java/org/acegisecurity/adapters/jetty/JettyAcegiUserRealmTests.java
  4. 2 0
      ant.bat
  5. 11 0
      core/src/main/resources/log4j.properties
  6. 137 0
      core/src/test/java/org/acegisecurity/ConfigAttributeEditorTests.java
  7. 34 0
      core/src/test/java/org/acegisecurity/ITargetObject.java
  8. 305 0
      core/src/test/java/org/acegisecurity/MethodDefinitionAttributesTests.java
  9. 215 0
      core/src/test/java/org/acegisecurity/MethodDefinitionSourceEditorTests.java
  10. 62 0
      core/src/test/java/org/acegisecurity/MockAccessDecisionManager.java
  11. 155 0
      core/src/test/java/org/acegisecurity/MockAttributes.java
  12. 31 0
      core/src/test/java/org/acegisecurity/MockAuthenticationManager.java
  13. 54 0
      core/src/test/java/org/acegisecurity/MockRunAsAuthenticationToken.java
  14. 58 0
      core/src/test/java/org/acegisecurity/MockRunAsManager.java
  15. 56 0
      core/src/test/java/org/acegisecurity/OtherTargetObject.java
  16. 108 0
      core/src/test/java/org/acegisecurity/SecurityConfigTests.java
  17. 420 0
      core/src/test/java/org/acegisecurity/SecurityInterceptorTests.java
  18. 103 0
      core/src/test/java/org/acegisecurity/TargetObject.java
  19. 163 0
      core/src/test/java/org/acegisecurity/adapters/AbstractAdapterAuthenticationTokenTests.java
  20. 38 0
      core/src/test/java/org/acegisecurity/adapters/adaptertest-invalid.xml
  21. 52 0
      core/src/test/java/org/acegisecurity/adapters/adaptertest-valid.xml
  22. 76 0
      core/src/test/java/org/acegisecurity/context/ContextHolderTests.java
  23. 53 0
      core/src/test/java/org/acegisecurity/context/ContextImplTests.java
  24. 106 0
      core/src/test/java/org/acegisecurity/context/ContextInterceptorTests.java
  25. 28 0
      core/src/test/java/org/acegisecurity/context/ITargetObject.java
  26. 82 0
      core/src/test/java/org/acegisecurity/context/SecureContextImplTests.java
  27. 30 0
      core/src/test/java/org/acegisecurity/context/TargetObject.java
  28. 165 0
      core/src/test/java/org/acegisecurity/providers/AbstractAuthenticationTokenTests.java
  29. 171 0
      core/src/test/java/org/acegisecurity/providers/ProviderManagerTests.java
  30. 76 0
      core/src/test/java/org/acegisecurity/providers/TestingAuthenticationProviderTests.java
  31. 78 0
      core/src/test/java/org/acegisecurity/providers/TestingAuthenticationTokenTests.java
  32. 91 0
      core/src/test/java/org/acegisecurity/providers/UsernamePasswordAuthenticationTokenTests.java
  33. 266 0
      core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java
  34. 102 0
      core/src/test/java/org/acegisecurity/providers/dao/UserTests.java
  35. 135 0
      core/src/test/java/org/acegisecurity/providers/dao/memory/UserAttributeEditorTests.java
  36. 103 0
      core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapEditorTests.java
  37. 102 0
      core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java
  38. 113 0
      core/src/test/java/org/acegisecurity/runas/RunAsImplAuthenticationProviderTests.java
  39. 128 0
      core/src/test/java/org/acegisecurity/runas/RunAsManagerImplTests.java
  40. 90 0
      core/src/test/java/org/acegisecurity/runas/RunAsUserTokenTests.java

+ 292 - 0
adapters/catalina/src/test/java/org/acegisecurity/adapters/catalina/CatalinaAcegiUserRealmTests.java

@@ -0,0 +1,292 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.adapters.catalina;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken;
+
+import org.apache.catalina.LifecycleException;
+
+import java.io.File;
+
+import java.net.URL;
+
+import java.security.Principal;
+
+
+/**
+ * Tests {@link CatalinaAcegiUserRealm}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class CatalinaAcegiUserRealmTests extends TestCase {
+    //~ Instance fields ========================================================
+
+    private final String ADAPTER_KEY = "my_key";
+
+    //~ Constructors ===========================================================
+
+    public CatalinaAcegiUserRealmTests() {
+        super();
+    }
+
+    public CatalinaAcegiUserRealmTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(CatalinaAcegiUserRealmTests.class);
+    }
+
+    public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
+        throws Exception {
+        try {
+            CatalinaAcegiUserRealm adapter = makeAdapter(
+                    "adaptertest-invalid.xml");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAdapterAbortsIfNoAppContextSpecified()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+
+        adapter.setKey("KEY");
+
+        try {
+            adapter.startForTest();
+            fail("Should have thrown LifecycleException");
+        } catch (LifecycleException expected) {
+            assertEquals("appContextLocation must be defined",
+                expected.getMessage());
+        }
+
+        adapter.setAppContextLocation("");
+
+        try {
+            adapter.startForTest();
+            fail("Should have thrown LifecycleException");
+        } catch (LifecycleException expected) {
+            assertEquals("appContextLocation must be defined",
+                expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsIfNoKeySpecified() throws Exception {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+
+        adapter.setAppContextLocation("SOMETHING");
+
+        try {
+            adapter.startForTest();
+            fail("Should have thrown LifecycleException");
+        } catch (LifecycleException expected) {
+            assertEquals("key must be defined", expected.getMessage());
+        }
+
+        adapter.setKey("");
+
+        try {
+            adapter.startForTest();
+            fail("Should have thrown LifecycleException");
+        } catch (LifecycleException expected) {
+            assertEquals("key must be defined", expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsWithIncorrectApplicationContextLocation()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        adapter.setAppContextLocation("SOME_INVALID_PATH");
+        adapter.setKey("KEY");
+
+        try {
+            adapter.startForTest();
+            fail("Should have thrown LifecycleException");
+        } catch (LifecycleException expected) {
+            assertTrue(expected.getMessage().startsWith("appContextLocation does not seem to exist in"));
+        }
+    }
+
+    public void testAdapterIdentifiesItself() throws Exception {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertTrue(adapter.getName().lastIndexOf("CatalinaSpringUserRealm") != -1);
+    }
+
+    public void testAdapterStartsUpSuccess() throws Exception {
+        CatalinaAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertTrue(true);
+    }
+
+    public void testAuthenticateManyParamsReturnsNull() {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertEquals(null,
+            adapter.authenticate(null, null, null, null, null, null, null, null));
+    }
+
+    public void testAuthenticateX509ReturnsNull() {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertEquals(null, adapter.authenticate(null));
+    }
+
+    public void testAuthenticationFailsForIncorrectPassword()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate("marissa", "kangaroo"));
+    }
+
+    public void testAuthenticationFailsForIncorrectUserName()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate("melissa", "koala"));
+    }
+
+    public void testAuthenticationUsingByteArrayForCredentials()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        byte[] credentials = {'k', 'o', 'a', 'l', 'a'};
+        Principal result = adapter.authenticate("marissa", credentials);
+
+        if (!(result instanceof PrincipalAcegiUserToken)) {
+            fail("Should have returned PrincipalAcegiUserToken");
+        }
+
+        PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
+        assertEquals("marissa", castResult.getPrincipal());
+        assertEquals("koala", castResult.getCredentials());
+        assertEquals("ROLE_TELLER",
+            castResult.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_SUPERVISOR",
+            castResult.getAuthorities()[1].getAuthority());
+        assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
+    }
+
+    public void testAuthenticationUsingStringForCredentials()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        Principal result = adapter.authenticate("marissa", "koala");
+
+        if (!(result instanceof PrincipalAcegiUserToken)) {
+            fail("Should have returned PrincipalAcegiUserToken");
+        }
+
+        PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
+        assertEquals("marissa", castResult.getPrincipal());
+        assertEquals("koala", castResult.getCredentials());
+        assertEquals("ROLE_TELLER",
+            castResult.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_SUPERVISOR",
+            castResult.getAuthorities()[1].getAuthority());
+        assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
+    }
+
+    public void testAuthenticationWithNullPasswordHandledGracefully()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate("marissa", (String) null));
+    }
+
+    public void testAuthenticationWithNullUserNameHandledGracefully()
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate(null, "koala"));
+    }
+
+    public void testGetPasswordReturnsNull() {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertEquals(null, adapter.getPassword(null));
+    }
+
+    public void testGetPrincipalReturnsNull() {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertEquals(null, adapter.getPrincipal(null));
+    }
+
+    public void testGetters() {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        adapter.setKey("KEY");
+        assertEquals("KEY", adapter.getKey());
+        adapter.setAppContextLocation("SOME_LOCATION");
+        assertEquals("SOME_LOCATION", adapter.getAppContextLocation());
+    }
+
+    public void testHasRoleWithANullPrincipalFails() {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertTrue(!adapter.hasRole(null, "ROLE_ONE"));
+    }
+
+    public void testHasRoleWithAPrincipalTheAdapterDidNotCreateFails() {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertTrue(!adapter.hasRole(new MockPrincipal(), "ROLE_ONE"));
+    }
+
+    public void testHasRoleWithPrincipalAcegiUserToken() {
+        PrincipalAcegiUserToken token = new PrincipalAcegiUserToken("KEY",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+        assertTrue(adapter.hasRole(token, "ROLE_ONE"));
+        assertTrue(adapter.hasRole(token, "ROLE_TWO"));
+        assertTrue(!adapter.hasRole(token, "ROLE_WE_DO_NOT_HAVE"));
+    }
+
+    private CatalinaAcegiUserRealm makeAdapter(String fileName)
+        throws Exception {
+        CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
+
+        URL url = ClassLoader.getSystemResource(
+                "net/sf/acegisecurity/adapters/" + fileName);
+
+        if (url == null) {
+            throw new Exception("Could not find " + fileName
+                + " - cannot continue");
+        }
+
+        File file = new File(url.getFile());
+
+        System.setProperty("catalina.base",
+            file.getParentFile().getAbsolutePath());
+        System.out.println("catalina.base set to: "
+            + System.getProperty("catalina.base"));
+        adapter.setAppContextLocation(fileName);
+        adapter.setKey(ADAPTER_KEY);
+        adapter.startForTest();
+
+        return adapter;
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockPrincipal implements Principal {
+        public String getName() {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+    }
+}

+ 378 - 0
adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModuleTests.java

@@ -0,0 +1,378 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.adapters.jboss;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken;
+
+import org.jboss.security.SimplePrincipal;
+
+import java.io.IOException;
+
+import java.security.Principal;
+import java.security.acl.Group;
+
+import java.util.Properties;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+
+/**
+ * Tests {@link JbossAcegiLoginModule}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class JbossAcegiLoginModuleTests extends TestCase {
+    //~ Instance fields ========================================================
+
+    private final String ADAPTER_KEY = "my_key";
+
+    //~ Constructors ===========================================================
+
+    public JbossAcegiLoginModuleTests() {
+        super();
+    }
+
+    public JbossAcegiLoginModuleTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(JbossAcegiLoginModuleTests.class);
+    }
+
+    public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-invalid.xml");
+
+        try {
+            adapter.initialize(null, null, null, props);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAdapterAbortsIfNoAppContextSpecified()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+
+        try {
+            adapter.initialize(null, null, null, props);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("appContextLocation must be defined",
+                expected.getMessage());
+        }
+
+        props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation", "");
+
+        try {
+            adapter.initialize(null, null, null, props);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("appContextLocation must be defined",
+                expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsIfNoKeySpecified() throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+
+        Properties props = new Properties();
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        try {
+            adapter.initialize(null, null, null, props);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("key must be defined", expected.getMessage());
+        }
+
+        props = new Properties();
+        props.put("key", "");
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        try {
+            adapter.initialize(null, null, null, props);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("key must be defined", expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsWithIncorrectApplicationContextLocation()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation", "INVALID_PATH");
+
+        try {
+            adapter.initialize(null, null, null, props);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue("Cannot locate INVALID_PATH".equals(
+                    expected.getMessage()));
+        }
+    }
+
+    public void testAdapterFailsToAuthenticateIfNoCallbackHandlerAvailable()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+
+        adapter.initialize(subject, null, null, props);
+
+        try {
+            adapter.login();
+        } catch (LoginException loginException) {
+            assertEquals("Error: no CallbackHandler available to collect authentication information",
+                loginException.getMessage());
+        }
+    }
+
+    public void testAdapterStartsUpSuccess() throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+        adapter.initialize(null, null, null, props);
+        assertTrue(true);
+    }
+
+    public void testAuthenticationFailsForIncorrectPassword()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+        CallbackHandler callback = new MockCallbackHandler("marissa", "kangaroo");
+
+        adapter.initialize(subject, callback, null, props);
+
+        try {
+            adapter.login();
+            fail("Should have thrown FailedLoginException");
+        } catch (FailedLoginException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticationFailsForIncorrectUserName()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+        CallbackHandler callback = new MockCallbackHandler("melissa", "koala");
+
+        adapter.initialize(subject, callback, null, props);
+
+        try {
+            adapter.login();
+            fail("Should have thrown FailedLoginException");
+        } catch (FailedLoginException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticationSuccess() throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+        CallbackHandler callback = new MockCallbackHandler("marissa", "koala");
+
+        adapter.initialize(subject, callback, null, props);
+        assertTrue(adapter.login());
+
+        Principal result = adapter.getIdentity();
+
+        if (!(result instanceof PrincipalAcegiUserToken)) {
+            fail("Should have returned PrincipalAcegiUserToken");
+        }
+
+        PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
+        assertEquals("marissa", castResult.getPrincipal());
+        assertEquals("koala", castResult.getCredentials());
+        assertEquals("ROLE_TELLER",
+            castResult.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_SUPERVISOR",
+            castResult.getAuthorities()[1].getAuthority());
+        assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
+    }
+
+    public void testAuthenticationWithNullPasswordHandledGracefully()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+        CallbackHandler callback = new MockCallbackHandler("marissa", null);
+
+        adapter.initialize(subject, callback, null, props);
+
+        try {
+            adapter.login();
+            fail("Should have thrown FailedLoginException");
+        } catch (FailedLoginException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticationWithNullUserNameAndNullPasswordHandledGracefully()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+        CallbackHandler callback = new MockCallbackHandler(null, null);
+
+        adapter.initialize(subject, callback, null, props);
+
+        try {
+            adapter.login();
+            fail("Should have thrown FailedLoginException");
+        } catch (FailedLoginException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticationWithNullUserNameHandledGracefully()
+        throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+        CallbackHandler callback = new MockCallbackHandler(null, "kangaroo");
+
+        adapter.initialize(subject, callback, null, props);
+
+        try {
+            adapter.login();
+            fail("Should have thrown FailedLoginException");
+        } catch (FailedLoginException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testGetRoleSets() throws Exception {
+        JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
+        Properties props = new Properties();
+        props.put("key", ADAPTER_KEY);
+        props.put("appContextLocation",
+            "net/sf/acegisecurity/adapters/adaptertest-valid.xml");
+
+        Subject subject = new Subject();
+        CallbackHandler callback = new MockCallbackHandler("marissa", "koala");
+
+        adapter.initialize(subject, callback, null, props);
+        assertTrue(adapter.login());
+
+        Group[] result = adapter.getRoleSets();
+        assertEquals(1, result.length); // SimpleGroup called "Roles"
+
+        Group roles = result[0];
+        assertTrue(roles.isMember(new SimplePrincipal("ROLE_TELLER")));
+        assertTrue(roles.isMember(new SimplePrincipal("ROLE_SUPERVISOR")));
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockCallbackHandler implements CallbackHandler {
+        private String password;
+        private String username;
+
+        public MockCallbackHandler(String username, String password) {
+            this.username = username;
+            this.password = password;
+        }
+
+        private MockCallbackHandler() {
+            super();
+        }
+
+        public void handle(Callback[] callbacks)
+            throws IOException, UnsupportedCallbackException {
+            for (int i = 0; i < callbacks.length; i++) {
+                if (callbacks[i] instanceof NameCallback) {
+                    ((NameCallback) callbacks[i]).setName(username);
+                } else if (callbacks[i] instanceof PasswordCallback) {
+                    if (this.password == null) {
+                        ((PasswordCallback) callbacks[i]).setPassword(null);
+                    } else {
+                        ((PasswordCallback) callbacks[i]).setPassword(password
+                            .toCharArray());
+                    }
+                } else {
+                    throw new UnsupportedCallbackException(callbacks[i]);
+                }
+            }
+        }
+    }
+}

+ 245 - 0
adapters/jetty/src/test/java/org/acegisecurity/adapters/jetty/JettyAcegiUserRealmTests.java

@@ -0,0 +1,245 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.adapters.jetty;
+
+import junit.framework.TestCase;
+
+import org.mortbay.http.UserPrincipal;
+
+
+/**
+ * Tests {@link JettyAcegiUserRealm}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class JettyAcegiUserRealmTests extends TestCase {
+    //~ Instance fields ========================================================
+
+    private final String ADAPTER_KEY = "my_key";
+    private final String REALM_NAME = "Acegi Powered Realm";
+
+    //~ Constructors ===========================================================
+
+    public JettyAcegiUserRealmTests() {
+        super();
+    }
+
+    public JettyAcegiUserRealmTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(JettyAcegiUserRealmTests.class);
+    }
+
+    public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
+        throws Exception {
+        try {
+            JettyAcegiUserRealm adapter = makeAdapter("adaptertest-invalid.xml");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("Bean context must contain at least one bean of type AuthenticationManager",
+                expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsIfNoAppContextSpecified()
+        throws Exception {
+        try {
+            new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY, null);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("appContextLocation must be specified",
+                expected.getMessage());
+        }
+
+        try {
+            new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY, "");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("appContextLocation must be specified",
+                expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsIfNoKeySpecified() throws Exception {
+        try {
+            new JettyAcegiUserRealm(REALM_NAME, null, "SOME_PATH");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("key must be specified", expected.getMessage());
+        }
+
+        try {
+            new JettyAcegiUserRealm(REALM_NAME, "", "SOME_PATH");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("key must be specified", expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsIfNoRealmNameSpecified()
+        throws Exception {
+        try {
+            new JettyAcegiUserRealm(null, ADAPTER_KEY, "SOME_PATH");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("realm must be specified", expected.getMessage());
+        }
+
+        try {
+            new JettyAcegiUserRealm(null, ADAPTER_KEY, "SOME_PATH");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("realm must be specified", expected.getMessage());
+        }
+    }
+
+    public void testAdapterAbortsWithIncorrectApplicationContextLocation()
+        throws Exception {
+        try {
+            new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY,
+                "SOME_INVALID_LOCATION");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(expected.getMessage().startsWith("Cannot locate"));
+        }
+    }
+
+    public void testAdapterIdentifiesTheRealmItManages()
+        throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(REALM_NAME, adapter.getName());
+    }
+
+    public void testAdapterStartsUpSuccess() throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertTrue(true);
+    }
+
+    public void testAuthenticationFailsForIncorrectPassword()
+        throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate("marissa", "kangaroo", null));
+    }
+
+    public void testAuthenticationFailsForIncorrectUserName()
+        throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate("melissa", "koala", null));
+    }
+
+    public void testAuthenticationSuccess() throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        UserPrincipal result = adapter.authenticate("marissa", "koala", null);
+
+        if (!(result instanceof JettyAcegiUserToken)) {
+            fail("Should have returned JettyAcegiUserToken");
+        }
+
+        JettyAcegiUserToken castResult = (JettyAcegiUserToken) result;
+        assertEquals("marissa", castResult.getPrincipal());
+        assertEquals("koala", castResult.getCredentials());
+        assertEquals("ROLE_TELLER",
+            castResult.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_SUPERVISOR",
+            castResult.getAuthorities()[1].getAuthority());
+        assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
+    }
+
+    public void testAuthenticationWithNullPasswordHandledGracefully()
+        throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate("marissa", null, null));
+    }
+
+    public void testAuthenticationWithNullUserNameHandledGracefully()
+        throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertEquals(null, adapter.authenticate(null, "koala", null));
+    }
+
+    public void testDisassociateImplemented() throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        adapter.disassociate(new MockUserPrincipal());
+        assertTrue(true);
+    }
+
+    public void testGetAuthenticationManager() throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        assertTrue(adapter.getAuthenticationManager() != null);
+    }
+
+    public void testLogoutImplemented() throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        adapter.logout(new MockUserPrincipal());
+        assertTrue(true);
+    }
+
+    public void testNoArgsConstructor() {
+        try {
+            new JettyAcegiUserRealm();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testPopRoleImplemented() throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        MockUserPrincipal user = new MockUserPrincipal();
+        assertEquals(user, adapter.popRole(user));
+    }
+
+    public void testPushRoleImplemented() throws Exception {
+        JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
+        MockUserPrincipal user = new MockUserPrincipal();
+        assertEquals(user, adapter.pushRole(user, "SOME_ROLE"));
+    }
+
+    private JettyAcegiUserRealm makeAdapter(String fileName)
+        throws Exception {
+        String useFile = "net/sf/acegisecurity/adapters/" + fileName;
+
+        return new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY, useFile);
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockUserPrincipal implements UserPrincipal {
+        public boolean isAuthenticated() {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+
+        public String getName() {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+
+        public boolean isUserInRole(String arg0) {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+    }
+}

+ 2 - 0
ant.bat

@@ -0,0 +1,2 @@
+%JAVA_HOME%/bin/java -cp lib/ant/ant.jar;lib/ant/ant-launcher.jar;lib/ant/ant-junit.jar;lib/junit/junit.jar;lib/clover/clover.jar;%JAVA_HOME%/lib/tools.jar org.apache.tools.ant.Main %1 %2 %3 %4 %5 %6 %7 %8
+

+ 11 - 0
core/src/main/resources/log4j.properties

@@ -0,0 +1,11 @@
+# Logging
+#
+# $Id$
+
+log4j.rootCategory=WARN, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
+
+log4j.category.net.sf.acegisecurity=DEBUG

+ 137 - 0
core/src/test/java/org/acegisecurity/ConfigAttributeEditorTests.java

@@ -0,0 +1,137 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import junit.framework.TestCase;
+
+import java.util.Iterator;
+
+
+/**
+ * Tests {@link ConfigAttributeEditor} and associated {@link
+ * ConfigAttributeDefinition}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class ConfigAttributeEditorTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public ConfigAttributeEditorTests() {
+        super();
+    }
+
+    public ConfigAttributeEditorTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(ConfigAttributeEditorTests.class);
+    }
+
+    public void testCorrectOperation() {
+        ConfigAttributeEditor editor = new ConfigAttributeEditor();
+        editor.setAsText("HELLO,DOCTOR,NAME,YESTERDAY,TOMORROW");
+
+        ConfigAttributeDefinition result = (ConfigAttributeDefinition) editor
+            .getValue();
+        Iterator iter = result.getConfigAttributes();
+        int position = 0;
+
+        while (iter.hasNext()) {
+            position++;
+            iter.next();
+        }
+
+        assertEquals(5, position);
+    }
+
+    public void testEmptyStringReturnsNull() {
+        ConfigAttributeEditor editor = new ConfigAttributeEditor();
+        editor.setAsText("");
+
+        ConfigAttributeDefinition result = (ConfigAttributeDefinition) editor
+            .getValue();
+        assertTrue(result == null);
+    }
+
+    public void testEqualsHandlingWhenDifferentObjectTypes() {
+        ConfigAttributeDefinition def1 = new ConfigAttributeDefinition();
+        def1.addConfigAttribute(new SecurityConfig("A"));
+        def1.addConfigAttribute(new SecurityConfig("B"));
+
+        assertTrue(!def1.equals("A_STRING"));
+    }
+
+    public void testEqualsHandlingWhenExactlyEqual() {
+        ConfigAttributeDefinition def1 = new ConfigAttributeDefinition();
+        def1.addConfigAttribute(new SecurityConfig("A"));
+        def1.addConfigAttribute(new SecurityConfig("B"));
+
+        ConfigAttributeDefinition def2 = new ConfigAttributeDefinition();
+        def2.addConfigAttribute(new SecurityConfig("A"));
+        def2.addConfigAttribute(new SecurityConfig("B"));
+
+        assertEquals(def1, def2);
+    }
+
+    public void testEqualsHandlingWhenOrderingNotEqual() {
+        ConfigAttributeDefinition def1 = new ConfigAttributeDefinition();
+        def1.addConfigAttribute(new SecurityConfig("A"));
+        def1.addConfigAttribute(new SecurityConfig("B"));
+
+        ConfigAttributeDefinition def2 = new ConfigAttributeDefinition();
+        def2.addConfigAttribute(new SecurityConfig("B"));
+        def2.addConfigAttribute(new SecurityConfig("A"));
+
+        assertTrue(!def1.equals(def2));
+    }
+
+    public void testEqualsHandlingWhenTestObjectHasNoAttributes() {
+        ConfigAttributeDefinition def1 = new ConfigAttributeDefinition();
+        def1.addConfigAttribute(new SecurityConfig("A"));
+        def1.addConfigAttribute(new SecurityConfig("B"));
+
+        ConfigAttributeDefinition def2 = new ConfigAttributeDefinition();
+
+        assertTrue(!def1.equals(def2));
+        assertTrue(!def2.equals(def1));
+    }
+
+    public void testNullReturnsNull() {
+        ConfigAttributeEditor editor = new ConfigAttributeEditor();
+        editor.setAsText(null);
+
+        ConfigAttributeDefinition result = (ConfigAttributeDefinition) editor
+            .getValue();
+        assertTrue(result == null);
+    }
+
+    public void testToString() {
+        ConfigAttributeEditor editor = new ConfigAttributeEditor();
+        editor.setAsText("KOALA,KANGAROO,EMU,WOMBAT");
+
+        ConfigAttributeDefinition result = (ConfigAttributeDefinition) editor
+            .getValue();
+        assertEquals("[KOALA, KANGAROO, EMU, WOMBAT]", result.toString());
+    }
+}

+ 34 - 0
core/src/test/java/org/acegisecurity/ITargetObject.java

@@ -0,0 +1,34 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+/**
+ * Represents the interface of a secured object.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface ITargetObject {
+    //~ Methods ================================================================
+
+    public int countLength(String input);
+
+    public String makeLowerCase(String input);
+
+    public String makeUpperCase(String input);
+
+    public String publicMakeLowerCase(String input);
+}

+ 305 - 0
core/src/test/java/org/acegisecurity/MethodDefinitionAttributesTests.java

@@ -0,0 +1,305 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.context.ContextHolder;
+import net.sf.acegisecurity.context.SecureContext;
+import net.sf.acegisecurity.context.SecureContextImpl;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+
+/**
+ * Tests {@link MethodDefinitionAttributes}.
+ *
+ * @author Cameron Braid
+ * @author Ben Alex
+ */
+public class MethodDefinitionAttributesTests extends TestCase {
+    //~ Instance fields ========================================================
+
+    ClassPathXmlApplicationContext applicationContext;
+
+    //~ Constructors ===========================================================
+
+    public MethodDefinitionAttributesTests(String a) {
+        super(a);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(MethodDefinitionAttributesTests.class);
+    }
+
+    public void testAttributesForInterfaceTargetObject()
+        throws Exception {
+        ConfigAttributeDefinition def1 = getConfigAttributeDefinition(ITargetObject.class,
+                "countLength", new Class[] {String.class});
+        Set set1 = toSet(def1);
+        assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set1.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_COUNT_LENGTH")));
+
+        ConfigAttributeDefinition def2 = getConfigAttributeDefinition(ITargetObject.class,
+                "makeLowerCase", new Class[] {String.class});
+        Set set2 = toSet(def2);
+        assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set2.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")));
+
+        ConfigAttributeDefinition def3 = getConfigAttributeDefinition(ITargetObject.class,
+                "makeUpperCase", new Class[] {String.class});
+        Set set3 = toSet(def3);
+        assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set3.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")));
+    }
+
+    public void testAttributesForOtherTargetObject() throws Exception {
+        ConfigAttributeDefinition def1 = getConfigAttributeDefinition(OtherTargetObject.class,
+                "countLength", new Class[] {String.class});
+        Set set1 = toSet(def1);
+        assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set1.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_COUNT_LENGTH")));
+
+        // Confirm MOCK_CLASS_METHOD_COUNT_LENGTH not added, as it's a String (not a ConfigAttribute)
+        // Confirm also MOCK_CLASS not added, as we return null for class
+        assertEquals(2, set1.size());
+
+        ConfigAttributeDefinition def2 = getConfigAttributeDefinition(OtherTargetObject.class,
+                "makeLowerCase", new Class[] {String.class});
+        Set set2 = toSet(def2);
+        assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set2.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")));
+        assertTrue(set2.contains(
+                new SecurityConfig("MOCK_CLASS_METHOD_MAKE_LOWER_CASE")));
+
+        // Confirm MOCK_CLASS not added, as we return null for class
+        assertEquals(3, set2.size());
+
+        ConfigAttributeDefinition def3 = getConfigAttributeDefinition(OtherTargetObject.class,
+                "makeUpperCase", new Class[] {String.class});
+        Set set3 = toSet(def3);
+        assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set3.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")));
+        assertTrue(set3.contains(new SecurityConfig("RUN_AS"))); // defined against interface
+
+        assertEquals(3, set3.size());
+    }
+
+    public void testAttributesForTargetObject() throws Exception {
+        ConfigAttributeDefinition def1 = getConfigAttributeDefinition(TargetObject.class,
+                "countLength", new Class[] {String.class});
+        Set set1 = toSet(def1);
+        assertTrue(set1.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set1.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_COUNT_LENGTH")));
+
+        assertTrue(set1.contains(new SecurityConfig("MOCK_CLASS")));
+
+        // Confirm the MOCK_CLASS_METHOD_COUNT_LENGTH was not added, as it's not a ConfigAttribute
+        assertEquals(3, set1.size());
+
+        ConfigAttributeDefinition def2 = getConfigAttributeDefinition(TargetObject.class,
+                "makeLowerCase", new Class[] {String.class});
+        Set set2 = toSet(def2);
+        assertTrue(set2.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set2.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")));
+        assertTrue(set2.contains(new SecurityConfig("MOCK_CLASS")));
+        assertTrue(set2.contains(
+                new SecurityConfig("MOCK_CLASS_METHOD_MAKE_LOWER_CASE")));
+        assertEquals(4, set2.size());
+
+        ConfigAttributeDefinition def3 = getConfigAttributeDefinition(TargetObject.class,
+                "makeUpperCase", new Class[] {String.class});
+        Set set3 = toSet(def3);
+        assertTrue(set3.contains(new SecurityConfig("MOCK_INTERFACE")));
+        assertTrue(set3.contains(
+                new SecurityConfig("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")));
+        assertTrue(set3.contains(new SecurityConfig("MOCK_CLASS")));
+        assertTrue(set3.contains(
+                new SecurityConfig("MOCK_CLASS_METHOD_MAKE_UPPER_CASE")));
+        assertTrue(set3.contains(new SecurityConfig("RUN_AS")));
+        assertEquals(5, set3.size());
+    }
+
+    public void testMethodCallWithRunAsReplacement() throws Exception {
+        SecureContext context = new SecureContextImpl();
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")});
+        context.setAuthentication(token);
+        ContextHolder.setContext(context);
+
+        ITargetObject target = makeInterceptedTarget();
+        String result = target.makeUpperCase("hello");
+        assertEquals("HELLO net.sf.acegisecurity.MockRunAsAuthenticationToken true",
+            result);
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testMethodCallWithoutRunAsReplacement()
+        throws Exception {
+        SecureContext context = new SecureContextImpl();
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")});
+        context.setAuthentication(token);
+        ContextHolder.setContext(context);
+
+        ITargetObject target = makeInterceptedTarget();
+        String result = target.makeLowerCase("HELLO");
+
+        assertEquals("hello net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken true",
+            result);
+
+        ContextHolder.setContext(null);
+    }
+
+    private ConfigAttributeDefinition getConfigAttributeDefinition(
+        Class clazz, String methodName, Class[] args) throws Exception {
+        final Method method = clazz.getMethod(methodName, args);
+        MethodDefinitionAttributes source = new MethodDefinitionAttributes();
+        source.setAttributes(new MockAttributes());
+
+        ConfigAttributeDefinition config = source.getAttributes(new MockMethodInvocation() {
+                    public Method getMethod() {
+                        return method;
+                    }
+                });
+
+        return config;
+    }
+
+    private ITargetObject makeInterceptedTarget() {
+        String PREFIX = "beans.";
+        DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
+        Properties p = new Properties();
+        p.setProperty(PREFIX + "authentication.class",
+            "net.sf.acegisecurity.MockAuthenticationManager");
+        p.setProperty(PREFIX + "accessDecision.class",
+            "net.sf.acegisecurity.MockAccessDecisionManager");
+        p.setProperty(PREFIX + "runAs.class",
+            "net.sf.acegisecurity.MockRunAsManager");
+        p.setProperty(PREFIX + "attributes.class",
+            "net.sf.acegisecurity.MockAttributes");
+
+        p.setProperty(PREFIX + "methodDefinitionSource.class",
+            "net.sf.acegisecurity.MethodDefinitionAttributes");
+        p.setProperty(PREFIX + "methodDefinitionSource.attributes(ref)",
+            "attributes");
+
+        p.setProperty(PREFIX + "securityInterceptor.class",
+            "net.sf.acegisecurity.SecurityInterceptor");
+        p.setProperty(PREFIX + "securityInterceptor.authenticationManager(ref)",
+            "authentication");
+        p.setProperty(PREFIX + "securityInterceptor.accessDecisionManager(ref)",
+            "accessDecision");
+        p.setProperty(PREFIX + "securityInterceptor.runAsManager(ref)", "runAs");
+        p.setProperty(PREFIX
+            + "securityInterceptor.methodDefinitionSource(ref)",
+            "methodDefinitionSource");
+
+        p.setProperty(PREFIX + "targetObject.class",
+            "net.sf.acegisecurity.TargetObject");
+        p.setProperty(PREFIX + "target.class",
+            "org.springframework.aop.framework.ProxyFactoryBean");
+        p.setProperty(PREFIX + "target.proxyInterfaces",
+            "net.sf.acegisecurity.ITargetObject");
+        p.setProperty(PREFIX + "target.interceptorNames",
+            "securityInterceptor,targetObject");
+
+        (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p,
+            PREFIX);
+
+        return (ITargetObject) lbf.getBean("target");
+    }
+
+    /**
+     * convert a <code>ConfigAttributeDefinition</code> into a set of
+     * <code>ConfigAttribute</code>(s)
+     *
+     * @param def the <code>ConfigAttributeDefinition</code> to cover
+     *
+     * @return a Set of <code>ConfigAttributes</code>
+     */
+    private Set toSet(ConfigAttributeDefinition def) {
+        Set set = new HashSet();
+        Iterator i = def.getConfigAttributes();
+
+        while (i.hasNext()) {
+            ConfigAttribute a = (ConfigAttribute) i.next();
+            set.add(a);
+        }
+
+        return set;
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockMethodInvocation implements MethodInvocation {
+        public Object[] getArguments() {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+
+        public Method getMethod() {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+
+        public AccessibleObject getStaticPart() {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+
+        public Object getThis() {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+
+        public Object proceed() throws Throwable {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+    }
+}

+ 215 - 0
core/src/test/java/org/acegisecurity/MethodDefinitionSourceEditorTests.java

@@ -0,0 +1,215 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import junit.framework.TestCase;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+
+import java.util.Iterator;
+
+
+/**
+ * Tests {@link MethodDefinitionSourceEditor}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MethodDefinitionSourceEditorTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public MethodDefinitionSourceEditorTests() {
+        super();
+    }
+
+    public MethodDefinitionSourceEditorTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(MethodDefinitionSourceEditorTests.class);
+    }
+
+    public void testClassNameNotFoundResultsInException() {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+
+        try {
+            editor.setAsText("net.sf.acegisecurity.DOES_NOT_EXIST_NAME=FOO,BAR");
+            fail("Should have given IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testClassNameNotInProperFormatResultsInException() {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+
+        try {
+            editor.setAsText("DOES_NOT_EXIST_NAME=FOO,BAR");
+            fail("Should have given IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testClassNameValidButMethodNameInvalidResultsInException() {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+
+        try {
+            editor.setAsText(
+                "net.sf.acegisecurity.TargetObject.INVALID_METHOD=FOO,BAR");
+            fail("Should have given IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testEmptyStringReturnsEmptyMap() {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+        editor.setAsText("");
+
+        MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+        assertEquals(0, map.getMethodMapSize());
+    }
+
+    public void testIterator() {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+        editor.setAsText(
+            "net.sf.acegisecurity.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY\r\nnet.sf.acegisecurity.TargetObject.make*=ROLE_NINE,ROLE_SUPERVISOR");
+
+        MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+        Iterator iter = map.getConfigAttributeDefinitions();
+        int counter = 0;
+
+        while (iter.hasNext()) {
+            iter.next();
+            counter++;
+        }
+
+        assertEquals(3, counter);
+    }
+
+    public void testMultiMethodParsing() {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+        editor.setAsText(
+            "net.sf.acegisecurity.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY\r\nnet.sf.acegisecurity.TargetObject.make*=ROLE_NINE,ROLE_SUPERVISOR");
+
+        MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+        assertEquals(3, map.getMethodMapSize());
+    }
+
+    public void testMultiMethodParsingWhereLaterMethodsOverrideEarlierMethods()
+        throws Exception {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+        editor.setAsText(
+            "net.sf.acegisecurity.TargetObject.*=ROLE_GENERAL\r\nnet.sf.acegisecurity.TargetObject.makeLower*=ROLE_LOWER\r\nnet.sf.acegisecurity.TargetObject.make*=ROLE_MAKE\r\nnet.sf.acegisecurity.TargetObject.makeUpper*=ROLE_UPPER");
+
+        MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+        assertEquals(4, map.getMethodMapSize());
+
+        ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(
+                    TargetObject.class, "makeLowerCase",
+                    new Class[] {String.class}));
+        ConfigAttributeDefinition expectedMakeLower = new ConfigAttributeDefinition();
+        expectedMakeLower.addConfigAttribute(new SecurityConfig("ROLE_LOWER"));
+        assertEquals(expectedMakeLower, returnedMakeLower);
+
+        ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(
+                    TargetObject.class, "makeUpperCase",
+                    new Class[] {String.class}));
+        ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition();
+        expectedMakeUpper.addConfigAttribute(new SecurityConfig("ROLE_UPPER"));
+        assertEquals(expectedMakeUpper, returnedMakeUpper);
+
+        ConfigAttributeDefinition returnedCountLength = map.getAttributes(new MockMethodInvocation(
+                    TargetObject.class, "countLength",
+                    new Class[] {String.class}));
+        ConfigAttributeDefinition expectedCountLength = new ConfigAttributeDefinition();
+        expectedCountLength.addConfigAttribute(new SecurityConfig(
+                "ROLE_GENERAL"));
+        assertEquals(expectedCountLength, returnedCountLength);
+    }
+
+    public void testNullReturnsEmptyMap() {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+        editor.setAsText(null);
+
+        MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+        assertEquals(0, map.getMethodMapSize());
+    }
+
+    public void testSingleMethodParsing() throws Exception {
+        MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+        editor.setAsText(
+            "net.sf.acegisecurity.TargetObject.countLength=ROLE_ONE,ROLE_TWO,RUN_AS_ENTRY");
+
+        MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+
+        ConfigAttributeDefinition returnedCountLength = map.getAttributes(new MockMethodInvocation(
+                    TargetObject.class, "countLength",
+                    new Class[] {String.class}));
+        ConfigAttributeDefinition expectedCountLength = new ConfigAttributeDefinition();
+        expectedCountLength.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
+        expectedCountLength.addConfigAttribute(new SecurityConfig("ROLE_TWO"));
+        expectedCountLength.addConfigAttribute(new SecurityConfig(
+                "RUN_AS_ENTRY"));
+        assertEquals(expectedCountLength, returnedCountLength);
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockMethodInvocation implements MethodInvocation {
+        Method method;
+
+        public MockMethodInvocation(Class clazz, String methodName,
+            Class[] parameterTypes) throws NoSuchMethodException {
+            method = clazz.getMethod(methodName, parameterTypes);
+        }
+
+        private MockMethodInvocation() {
+            super();
+        }
+
+        public Object[] getArguments() {
+            return null;
+        }
+
+        public Method getMethod() {
+            return method;
+        }
+
+        public AccessibleObject getStaticPart() {
+            return null;
+        }
+
+        public Object getThis() {
+            return null;
+        }
+
+        public Object proceed() throws Throwable {
+            return null;
+        }
+    }
+}

+ 62 - 0
core/src/test/java/org/acegisecurity/MockAccessDecisionManager.java

@@ -0,0 +1,62 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.util.Iterator;
+
+
+/**
+ * Grants access if the user holds any of the authorities listed in the
+ * configuration attributes starting with "MOCK_".
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MockAccessDecisionManager implements AccessDecisionManager {
+    //~ Methods ================================================================
+
+    public void decide(Authentication authentication,
+        MethodInvocation invocation, ConfigAttributeDefinition config)
+        throws AccessDeniedException {
+        Iterator iter = config.getConfigAttributes();
+
+        while (iter.hasNext()) {
+            ConfigAttribute attr = (ConfigAttribute) iter.next();
+
+            if (this.supports(attr)) {
+                for (int i = 0; i < authentication.getAuthorities().length;
+                    i++) {
+                    if (attr.getAttribute().equals(authentication
+                            .getAuthorities()[i].getAuthority())) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        throw new AccessDeniedException("Didn't hold required authority");
+    }
+
+    public boolean supports(ConfigAttribute attribute) {
+        if (attribute.getAttribute().startsWith("MOCK_")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}

+ 155 - 0
core/src/test/java/org/acegisecurity/MockAttributes.java

@@ -0,0 +1,155 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import org.springframework.metadata.Attributes;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * Used by the {@link MethodDefinitionAttributesTests}.
+ *
+ * @author Cameron Braid
+ * @author Ben Alex
+ */
+public class MockAttributes implements Attributes {
+    //~ Instance fields ========================================================
+
+    List classAttributes = Arrays.asList(new SecurityConfig[] {new SecurityConfig(
+                    "MOCK_CLASS")});
+    List classMethodAttributesCountLength = Arrays.asList(new String[] {new String(
+                    "MOCK_CLASS_METHOD_COUNT_LENGTH")});
+    List classMethodAttributesMakeLowerCase = Arrays.asList(new SecurityConfig[] {new SecurityConfig(
+                    "MOCK_CLASS_METHOD_MAKE_LOWER_CASE")});
+    List classMethodAttributesMakeUpperCase = Arrays.asList(new SecurityConfig[] {new SecurityConfig(
+                    "MOCK_CLASS_METHOD_MAKE_UPPER_CASE")});
+    List interfaceAttributes = Arrays.asList(new SecurityConfig[] {new SecurityConfig(
+                    "MOCK_INTERFACE")});
+    List interfaceMethodAttributesCountLength = Arrays.asList(new SecurityConfig[] {new SecurityConfig(
+                    "MOCK_INTERFACE_METHOD_COUNT_LENGTH")});
+    List interfaceMethodAttributesMakeLowerCase = Arrays.asList(new SecurityConfig[] {new SecurityConfig(
+                    "MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")});
+    List interfaceMethodAttributesMakeUpperCase = Arrays.asList(new SecurityConfig[] {new SecurityConfig(
+                    "MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE"), new SecurityConfig(
+                    "RUN_AS")});
+
+    //~ Methods ================================================================
+
+    public Collection getAttributes(Class clazz) {
+        // Emphasise we return null for OtherTargetObject
+        if (clazz.equals(OtherTargetObject.class)) {
+            return null;
+        }
+
+        // interface
+        if (clazz.equals(ITargetObject.class)) {
+            return interfaceAttributes;
+        }
+
+        // class
+        if (clazz.equals(TargetObject.class)) {
+            return classAttributes;
+        }
+
+        return null;
+    }
+
+    public Collection getAttributes(Method method) {
+        // interface
+        if (method.getDeclaringClass().equals(ITargetObject.class)) {
+            if (method.getName().equals("countLength")) {
+                return interfaceMethodAttributesCountLength;
+            }
+
+            if (method.getName().equals("makeLowerCase")) {
+                return interfaceMethodAttributesMakeLowerCase;
+            }
+
+            if (method.getName().equals("makeUpperCase")) {
+                return interfaceMethodAttributesMakeUpperCase;
+            }
+
+            if (method.getName().equals("publicMakeLowerCase")) {
+                throw new UnsupportedOperationException(
+                    "mock support not implemented");
+            }
+        }
+
+        // class
+        if (method.getDeclaringClass().equals(TargetObject.class)) {
+            if (method.getName().equals("countLength")) {
+                return classMethodAttributesCountLength;
+            }
+
+            if (method.getName().equals("makeLowerCase")) {
+                return classMethodAttributesMakeLowerCase;
+            }
+
+            if (method.getName().equals("makeUpperCase")) {
+                return classMethodAttributesMakeUpperCase;
+            }
+
+            if (method.getName().equals("publicMakeLowerCase")) {
+                throw new UnsupportedOperationException(
+                    "mock support not implemented");
+            }
+        }
+
+        // other target object
+        if (method.getDeclaringClass().equals(OtherTargetObject.class)) {
+            if (method.getName().equals("countLength")) {
+                return classMethodAttributesCountLength;
+            }
+
+            if (method.getName().equals("makeLowerCase")) {
+                return classMethodAttributesMakeLowerCase;
+            }
+
+            if (method.getName().equals("makeUpperCase")) {
+                return null; // NB
+            }
+
+            if (method.getName().equals("publicMakeLowerCase")) {
+                throw new UnsupportedOperationException(
+                    "mock support not implemented");
+            }
+        }
+
+        return null;
+    }
+
+    public Collection getAttributes(Class arg0, Class arg1) {
+        throw new UnsupportedOperationException("mock method not implemented");
+    }
+
+    public Collection getAttributes(Field arg0, Class arg1) {
+        throw new UnsupportedOperationException("mock method not implemented");
+    }
+
+    public Collection getAttributes(Field arg0) {
+        throw new UnsupportedOperationException("mock method not implemented");
+    }
+
+    public Collection getAttributes(Method arg0, Class arg1) {
+        throw new UnsupportedOperationException("mock method not implemented");
+    }
+}

+ 31 - 0
core/src/test/java/org/acegisecurity/MockAuthenticationManager.java

@@ -0,0 +1,31 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+/**
+ * Simply accepts as valid whatever is passed to it.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MockAuthenticationManager implements AuthenticationManager {
+    //~ Methods ================================================================
+
+    public Authentication authenticate(Authentication authentication)
+        throws AuthenticationException {
+        return authentication;
+    }
+}

+ 54 - 0
core/src/test/java/org/acegisecurity/MockRunAsAuthenticationToken.java

@@ -0,0 +1,54 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import net.sf.acegisecurity.providers.AbstractAuthenticationToken;
+
+
+/**
+ * Simple holder that indicates the {@link MockRunAsManager} returned a
+ * different <Code>Authentication</code> object.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MockRunAsAuthenticationToken extends AbstractAuthenticationToken {
+    //~ Instance fields ========================================================
+
+    private boolean authenticated = false;
+
+    //~ Methods ================================================================
+
+    public void setAuthenticated(boolean isAuthenticated) {
+        authenticated = isAuthenticated;
+    }
+
+    public boolean isAuthenticated() {
+        return authenticated;
+    }
+
+    public GrantedAuthority[] getAuthorities() {
+        return null;
+    }
+
+    public Object getCredentials() {
+        return null;
+    }
+
+    public Object getPrincipal() {
+        return null;
+    }
+}

+ 58 - 0
core/src/test/java/org/acegisecurity/MockRunAsManager.java

@@ -0,0 +1,58 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.util.Iterator;
+
+
+/**
+ * Returns a new run-as identity if configuration attribute RUN_AS is found.
+ * The new identity is simply an empty {@link MockRunAsAuthenticationToken}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MockRunAsManager implements RunAsManager {
+    //~ Methods ================================================================
+
+    public Authentication buildRunAs(Authentication authentication,
+        MethodInvocation invocation, ConfigAttributeDefinition config) {
+        Iterator iter = config.getConfigAttributes();
+
+        while (iter.hasNext()) {
+            ConfigAttribute attr = (ConfigAttribute) iter.next();
+
+            if (this.supports(attr)) {
+                Authentication response = new MockRunAsAuthenticationToken();
+                response.setAuthenticated(true);
+
+                return response;
+            }
+        }
+
+        return null;
+    }
+
+    public boolean supports(ConfigAttribute attribute) {
+        if ("RUN_AS".equals(attribute.getAttribute())) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}

+ 56 - 0
core/src/test/java/org/acegisecurity/OtherTargetObject.java

@@ -0,0 +1,56 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+/**
+ * Simply extends {@link TargetObject} so we have a different object to put
+ * configuration attributes against.
+ * 
+ * <P>
+ * There is no different behaviour. We have to define each method so that
+ * <code>Class.getMethod(methodName, args)</code> returns a
+ * <code>Method</code> referencing this class rather than the parent class.
+ * </p>
+ * 
+ * <P>
+ * We need to implement <code>ITargetObject</code> again because the
+ * <code>MethodDefinitionAttributes</code> only locates attributes on
+ * interfaces explicitly defined by the intercepted class (not the interfaces
+ * defined by its parent class or classes).
+ * </p>
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class OtherTargetObject extends TargetObject implements ITargetObject {
+    //~ Methods ================================================================
+
+    public int countLength(String input) {
+        return super.countLength(input);
+    }
+
+    public String makeLowerCase(String input) {
+        return super.makeLowerCase(input);
+    }
+
+    public String makeUpperCase(String input) {
+        return super.makeUpperCase(input);
+    }
+
+    public String publicMakeLowerCase(String input) {
+        return super.publicMakeLowerCase(input);
+    }
+}

+ 108 - 0
core/src/test/java/org/acegisecurity/SecurityConfigTests.java

@@ -0,0 +1,108 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests {@link SecurityConfig}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class SecurityConfigTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public SecurityConfigTests() {
+        super();
+    }
+
+    public SecurityConfigTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(SecurityConfigTests.class);
+    }
+
+    public void testHashCode() {
+        SecurityConfig config = new SecurityConfig("TEST");
+        assertEquals("TEST".hashCode(), config.hashCode());
+    }
+
+    public void testNoArgsConstructor() {
+        try {
+            new SecurityConfig();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testObjectEquals() throws Exception {
+        SecurityConfig security1 = new SecurityConfig("TEST");
+        SecurityConfig security2 = new SecurityConfig("TEST");
+        assertEquals(security1, security2);
+
+        String securityString1 = "TEST";
+        assertEquals(security1, securityString1);
+
+        String securityString2 = "NOT_EQUAL";
+        assertTrue(!security1.equals(securityString2));
+
+        SecurityConfig security3 = new SecurityConfig("NOT_EQUAL");
+        assertTrue(!security1.equals(security3));
+
+        MockConfigAttribute mock1 = new MockConfigAttribute("TEST");
+        assertEquals(security1, mock1);
+
+        MockConfigAttribute mock2 = new MockConfigAttribute("NOT_EQUAL");
+        assertTrue(!security1.equals(mock2));
+
+        Integer int1 = new Integer(987);
+        assertTrue(!security1.equals(int1));
+    }
+
+    public void testToString() {
+        SecurityConfig config = new SecurityConfig("TEST");
+        assertEquals("TEST", config.toString());
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockConfigAttribute implements ConfigAttribute {
+        private String attribute;
+
+        public MockConfigAttribute(String configuration) {
+            this.attribute = configuration;
+        }
+
+        private MockConfigAttribute() {
+            super();
+        }
+
+        public String getAttribute() {
+            return this.attribute;
+        }
+    }
+}

+ 420 - 0
core/src/test/java/org/acegisecurity/SecurityInterceptorTests.java

@@ -0,0 +1,420 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.context.ContextHolder;
+import net.sf.acegisecurity.context.ContextImpl;
+import net.sf.acegisecurity.context.SecureContext;
+import net.sf.acegisecurity.context.SecureContextImpl;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Vector;
+
+
+/**
+ * Tests {@link SecurityInterceptor}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class SecurityInterceptorTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public SecurityInterceptorTests() {
+        super();
+    }
+
+    public SecurityInterceptorTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(SecurityInterceptorTests.class);
+    }
+
+    public void testCallingAPublicMethodFacadeWillNotRepeatSecurityChecksWhenPassedToTheSecuredMethodItFronts()
+        throws Exception {
+        ITargetObject target = makeInterceptedTarget();
+        String result = target.publicMakeLowerCase("HELLO");
+        assertEquals("hello ContextHolder Not Security Aware", result);
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testCallingAPublicMethodWhenPresentingASecureContextButWithoutAnyAuthenticationObject()
+        throws Exception {
+        SecureContext context = new SecureContextImpl();
+        ContextHolder.setContext(context);
+
+        ITargetObject target = makeInterceptedTarget();
+        String result = target.publicMakeLowerCase("HELLO");
+        assertEquals("hello Authentication empty", result);
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testCallingAPublicMethodWhenPresentingAnAuthenticationObjectWillProperlySetItsIsAuthenticatedProperty()
+        throws Exception {
+        SecureContext context = new SecureContextImpl();
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_THIS_IS_NOT_REQUIRED_AS_IT_IS_PUBLIC")});
+        assertTrue(!token.isAuthenticated());
+        context.setAuthentication(token);
+        ContextHolder.setContext(context);
+
+        ITargetObject target = makeInterceptedTarget();
+        String result = target.publicMakeLowerCase("HELLO");
+        assertEquals("hello net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken false",
+            result);
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testDeniesWhenAppropriate() throws Exception {
+        SecureContext context = new SecureContextImpl();
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_NO_BENEFIT_TO_THIS_GRANTED_AUTHORITY")});
+        context.setAuthentication(token);
+        ContextHolder.setContext(context);
+
+        ITargetObject target = makeInterceptedTarget();
+
+        try {
+            target.makeUpperCase("HELLO");
+            fail("Should have thrown AccessDeniedException");
+        } catch (AccessDeniedException expected) {
+            assertTrue(true);
+        }
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testGetters() {
+        MockAccessDecisionManager accessDecision = new MockAccessDecisionManager();
+        MockRunAsManager runAs = new MockRunAsManager();
+        MockAuthenticationManager authManager = new MockAuthenticationManager();
+        MockMethodDefinitionSource methodSource = new MockMethodDefinitionSource(false,
+                true);
+
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setAccessDecisionManager(accessDecision);
+        si.setRunAsManager(runAs);
+        si.setAuthenticationManager(authManager);
+        si.setMethodDefinitionSource(methodSource);
+
+        assertEquals(accessDecision, si.getAccessDecisionManager());
+        assertEquals(runAs, si.getRunAsManager());
+        assertEquals(authManager, si.getAuthenticationManager());
+        assertEquals(methodSource, si.getMethodDefinitionSource());
+    }
+
+    public void testMethodCallWithRunAsReplacement() throws Exception {
+        SecureContext context = new SecureContextImpl();
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_UPPER")});
+        context.setAuthentication(token);
+        ContextHolder.setContext(context);
+
+        ITargetObject target = makeInterceptedTarget();
+        String result = target.makeUpperCase("hello");
+        assertEquals("HELLO net.sf.acegisecurity.MockRunAsAuthenticationToken true",
+            result);
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testMethodCallWithoutRunAsReplacement()
+        throws Exception {
+        SecureContext context = new SecureContextImpl();
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_LOWER")});
+        assertTrue(!token.isAuthenticated());
+        context.setAuthentication(token);
+        ContextHolder.setContext(context);
+
+        ITargetObject target = makeInterceptedTarget();
+        String result = target.makeLowerCase("HELLO");
+
+        // Note we check the isAuthenticated becomes true in following line
+        assertEquals("hello net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken true",
+            result);
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testRejectionOfEmptyContextHolder() throws Exception {
+        ITargetObject target = makeInterceptedTarget();
+
+        try {
+            target.makeUpperCase("hello");
+            fail(
+                "Should have thrown AuthenticationCredentialsNotFoundException");
+        } catch (AuthenticationCredentialsNotFoundException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testRejectionOfNonSecureContextOnContextHolder()
+        throws Exception {
+        ContextHolder.setContext(new ContextImpl());
+
+        ITargetObject target = makeInterceptedTarget();
+
+        try {
+            target.makeUpperCase("hello");
+            fail(
+                "Should have thrown AuthenticationCredentialsNotFoundException");
+        } catch (AuthenticationCredentialsNotFoundException expected) {
+            assertTrue(true);
+        }
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testRejectionOfSecureContextThatContainsNoAuthenticationObject()
+        throws Exception {
+        ContextHolder.setContext(new SecureContextImpl());
+
+        ITargetObject target = makeInterceptedTarget();
+
+        try {
+            target.makeUpperCase("hello");
+            fail(
+                "Should have thrown AuthenticationCredentialsNotFoundException");
+        } catch (AuthenticationCredentialsNotFoundException expected) {
+            assertTrue(true);
+        }
+
+        ContextHolder.setContext(null);
+    }
+
+    public void testStartupCheckForAccessDecisionManager() {
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setRunAsManager(new MockRunAsManager());
+        si.setAuthenticationManager(new MockAuthenticationManager());
+
+        si.setMethodDefinitionSource(new MockMethodDefinitionSource(false, true));
+
+        try {
+            si.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("An AccessDecisionManager is required",
+                expected.getMessage());
+        }
+    }
+
+    public void testStartupCheckForAuthenticationManager() {
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setAccessDecisionManager(new MockAccessDecisionManager());
+        si.setRunAsManager(new MockRunAsManager());
+
+        si.setMethodDefinitionSource(new MockMethodDefinitionSource(false, true));
+
+        try {
+            si.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("An AuthenticationManager is required",
+                expected.getMessage());
+        }
+    }
+
+    public void testStartupCheckForMethodDefinitionSource() {
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setAccessDecisionManager(new MockAccessDecisionManager());
+        si.setRunAsManager(new MockRunAsManager());
+        si.setAuthenticationManager(new MockAuthenticationManager());
+
+        try {
+            si.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("A MethodDefinitionSource is required",
+                expected.getMessage());
+        }
+    }
+
+    public void testStartupCheckForRunAsManager() {
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setAccessDecisionManager(new MockAccessDecisionManager());
+        si.setAuthenticationManager(new MockAuthenticationManager());
+
+        si.setMethodDefinitionSource(new MockMethodDefinitionSource(false, true));
+
+        try {
+            si.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("A RunAsManager is required", expected.getMessage());
+        }
+    }
+
+    public void testValidationFailsIfInvalidAttributePresented() {
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setAccessDecisionManager(new MockAccessDecisionManager());
+        si.setRunAsManager(new MockRunAsManager());
+        si.setAuthenticationManager(new MockAuthenticationManager());
+
+        assertTrue(si.isValidateConfigAttributes()); // check default
+        si.setMethodDefinitionSource(new MockMethodDefinitionSource(true, true));
+
+        try {
+            si.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("Unsupported configuration attributes: [ANOTHER_INVALID, INVALID_ATTRIBUTE]",
+                expected.getMessage());
+        }
+    }
+
+    public void testValidationNotAttemptedIfIsValidateConfigAttributesSetToFalse() {
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setAccessDecisionManager(new MockAccessDecisionManager());
+        si.setRunAsManager(new MockRunAsManager());
+        si.setAuthenticationManager(new MockAuthenticationManager());
+
+        assertTrue(si.isValidateConfigAttributes()); // check default
+        si.setValidateConfigAttributes(false);
+        assertTrue(!si.isValidateConfigAttributes()); // check changed
+
+        si.setMethodDefinitionSource(new MockMethodDefinitionSource(true, true));
+        si.afterPropertiesSet();
+        assertTrue(true);
+    }
+
+    public void testValidationNotAttemptedIfMethodDefinitionSourceCannotReturnIterator() {
+        SecurityInterceptor si = new SecurityInterceptor();
+        si.setAccessDecisionManager(new MockAccessDecisionManager());
+        si.setRunAsManager(new MockRunAsManager());
+        si.setAuthenticationManager(new MockAuthenticationManager());
+
+        assertTrue(si.isValidateConfigAttributes()); // check default
+        si.setMethodDefinitionSource(new MockMethodDefinitionSource(true, false));
+        si.afterPropertiesSet();
+        assertTrue(true);
+    }
+
+    private ITargetObject makeInterceptedTarget() {
+        String PREFIX = "beans.";
+        DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
+        Properties p = new Properties();
+        p.setProperty(PREFIX + "authentication.class",
+            "net.sf.acegisecurity.MockAuthenticationManager");
+        p.setProperty(PREFIX + "accessDecision.class",
+            "net.sf.acegisecurity.MockAccessDecisionManager");
+        p.setProperty(PREFIX + "runAs.class",
+            "net.sf.acegisecurity.MockRunAsManager");
+
+        p.setProperty(PREFIX + "securityInterceptor.class",
+            "net.sf.acegisecurity.SecurityInterceptor");
+        p.setProperty(PREFIX + "securityInterceptor.authenticationManager(ref)",
+            "authentication");
+        p.setProperty(PREFIX + "securityInterceptor.accessDecisionManager(ref)",
+            "accessDecision");
+        p.setProperty(PREFIX + "securityInterceptor.runAsManager(ref)", "runAs");
+        p.setProperty(PREFIX + "securityInterceptor.methodDefinitionSource",
+            "net.sf.acegisecurity.ITargetObject.makeLower*=MOCK_LOWER\r\nnet.sf.acegisecurity.ITargetObject.makeUpper*=MOCK_UPPER,RUN_AS");
+
+        p.setProperty(PREFIX + "targetObject.class",
+            "net.sf.acegisecurity.TargetObject");
+        p.setProperty(PREFIX + "target.class",
+            "org.springframework.aop.framework.ProxyFactoryBean");
+        p.setProperty(PREFIX + "target.proxyInterfaces",
+            "net.sf.acegisecurity.ITargetObject");
+        p.setProperty(PREFIX + "target.interceptorNames",
+            "securityInterceptor,targetObject");
+
+        (new PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p,
+            PREFIX);
+
+        return (ITargetObject) lbf.getBean("target");
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockMethodDefinitionSource implements MethodDefinitionSource {
+        private List list;
+        private boolean returnAnIterator;
+
+        public MockMethodDefinitionSource(boolean includeInvalidAttributes,
+            boolean returnAnIteratorWhenRequested) {
+            returnAnIterator = returnAnIteratorWhenRequested;
+            list = new Vector();
+
+            ConfigAttributeDefinition def1 = new ConfigAttributeDefinition();
+            def1.addConfigAttribute(new SecurityConfig("MOCK_LOWER"));
+            list.add(def1);
+
+            if (includeInvalidAttributes) {
+                ConfigAttributeDefinition def2 = new ConfigAttributeDefinition();
+                def2.addConfigAttribute(new SecurityConfig("MOCK_LOWER"));
+                def2.addConfigAttribute(new SecurityConfig("INVALID_ATTRIBUTE"));
+                list.add(def2);
+            }
+
+            ConfigAttributeDefinition def3 = new ConfigAttributeDefinition();
+            def3.addConfigAttribute(new SecurityConfig("MOCK_UPPER"));
+            def3.addConfigAttribute(new SecurityConfig("RUN_AS"));
+            list.add(def3);
+
+            if (includeInvalidAttributes) {
+                ConfigAttributeDefinition def4 = new ConfigAttributeDefinition();
+                def4.addConfigAttribute(new SecurityConfig("MOCK_SOMETHING"));
+                def4.addConfigAttribute(new SecurityConfig("ANOTHER_INVALID"));
+                list.add(def4);
+            }
+        }
+
+        private MockMethodDefinitionSource() {
+            super();
+        }
+
+        public ConfigAttributeDefinition getAttributes(
+            MethodInvocation invocation) {
+            throw new UnsupportedOperationException(
+                "mock method not implemented");
+        }
+
+        public Iterator getConfigAttributeDefinitions() {
+            if (returnAnIterator) {
+                return list.iterator();
+            } else {
+                return null;
+            }
+        }
+    }
+}

+ 103 - 0
core/src/test/java/org/acegisecurity/TargetObject.java

@@ -0,0 +1,103 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity;
+
+import net.sf.acegisecurity.context.Context;
+import net.sf.acegisecurity.context.ContextHolder;
+import net.sf.acegisecurity.context.SecureContext;
+
+
+/**
+ * Represents a secured object.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class TargetObject implements ITargetObject {
+    //~ Methods ================================================================
+
+    public int countLength(String input) {
+        return input.length();
+    }
+
+    /**
+     * Returns the lowercase string, followed by security environment
+     * information.
+     *
+     * @param input the message to make lowercase
+     *
+     * @return the lowercase message, a space, the <code>Authentication</code>
+     *         class that was on the <code>ContextHolder</code> at the time of
+     *         method invocation, and a boolean indicating if the
+     *         <code>Authentication</code> object is authenticated or not
+     */
+    public String makeLowerCase(String input) {
+        Context context = ContextHolder.getContext();
+
+        if ((context != null) && (context instanceof SecureContext)) {
+            Authentication auth = ((SecureContext) context).getAuthentication();
+
+            if (auth == null) {
+                return input.toLowerCase() + " Authentication empty";
+            } else {
+                return input.toLowerCase() + " " + auth.getClass().getName()
+                + " " + auth.isAuthenticated();
+            }
+        } else {
+            return input.toLowerCase() + " ContextHolder Not Security Aware";
+        }
+    }
+
+    /**
+     * Returns the uppercase string, followed by security environment
+     * information.
+     *
+     * @param input the message to make uppercase
+     *
+     * @return the uppercase message, a space, the <code>Authentication</code>
+     *         class that was on the <code>ContextHolder</code> at the time of
+     *         method invocation, and a boolean indicating if the
+     *         <code>Authentication</code> object is authenticated or not
+     *
+     * @throws AccessDeniedException if for some reason this method was being
+     *         called and the <code>ContextHolder</code> was <code>null</code>
+     *         or did not hold a <code>SecureContext</code>
+     */
+    public String makeUpperCase(String input) {
+        Context context = ContextHolder.getContext();
+
+        if ((context == null) || !(context instanceof SecureContext)) {
+            throw new AccessDeniedException(
+                "For some reason the SecurityInterceptor allowed this call, meaning the ContextHolder should have been populated, but it was not.");
+        }
+
+        Authentication auth = ((SecureContext) context).getAuthentication();
+
+        return input.toUpperCase() + " " + auth.getClass().getName() + " "
+        + auth.isAuthenticated();
+    }
+
+    /**
+     * Delegates through to the {@link #toLowerCase(String)} method.
+     *
+     * @param input the method to be made uppercase
+     *
+     * @return
+     */
+    public String publicMakeLowerCase(String input) {
+        return this.makeLowerCase(input);
+    }
+}

+ 163 - 0
core/src/test/java/org/acegisecurity/adapters/AbstractAdapterAuthenticationTokenTests.java

@@ -0,0 +1,163 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.adapters;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+
+
+/**
+ * Tests {@link AbstractAdapterAuthenticationToken}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AbstractAdapterAuthenticationTokenTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public AbstractAdapterAuthenticationTokenTests() {
+        super();
+    }
+
+    public AbstractAdapterAuthenticationTokenTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AbstractAdapterAuthenticationTokenTests.class);
+    }
+
+    public void testGetters() throws Exception {
+        MockDecisionManagerImpl token = new MockDecisionManagerImpl("my_password",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertEquals("Test", token.getPrincipal());
+        assertEquals("Password", token.getCredentials());
+        assertEquals("my_password".hashCode(), token.getKeyHash());
+    }
+
+    public void testIsUserInRole() throws Exception {
+        MockDecisionManagerImpl token = new MockDecisionManagerImpl("my_password",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(token.isUserInRole("ROLE_ONE"));
+        assertTrue(token.isUserInRole("ROLE_TWO"));
+        assertTrue(!token.isUserInRole(""));
+        assertTrue(!token.isUserInRole("ROLE_ONE "));
+        assertTrue(!token.isUserInRole("role_one"));
+        assertTrue(!token.isUserInRole("ROLE_XXXX"));
+    }
+
+    public void testNoArgsConstructor() {
+        try {
+            new MockDecisionManagerImpl();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testObjectsEquals() throws Exception {
+        MockDecisionManagerImpl token1 = new MockDecisionManagerImpl("my_password",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        MockDecisionManagerImpl token2 = new MockDecisionManagerImpl("my_password",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertEquals(token1, token2);
+
+        MockDecisionManagerImpl token3 = new MockDecisionManagerImpl("my_password",
+                "Test", "Password_Changed",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(!token1.equals(token3));
+
+        MockDecisionManagerImpl token4 = new MockDecisionManagerImpl("my_password",
+                "Test_Changed", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(!token1.equals(token4));
+
+        MockDecisionManagerImpl token5 = new MockDecisionManagerImpl("password_changed",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(!token1.equals(token5));
+
+        MockDecisionManagerImpl token6 = new MockDecisionManagerImpl("my_password",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO_CHANGED")});
+        assertTrue(!token1.equals(token6));
+
+        MockDecisionManagerImpl token7 = new MockDecisionManagerImpl("my_password",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE")});
+        assertTrue(!token1.equals(token7));
+
+        assertTrue(!token1.equals(new Integer(100)));
+    }
+
+    public void testSetAuthenticatedAlwaysReturnsTrue()
+        throws Exception {
+        MockDecisionManagerImpl token = new MockDecisionManagerImpl("my_password",
+                "Test", "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(token.isAuthenticated());
+        token.setAuthenticated(false);
+        assertTrue(token.isAuthenticated());
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockDecisionManagerImpl
+        extends AbstractAdapterAuthenticationToken {
+        private String password;
+        private String username;
+
+        public MockDecisionManagerImpl(String key, String username,
+            String password, GrantedAuthority[] authorities) {
+            super(key, authorities);
+            this.username = username;
+            this.password = password;
+        }
+
+        private MockDecisionManagerImpl() {
+            throw new IllegalArgumentException();
+        }
+
+        public Object getCredentials() {
+            return this.password;
+        }
+
+        public Object getPrincipal() {
+            return this.username;
+        }
+    }
+}

+ 38 - 0
core/src/test/java/org/acegisecurity/adapters/adaptertest-invalid.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+<!--
+ * Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * $Id$
+-->
+
+<beans>
+
+	<!-- Data access object which stores authentication information -->
+	<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
+  		<property name="userMap">
+			<value>
+				marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
+				dianne=emu,ROLE_TELLER
+				scott=wombat,ROLE_TELLER
+				peter=opal,disabled,ROLE_TELLER
+			</value>
+		</property>
+	</bean>
+	
+	<!-- The authentication manager is deliberately missing in order to test error detection -->
+
+</beans>

+ 52 - 0
core/src/test/java/org/acegisecurity/adapters/adaptertest-valid.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+<!--
+ * Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * $Id$
+-->
+
+<beans>
+
+	<!-- Data access object which stores authentication information -->
+	<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
+  		<property name="userMap">
+			<value>
+				marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
+				dianne=emu,ROLE_TELLER
+				scott=wombat,ROLE_TELLER
+				peter=opal,disabled,ROLE_TELLER
+			</value>
+		</property>
+	</bean>
+	
+	<!-- Authentication provider that queries our data access object  -->
+	<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
+     	<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
+ 		<property name="ignorePasswordCase"><value>false</value></property>
+ 		<property name="ignoreUsernameCase"><value>true</value></property>
+	</bean>
+
+	<!-- The authentication manager that iterates through our only authentication provider -->
+	<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
+		<property name="providers">
+		  <list>
+		    <ref bean="daoAuthenticationProvider"/>
+		  </list>
+		</property>
+	</bean>
+
+</beans>

+ 76 - 0
core/src/test/java/org/acegisecurity/context/ContextHolderTests.java

@@ -0,0 +1,76 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests {@link ContextHolder}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class ContextHolderTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public ContextHolderTests() {
+        super();
+    }
+
+    public ContextHolderTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(ContextHolderTests.class);
+    }
+
+    public void testContextHolderGetterSetter() {
+        assertEquals(null, ContextHolder.getContext());
+
+        MockContext context = new MockContext();
+        context.setColour("red");
+        ContextHolder.setContext(context);
+
+        MockContext offContext = (MockContext) ContextHolder.getContext();
+        assertEquals("red", offContext.getColour());
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockContext implements Context {
+        private String colour;
+
+        public void setColour(String colour) {
+            this.colour = colour;
+        }
+
+        public String getColour() {
+            return colour;
+        }
+
+        public void validate() throws ContextInvalidException {
+            return;
+        }
+    }
+}

+ 53 - 0
core/src/test/java/org/acegisecurity/context/ContextImplTests.java

@@ -0,0 +1,53 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests {@link ContextImpl}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class ContextImplTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public ContextImplTests() {
+        super();
+    }
+
+    public ContextImplTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(ContextImplTests.class);
+    }
+
+    public void testConfirmsContextImplHasTheValidateMethod() {
+        Context context = new ContextImpl();
+        context.validate();
+        assertTrue(true);
+    }
+}

+ 106 - 0
core/src/test/java/org/acegisecurity/context/ContextInterceptorTests.java

@@ -0,0 +1,106 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+import junit.framework.TestCase;
+
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
+
+import java.util.Properties;
+
+
+/**
+ * Tests {@link ContextInterceptor}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class ContextInterceptorTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public ContextInterceptorTests() {
+        super();
+    }
+
+    public ContextInterceptorTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(ContextInterceptorTests.class);
+    }
+
+    public ITargetObject makeInterceptedTarget() {
+        String PREFIX = "beans.";
+        DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
+        Properties p = new Properties();
+        p.setProperty(PREFIX + "contextInterceptor.class",
+            "net.sf.acegisecurity.context.ContextInterceptor");
+        p.setProperty(PREFIX + "targetObject.class",
+            "net.sf.acegisecurity.context.TargetObject");
+        p.setProperty(PREFIX + "target.class",
+            "org.springframework.aop.framework.ProxyFactoryBean");
+        p.setProperty(PREFIX + "target.proxyInterfaces",
+            "net.sf.acegisecurity.context.ITargetObject");
+        p.setProperty(PREFIX + "target.interceptorNames",
+            "contextInterceptor,targetObject");
+
+        int count = (new PropertiesBeanDefinitionReader(lbf))
+            .registerBeanDefinitions(p, PREFIX);
+
+        return (ITargetObject) lbf.getBean("target");
+    }
+
+    public void testInterceptorDetectsEmptyContextHolder()
+        throws Exception {
+        ITargetObject target = makeInterceptedTarget();
+
+        try {
+            target.makeUpperCase("hello");
+            fail("Should have thrown ContextHolderEmptyException");
+        } catch (ContextHolderEmptyException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testInterceptorDetectsInvalidContext()
+        throws Exception {
+        ITargetObject target = makeInterceptedTarget();
+        ContextHolder.setContext(new SecureContextImpl()); // Authentication not set
+
+        try {
+            target.makeUpperCase("hello");
+            fail("Should have thrown ContextInvalidException");
+        } catch (ContextInvalidException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testInterceptorNormalOperation() throws Exception {
+        ITargetObject target = makeInterceptedTarget();
+        ContextHolder.setContext(new ContextImpl());
+
+        String result = target.makeUpperCase("hello");
+        assertEquals("HELLO", result);
+    }
+}

+ 28 - 0
core/src/test/java/org/acegisecurity/context/ITargetObject.java

@@ -0,0 +1,28 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+/**
+ * Represents the interface of a secured object.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface ITargetObject {
+    //~ Methods ================================================================
+
+    public String makeUpperCase(String input);
+}

+ 82 - 0
core/src/test/java/org/acegisecurity/context/SecureContextImplTests.java

@@ -0,0 +1,82 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+
+/**
+ * Tests {@link SecureContextImpl}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class SecureContextImplTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public SecureContextImplTests() {
+        super();
+    }
+
+    public SecureContextImplTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(SecureContextImplTests.class);
+    }
+
+    public void testSecureContextCorrectOperation() {
+        SecureContext context = new SecureContextImpl();
+        Authentication auth = new UsernamePasswordAuthenticationToken("marissa",
+                "koala");
+        context.setAuthentication(auth);
+        context.validate();
+        assertEquals(auth, context.getAuthentication());
+    }
+
+    public void testSecureContextDetectsMissingAuthenticationObject() {
+        SecureContext context = new SecureContextImpl();
+
+        try {
+            context.validate();
+            fail("Should have thrown ContextInvalidException");
+        } catch (ContextInvalidException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testSecureContextDetectsNullAuthenticationObject() {
+        SecureContext context = new SecureContextImpl();
+        context.setAuthentication(null);
+
+        try {
+            context.validate();
+            fail("Should have thrown ContextInvalidException");
+        } catch (ContextInvalidException expected) {
+            assertTrue(true);
+        }
+    }
+}

+ 30 - 0
core/src/test/java/org/acegisecurity/context/TargetObject.java

@@ -0,0 +1,30 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+/**
+ * Represents a secured object.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class TargetObject implements ITargetObject {
+    //~ Methods ================================================================
+
+    public String makeUpperCase(String input) {
+        return input.toUpperCase();
+    }
+}

+ 165 - 0
core/src/test/java/org/acegisecurity/providers/AbstractAuthenticationTokenTests.java

@@ -0,0 +1,165 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+
+
+/**
+ * Tests {@link AbstractAuthenticationToken}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AbstractAuthenticationTokenTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public AbstractAuthenticationTokenTests() {
+        super();
+    }
+
+    public AbstractAuthenticationTokenTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AbstractAuthenticationTokenTests.class);
+    }
+
+    public void testGetters() throws Exception {
+        MockAuthenticationImpl token = new MockAuthenticationImpl("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertEquals("Test", token.getPrincipal());
+        assertEquals("Password", token.getCredentials());
+    }
+
+    public void testObjectsEquals() throws Exception {
+        MockAuthenticationImpl token1 = new MockAuthenticationImpl("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        MockAuthenticationImpl token2 = new MockAuthenticationImpl("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertEquals(token1, token2);
+
+        MockAuthenticationImpl token3 = new MockAuthenticationImpl("Test",
+                "Password_Changed",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(!token1.equals(token3));
+
+        MockAuthenticationImpl token4 = new MockAuthenticationImpl("Test_Changed",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(!token1.equals(token4));
+
+        MockAuthenticationImpl token5 = new MockAuthenticationImpl("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO_CHANGED")});
+        assertTrue(!token1.equals(token5));
+
+        MockAuthenticationImpl token6 = new MockAuthenticationImpl("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE")});
+        assertTrue(!token1.equals(token6));
+
+        MockAuthenticationImpl token7 = new MockAuthenticationImpl("Test",
+                "Password", null);
+        assertTrue(!token1.equals(token7));
+        assertTrue(!token7.equals(token1));
+
+        assertTrue(!token1.equals(new Integer(100)));
+    }
+
+    public void testSetAuthenticated() throws Exception {
+        MockAuthenticationImpl token = new MockAuthenticationImpl("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(!token.isAuthenticated());
+        token.setAuthenticated(true);
+        assertTrue(token.isAuthenticated());
+    }
+
+    public void testToStringWithAuthorities() {
+        MockAuthenticationImpl token = new MockAuthenticationImpl("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(token.toString().lastIndexOf("ROLE_TWO") != -1);
+    }
+
+    public void testToStringWithNullAuthorities() {
+        MockAuthenticationImpl token = new MockAuthenticationImpl("Test",
+                "Password", null);
+        assertTrue(token.toString().lastIndexOf("Not granted any authorities") != -1);
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockAuthenticationImpl extends AbstractAuthenticationToken {
+        private Object credentials;
+        private Object principal;
+        private GrantedAuthority[] authorities;
+        private boolean authenticated = false;
+
+        public MockAuthenticationImpl(Object principal, Object credentials,
+            GrantedAuthority[] authorities) {
+            this.principal = principal;
+            this.credentials = credentials;
+            this.authorities = authorities;
+        }
+
+        private MockAuthenticationImpl() {
+            super();
+        }
+
+        public void setAuthenticated(boolean isAuthenticated) {
+            this.authenticated = isAuthenticated;
+        }
+
+        public boolean isAuthenticated() {
+            return this.authenticated;
+        }
+
+        public GrantedAuthority[] getAuthorities() {
+            return this.authorities;
+        }
+
+        public Object getCredentials() {
+            return this.credentials;
+        }
+
+        public Object getPrincipal() {
+            return this.principal;
+        }
+    }
+}

+ 171 - 0
core/src/test/java/org/acegisecurity/providers/ProviderManagerTests.java

@@ -0,0 +1,171 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.AuthenticationException;
+import net.sf.acegisecurity.AuthenticationServiceException;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+
+import java.util.List;
+import java.util.Vector;
+
+
+/**
+ * Tests {@link ProviderManager}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class ProviderManagerTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public ProviderManagerTests() {
+        super();
+    }
+
+    public ProviderManagerTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(ProviderManagerTests.class);
+    }
+
+    public void testAuthenticationFails() throws Exception {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+
+        ProviderManager mgr = makeProviderManager();
+
+        try {
+            mgr.authenticate(token);
+            fail("Should have thrown ProviderNotFoundException");
+        } catch (ProviderNotFoundException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticationSuccess() {
+        TestingAuthenticationToken token = new TestingAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+
+        ProviderManager mgr = makeProviderManager();
+        Authentication result = mgr.authenticate(token);
+
+        if (!(result instanceof TestingAuthenticationToken)) {
+            fail("Should have returned instance of TestingAuthenticationToken");
+        }
+
+        TestingAuthenticationToken castResult = (TestingAuthenticationToken) result;
+        assertEquals("Test", castResult.getPrincipal());
+        assertEquals("Password", castResult.getCredentials());
+        assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
+    }
+
+    public void testStartupFailsIfProviderListDoesNotContainingProviders()
+        throws Exception {
+        List providers = new Vector();
+        providers.add("THIS_IS_NOT_A_PROVIDER");
+
+        ProviderManager mgr = new ProviderManager();
+
+        try {
+            mgr.setProviders(providers);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testStartupFailsIfProviderListNotSet()
+        throws Exception {
+        ProviderManager mgr = new ProviderManager();
+
+        try {
+            mgr.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testStartupFailsIfProviderListNull() throws Exception {
+        ProviderManager mgr = new ProviderManager();
+
+        try {
+            mgr.setProviders(null);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testSuccessfulStartup() throws Exception {
+        ProviderManager mgr = makeProviderManager();
+        mgr.afterPropertiesSet();
+        assertTrue(true);
+        assertEquals(1, mgr.getProviders().size());
+    }
+
+    private ProviderManager makeProviderManager() {
+        MockProvider provider1 = new MockProvider();
+        List providers = new Vector();
+        providers.add(provider1);
+
+        ProviderManager mgr = new ProviderManager();
+        mgr.setProviders(providers);
+
+        return mgr;
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockProvider implements AuthenticationProvider {
+        public Authentication authenticate(Authentication authentication)
+            throws AuthenticationException {
+            if (supports(authentication.getClass())) {
+                return authentication;
+            } else {
+                throw new AuthenticationServiceException(
+                    "Don't support this class");
+            }
+        }
+
+        public boolean supports(Class authentication) {
+            if (TestingAuthenticationToken.class.isAssignableFrom(
+                    authentication)) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+}

+ 76 - 0
core/src/test/java/org/acegisecurity/providers/TestingAuthenticationProviderTests.java

@@ -0,0 +1,76 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+
+
+/**
+ * Tests {@link TestingAuthenticationProvider}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class TestingAuthenticationProviderTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public TestingAuthenticationProviderTests() {
+        super();
+    }
+
+    public TestingAuthenticationProviderTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(TestingAuthenticationProviderTests.class);
+    }
+
+    public void testAuthenticates() {
+        TestingAuthenticationProvider provider = new TestingAuthenticationProvider();
+        TestingAuthenticationToken token = new TestingAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        Authentication result = provider.authenticate(token);
+
+        if (!(result instanceof TestingAuthenticationToken)) {
+            fail("Should have returned instance of TestingAuthenticationToken");
+        }
+
+        TestingAuthenticationToken castResult = (TestingAuthenticationToken) result;
+        assertEquals("Test", castResult.getPrincipal());
+        assertEquals("Password", castResult.getCredentials());
+        assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
+    }
+
+    public void testSupports() {
+        TestingAuthenticationProvider provider = new TestingAuthenticationProvider();
+        assertTrue(provider.supports(TestingAuthenticationToken.class));
+        assertTrue(!provider.supports(String.class));
+    }
+}

+ 78 - 0
core/src/test/java/org/acegisecurity/providers/TestingAuthenticationTokenTests.java

@@ -0,0 +1,78 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+
+
+/**
+ * Tests {@link TestingAuthenticationToken}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class TestingAuthenticationTokenTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public TestingAuthenticationTokenTests() {
+        super();
+    }
+
+    public TestingAuthenticationTokenTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(TestingAuthenticationTokenTests.class);
+    }
+
+    public void testAuthenticated() {
+        TestingAuthenticationToken token = new TestingAuthenticationToken("Test",
+                "Password", null);
+        assertTrue(!token.isAuthenticated());
+        token.setAuthenticated(true);
+        assertTrue(token.isAuthenticated());
+    }
+
+    public void testGetters() {
+        TestingAuthenticationToken token = new TestingAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertEquals("Test", token.getPrincipal());
+        assertEquals("Password", token.getCredentials());
+        assertEquals("ROLE_ONE", token.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", token.getAuthorities()[1].getAuthority());
+    }
+
+    public void testNoArgConstructor() {
+        try {
+            new TestingAuthenticationToken();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+}

+ 91 - 0
core/src/test/java/org/acegisecurity/providers/UsernamePasswordAuthenticationTokenTests.java

@@ -0,0 +1,91 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+
+
+/**
+ * Tests {@link UsernamePasswordAuthenticationToken}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class UsernamePasswordAuthenticationTokenTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public UsernamePasswordAuthenticationTokenTests() {
+        super();
+    }
+
+    public UsernamePasswordAuthenticationTokenTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(UsernamePasswordAuthenticationTokenTests.class);
+    }
+
+    public void testAuthenticated() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password", null);
+        assertTrue(!token.isAuthenticated());
+        token.setAuthenticated(true);
+        assertTrue(token.isAuthenticated());
+    }
+
+    public void testGetters() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertEquals("Test", token.getPrincipal());
+        assertEquals("Password", token.getCredentials());
+        assertEquals("ROLE_ONE", token.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", token.getAuthorities()[1].getAuthority());
+    }
+
+    public void testNewAuthorities() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
+                "Password", null);
+        assertEquals("Test", token.getPrincipal());
+        assertEquals("Password", token.getCredentials());
+        assertEquals(null, token.getAuthorities());
+
+        token.setAuthorities(new GrantedAuthority[] {new GrantedAuthorityImpl(
+                    "ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")});
+        assertEquals("ROLE_ONE", token.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", token.getAuthorities()[1].getAuthority());
+    }
+
+    public void testNoArgConstructor() {
+        try {
+            new UsernamePasswordAuthenticationToken();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+}

+ 266 - 0
core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java

@@ -0,0 +1,266 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.AuthenticationServiceException;
+import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.DisabledException;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.providers.TestingAuthenticationToken;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataRetrievalFailureException;
+
+
+/**
+ * Tests {@link DaoAuthenticationProvider}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class DaoAuthenticationProviderTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public DaoAuthenticationProviderTests() {
+        super();
+    }
+
+    public DaoAuthenticationProviderTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(DaoAuthenticationProviderTests.class);
+    }
+
+    public void testAuthenticateFailsForIncorrectPasswordCase() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
+                "KOala");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
+        assertTrue(!provider.isIgnorePasswordCase()); // default
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown BadCredentialsException");
+        } catch (BadCredentialsException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticateFailsIfUserDisabled() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter",
+                "opal");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserPeter());
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown DisabledException");
+        } catch (DisabledException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticateFailsWhenAuthenticationDaoHasBackendFailure() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
+                "koala");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoSimulateBackendError());
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown AuthenticationServiceException");
+        } catch (AuthenticationServiceException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticateFailsWithInvalidPassword() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
+                "INVALID_PASSWORD");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown BadCredentialsException");
+        } catch (BadCredentialsException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticateFailsWithInvalidUsername() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("INVALID_USER",
+                "koala");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown BadCredentialsException");
+        } catch (BadCredentialsException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticateFailsWithMixedCaseUsernameIfDefaultChanged() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("MaRiSSA",
+                "koala");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
+        assertTrue(provider.isIgnoreUsernameCase()); // default
+        provider.setIgnoreUsernameCase(false);
+        assertTrue(!provider.isIgnoreUsernameCase()); // changed
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown BadCredentialsException");
+        } catch (BadCredentialsException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticateSuccessfulWithMixedCaseIfDefaultChanged() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
+                "KOAla");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
+        assertTrue(!provider.isIgnorePasswordCase()); // default
+        provider.setIgnorePasswordCase(true);
+        assertTrue(provider.isIgnorePasswordCase()); // changed
+
+        Authentication result = provider.authenticate(token);
+        assertEquals("marissa", result.getPrincipal().toString());
+    }
+
+    public void testAuthenticateSuccessfulWithMixedCaseUsername() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("MaRiSSA",
+                "koala");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
+        assertTrue(provider.isIgnoreUsernameCase()); // default
+
+        Authentication result = provider.authenticate(token);
+        assertEquals("marissa", result.getPrincipal().toString());
+    }
+
+    public void testAuthenticates() {
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
+                "koala");
+
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
+
+        Authentication result = provider.authenticate(token);
+
+        if (!(result instanceof UsernamePasswordAuthenticationToken)) {
+            fail(
+                "Should have returned instance of UsernamePasswordAuthenticationToken");
+        }
+
+        UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
+        assertEquals("marissa", castResult.getPrincipal());
+        assertEquals("koala", castResult.getCredentials());
+        assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
+    }
+
+    public void testStartupFailsIfNoAuthenticationDao()
+        throws Exception {
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+
+        try {
+            provider.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testStartupSuccess() throws Exception {
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        AuthenticationDao dao = new MockAuthenticationDaoUserMarissa();
+        provider.setAuthenticationDao(dao);
+        assertEquals(dao, provider.getAuthenticationDao());
+        provider.afterPropertiesSet();
+        assertTrue(true);
+    }
+
+    public void testSupports() {
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class));
+        assertTrue(!provider.supports(TestingAuthenticationToken.class));
+    }
+
+    //~ Inner Classes ==========================================================
+
+    private class MockAuthenticationDaoSimulateBackendError
+        implements AuthenticationDao {
+        public User loadUserByUsername(String username)
+            throws UsernameNotFoundException, DataAccessException {
+            throw new DataRetrievalFailureException(
+                "This mock simulator is designed to fail");
+        }
+    }
+
+    private class MockAuthenticationDaoUserMarissa implements AuthenticationDao {
+        public User loadUserByUsername(String username)
+            throws UsernameNotFoundException, DataAccessException {
+            if ("marissa".equals(username.toLowerCase())) {
+                return new User("marissa", "koala", true,
+                    new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                            "ROLE_TWO")});
+            } else {
+                throw new UsernameNotFoundException("Could not find: "
+                    + username);
+            }
+        }
+    }
+
+    private class MockAuthenticationDaoUserPeter implements AuthenticationDao {
+        public User loadUserByUsername(String username)
+            throws UsernameNotFoundException, DataAccessException {
+            if ("peter".equals(username.toLowerCase())) {
+                return new User("peter", "opal", false,
+                    new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                            "ROLE_TWO")});
+            } else {
+                throw new UsernameNotFoundException("Could not find: "
+                    + username);
+            }
+        }
+    }
+}

+ 102 - 0
core/src/test/java/org/acegisecurity/providers/dao/UserTests.java

@@ -0,0 +1,102 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+
+
+/**
+ * Tests {@link User}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class UserTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public UserTests() {
+        super();
+    }
+
+    public UserTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(UserTests.class);
+    }
+
+    public void testNoArgsConstructor() throws Exception {
+        User user = new User();
+        assertTrue(true);
+    }
+
+    public void testNullValuesRejected() throws Exception {
+        try {
+            User user = new User(null, "koala", true,
+                    new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                            "ROLE_TWO")});
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+
+        try {
+            User user = new User("marissa", null, true,
+                    new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                            "ROLE_TWO")});
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+
+        try {
+            User user = new User("marissa", "koala", true, null);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testUserGettersSetter() throws Exception {
+        User user = new User("marissa", "koala", true,
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertEquals("marissa", user.getUsername());
+        assertEquals("koala", user.getPassword());
+        assertTrue(user.isEnabled());
+        assertEquals(new GrantedAuthorityImpl("ROLE_ONE"),
+            user.getAuthorities()[0]);
+        assertEquals(new GrantedAuthorityImpl("ROLE_TWO"),
+            user.getAuthorities()[1]);
+    }
+
+    public void testUserIsEnabled() throws Exception {
+        User user = new User("marissa", "koala", false,
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        assertTrue(!user.isEnabled());
+    }
+}

+ 135 - 0
core/src/test/java/org/acegisecurity/providers/dao/memory/UserAttributeEditorTests.java

@@ -0,0 +1,135 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao.memory;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests {@link UserAttributeEditor} and associated {@link
+ * UserAttributeDefinition}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class UserAttributeEditorTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public UserAttributeEditorTests() {
+        super();
+    }
+
+    public UserAttributeEditorTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(UserAttributeEditorTests.class);
+    }
+
+    public void testCorrectOperationWithoutEnabledDisabledKeyword() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText("password,ROLE_ONE,ROLE_TWO");
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user.isValid());
+        assertTrue(user.isEnabled()); // default
+        assertEquals("password", user.getPassword());
+        assertEquals(2, user.getAuthorities().length);
+        assertEquals("ROLE_ONE", user.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", user.getAuthorities()[1].getAuthority());
+    }
+
+    public void testDisabledKeyword() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText("password,disabled,ROLE_ONE,ROLE_TWO");
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user.isValid());
+        assertTrue(!user.isEnabled());
+        assertEquals("password", user.getPassword());
+        assertEquals(2, user.getAuthorities().length);
+        assertEquals("ROLE_ONE", user.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", user.getAuthorities()[1].getAuthority());
+    }
+
+    public void testEmptyStringReturnsNull() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText("");
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user == null);
+    }
+
+    public void testEnabledKeyword() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText("password,ROLE_ONE,enabled,ROLE_TWO");
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user.isValid());
+        assertTrue(user.isEnabled());
+        assertEquals("password", user.getPassword());
+        assertEquals(2, user.getAuthorities().length);
+        assertEquals("ROLE_ONE", user.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO", user.getAuthorities()[1].getAuthority());
+    }
+
+    public void testMalformedStringReturnsNull() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText("MALFORMED_STRING");
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user == null);
+    }
+
+    public void testNoPasswordOrRolesReturnsNull() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText("disabled");
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user == null);
+    }
+
+    public void testNoRolesReturnsNull() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText("password,enabled");
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user == null);
+    }
+
+    public void testNullReturnsNull() {
+        UserAttributeEditor editor = new UserAttributeEditor();
+        editor.setAsText(null);
+
+        UserAttributeDefinition user = (UserAttributeDefinition) editor
+            .getValue();
+        assertTrue(user == null);
+    }
+}

+ 103 - 0
core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapEditorTests.java

@@ -0,0 +1,103 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao.memory;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests {@link UserMapEditor}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class UserMapEditorTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public UserMapEditorTests() {
+        super();
+    }
+
+    public UserMapEditorTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(UserMapEditorTests.class);
+    }
+
+    public void testConvertedIntoUserSuccessfullyWhenDisabled() {
+        UserMapEditor editor = new UserMapEditor();
+        editor.setAsText("marissa=koala,ROLE_ONE,ROLE_TWO,disabled");
+
+        UserMap map = (UserMap) editor.getValue();
+        assertTrue(!map.getUser("marissa").isEnabled());
+    }
+
+    public void testConvertedIntoUserSuccessfullyWhenEnabled() {
+        UserMapEditor editor = new UserMapEditor();
+        editor.setAsText("marissa=koala,ROLE_ONE,ROLE_TWO");
+
+        UserMap map = (UserMap) editor.getValue();
+        assertEquals("marissa", map.getUser("marissa").getUsername());
+        assertEquals("koala", map.getUser("marissa").getPassword());
+        assertEquals("ROLE_ONE",
+            map.getUser("marissa").getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_TWO",
+            map.getUser("marissa").getAuthorities()[1].getAuthority());
+        assertTrue(map.getUser("marissa").isEnabled());
+    }
+
+    public void testEmptyStringReturnsEmptyMap() {
+        UserMapEditor editor = new UserMapEditor();
+        editor.setAsText("");
+
+        UserMap map = (UserMap) editor.getValue();
+        assertEquals(0, map.getUserCount());
+    }
+
+    public void testMalformedStringReturnsEmptyMap() {
+        UserMapEditor editor = new UserMapEditor();
+        editor.setAsText("MALFORMED_STRING");
+
+        UserMap map = (UserMap) editor.getValue();
+        assertEquals(0, map.getUserCount());
+    }
+
+    public void testMultiUserParsing() {
+        UserMapEditor editor = new UserMapEditor();
+        editor.setAsText(
+            "marissa=koala,ROLE_ONE,ROLE_TWO,enabled\r\nscott=wombat,ROLE_ONE,ROLE_TWO,enabled");
+
+        UserMap map = (UserMap) editor.getValue();
+        assertEquals("marissa", map.getUser("marissa").getUsername());
+        assertEquals("scott", map.getUser("scott").getUsername());
+    }
+
+    public void testNullReturnsEmptyMap() {
+        UserMapEditor editor = new UserMapEditor();
+        editor.setAsText(null);
+
+        UserMap map = (UserMap) editor.getValue();
+        assertEquals(0, map.getUserCount());
+    }
+}

+ 102 - 0
core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java

@@ -0,0 +1,102 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao.memory;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
+
+
+/**
+ * Tests {@link UserMap}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class UserMapTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public UserMapTests() {
+        super();
+    }
+
+    public UserMapTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(UserMapTests.class);
+    }
+
+    public void testAddAndRetrieveUser() {
+        User marissa = new User("marissa", "koala", true,
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        User scott = new User("scott", "wombat", true,
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_THREE")});
+        User peter = new User("peter", "opal", true,
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_FOUR")});
+        UserMap map = new UserMap();
+        map.addUser(marissa);
+        map.addUser(scott);
+        map.addUser(peter);
+        assertEquals(3, map.getUserCount());
+
+        assertEquals(marissa, map.getUser("marissa"));
+        assertEquals(scott, map.getUser("scott"));
+        assertEquals(peter, map.getUser("peter"));
+    }
+
+    public void testNullUserCannotBeAdded() {
+        UserMap map = new UserMap();
+        assertEquals(0, map.getUserCount());
+
+        try {
+            map.addUser(null);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testUnknownUserIsNotRetrieved() {
+        User marissa = new User("marissa", "koala", true,
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")});
+        UserMap map = new UserMap();
+        assertEquals(0, map.getUserCount());
+        map.addUser(marissa);
+        assertEquals(1, map.getUserCount());
+
+        try {
+            map.getUser("scott");
+            fail("Should have thrown UsernameNotFoundException");
+        } catch (UsernameNotFoundException expected) {
+            assertTrue(true);
+        }
+    }
+}

+ 113 - 0
core/src/test/java/org/acegisecurity/runas/RunAsImplAuthenticationProviderTests.java

@@ -0,0 +1,113 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.runas;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.providers.TestingAuthenticationToken;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+
+/**
+ * Tests {@link RunAsImplAuthenticationProvider}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class RunAsImplAuthenticationProviderTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public RunAsImplAuthenticationProviderTests() {
+        super();
+    }
+
+    public RunAsImplAuthenticationProviderTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(RunAsImplAuthenticationProviderTests.class);
+    }
+
+    public void testAuthenticationFailDueToWrongKey() {
+        RunAsUserToken token = new RunAsUserToken("WRONG_PASSWORD", "Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")}, UsernamePasswordAuthenticationToken.class);
+        RunAsImplAuthenticationProvider provider = new RunAsImplAuthenticationProvider();
+        provider.setKey("hello_world");
+
+        try {
+            provider.authenticate(token);
+            fail("Should have thrown BadCredentialsException");
+        } catch (BadCredentialsException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testAuthenticationSuccess() {
+        RunAsUserToken token = new RunAsUserToken("my_password", "Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")}, UsernamePasswordAuthenticationToken.class);
+        RunAsImplAuthenticationProvider provider = new RunAsImplAuthenticationProvider();
+        provider.setKey("my_password");
+
+        Authentication result = provider.authenticate(token);
+
+        if (!(result instanceof RunAsUserToken)) {
+            fail("Should have returned RunAsUserToken");
+        }
+
+        RunAsUserToken resultCast = (RunAsUserToken) result;
+        assertEquals("my_password".hashCode(), resultCast.getKeyHash());
+    }
+
+    public void testStartupFailsIfNoKey() throws Exception {
+        RunAsImplAuthenticationProvider provider = new RunAsImplAuthenticationProvider();
+
+        try {
+            provider.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testStartupSuccess() throws Exception {
+        RunAsImplAuthenticationProvider provider = new RunAsImplAuthenticationProvider();
+        provider.setKey("hello_world");
+        assertEquals("hello_world", provider.getKey());
+        provider.afterPropertiesSet();
+        assertTrue(true);
+    }
+
+    public void testSupports() {
+        RunAsImplAuthenticationProvider provider = new RunAsImplAuthenticationProvider();
+        assertTrue(provider.supports(RunAsUserToken.class));
+        assertTrue(!provider.supports(TestingAuthenticationToken.class));
+    }
+}

+ 128 - 0
core/src/test/java/org/acegisecurity/runas/RunAsManagerImplTests.java

@@ -0,0 +1,128 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.runas;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.ConfigAttributeDefinition;
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.RunAsManager;
+import net.sf.acegisecurity.SecurityConfig;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+
+/**
+ * Tests {@link RunAsManagerImpl}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class RunAsManagerImplTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public RunAsManagerImplTests() {
+        super();
+    }
+
+    public RunAsManagerImplTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(RunAsManagerImplTests.class);
+    }
+
+    public void testDoesNotReturnAdditionalAuthoritiesIfCalledWithoutARunAsSetting()
+        throws Exception {
+        ConfigAttributeDefinition def = new ConfigAttributeDefinition();
+        def.addConfigAttribute(new SecurityConfig("SOMETHING_WE_IGNORE"));
+
+        UsernamePasswordAuthenticationToken inputToken = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")});
+
+        RunAsManagerImpl runAs = new RunAsManagerImpl();
+        runAs.setKey("my_password");
+
+        Authentication resultingToken = runAs.buildRunAs(inputToken, null, def);
+        assertEquals(null, resultingToken);
+    }
+
+    public void testReturnsAdditionalGrantedAuthorities()
+        throws Exception {
+        ConfigAttributeDefinition def = new ConfigAttributeDefinition();
+        def.addConfigAttribute(new SecurityConfig("RUN_AS_SOMETHING"));
+
+        UsernamePasswordAuthenticationToken inputToken = new UsernamePasswordAuthenticationToken("Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")});
+
+        RunAsManagerImpl runAs = new RunAsManagerImpl();
+        runAs.setKey("my_password");
+
+        Authentication resultingToken = runAs.buildRunAs(inputToken, null, def);
+
+        if (!(resultingToken instanceof RunAsUserToken)) {
+            fail("Should have returned a RunAsUserToken");
+        }
+
+        assertEquals(inputToken.getPrincipal(), resultingToken.getPrincipal());
+        assertEquals(inputToken.getCredentials(),
+            resultingToken.getCredentials());
+        assertEquals("ROLE_RUN_AS_SOMETHING",
+            resultingToken.getAuthorities()[0].getAuthority());
+        assertEquals("ROLE_ONE",
+            resultingToken.getAuthorities()[1].getAuthority());
+        assertEquals("ROLE_TWO",
+            resultingToken.getAuthorities()[2].getAuthority());
+
+        RunAsUserToken resultCast = (RunAsUserToken) resultingToken;
+        assertEquals("my_password".hashCode(), resultCast.getKeyHash());
+    }
+
+    public void testStartupDetectsMissingKey() throws Exception {
+        RunAsManagerImpl runAs = new RunAsManagerImpl();
+
+        try {
+            runAs.afterPropertiesSet();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testStartupSuccessfulWithKey() throws Exception {
+        RunAsManagerImpl runAs = new RunAsManagerImpl();
+        runAs.setKey("hello_world");
+        runAs.afterPropertiesSet();
+        assertEquals("hello_world", runAs.getKey());
+    }
+
+    public void testSupports() throws Exception {
+        RunAsManager runAs = new RunAsManagerImpl();
+        assertTrue(runAs.supports(new SecurityConfig("RUN_AS_SOMETHING")));
+        assertTrue(!runAs.supports(new SecurityConfig("ROLE_WHICH_IS_IGNORED")));
+        assertTrue(!runAs.supports(new SecurityConfig("role_LOWER_CASE_FAILS")));
+    }
+}

+ 90 - 0
core/src/test/java/org/acegisecurity/runas/RunAsUserTokenTests.java

@@ -0,0 +1,90 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.runas;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.GrantedAuthority;
+import net.sf.acegisecurity.GrantedAuthorityImpl;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+
+/**
+ * Tests {@link RunAsUserToken}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class RunAsUserTokenTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public RunAsUserTokenTests() {
+        super();
+    }
+
+    public RunAsUserTokenTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(RunAsUserTokenTests.class);
+    }
+
+    public void testAuthenticationSettingAlwaysReturnsTrue() {
+        RunAsUserToken token = new RunAsUserToken("my_password", "Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")}, UsernamePasswordAuthenticationToken.class);
+        assertTrue(token.isAuthenticated());
+        token.setAuthenticated(false);
+        assertTrue(token.isAuthenticated());
+    }
+
+    public void testGetters() {
+        RunAsUserToken token = new RunAsUserToken("my_password", "Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")}, UsernamePasswordAuthenticationToken.class);
+        assertEquals("Test", token.getPrincipal());
+        assertEquals("Password", token.getCredentials());
+        assertEquals("my_password".hashCode(), token.getKeyHash());
+        assertEquals(UsernamePasswordAuthenticationToken.class,
+            token.getOriginalAuthentication());
+    }
+
+    public void testNoArgsConstructor() {
+        try {
+            new RunAsUserToken();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
+    }
+
+    public void testToString() {
+        RunAsUserToken token = new RunAsUserToken("my_password", "Test",
+                "Password",
+                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
+                        "ROLE_TWO")}, UsernamePasswordAuthenticationToken.class);
+        assertTrue(token.toString().lastIndexOf("Original Class:") != -1);
+    }
+}