Compare commits
120 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 37fb78baf8 | |||
| 2ed9723b9a | |||
| f935830cdf | |||
| ee04b189b7 | |||
| 8661e17df9 | |||
| c45b4e0989 | |||
| 0f8ea229c2 | |||
| 5102be3a59 | |||
| de379dc2ac | |||
| 09c70bb28e | |||
| 4e2d6f8b2e | |||
| d781deffe7 | |||
| a4e4120443 | |||
| 83868a7334 | |||
| 150f3d97d0 | |||
| 7f28a8bc5d | |||
| 1cfd886517 | |||
| bb457e1d07 | |||
| 09cf90258f | |||
| e15d7a78cd | |||
| 3bf5e406b7 | |||
| 6a68a2531c | |||
| 959cdd8335 | |||
| 8e0a6b9d1a | |||
| 827d0e1ebf | |||
| 55d357f42d | |||
| d9ab0758ee | |||
| 36b35e3b1f | |||
| 39a656eb78 | |||
| b6dec19e90 | |||
| 69e776f581 | |||
| 3ab9fcdcaf | |||
| 5e3204a5cb | |||
| 6409f140e0 | |||
| 130e70373f | |||
| 3a9eb018ba | |||
| 8b376ccdeb | |||
| b3a23b4377 | |||
| 7461d0e5f1 | |||
| 566f656eba | |||
| e5d2578aec | |||
| fb3d0b7f25 | |||
| 2d0b594a97 | |||
| 42af39a59e | |||
| 930be9338b | |||
| c1a6ae0832 | |||
| c49bc7ffbb | |||
| 25814d341d | |||
| 21eb70c576 | |||
| e951c42c2b | |||
| 7258d30e13 | |||
| 22a64c1555 | |||
| ff13df03ac | |||
| ecd63cabda | |||
| f31bcbee07 | |||
| 3ee3591feb | |||
| fbeb47d559 | |||
| 1c9c8f0883 | |||
| f821b0f0f8 | |||
| 4165e15861 | |||
| aa75b2fa6d | |||
| d6918c88a7 | |||
| b6d088e40d | |||
| 069a75b8fc | |||
| 1af7eed433 | |||
| e982e91846 | |||
| 54ac7b3e46 | |||
| 3049b933d9 | |||
| c8b22d8e36 | |||
| 1d96283876 | |||
| ef44bd91f2 | |||
| d7926f3557 | |||
| e5d86b13b7 | |||
| 3393ea7aaa | |||
| 67e5afbb79 | |||
| 000bb1cbed | |||
| 243c4f22d4 | |||
| d4c105d8ba | |||
| f6ff958411 | |||
| 4bb3eb12c3 | |||
| f538a36cd3 | |||
| 6e06789a28 | |||
| 6b45eda37c | |||
| f453264bde | |||
| 1ddc033fe5 | |||
| e303e8b71a | |||
| bf5896600e | |||
| b4c63db680 | |||
| a56c13fb22 | |||
| 697c7c5f48 | |||
| b32a418175 | |||
| 4cebc67088 | |||
| fbc7c31b5e | |||
| 7dc998196a | |||
| 768219af81 | |||
| 7039bfdfbe | |||
| d13b32c77f | |||
| dce709a669 | |||
| d9634bcb39 | |||
| 8fe1b4b402 | |||
| 30f1e5729a | |||
| 6d179122d3 | |||
| bd4ed794ea | |||
| 2cda6242c8 | |||
| 479693ced7 | |||
| d5df35f739 | |||
| b99a5dec29 | |||
| e1fcacbca5 | |||
| bf45ff94e7 | |||
| c372c2df87 | |||
| dd5edbcce9 | |||
| 3a25766da1 | |||
| 6ff0b969d5 | |||
| 775a6c3939 | |||
| 87d50aecce | |||
| 125f5911c0 | |||
| 57558de3ec | |||
| 456e737d31 | |||
| 66008817c4 | |||
| 5ec06778f5 |
+8
-2
@@ -3,13 +3,12 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<name>Spring Security - ACL module</name>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
@@ -25,6 +24,13 @@
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides an abstract base for standard {@link Permission} instances that wish to offer static convenience
|
||||
* methods to callers via delegation to {@link DefaultPermissionFactory}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractRegisteredPermission extends AbstractPermission {
|
||||
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
protected AbstractRegisteredPermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
|
||||
protected final static void registerPermissionsFor(Class subClass) {
|
||||
defaultPermissionFactory.registerPublicPermissions(subClass);
|
||||
}
|
||||
|
||||
public final static Permission buildFromMask(int mask) {
|
||||
return defaultPermissionFactory.buildFromMask(mask);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromMask(int[] masks) {
|
||||
return defaultPermissionFactory.buildFromMask(masks);
|
||||
}
|
||||
|
||||
public final static Permission buildFromName(String name) {
|
||||
return defaultPermissionFactory.buildFromName(name);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromName(String[] names) {
|
||||
return defaultPermissionFactory.buildFromName(names);
|
||||
}
|
||||
}
|
||||
@@ -28,14 +28,16 @@ import org.springframework.security.acls.Permission;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class BasePermission extends AbstractRegisteredPermission {
|
||||
public class BasePermission extends AbstractPermission {
|
||||
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
|
||||
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
|
||||
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
|
||||
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
|
||||
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
|
||||
|
||||
/**
|
||||
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
/**
|
||||
* Registers the public static permissions defined on this class. This is mandatory so
|
||||
* that the static methods will operate correctly.
|
||||
*/
|
||||
@@ -46,4 +48,25 @@ public class BasePermission extends AbstractRegisteredPermission {
|
||||
protected BasePermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
}
|
||||
|
||||
protected final static void registerPermissionsFor(Class subClass) {
|
||||
defaultPermissionFactory.registerPublicPermissions(subClass);
|
||||
}
|
||||
|
||||
public final static Permission buildFromMask(int mask) {
|
||||
return defaultPermissionFactory.buildFromMask(mask);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromMask(int[] masks) {
|
||||
return defaultPermissionFactory.buildFromMask(masks);
|
||||
}
|
||||
|
||||
public final static Permission buildFromName(String name) {
|
||||
return defaultPermissionFactory.buildFromName(name);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromName(String[] names) {
|
||||
return defaultPermissionFactory.buildFromName(names);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,12 +18,14 @@ import java.lang.reflect.Field;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -173,14 +175,33 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
Field field = FieldUtils.getField(AclImpl.class, "aces");
|
||||
|
||||
Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
|
||||
Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
|
||||
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
field.set(result, field.get(inputAcl));
|
||||
fieldAces.setAccessible(true);
|
||||
fieldAcl.setAccessible(true);
|
||||
|
||||
// Obtain the "aces" from the input ACL
|
||||
Iterator i = ((List) fieldAces.get(inputAcl)).iterator();
|
||||
|
||||
// Create a list in which to store the "aces" for the "result" AclImpl instance
|
||||
List acesNew = new ArrayList();
|
||||
|
||||
// Iterate over the "aces" input and replace each nested AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
|
||||
// This ensures StubAclParent instances are removed, as per SEC-951
|
||||
while(i.hasNext()) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) i.next();
|
||||
fieldAcl.set(ace, result);
|
||||
acesNew.add(ace);
|
||||
}
|
||||
|
||||
// Finally, now that the "aces" have been converted to have the "result" AclImpl instance, modify the "result" AclImpl instance
|
||||
fieldAces.set(result, acesNew);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not obtain or set AclImpl.ace field");
|
||||
throw new IllegalStateException("Could not obtain or set AclImpl or AccessControlEntryImpl fields");
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,12 @@ public class PermissionTests {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void basePermissionTest() {
|
||||
Permission p = BasePermission.buildFromName("WRITE");
|
||||
assertNotNull(p);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expectedIntegerValues() {
|
||||
assertEquals(1, BasePermission.READ.getMask());
|
||||
|
||||
@@ -53,7 +53,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken(null, "password", null);
|
||||
Authentication authentication = new TestingAuthenticationToken(null, "password");
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
@@ -128,15 +128,15 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testPrincipalSidEquals() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
|
||||
Assert.assertFalse(principalSid.equals(null));
|
||||
Assert.assertFalse(principalSid.equals("DIFFERENT_TYPE_OBJECT"));
|
||||
Assert.assertTrue(principalSid.equals(principalSid));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(authentication)));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null, null))));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null, null))));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null))));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null))));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid("johndoe")));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid("scott")));
|
||||
}
|
||||
@@ -156,14 +156,13 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testPrincipalSidHashCode() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
|
||||
Assert.assertTrue(principalSid.hashCode() == new String("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() == new PrincipalSid("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid("scott").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password",
|
||||
null)).hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
|
||||
}
|
||||
|
||||
public void testGrantedAuthoritySidHashCode() throws Exception {
|
||||
@@ -177,7 +176,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testGetters() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
PrincipalSid principalSid = new PrincipalSid(authentication);
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-catalina</artifactId>
|
||||
<name>Spring Security - Catalina adapter</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jboss</artifactId>
|
||||
<name>Spring Security - JBoss adapter</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jetty</artifactId>
|
||||
<name>Spring Security - Jetty adapter</name>
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<name>Spring Security - Adapters</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-resin</artifactId>
|
||||
<name>Spring Security - Resin adapter</name>
|
||||
|
||||
+8
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-cas-client</artifactId>
|
||||
<name>Spring Security - CAS support</name>
|
||||
@@ -15,6 +15,13 @@
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-dao</artifactId>
|
||||
|
||||
+7
-2
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core-tiger</artifactId>
|
||||
@@ -21,7 +21,12 @@
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-remoting</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
|
||||
+4
-2
@@ -39,8 +39,10 @@ public interface BusinessService {
|
||||
public void someUserMethod1();
|
||||
|
||||
@Secured({"ROLE_USER"})
|
||||
@RolesAllowed({"ROLE_USER"})
|
||||
@RolesAllowed({"ROLE_USER"})
|
||||
public void someUserMethod2();
|
||||
|
||||
|
||||
public int someOther(String s);
|
||||
|
||||
public int someOther(int input);
|
||||
}
|
||||
|
||||
+7
-3
@@ -26,7 +26,11 @@ public class BusinessServiceImpl<E extends Entity> implements BusinessService {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public int someOther(int input) {
|
||||
return input;
|
||||
}
|
||||
public int someOther(String s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int someOther(int input) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -27,7 +27,11 @@ public class Jsr250BusinessServiceImpl implements BusinessService {
|
||||
public void someAdminMethod() {
|
||||
}
|
||||
|
||||
public int someOther(String input) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int someOther(int input) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
+108
-14
@@ -1,13 +1,12 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.security.config.ConfigTestUtils.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
@@ -15,10 +14,12 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
@@ -27,29 +28,36 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private BusinessService target;
|
||||
|
||||
public void loadContext() {
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/global-method-security.xml");
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>" +
|
||||
" <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
target = null;
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
loadContext();
|
||||
loadContext();
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER")});
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
@@ -57,20 +65,19 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
loadContext();
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doesntInterfereWithBeanPostProcessing() {
|
||||
setContext(
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<global-method-security />" +
|
||||
// "<http auto-config='true'/>" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>" +
|
||||
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
|
||||
);
|
||||
@@ -79,7 +86,75 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithAspectJAutoproxy() {
|
||||
setContext(
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'" +
|
||||
" access='ROLE_SOMETHING' />" +
|
||||
"</global-method-security>" +
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<aop:aspectj-autoproxy />" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>"
|
||||
);
|
||||
|
||||
UserDetailsService service = (UserDetailsService) appContext.getBean("myUserService");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
service.loadUserByUsername("notused");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsMethodArgumentsInPointcut() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.*(..))' access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// someOther(int) should not be matched by someOther(String), but should require ROLE_USER
|
||||
target.someOther(0);
|
||||
|
||||
try {
|
||||
// String version should required admin role
|
||||
target.someOther("somestring");
|
||||
fail("Expected AccessDeniedException");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsBooleanPointcutExpressions() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression=" +
|
||||
" 'execution(* org.springframework.security.annotation.BusinessService.*(..)) " +
|
||||
" and not execution(* org.springframework.security.annotation.BusinessService.someOther(String)))' " +
|
||||
" access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// String method should not be protected
|
||||
target.someOther("somestring");
|
||||
|
||||
// All others should require ROLE_USER
|
||||
try {
|
||||
target.someOther(0);
|
||||
fail("Expected AuthenticationCredentialsNotFoundException");
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() {
|
||||
setContext(
|
||||
@@ -87,8 +162,27 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
"<global-method-security />"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithoutTargetOrClass() {
|
||||
setContext(
|
||||
"<global-method-security secured-annotations='enabled'/>" +
|
||||
"<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>" +
|
||||
" <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>" +
|
||||
" <b:property name='serviceInterface' value='org.springframework.security.annotation.BusinessService'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
target = (BusinessService) appContext.getBean("businessService");
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+8
-5
@@ -3,7 +3,6 @@ package org.springframework.security.config;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
@@ -11,19 +10,23 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
private ClassPathXmlApplicationContext appContext;
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new ClassPathXmlApplicationContext("/org/springframework/security/config/jsr250-annotated-method-security.xml");
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
|
||||
"<global-method-security jsr250-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@@ -48,7 +51,7 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
@@ -66,4 +69,4 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -3,7 +3,6 @@ package org.springframework.security.config;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
@@ -11,19 +10,23 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecuredAnnotationDrivenBeanDefinitionParserTests {
|
||||
private ClassPathXmlApplicationContext appContext;
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/secured-annotated-method-security.xml");
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
|
||||
"<global-method-security secured-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<b:bean id="target" class="org.springframework.security.annotation.BusinessServiceImpl"/>
|
||||
|
||||
<global-method-security>
|
||||
<protect-pointcut expression="execution(* *.someUser*(..))" access="ROLE_USER"/>
|
||||
<protect-pointcut expression="execution(* *.someAdmin*(..))" access="ROLE_ADMIN"/>
|
||||
</global-method-security>
|
||||
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
|
||||
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
|
||||
</b:beans>
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<b:bean id="target" class="org.springframework.security.annotation.Jsr250BusinessServiceImpl"/>
|
||||
|
||||
<global-method-security jsr250-annotations="enabled"/>
|
||||
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
|
||||
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
|
||||
</b:beans>
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<b:bean id="target" class="org.springframework.security.annotation.Jsr250BusinessServiceImpl"/>
|
||||
|
||||
<global-method-security secured-annotations="enabled"/>
|
||||
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
|
||||
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
|
||||
</b:beans>
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.3-SNAPSHOT</version>
|
||||
<version>2.0.4</version>
|
||||
</parent>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
|
||||
@@ -21,8 +21,13 @@ import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Basic concrete implementation of a {@link GrantedAuthority}.<p>Stores a <code>String</code> representation of an
|
||||
* authority granted to the {@link Authentication} object.</p>
|
||||
* Basic concrete implementation of a {@link GrantedAuthority}.
|
||||
*
|
||||
* <p>
|
||||
* Stores a <code>String</code> representation of an authority granted to the {@link Authentication} object.
|
||||
* <p>
|
||||
* If compared to a custom authority which returns null from {@link #getAuthority}, the <tt>compareTo</tt>
|
||||
* method will return -1, so the custom authority will take precedence.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -36,7 +41,6 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public GrantedAuthorityImpl(String role) {
|
||||
super();
|
||||
Assert.hasText(role, "A granted authority textual representation is required");
|
||||
this.role = role;
|
||||
}
|
||||
@@ -71,8 +75,13 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
|
||||
|
||||
public int compareTo(Object o) {
|
||||
if (o != null && o instanceof GrantedAuthority) {
|
||||
GrantedAuthority rhs = (GrantedAuthority) o;
|
||||
return this.role.compareTo(rhs.getAuthority());
|
||||
String rhsRole = ((GrantedAuthority) o).getAuthority();
|
||||
|
||||
if (rhsRole == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return role.compareTo(rhsRole);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package org.springframework.security.authoritymapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class implements the Attributes2GrantedAuthoritiesMapper and
|
||||
* MappableAttributesRetriever interfaces based on the supplied Map.
|
||||
* It supports both one-to-one and one-to-many mappings. The granted
|
||||
* authorities to map to can be supplied either as a String or as a
|
||||
* GrantedAuthority object.
|
||||
* </p>
|
||||
* @author Ruud Senden
|
||||
*/
|
||||
public class MapBasedAttributes2GrantedAuthoritiesMapper implements Attributes2GrantedAuthoritiesMapper, MappableAttributesRetriever, InitializingBean {
|
||||
private Map attributes2grantedAuthoritiesMap = null;
|
||||
private String stringSeparator = ",";
|
||||
private String[] mappableAttributes = null;
|
||||
|
||||
/**
|
||||
* Check whether all properties have been set to correct values, and do some preprocessing.
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notEmpty(attributes2grantedAuthoritiesMap,"A non-empty attributes2grantedAuthoritiesMap must be supplied");
|
||||
attributes2grantedAuthoritiesMap = preProcessMap(attributes2grantedAuthoritiesMap);
|
||||
try {
|
||||
mappableAttributes = (String[])attributes2grantedAuthoritiesMap.keySet().toArray(new String[]{});
|
||||
} catch ( ArrayStoreException ase ) {
|
||||
throw new IllegalArgumentException("attributes2grantedAuthoritiesMap contains non-String objects as keys");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocess the given map
|
||||
* @param orgMap The map to process
|
||||
* @return the processed Map
|
||||
*/
|
||||
private Map preProcessMap(Map orgMap) {
|
||||
Map result = new HashMap(orgMap.size());
|
||||
Iterator it = orgMap.entrySet().iterator();
|
||||
while ( it.hasNext() ) {
|
||||
Map.Entry entry = (Map.Entry)it.next();
|
||||
result.put(entry.getKey(),getGrantedAuthorityCollection(entry.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given value to a collection of Granted Authorities
|
||||
*
|
||||
* @param value
|
||||
* The value to convert to a GrantedAuthority Collection
|
||||
* @return Collection containing the GrantedAuthority Collection
|
||||
*/
|
||||
private Collection getGrantedAuthorityCollection(Object value) {
|
||||
Collection result = new ArrayList();
|
||||
addGrantedAuthorityCollection(result,value);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given value to a collection of Granted Authorities,
|
||||
* adding the result to the given result collection.
|
||||
*
|
||||
* @param value
|
||||
* The value to convert to a GrantedAuthority Collection
|
||||
* @return Collection containing the GrantedAuthority Collection
|
||||
*/
|
||||
private void addGrantedAuthorityCollection(Collection result, Object value) {
|
||||
if ( value != null ) {
|
||||
if ( value instanceof Collection ) {
|
||||
addGrantedAuthorityCollection(result,(Collection)value);
|
||||
} else if ( value instanceof Object[] ) {
|
||||
addGrantedAuthorityCollection(result,(Object[])value);
|
||||
} else if ( value instanceof String ) {
|
||||
addGrantedAuthorityCollection(result,(String)value);
|
||||
} else if ( value instanceof GrantedAuthority ) {
|
||||
result.add(value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid object type: "+value.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addGrantedAuthorityCollection(Collection result, Collection value) {
|
||||
Iterator it = value.iterator();
|
||||
while ( it.hasNext() ) {
|
||||
addGrantedAuthorityCollection(result,it.next());
|
||||
}
|
||||
}
|
||||
|
||||
private void addGrantedAuthorityCollection(Collection result, Object[] value) {
|
||||
for ( int i = 0 ; i < value.length ; i++ ) {
|
||||
addGrantedAuthorityCollection(result,value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void addGrantedAuthorityCollection(Collection result, String value) {
|
||||
StringTokenizer st = new StringTokenizer(value,stringSeparator,false);
|
||||
while ( st.hasMoreTokens() ) {
|
||||
String nextToken = st.nextToken();
|
||||
if ( StringUtils.hasText(nextToken) ) {
|
||||
result.add(new GrantedAuthorityImpl(nextToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the given array of attributes to Spring Security GrantedAuthorities.
|
||||
*/
|
||||
public GrantedAuthority[] getGrantedAuthorities(String[] attributes) {
|
||||
List gaList = new ArrayList();
|
||||
for (int i = 0; i < attributes.length; i++) {
|
||||
Collection c = (Collection)attributes2grantedAuthoritiesMap.get(attributes[i]);
|
||||
if ( c != null ) { gaList.addAll(c); }
|
||||
}
|
||||
GrantedAuthority[] result = new GrantedAuthority[gaList.size()];
|
||||
result = (GrantedAuthority[])gaList.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the attributes2grantedAuthoritiesMap.
|
||||
*/
|
||||
public Map getAttributes2grantedAuthoritiesMap() {
|
||||
return attributes2grantedAuthoritiesMap;
|
||||
}
|
||||
/**
|
||||
* @param attributes2grantedAuthoritiesMap The attributes2grantedAuthoritiesMap to set.
|
||||
*/
|
||||
public void setAttributes2grantedAuthoritiesMap(Map attributes2grantedAuthoritiesMap) {
|
||||
this.attributes2grantedAuthoritiesMap = attributes2grantedAuthoritiesMap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.springframework.security.authoritymapping.MappableAttributesRetriever#getMappableAttributes()
|
||||
*/
|
||||
public String[] getMappableAttributes() {
|
||||
return mappableAttributes;
|
||||
}
|
||||
/**
|
||||
* @return Returns the stringSeparator.
|
||||
*/
|
||||
public String getStringSeparator() {
|
||||
return stringSeparator;
|
||||
}
|
||||
/**
|
||||
* @param stringSeparator The stringSeparator to set.
|
||||
*/
|
||||
public void setStringSeparator(String stringSeparator) {
|
||||
this.stringSeparator = stringSeparator;
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -61,14 +61,13 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
|
||||
filter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority);
|
||||
filter.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
|
||||
provider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
ManagedList authMgrProviderList = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
authMgrProviderList.add(provider);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
|
||||
+2
-1
@@ -22,7 +22,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
String alias = element.getAttribute(ATT_ALIAS);
|
||||
|
||||
@@ -33,6 +33,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
|
||||
|
||||
if (StringUtils.hasText(sessionControllerRef)) {
|
||||
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
|
||||
BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController",
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser
|
||||
parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
|
||||
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(id));
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public abstract class BeanIds {
|
||||
public static final String MAIN_ENTRY_POINT = "_mainEntryPoint";
|
||||
public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
|
||||
public static final String HTTP_SESSION_CONTEXT_INTEGRATION_FILTER = "_httpSessionContextIntegrationFilter";
|
||||
public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";
|
||||
public static final String LOGOUT_FILTER = "_logoutFilter";
|
||||
public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
|
||||
public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
|
||||
@@ -49,6 +50,7 @@ public abstract class BeanIds {
|
||||
public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager";
|
||||
public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
|
||||
public static final String REMEMBER_ME_SERVICES = "_rememberMeServices";
|
||||
public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider";
|
||||
public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
|
||||
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
||||
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
||||
@@ -66,5 +68,4 @@ public abstract class BeanIds {
|
||||
public static final String X509_AUTH_PROVIDER = "_x509AuthenticationProvider";
|
||||
public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
|
||||
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -9,15 +9,12 @@ import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
@@ -80,21 +77,20 @@ public abstract class ConfigUtils {
|
||||
* using the <security:provider /> tag or by other beans which have a dependency on the
|
||||
* authentication manager.
|
||||
*/
|
||||
static BeanDefinition registerProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
static void registerProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
|
||||
return parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
return;
|
||||
}
|
||||
|
||||
BeanDefinition authManager = new RootBeanDefinition(ProviderManager.class);
|
||||
authManager.getPropertyValues().addPropertyValue("providers", new ManagedList());
|
||||
BeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class);
|
||||
authManager.getPropertyValues().addPropertyValue("providerBeanNames", new ArrayList());
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager);
|
||||
|
||||
return authManager;
|
||||
}
|
||||
|
||||
static ManagedList getRegisteredProviders(ParserContext parserContext) {
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext);
|
||||
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
static void addAuthenticationProvider(ParserContext parserContext, String beanName) {
|
||||
registerProviderManagerIfNecessary(parserContext);
|
||||
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName);
|
||||
}
|
||||
|
||||
static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
|
||||
@@ -172,7 +168,8 @@ public abstract class ConfigUtils {
|
||||
}
|
||||
|
||||
static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(pc);
|
||||
registerProviderManagerIfNecessary(pc);
|
||||
BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
|
||||
|
||||
if (pv != null && pv.getValue() != null) {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import org.w3c.dom.Node;
|
||||
*/
|
||||
public class CustomAuthenticationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(holder.getBeanName()));
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, holder.getBeanName());
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
+142
-127
@@ -50,16 +50,16 @@ import org.w3c.dom.Element;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class);
|
||||
|
||||
static final String ATT_REALM = "realm";
|
||||
static final String DEF_REALM = "Spring Security Application";
|
||||
|
||||
static final String ATT_PATH_PATTERN = "pattern";
|
||||
|
||||
|
||||
static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
|
||||
static final String OPT_SESSION_FIXATION_NO_PROTECTION = "none";
|
||||
static final String OPT_SESSION_FIXATION_CLEAN_SESSION = "newSession";
|
||||
static final String OPT_SESSION_FIXATION_CLEAN_SESSION = "newSession";
|
||||
static final String OPT_SESSION_FIXATION_MIGRATE_SESSION = "migrateSession";
|
||||
|
||||
static final String ATT_PATH_TYPE = "path-type";
|
||||
@@ -91,9 +91,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
|
||||
static final String DEF_SERVLET_API_PROVISION = "true";
|
||||
|
||||
static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
|
||||
static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
|
||||
static final String ATT_ONCE_PER_REQUEST = "once-per-request";
|
||||
static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
@@ -106,20 +106,20 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
final boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
|
||||
final List interceptUrlElts = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
final Map filterChainMap = new LinkedHashMap();
|
||||
final LinkedHashMap channelRequestMap = new LinkedHashMap();
|
||||
|
||||
registerFilterChainProxy(parserContext, filterChainMap, matcher, source);
|
||||
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
boolean allowSessionCreation = registerHttpSessionIntegrationFilter(element, parserContext);
|
||||
|
||||
|
||||
registerServletApiFilter(element, parserContext);
|
||||
|
||||
|
||||
// Set up the access manager reference for http
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
@@ -127,7 +127,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
accessManagerId = BeanIds.ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
|
||||
// Register the portMapper. A default will always be created, even if no element exists.
|
||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
|
||||
@@ -139,19 +139,19 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (channelRequestMap.size() > 0) {
|
||||
// At least one channel requirement has been specified
|
||||
registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
|
||||
}
|
||||
|
||||
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
|
||||
}
|
||||
|
||||
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext));
|
||||
|
||||
boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
|
||||
|
||||
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
|
||||
|
||||
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
|
||||
sessionControlEnabled);
|
||||
|
||||
boolean autoConfig = false;
|
||||
if ("true".equals(element.getAttribute(ATT_AUTO_CONFIG))) {
|
||||
autoConfig = true;
|
||||
autoConfig = true;
|
||||
}
|
||||
|
||||
Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
|
||||
@@ -159,21 +159,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
new AnonymousBeanDefinitionParser().parse(anonymousElt, parserContext);
|
||||
}
|
||||
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(element, Elements.REMEMBER_ME);
|
||||
if (rememberMeElt != null || autoConfig) {
|
||||
new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext);
|
||||
// Post processor to inject RememberMeServices into filters which need it
|
||||
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
|
||||
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
|
||||
}
|
||||
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(element, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
new LogoutBeanDefinitionParser().parse(logoutElt, parserContext);
|
||||
}
|
||||
|
||||
parseRememberMeAndLogout(element, autoConfig, parserContext);
|
||||
|
||||
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig, allowSessionCreation);
|
||||
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509);
|
||||
@@ -188,27 +175,49 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2);
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void parseRememberMeAndLogout(Element elt, boolean autoConfig, ParserContext pc) {
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME);
|
||||
String rememberMeServices = null;
|
||||
|
||||
if (rememberMeElt != null || autoConfig) {
|
||||
RememberMeBeanDefinitionParser rmbdp = new RememberMeBeanDefinitionParser();
|
||||
rmbdp.parse(rememberMeElt, pc);
|
||||
rememberMeServices = rmbdp.getServicesName();
|
||||
// Post processor to inject RememberMeServices into filters which need it
|
||||
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
|
||||
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
|
||||
}
|
||||
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
new LogoutBeanDefinitionParser(rememberMeServices).parse(logoutElt, pc);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||
}
|
||||
|
||||
|
||||
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
|
||||
filterChainProxy.setSource(source);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
}
|
||||
|
||||
private boolean registerHttpSessionIntegrationFilter(Element element, ParserContext pc) {
|
||||
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
|
||||
boolean sessionCreationAllowed = true;
|
||||
|
||||
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
@@ -225,11 +234,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER));
|
||||
|
||||
|
||||
return sessionCreationAllowed;
|
||||
}
|
||||
|
||||
// Adds the servlet-api integration filter if required
|
||||
// Adds the servlet-api integration filter if required
|
||||
private void registerServletApiFilter(Element element, ParserContext pc) {
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
@@ -242,27 +251,27 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean registerConcurrentSessionControlBeansIfRequired(Element element, ParserContext parserContext) {
|
||||
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
|
||||
if (sessionControlElt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
|
||||
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
|
||||
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
|
||||
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
|
||||
sessionIntegrationFilter.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void registerExceptionTranslationFilter(Element element, ParserContext pc, boolean allowSessionCreation) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", new Boolean(allowSessionCreation));
|
||||
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
accessDeniedHandler.setErrorPage(accessDeniedPage);
|
||||
@@ -272,27 +281,27 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
|
||||
}
|
||||
|
||||
|
||||
private void registerFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher,
|
||||
String accessManagerId, LinkedHashMap filterInvocationDefinitionMap) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
||||
builder.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||
builder.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
|
||||
|
||||
|
||||
if ("false".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) {
|
||||
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
|
||||
}
|
||||
|
||||
DefaultFilterInvocationDefinitionSource fids =
|
||||
|
||||
DefaultFilterInvocationDefinitionSource fids =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap);
|
||||
fids.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
|
||||
builder.addPropertyValue("objectDefinitionSource", fids);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
|
||||
}
|
||||
|
||||
|
||||
private void registerChannelProcessingBeans(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
|
||||
@@ -300,7 +309,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap);
|
||||
channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
@@ -321,161 +330,161 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void registerSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
|
||||
if(!StringUtils.hasText(sessionFixationAttribute)) {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
}
|
||||
|
||||
|
||||
if (!sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION)) {
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionFilter.class);
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
|
||||
if (sessionControlEnabled) {
|
||||
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
sessionFixationFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void parseBasicFormLoginAndOpenID(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) {
|
||||
RootBeanDefinition formLoginFilter = null;
|
||||
RootBeanDefinition formLoginEntryPoint = null;
|
||||
String formLoginPage = null;
|
||||
String formLoginPage = null;
|
||||
RootBeanDefinition openIDFilter = null;
|
||||
RootBeanDefinition openIDEntryPoint = null;
|
||||
String openIDLoginPage = null;
|
||||
|
||||
|
||||
String realm = element.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
|
||||
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
|
||||
}
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
|
||||
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
|
||||
|
||||
if (formLoginElt != null || autoConfig) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
|
||||
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(formLoginElt, pc);
|
||||
formLoginFilter = parser.getFilterBean();
|
||||
formLoginEntryPoint = parser.getEntryPointBean();
|
||||
formLoginPage = parser.getLoginPage();
|
||||
}
|
||||
|
||||
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN);
|
||||
|
||||
if (openIDLoginElt != null) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
|
||||
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(openIDLoginElt, pc);
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
openIDLoginPage = parser.getLoginPage();
|
||||
|
||||
BeanDefinitionBuilder openIDProviderBuilder =
|
||||
|
||||
BeanDefinitionBuilder openIDProviderBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.providers.openid.OpenIDAuthenticationProvider");
|
||||
|
||||
|
||||
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
|
||||
if (StringUtils.hasText(userService)) {
|
||||
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
|
||||
}
|
||||
|
||||
|
||||
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
|
||||
ConfigUtils.getRegisteredProviders(pc).add(new RuntimeBeanReference(BeanIds.OPEN_ID_PROVIDER));
|
||||
ConfigUtils.addAuthenticationProvider(pc, BeanIds.OPEN_ID_PROVIDER);
|
||||
}
|
||||
|
||||
|
||||
boolean needLoginPage = false;
|
||||
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
needLoginPage = true;
|
||||
formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
}
|
||||
needLoginPage = true;
|
||||
formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
needLoginPage = true;
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
needLoginPage = true;
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
}
|
||||
|
||||
// If no login page has been defined, add in the default page generator.
|
||||
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
|
||||
logger.info("No login page configured. The default internal one will be used. Use the '"
|
||||
+ FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE + "' attribute to set the URL of the login page.");
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
|
||||
loginPageFilter.getBeanDefinition());
|
||||
if (openIDFilter != null) {
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
|
||||
loginPageFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
|
||||
}
|
||||
|
||||
|
||||
// We need to establish the main entry point.
|
||||
// First check if a custom entry point bean is set
|
||||
String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
|
||||
|
||||
|
||||
if (StringUtils.hasText(customEntryPoint)) {
|
||||
pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Basic takes precedence if explicit element is used and no others are configured
|
||||
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
|
||||
// has been set
|
||||
if (formLoginFilter != null && openIDLoginPage == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise use OpenID if enabled
|
||||
if (openIDFilter != null && formLoginFilter == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If X.509 has been enabled, use the preauth entry point.
|
||||
if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
|
||||
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
|
||||
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
|
||||
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
|
||||
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
|
||||
pc.extractSource(element));
|
||||
}
|
||||
|
||||
|
||||
static UrlMatcher createUrlMatcher(Element element) {
|
||||
String patternType = element.getAttribute(ATT_PATH_TYPE);
|
||||
if (!StringUtils.hasText(patternType)) {
|
||||
@@ -509,8 +518,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
// Default for regex is no change
|
||||
}
|
||||
|
||||
return matcher;
|
||||
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -554,7 +563,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
editor.setAsText(channelConfigAttribute);
|
||||
channelRequestMap.put(new RequestKey(path), (ConfigAttributeDefinition) editor.getValue());
|
||||
}
|
||||
|
||||
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
|
||||
if (StringUtils.hasText(filters)) {
|
||||
@@ -567,10 +576,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LinkedHashMap parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap();
|
||||
|
||||
|
||||
Iterator urlEltsIterator = urlElts.iterator();
|
||||
ConfigAttributeEditor editor = new ConfigAttributeEditor();
|
||||
|
||||
@@ -597,11 +606,17 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
// Convert the comma-separated list of access attributes to a ConfigAttributeDefinition
|
||||
if (StringUtils.hasText(access)) {
|
||||
editor.setAsText(access);
|
||||
filterInvocationDefinitionMap.put(new RequestKey(path, method), editor.getValue());
|
||||
Object key = new RequestKey(path, method);
|
||||
|
||||
if (filterInvocationDefinitionMap.containsKey(key)) {
|
||||
logger.warn("Duplicate URL defined: " + key + ". The original attribute values will be overwritten");
|
||||
}
|
||||
|
||||
filterInvocationDefinitionMap.put(key, editor.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return filterInvocationDefinitionMap;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
|
||||
if (StringUtils.hasText(groupAuthoritiesQuery)) {
|
||||
builder.addPropertyValue("enableGroups", Boolean.TRUE);
|
||||
builder.addPropertyValue("authoritiesByUsernameQuery", groupAuthoritiesQuery);
|
||||
builder.addPropertyValue("groupAuthoritiesByUsernameQuery", groupAuthoritiesQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -100,8 +100,9 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ldapProvider.addConstructorArg(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
ldapProvider.addPropertyValue("userDetailsContextMapper",
|
||||
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.LDAP_AUTHENTICATION_PROVIDER, ldapProvider.getBeanDefinition());
|
||||
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider.getBeanDefinition());
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.LDAP_AUTHENTICATION_PROVIDER);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+30
-30
@@ -14,22 +14,22 @@ import org.w3c.dom.Element;
|
||||
* @since 2.0
|
||||
*/
|
||||
public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
public static final String ATT_SERVER = "server-ref";
|
||||
public static final String ATT_SERVER = "server-ref";
|
||||
public static final String ATT_USER_SEARCH_FILTER = "user-search-filter";
|
||||
public static final String ATT_USER_SEARCH_BASE = "user-search-base";
|
||||
public static final String DEF_USER_SEARCH_BASE = "";
|
||||
|
||||
public static final String ATT_GROUP_SEARCH_FILTER = "group-search-filter";
|
||||
public static final String ATT_GROUP_SEARCH_BASE = "group-search-base";
|
||||
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
|
||||
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
|
||||
public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})";
|
||||
public static final String DEF_GROUP_SEARCH_BASE = "ou=groups";
|
||||
|
||||
public static final String DEF_GROUP_SEARCH_BASE = "";
|
||||
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
static final String ATT_USER_CLASS = "user-details-class";
|
||||
static final String OPT_PERSON = "person";
|
||||
static final String OPT_INETORGPERSON = "inetOrgPerson";
|
||||
|
||||
|
||||
public static final String LDAP_SEARCH_CLASS = "org.springframework.security.ldap.search.FilterBasedLdapUserSearch";
|
||||
public static final String PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.PersonContextMapper";
|
||||
public static final String INET_ORG_PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper";
|
||||
@@ -45,42 +45,42 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
if (!StringUtils.hasText(elt.getAttribute(ATT_USER_SEARCH_FILTER))) {
|
||||
parserContext.getReaderContext().error("User search filter must be supplied", elt);
|
||||
}
|
||||
|
||||
|
||||
builder.addConstructorArg(parseSearchBean(elt, parserContext));
|
||||
builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext));
|
||||
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
|
||||
}
|
||||
|
||||
|
||||
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
|
||||
String userSearchFilter = elt.getAttribute(ATT_USER_SEARCH_FILTER);
|
||||
String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE);
|
||||
Object source = parserContext.extractSource(elt);
|
||||
|
||||
|
||||
if (StringUtils.hasText(userSearchBase)) {
|
||||
if(!StringUtils.hasText(userSearchFilter)) {
|
||||
parserContext.getReaderContext().error(ATT_USER_SEARCH_BASE + " cannot be used without a " + ATT_USER_SEARCH_FILTER, source);
|
||||
}
|
||||
} else {
|
||||
userSearchBase = DEF_USER_SEARCH_BASE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(userSearchFilter)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
BeanDefinitionBuilder searchBuilder = BeanDefinitionBuilder.rootBeanDefinition(LDAP_SEARCH_CLASS);
|
||||
searchBuilder.setSource(source);
|
||||
searchBuilder.addConstructorArg(userSearchBase);
|
||||
searchBuilder.addConstructorArg(userSearchFilter);
|
||||
searchBuilder.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
|
||||
|
||||
return (RootBeanDefinition) searchBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
||||
static RuntimeBeanReference parseServerReference(Element elt, ParserContext parserContext) {
|
||||
String server = elt.getAttribute(ATT_SERVER);
|
||||
boolean requiresDefaultName = false;
|
||||
|
||||
|
||||
if (!StringUtils.hasText(server)) {
|
||||
server = BeanIds.CONTEXT_SOURCE;
|
||||
requiresDefaultName = true;
|
||||
@@ -89,27 +89,27 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
RuntimeBeanReference contextSource = new RuntimeBeanReference(server);
|
||||
contextSource.setSource(parserContext.extractSource(elt));
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry(), requiresDefaultName);
|
||||
|
||||
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
|
||||
static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) {
|
||||
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
|
||||
|
||||
if (OPT_PERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
}
|
||||
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
|
||||
|
||||
if (OPT_PERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
}
|
||||
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
}
|
||||
|
||||
|
||||
static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
|
||||
String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER);
|
||||
String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE);
|
||||
String groupRoleAttribute = elt.getAttribute(ATT_GROUP_ROLE_ATTRIBUTE);
|
||||
String rolePrefix = elt.getAttribute(ATT_ROLE_PREFIX);
|
||||
|
||||
|
||||
if (!StringUtils.hasText(groupSearchFilter)) {
|
||||
groupSearchFilter = DEF_GROUP_SEARCH_FILTER;
|
||||
}
|
||||
@@ -117,25 +117,25 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
if (!StringUtils.hasText(groupSearchBase)) {
|
||||
groupSearchBase = DEF_GROUP_SEARCH_BASE;
|
||||
}
|
||||
|
||||
|
||||
BeanDefinitionBuilder populator = BeanDefinitionBuilder.rootBeanDefinition(LDAP_AUTHORITIES_POPULATOR_CLASS);
|
||||
populator.setSource(parserContext.extractSource(elt));
|
||||
populator.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
populator.addConstructorArg(groupSearchBase);
|
||||
populator.addPropertyValue("groupSearchFilter", groupSearchFilter);
|
||||
populator.addPropertyValue("searchSubtree", Boolean.TRUE);
|
||||
|
||||
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
if ("none".equals(rolePrefix)) {
|
||||
rolePrefix = "";
|
||||
}
|
||||
populator.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.hasLength(groupRoleAttribute)) {
|
||||
populator.addPropertyValue("groupRoleAttribute", groupRoleAttribute);
|
||||
}
|
||||
|
||||
|
||||
return (RootBeanDefinition) populator.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -25,6 +25,12 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
static final String ATT_LOGOUT_URL = "logout-url";
|
||||
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
|
||||
|
||||
String rememberMeServices;
|
||||
|
||||
public LogoutBeanDefinitionParser(String rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String logoutUrl = null;
|
||||
@@ -66,8 +72,8 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
handlers.add(sclh);
|
||||
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
|
||||
handlers.add(new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
|
||||
if (rememberMeServices != null) {
|
||||
handlers.add(new RuntimeBeanReference(rememberMeServices));
|
||||
}
|
||||
|
||||
builder.addConstructorArg(handlers);
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extended version of {@link ProviderManager the default authentication manager} which lazily initializes
|
||||
* the list of {@link AuthenticationProvider}s. This prevents some of the issues that have occurred with
|
||||
* namespace configuration where early instantiation of a security interceptor has caused the AuthenticationManager
|
||||
* and thus dependent beans (typically UserDetailsService implementations or DAOs) to be initialized too early.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class NamespaceAuthenticationManager extends ProviderManager implements BeanFactoryAware {
|
||||
BeanFactory beanFactory;
|
||||
List providerBeanNames;
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(providerBeanNames, "provideBeanNames has not been set");
|
||||
Assert.notEmpty(providerBeanNames, "No authentication providers were found in the application context");
|
||||
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to lazily-initialize the list of providers on first use.
|
||||
*/
|
||||
public List getProviders() {
|
||||
// We use the names array to determine whether the list has been set yet.
|
||||
if (providerBeanNames != null) {
|
||||
List providers = new ArrayList();
|
||||
Iterator beanNames = providerBeanNames.iterator();
|
||||
|
||||
while (beanNames.hasNext()) {
|
||||
providers.add(beanFactory.getBean((String) beanNames.next()));
|
||||
}
|
||||
providerBeanNames = null;
|
||||
|
||||
setProviders(providers);
|
||||
}
|
||||
|
||||
return super.getProviders();
|
||||
}
|
||||
|
||||
public void setProviderBeanNames(List provideBeanNames) {
|
||||
this.providerBeanNames = provideBeanNames;
|
||||
}
|
||||
}
|
||||
+22
-18
@@ -22,7 +22,7 @@ import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
|
||||
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
|
||||
* This allows user to add their own custom filters to the security chain. If the user's filter
|
||||
* already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
|
||||
*
|
||||
@@ -33,7 +33,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
|
||||
public static final String ATT_AFTER = "after";
|
||||
public static final String ATT_BEFORE = "before";
|
||||
public static final String ATT_POSITION = "position";
|
||||
public static final String ATT_POSITION = "position";
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
Element elt = (Element)node;
|
||||
@@ -48,7 +48,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
}
|
||||
|
||||
ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
|
||||
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
@@ -59,22 +59,26 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
String after = elt.getAttribute(ATT_AFTER);
|
||||
String before = elt.getAttribute(ATT_BEFORE);
|
||||
String position = elt.getAttribute(ATT_POSITION);
|
||||
|
||||
|
||||
if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) {
|
||||
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
|
||||
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
|
||||
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
|
||||
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.hasText(position)) {
|
||||
return Integer.toString(FilterChainOrder.getOrder(position));
|
||||
return Integer.toString(FilterChainOrder.getOrder(position));
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.hasText(after)) {
|
||||
return Integer.toString(FilterChainOrder.getOrder(after) + 1);
|
||||
int order = FilterChainOrder.getOrder(after);
|
||||
|
||||
return Integer.toString(order == Integer.MAX_VALUE ? order : order + 1);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(before)) {
|
||||
return Integer.toString(FilterChainOrder.getOrder(before) - 1);
|
||||
int order = FilterChainOrder.getOrder(before);
|
||||
|
||||
return Integer.toString(order == Integer.MIN_VALUE ? order : order - 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -121,12 +125,12 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
return beanName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
|
||||
}
|
||||
|
||||
Filter getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
public String toString() {
|
||||
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
|
||||
}
|
||||
|
||||
Filter getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
@@ -32,6 +32,7 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_TOKEN_VALIDITY = "token-validity-seconds";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
private String servicesName;
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String tokenRepository = null;
|
||||
@@ -102,8 +103,10 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
services.setSource(source);
|
||||
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
servicesName = BeanIds.REMEMBER_ME_SERVICES;
|
||||
} else {
|
||||
servicesName = rememberMeServicesRef;
|
||||
parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
|
||||
}
|
||||
|
||||
@@ -114,13 +117,17 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerProvider(ParserContext pc, Object source, String key) {
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
String getServicesName() {
|
||||
return servicesName;
|
||||
}
|
||||
|
||||
private void registerProvider(ParserContext pc, Object source, String key) {
|
||||
//BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
providers.add(provider);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(pc, BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER);
|
||||
}
|
||||
|
||||
private void registerFilter(ParserContext pc, Object source) {
|
||||
|
||||
+2
-1
@@ -51,7 +51,8 @@ public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostPro
|
||||
Map beans = beanFactory.getBeansOfType(RememberMeServices.class);
|
||||
|
||||
Assert.isTrue(beans.size() > 0, "No RememberMeServices configured");
|
||||
Assert.isTrue(beans.size() == 1, "More than one RememberMeServices bean found.");
|
||||
Assert.isTrue(beans.size() == 1, "Use of '<remember-me />' requires a single instance of RememberMeServices " +
|
||||
"in the application context, but more than one was found.");
|
||||
|
||||
return (RememberMeServices) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
+72
-74
@@ -2,8 +2,6 @@ package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
@@ -21,91 +19,91 @@ import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* Registered by {@link HttpSecurityBeanDefinitionParser} to inject a UserDetailsService into
|
||||
* the X509Provider, RememberMeServices and OpenIDAuthenticationProvider instances created by
|
||||
* the namespace.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
|
||||
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
|
||||
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoOpenIDProvider(bean);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
|
||||
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
|
||||
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoOpenIDProvider(bean);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoRememberMeServices(AbstractRememberMeServices services) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
services.setUserDetailsService(getUserDetailsService());
|
||||
services.setUserDetailsService(getUserDetailsService());
|
||||
} else {
|
||||
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
services.setUserDetailsService(cachingUserService);
|
||||
}
|
||||
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
services.setUserDetailsService(cachingUserService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void injectUserDetailsServiceIntoX509Provider(PreAuthenticatedAuthenticationProvider provider) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService");
|
||||
UserDetailsByNameServiceWrapper wrapper = new UserDetailsByNameServiceWrapper();
|
||||
|
||||
|
||||
if (pv == null) {
|
||||
wrapper.setUserDetailsService(getUserDetailsService());
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
wrapper.setUserDetailsService(getUserDetailsService());
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
} else {
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
UserDetailsService cachingUserService = getCachingUserService(userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
wrapper.setUserDetailsService(cachingUserService);
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
}
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
UserDetailsService cachingUserService = getCachingUserService(userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
wrapper.setUserDetailsService(cachingUserService);
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void injectUserDetailsServiceIntoOpenIDProvider(Object bean) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.OPEN_ID_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
|
||||
beanWrapper.setPropertyValue("userDetailsService", getUserDetailsService());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a user details service for use in RememberMeServices etc. Will return a caching version
|
||||
* if available so should not be used for beans which need to separate the two.
|
||||
* if available so should not be used for beans which need to separate the two.
|
||||
*/
|
||||
UserDetailsService getUserDetailsService() {
|
||||
Map beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
beans = beanFactory.getBeansOfType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
Map beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
beans = beanFactory.getBeansOfType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new SecurityConfigurationException("No UserDetailsService registered.");
|
||||
|
||||
@@ -116,24 +114,24 @@ public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostPro
|
||||
|
||||
return (UserDetailsService) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
private UserDetailsService getCachingUserService(Object userServiceRef) {
|
||||
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
|
||||
"userDetailsService property value must be a RuntimeBeanReference");
|
||||
|
||||
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
|
||||
// Overwrite with the caching version if available
|
||||
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (beanFactory.containsBeanDefinition(cachingId)) {
|
||||
return (UserDetailsService) beanFactory.getBean(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
private UserDetailsService getCachingUserService(Object userServiceRef) {
|
||||
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
|
||||
"userDetailsService property value must be a RuntimeBeanReference");
|
||||
|
||||
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
|
||||
// Overwrite with the caching version if available
|
||||
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (beanFactory.containsBeanDefinition(cachingId)) {
|
||||
return (UserDetailsService) beanFactory.getBean(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_AUTH_PROVIDER, provider);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(BeanIds.X509_AUTH_PROVIDER));
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.X509_AUTH_PROVIDER);
|
||||
|
||||
String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
|
||||
+101
-100
@@ -18,11 +18,11 @@ import org.springframework.util.ObjectUtils;
|
||||
* Abstract implementation of {@link MethodDefinitionSource} that supports both Spring AOP and AspectJ and
|
||||
* caches configuration attribute resolution from: 1. specific target method; 2. target class; 3. declaring method;
|
||||
* 4. declaring class/interface.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This class mimics the behaviour of Spring's AbstractFallbackTransactionAttributeSource class.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Note that this class cannot extract security metadata where that metadata is expressed by way of
|
||||
* a target method/class (ie #1 and #2 above) AND the target method/class is encapsulated in another
|
||||
@@ -31,7 +31,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* another proxy), move the metadata to declared methods or interfaces the proxy implements, or provide
|
||||
* your own replacement <tt>MethodDefinitionSource</tt>.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
@@ -39,15 +39,16 @@ import org.springframework.util.ObjectUtils;
|
||||
public abstract class AbstractFallbackMethodDefinitionSource implements MethodDefinitionSource {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractFallbackMethodDefinitionSource.class);
|
||||
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
|
||||
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
|
||||
private final Map attributeCache = new HashMap();
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
|
||||
Assert.notNull(object, "Object cannot be null");
|
||||
|
||||
if (object instanceof MethodInvocation) {
|
||||
MethodInvocation mi = (MethodInvocation) object;
|
||||
return getAttributes(mi.getMethod(), mi.getThis().getClass());
|
||||
MethodInvocation mi = (MethodInvocation) object;
|
||||
Object target = mi.getThis();
|
||||
return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
|
||||
}
|
||||
|
||||
if (object instanceof JoinPoint) {
|
||||
@@ -59,143 +60,143 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
|
||||
|
||||
Method method = ClassUtils.getMethodIfAvailable(declaringType, targetMethodName, types);
|
||||
Assert.notNull(method, "Could not obtain target method from JoinPoint: '"+ jp + "'");
|
||||
|
||||
|
||||
return getAttributes(method, targetClass);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Object must be a MethodInvocation or JoinPoint");
|
||||
}
|
||||
|
||||
|
||||
public final boolean supports(Class clazz) {
|
||||
return (MethodInvocation.class.isAssignableFrom(clazz) || JoinPoint.class.isAssignableFrom(clazz));
|
||||
}
|
||||
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = new DefaultCacheKey(method, targetClass);
|
||||
synchronized (this.attributeCache) {
|
||||
Object cached = this.attributeCache.get(cacheKey);
|
||||
if (cached != null) {
|
||||
// Value will either be canonical value indicating there is no config attribute,
|
||||
// or an actual config attribute.
|
||||
if (cached == NULL_CONFIG_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return (ConfigAttributeDefinition) cached;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need to work it out.
|
||||
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
|
||||
// Put it in the cache.
|
||||
if (cfgAtt == null) {
|
||||
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
|
||||
}
|
||||
this.attributeCache.put(cacheKey, cfgAtt);
|
||||
}
|
||||
return cfgAtt;
|
||||
}
|
||||
}
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = new DefaultCacheKey(method, targetClass);
|
||||
synchronized (this.attributeCache) {
|
||||
Object cached = this.attributeCache.get(cacheKey);
|
||||
if (cached != null) {
|
||||
// Value will either be canonical value indicating there is no config attribute,
|
||||
// or an actual config attribute.
|
||||
if (cached == NULL_CONFIG_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return (ConfigAttributeDefinition) cached;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need to work it out.
|
||||
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
|
||||
// Put it in the cache.
|
||||
if (cfgAtt == null) {
|
||||
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
|
||||
}
|
||||
this.attributeCache.put(cacheKey, cfgAtt);
|
||||
}
|
||||
return cfgAtt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for this invocation (may be <code>null</code>)
|
||||
*
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for this invocation (may be <code>null</code>)
|
||||
* @return
|
||||
*/
|
||||
private ConfigAttributeDefinition computeAttributes(Method method, Class targetClass) {
|
||||
// The method may be on an interface, but we need attributes from the target class.
|
||||
// If the target class is null, the method will be unchanged.
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
// First try is the method in the target class.
|
||||
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// The method may be on an interface, but we need attributes from the target class.
|
||||
// If the target class is null, the method will be unchanged.
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
// First try is the method in the target class.
|
||||
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
|
||||
// Second try is the config attribute on the target class.
|
||||
attr = findAttributes(specificMethod.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// Second try is the config attribute on the target class.
|
||||
attr = findAttributes(specificMethod.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
|
||||
if (specificMethod != method) {
|
||||
// Fallback is to look at the original method.
|
||||
attr = findAttributes(method, method.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// Last fallback is the class of the original method.
|
||||
return findAttributes(method.getDeclaringClass());
|
||||
}
|
||||
return null;
|
||||
if (specificMethod != method || targetClass == null) {
|
||||
// Fallback is to look at the original method.
|
||||
attr = findAttributes(method, method.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// Last fallback is the class of the original method.
|
||||
return findAttributes(method.getDeclaringClass());
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the security metadata applicable to the specified method invocation.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Note that the {@link Method#getDeclaringClass()} may not equal the <code>targetClass</code>.
|
||||
* Both parameters are provided to assist subclasses which may wish to provide advanced
|
||||
* capabilities related to method metadata being "registered" against a method even if the
|
||||
* target class does not declare the method (i.e. the subclass may only inherit the method).
|
||||
*
|
||||
*
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for the invocation (may be <code>null</code>)
|
||||
* @return the security metadata (or null if no metadata applies)
|
||||
*/
|
||||
protected abstract ConfigAttributeDefinition findAttributes(Method method, Class targetClass);
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the security metadata registered against the specified class.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Subclasses should only return metadata expressed at a class level. Subclasses should NOT
|
||||
* aggregate metadata for each method registered against a class, as the abstract superclass
|
||||
* will separate invoke {@link #findAttributes(Method, Class)} for individual methods as
|
||||
* appropriate.
|
||||
*
|
||||
* appropriate.
|
||||
*
|
||||
* @param clazz the target class for the invocation (never <code>null</code>)
|
||||
* @return the security metadata (or null if no metadata applies)
|
||||
*/
|
||||
protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
|
||||
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
private final Method method;
|
||||
private final Class targetClass;
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
public DefaultCacheKey(Method method, Class targetClass) {
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
private final Method method;
|
||||
private final Class targetClass;
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof DefaultCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) &&
|
||||
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
|
||||
}
|
||||
public DefaultCacheKey(Method method, Class targetClass) {
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof DefaultCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) &&
|
||||
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+105
-123
@@ -34,13 +34,13 @@ import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Stores a {@link ConfigAttributeDefinition} for a method or class signature.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This class is the preferred implementation of {@link MethodDefinitionSource} for XML-based
|
||||
* definition of method security metadata. To assist in XML-based definition, wildcard support
|
||||
* is provided.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
@@ -51,9 +51,9 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
private static final Log logger = LogFactory.getLog(MapBasedMethodDefinitionSource.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/** Map from RegisteredMethod to ConfigAttributeDefinition */
|
||||
/** Map from RegisteredMethod to ConfigAttributeDefinition */
|
||||
protected Map methodMap = new HashMap();
|
||||
|
||||
/** Map from RegisteredMethod to name pattern used for registration */
|
||||
@@ -74,48 +74,37 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
addSecureMethod((String)entry.getKey(), (ConfigAttributeDefinition)entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation does not support class-level attributes.
|
||||
*/
|
||||
protected ConfigAttributeDefinition findAttributes(Class clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will walk the method inheritance tree to find the most specific declaration applicable.
|
||||
*/
|
||||
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
|
||||
return findAttributesSpecifiedAgainst(method, targetClass);
|
||||
}
|
||||
|
||||
private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
|
||||
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
|
||||
if (methodMap.containsKey(registeredMethod)) {
|
||||
return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
|
||||
}
|
||||
// Search superclass
|
||||
if (clazz.getSuperclass() != null) {
|
||||
return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Implementation does not support class-level attributes.
|
||||
*/
|
||||
protected ConfigAttributeDefinition findAttributes(Class clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add configuration attributes for a secure method.
|
||||
*
|
||||
* @param method the method to be secured
|
||||
* @param attr required authorities associated with the method
|
||||
* Will walk the method inheritance tree to find the most specific declaration applicable.
|
||||
*/
|
||||
private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
|
||||
Assert.notNull(method, "RegisteredMethod required");
|
||||
Assert.notNull(attr, "Configuration attribute required");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
|
||||
}
|
||||
this.methodMap.put(method, attr);
|
||||
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
|
||||
if (targetClass == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return findAttributesSpecifiedAgainst(method, targetClass);
|
||||
}
|
||||
|
||||
private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
|
||||
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
|
||||
if (methodMap.containsKey(registeredMethod)) {
|
||||
return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
|
||||
}
|
||||
// Search superclass
|
||||
if (clazz.getSuperclass() != null) {
|
||||
return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +115,7 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
* @param attr required authorities associated with the method
|
||||
*/
|
||||
public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
|
||||
int lastDotIndex = name.lastIndexOf(".");
|
||||
int lastDotIndex = name.lastIndexOf(".");
|
||||
|
||||
if (lastDotIndex == -1) {
|
||||
throw new IllegalArgumentException("'" + name + "' is not a valid method name: format is FQN.methodName");
|
||||
@@ -134,17 +123,17 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
|
||||
String methodName = name.substring(lastDotIndex + 1);
|
||||
Assert.hasText(methodName, "Method not found for '" + name + "'");
|
||||
|
||||
|
||||
String typeName = name.substring(0, lastDotIndex);
|
||||
Class type = ClassUtils.resolveClassName(typeName, this.beanClassLoader);
|
||||
|
||||
|
||||
addSecureMethod(type, methodName, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add configuration attributes for a secure method. Mapped method names can end or start with <code>*</code>
|
||||
* for matching multiple methods.
|
||||
*
|
||||
*
|
||||
* @param javaType target interface or class the security configuration attribute applies to
|
||||
* @param mappedName mapped method name, which the javaType has declared or inherited
|
||||
* @param attr required authorities associated with the method
|
||||
@@ -192,6 +181,38 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds configuration attributes for a specific method, for example where the method has been
|
||||
* matched using a pointcut expression. If a match already exists in the map for the method, then
|
||||
* the existing match will be retained, so that if this method is called for a more general pointcut
|
||||
* it will not override a more specific one which has already been added. This
|
||||
*/
|
||||
public void addSecureMethod(Class javaType, Method method, ConfigAttributeDefinition attr) {
|
||||
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
||||
|
||||
if (methodMap.containsKey(key)) {
|
||||
logger.debug("Method [" + method + "] is already registered with attributes [" + methodMap.get(key) + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
methodMap.put(key, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add configuration attributes for a secure method.
|
||||
*
|
||||
* @param method the method to be secured
|
||||
* @param attr required authorities associated with the method
|
||||
*/
|
||||
private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
|
||||
Assert.notNull(method, "RegisteredMethod required");
|
||||
Assert.notNull(attr, "Configuration attribute required");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
|
||||
}
|
||||
this.methodMap.put(method, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the configuration attributes explicitly defined against this bean.
|
||||
*
|
||||
@@ -215,93 +236,54 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
|| (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
|
||||
}
|
||||
|
||||
protected ConfigAttributeDefinition lookupAttributes(Method method) {
|
||||
List attributesToReturn = new ArrayList();
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
Assert.notNull(beanClassLoader, "Bean class loader required");
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
|
||||
// Add attributes explicitly defined for this method invocation
|
||||
merge(attributesToReturn, (ConfigAttributeDefinition) this.methodMap.get(method));
|
||||
/**
|
||||
* @return map size (for unit tests and diagnostics)
|
||||
*/
|
||||
public int getMethodMapSize() {
|
||||
return methodMap.size();
|
||||
}
|
||||
|
||||
// Add attributes explicitly defined for this method invocation's interfaces
|
||||
Class[] interfaces = method.getDeclaringClass().getInterfaces();
|
||||
/**
|
||||
* Stores both the Java Method as well as the Class we obtained the Method from. This is necessary because Method only
|
||||
* provides us access to the declaring class. It doesn't provide a way for us to introspect which Class the Method
|
||||
* was registered against. If a given Class inherits and redeclares a method (i.e. calls super();) the registered Class
|
||||
* and declaring Class are the same. If a given class merely inherits but does not redeclare a method, the registered
|
||||
* Class will be the Class we're invoking against and the Method will provide details of the declared class.
|
||||
*/
|
||||
private class RegisteredMethod {
|
||||
private Method method;
|
||||
private Class registeredJavaType;
|
||||
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
Class clazz = interfaces[i];
|
||||
public RegisteredMethod(Method method, Class registeredJavaType) {
|
||||
Assert.notNull(method, "Method required");
|
||||
Assert.notNull(registeredJavaType, "Registered Java Type required");
|
||||
this.method = method;
|
||||
this.registeredJavaType = registeredJavaType;
|
||||
}
|
||||
|
||||
try {
|
||||
// Look for the method on the current interface
|
||||
Method interfaceMethod = clazz.getDeclaredMethod(method.getName(), (Class[]) method.getParameterTypes());
|
||||
ConfigAttributeDefinition interfaceAssigned =
|
||||
(ConfigAttributeDefinition) this.methodMap.get(interfaceMethod);
|
||||
merge(attributesToReturn, interfaceAssigned);
|
||||
} catch (Exception e) {
|
||||
// skip this interface
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof RegisteredMethod) {
|
||||
RegisteredMethod rhs = (RegisteredMethod) obj;
|
||||
return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return null if empty, as per abstract superclass contract
|
||||
if (attributesToReturn.size() == 0) {
|
||||
return null;
|
||||
public int hashCode() {
|
||||
return method.hashCode() * registeredJavaType.hashCode();
|
||||
}
|
||||
|
||||
return new ConfigAttributeDefinition(attributesToReturn);
|
||||
public String toString() {
|
||||
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private void merge(List attributes, ConfigAttributeDefinition toMerge) {
|
||||
if (toMerge == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
attributes.addAll(toMerge.getConfigAttributes());
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
Assert.notNull(beanClassLoader, "Bean class loader required");
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return map size (for unit tests and diagnostics)
|
||||
*/
|
||||
public int getMethodMapSize() {
|
||||
return methodMap.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores both the Java Method as well as the Class we obtained the Method from. This is necessary because Method only
|
||||
* provides us access to the declaring class. It doesn't provide a way for us to introspect which Class the Method
|
||||
* was registered against. If a given Class inherits and redeclares a method (i.e. calls super();) the registered Class
|
||||
* and declaring Class are the same. If a given class merely inherits but does not redeclare a method, the registered
|
||||
* Class will be the Class we're invoking against and the Method will provide details of the declared class.
|
||||
*/
|
||||
private class RegisteredMethod {
|
||||
private Method method;
|
||||
private Class registeredJavaType;
|
||||
|
||||
public RegisteredMethod(Method method, Class registeredJavaType) {
|
||||
Assert.notNull(method, "Method required");
|
||||
Assert.notNull(registeredJavaType, "Registered Java Type required");
|
||||
this.method = method;
|
||||
this.registeredJavaType = registeredJavaType;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof RegisteredMethod) {
|
||||
RegisteredMethod rhs = (RegisteredMethod) obj;
|
||||
return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return method.hashCode() * registeredJavaType.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+100
-88
@@ -17,29 +17,30 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parses AspectJ pointcut expressions, registering methods that match the pointcut with a
|
||||
* traditional {@link MapBasedMethodDefinitionSource}.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This class provides a convenient way of declaring a list of pointcuts, and then
|
||||
* having every method of every bean defined in the Spring application context compared with
|
||||
* those pointcuts. Where a match is found, the matching method will be registered with the
|
||||
* {@link MapBasedMethodDefinitionSource}.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* It is very important to understand that only the <b>first</b> pointcut that matches a given
|
||||
* method will be taken as authoritative for that method. This is why pointcuts should be provided
|
||||
* as a <tt>LinkedHashMap</tt>, because their order is very important.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Note also that only beans defined in the Spring application context will be examined by this
|
||||
* class.
|
||||
* class.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Because this class registers method security metadata with {@link MapBasedMethodDefinitionSource},
|
||||
* normal Spring Security capabilities such as {@link MethodDefinitionSourceAdvisor} can be used.
|
||||
@@ -57,18 +58,18 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
|
||||
|
||||
private Map pointcutMap = new LinkedHashMap(); /** Key: string-based pointcut, value: ConfigAttributeDefinition */
|
||||
private MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource;
|
||||
private PointcutParser parser;
|
||||
|
||||
public ProtectPointcutPostProcessor(MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource) {
|
||||
Assert.notNull(mapBasedMethodDefinitionSource, "MapBasedMethodDefinitionSource to populate is required");
|
||||
this.mapBasedMethodDefinitionSource = mapBasedMethodDefinitionSource;
|
||||
|
||||
// Setup AspectJ pointcut expression parser
|
||||
Set supportedPrimitives = new HashSet();
|
||||
supportedPrimitives.add(PointcutPrimitive.EXECUTION);
|
||||
supportedPrimitives.add(PointcutPrimitive.ARGS);
|
||||
supportedPrimitives.add(PointcutPrimitive.REFERENCE);
|
||||
private MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource;
|
||||
private PointcutParser parser;
|
||||
|
||||
public ProtectPointcutPostProcessor(MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource) {
|
||||
Assert.notNull(mapBasedMethodDefinitionSource, "MapBasedMethodDefinitionSource to populate is required");
|
||||
this.mapBasedMethodDefinitionSource = mapBasedMethodDefinitionSource;
|
||||
|
||||
// Setup AspectJ pointcut expression parser
|
||||
Set supportedPrimitives = new HashSet();
|
||||
supportedPrimitives.add(PointcutPrimitive.EXECUTION);
|
||||
supportedPrimitives.add(PointcutPrimitive.ARGS);
|
||||
supportedPrimitives.add(PointcutPrimitive.REFERENCE);
|
||||
// supportedPrimitives.add(PointcutPrimitive.THIS);
|
||||
// supportedPrimitives.add(PointcutPrimitive.TARGET);
|
||||
// supportedPrimitives.add(PointcutPrimitive.WITHIN);
|
||||
@@ -76,79 +77,90 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
// supportedPrimitives.add(PointcutPrimitive.AT_WITHIN);
|
||||
// supportedPrimitives.add(PointcutPrimitive.AT_ARGS);
|
||||
// supportedPrimitives.add(PointcutPrimitive.AT_TARGET);
|
||||
parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
|
||||
}
|
||||
parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
// Obtain methods for the present bean
|
||||
Method[] methods;
|
||||
try {
|
||||
methods = bean.getClass().getMethods();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
|
||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
Iterator iter = pointcutMap.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
String ex = iter.next().toString();
|
||||
|
||||
// Parse the presented AspectJ pointcut expression
|
||||
PointcutExpression expression = parser.parsePointcutExpression(ex);
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
// Obtain methods for the present bean
|
||||
Method[] methods;
|
||||
try {
|
||||
methods = bean.getClass().getMethods();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
|
||||
// Try for the bean class directly
|
||||
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
||||
// We've found the first expression that matches this method, so move onto the next method now
|
||||
break; // the "while" loop, not the "for" loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private boolean attemptMatch(Class targetClass, Method method, PointcutExpression expression, String beanName) {
|
||||
// Determine if the presented AspectJ pointcut expression matches this method
|
||||
boolean matches = expression.matchesMethodExecution(method).alwaysMatches();
|
||||
|
||||
// Handle accordingly
|
||||
if (matches) {
|
||||
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) pointcutMap.get(expression.getPointcutExpression());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'");
|
||||
}
|
||||
|
||||
mapBasedMethodDefinitionSource.addSecureMethod(targetClass, method.getName(), attr);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public void setPointcutMap(Map map) {
|
||||
Assert.notEmpty(map);
|
||||
Iterator i = map.keySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
String expression = i.next().toString();
|
||||
Object value = map.get(expression);
|
||||
Assert.isInstanceOf(ConfigAttributeDefinition.class, value, "Map keys must be instances of ConfigAttributeDefinition");
|
||||
addPointcut(expression, (ConfigAttributeDefinition) value);
|
||||
}
|
||||
}
|
||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
Iterator iter = pointcutMap.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
String ex = iter.next().toString();
|
||||
|
||||
// Parse the presented AspectJ pointcut expression
|
||||
PointcutExpression expression = parser.parsePointcutExpression(ex);
|
||||
|
||||
// Try for the bean class directly
|
||||
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
||||
// We've found the first expression that matches this method, so move onto the next method now
|
||||
break; // the "while" loop, not the "for" loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private boolean attemptMatch(Class targetClass, Method method, PointcutExpression expression, String beanName) {
|
||||
// Determine if the presented AspectJ pointcut expression matches this method
|
||||
boolean matches = expression.matchesMethodExecution(method).alwaysMatches();
|
||||
|
||||
// Handle accordingly
|
||||
if (matches) {
|
||||
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) pointcutMap.get(expression.getPointcutExpression());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'");
|
||||
}
|
||||
|
||||
mapBasedMethodDefinitionSource.addSecureMethod(targetClass, method, attr);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public void setPointcutMap(Map map) {
|
||||
Assert.notEmpty(map);
|
||||
Iterator i = map.keySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
String expression = i.next().toString();
|
||||
Object value = map.get(expression);
|
||||
Assert.isInstanceOf(ConfigAttributeDefinition.class, value, "Map keys must be instances of ConfigAttributeDefinition");
|
||||
addPointcut(expression, (ConfigAttributeDefinition) value);
|
||||
}
|
||||
}
|
||||
|
||||
private void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
|
||||
Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
|
||||
Assert.notNull(definition, "ConfigAttributeDefinition required");
|
||||
pointcutExpression = replaceBooleanOperators(pointcutExpression);
|
||||
pointcutMap.put(pointcutExpression, definition);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.aop.aspectj.AspectJExpressionPointcut#replaceBooleanOperators
|
||||
*/
|
||||
private String replaceBooleanOperators(String pcExpr) {
|
||||
pcExpr = StringUtils.replace(pcExpr," and "," && ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
|
||||
return pcExpr;
|
||||
}
|
||||
|
||||
public void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
|
||||
Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
|
||||
Assert.notNull(definition, "ConfigAttributeDefinition required");
|
||||
pointcutMap.put(pointcutExpression, definition);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
-36
@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
|
||||
* Advisor driven by a {@link MethodDefinitionSource}, used to exclude a {@link MethodSecurityInterceptor} from
|
||||
* public (ie non-secure) methods.
|
||||
* <p>
|
||||
* Because the AOP framework caches advice calculations, this is normally faster than just letting the
|
||||
* Because the AOP framework caches advice calculations, this is normally faster than just letting the
|
||||
* <code>MethodSecurityInterceptor</code> run and find out itself that it has no work to do.
|
||||
* <p>
|
||||
* This class also allows the use of Spring's
|
||||
@@ -63,64 +63,63 @@ public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor imple
|
||||
* @deprecated use the decoupled approach instead
|
||||
*/
|
||||
public MethodDefinitionSourceAdvisor(MethodSecurityInterceptor advice) {
|
||||
Assert.notNull(advice.getObjectDefinitionSource(), "Cannot construct a MethodDefinitionSourceAdvisor using a " +
|
||||
"MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
|
||||
Assert.notNull(advice.getObjectDefinitionSource(), "Cannot construct a MethodDefinitionSourceAdvisor using a " +
|
||||
"MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
|
||||
|
||||
this.interceptor = advice;
|
||||
this.interceptor = advice;
|
||||
this.attributeSource = advice.getObjectDefinitionSource();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alternative constructor for situations where we want the advisor decoupled from the advice. Instead the advice
|
||||
* bean name should be set. This prevents eager instantiation of the interceptor
|
||||
* bean name should be set. This prevents eager instantiation of the interceptor
|
||||
* (and hence the AuthenticationManager). See SEC-773, for example.
|
||||
* <p>
|
||||
* This is essentially the approach taken by subclasses of {@link AbstractBeanFactoryPointcutAdvisor}, which this
|
||||
* class should extend in future. The original hierarchy and constructor have been retained for backwards
|
||||
* compatibilty.
|
||||
*
|
||||
* class should extend in future. The original hierarchy and constructor have been retained for backwards
|
||||
* compatibility.
|
||||
*
|
||||
* @param adviceBeanName name of the MethodSecurityInterceptor bean
|
||||
* @param attributeSource the attribute source (should be the same as the one used on the interceptor)
|
||||
*/
|
||||
public MethodDefinitionSourceAdvisor(String adviceBeanName, MethodDefinitionSource attributeSource) {
|
||||
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
|
||||
Assert.notNull(attributeSource, "The attributeSource cannot be null");
|
||||
|
||||
this.adviceBeanName = adviceBeanName;
|
||||
this.attributeSource = attributeSource;
|
||||
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
|
||||
Assert.notNull(attributeSource, "The attributeSource cannot be null");
|
||||
|
||||
this.adviceBeanName = adviceBeanName;
|
||||
this.attributeSource = attributeSource;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Pointcut getPointcut() {
|
||||
return pointcut;
|
||||
}
|
||||
public Pointcut getPointcut() {
|
||||
return pointcut;
|
||||
}
|
||||
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (interceptor == null) {
|
||||
Assert.notNull(adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
interceptor = (MethodSecurityInterceptor)
|
||||
beanFactory.getBean(this.adviceBeanName, MethodSecurityInterceptor.class);
|
||||
attributeSource = interceptor.getObjectDefinitionSource();
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (interceptor == null) {
|
||||
Assert.notNull(adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
interceptor = (MethodSecurityInterceptor)
|
||||
beanFactory.getBean(this.adviceBeanName, MethodSecurityInterceptor.class);
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
|
||||
class MethodDefinitionSourcePointcut extends StaticMethodMatcherPointcut {
|
||||
public boolean matches(Method m, Class targetClass) {
|
||||
return attributeSource.getAttributes(m, targetClass) != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents a <code>MethodInvocation</code>.
|
||||
* <p>
|
||||
@@ -153,7 +152,7 @@ public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor imple
|
||||
}
|
||||
|
||||
public Object getThis() {
|
||||
return this.targetClass;
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
public Object proceed() throws Throwable {
|
||||
|
||||
+1
-1
@@ -12,5 +12,5 @@ package org.springframework.security.intercept.method.aspectj;
|
||||
public interface AspectJAnnotationCallback {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
Object proceedWithObject();
|
||||
Object proceedWithObject() throws Throwable;
|
||||
}
|
||||
|
||||
@@ -54,4 +54,16 @@ public class RequestKey {
|
||||
|
||||
return method.equals(key.method);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(url.length() + 7);
|
||||
sb.append("[");
|
||||
if (method != null) {
|
||||
sb.append(method).append(",");
|
||||
}
|
||||
sb.append(url);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ public final class LdapUtils {
|
||||
|
||||
if (url.startsWith("ldap:") || url.startsWith("ldaps:")) {
|
||||
URI uri = parseLdapUrl(url);
|
||||
urlRootDn = uri.getPath();
|
||||
urlRootDn = uri.getRawPath();
|
||||
} else {
|
||||
// Assume it's an embedded server
|
||||
urlRootDn = url;
|
||||
|
||||
+59
-50
@@ -15,6 +15,21 @@
|
||||
|
||||
package org.springframework.security.ldap;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.PartialResultException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.core.ContextExecutor;
|
||||
import org.springframework.ldap.core.ContextMapper;
|
||||
@@ -23,33 +38,18 @@ import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.LdapEncoder;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* LDAP equivalent of the Spring JdbcTemplate class.
|
||||
* <p>
|
||||
* This is mainly intended to simplify Ldap access within Spring Security's LDAP-related services.
|
||||
* </p>
|
||||
* Extension of Spring LDAP's LdapTemplate class which adds extra functionality required by Spring Security.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.LdapTemplate {
|
||||
public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
private static final Log logger = LogFactory.getLog(SpringSecurityLdapTemplate.class);
|
||||
|
||||
@@ -136,14 +136,14 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
|
||||
* @return the set of String values for the attribute as a union of the values found in all the matching entries.
|
||||
*/
|
||||
public Set searchForSingleAttributeValues(final String base, final String filter, final Object[] params,
|
||||
final String attributeName) {
|
||||
// Escape the params acording to RFC2254
|
||||
Object[] encodedParams = new String[params.length];
|
||||
|
||||
for (int i=0; i < params.length; i++) {
|
||||
encodedParams[i] = LdapEncoder.filterEncode(params[i].toString());
|
||||
}
|
||||
|
||||
final String attributeName) {
|
||||
// Escape the params acording to RFC2254
|
||||
Object[] encodedParams = new String[params.length];
|
||||
|
||||
for (int i=0; i < params.length; i++) {
|
||||
encodedParams[i] = LdapEncoder.filterEncode(params[i].toString());
|
||||
}
|
||||
|
||||
String formattedFilter = MessageFormat.format(filter, encodedParams);
|
||||
logger.debug("Using filter: " + formattedFilter);
|
||||
|
||||
@@ -175,12 +175,15 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
|
||||
/**
|
||||
* Performs a search, with the requirement that the search shall return a single directory entry, and uses
|
||||
* the supplied mapper to create the object from that entry.
|
||||
* <p>
|
||||
* Ignores <tt>PartialResultException</tt> if thrown, for compatibility with Active Directory
|
||||
* (see {@link LdapTemplate#setIgnorePartialResultException(boolean)}).
|
||||
*
|
||||
* @param base
|
||||
* @param filter
|
||||
* @param params
|
||||
* @param base the search base, relative to the base context supplied by the context source.
|
||||
* @param filter the LDAP search filter
|
||||
* @param params parameters to be substituted in the search.
|
||||
*
|
||||
* @return the object created by the mapper from the matching entry
|
||||
* @return a DirContextOperations instance created from the matching entry.
|
||||
*
|
||||
* @throws IncorrectResultSizeDataAccessException if no results are found or the search returns more than one
|
||||
* result.
|
||||
@@ -188,32 +191,38 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
|
||||
public DirContextOperations searchForSingleEntry(final String base, final String filter, final Object[] params) {
|
||||
|
||||
return (DirContextOperations) executeReadOnly(new ContextExecutor() {
|
||||
public Object executeWithContext(DirContext ctx)
|
||||
throws NamingException {
|
||||
public Object executeWithContext(DirContext ctx) throws NamingException {
|
||||
DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
|
||||
NamingEnumeration resultsEnum = ctx.search(base, filter, params, searchControls);
|
||||
Set results = new HashSet();
|
||||
try {
|
||||
while (resultsEnum.hasMore()) {
|
||||
|
||||
NamingEnumeration results = ctx.search(base, filter, params, searchControls);
|
||||
SearchResult searchResult = (SearchResult) resultsEnum.next();
|
||||
// Work out the DN of the matched entry
|
||||
StringBuffer dn = new StringBuffer(searchResult.getName());
|
||||
|
||||
if (!results.hasMore()) {
|
||||
if (base.length() > 0) {
|
||||
dn.append(",");
|
||||
dn.append(base);
|
||||
}
|
||||
|
||||
results.add(new DirContextAdapter(searchResult.getAttributes(),
|
||||
new DistinguishedName(dn.toString()), ctxBaseDn));
|
||||
}
|
||||
} catch (PartialResultException e) {
|
||||
logger.info("Ignoring PartialResultException");
|
||||
}
|
||||
|
||||
if (results.size() == 0) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, 0);
|
||||
}
|
||||
|
||||
SearchResult searchResult = (SearchResult) results.next();
|
||||
|
||||
if (results.hasMore()) {
|
||||
// We don't know how many results but set to 2 which is good enough
|
||||
throw new IncorrectResultSizeDataAccessException(1, 2);
|
||||
if (results.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, results.size());
|
||||
}
|
||||
|
||||
// Work out the DN of the matched entry
|
||||
StringBuffer dn = new StringBuffer(searchResult.getName());
|
||||
|
||||
if (base.length() > 0) {
|
||||
dn.append(",");
|
||||
dn.append(base);
|
||||
}
|
||||
|
||||
return new DirContextAdapter(searchResult.getAttributes(),
|
||||
new DistinguishedName(dn.toString()), new DistinguishedName(ctx.getNameInNamespace()));
|
||||
return results.toArray()[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+5
-18
@@ -99,8 +99,6 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
*/
|
||||
private GrantedAuthority defaultRole;
|
||||
|
||||
private ContextSource contextSource;
|
||||
|
||||
private SpringSecurityLdapTemplate ldapTemplate;
|
||||
|
||||
/**
|
||||
@@ -143,8 +141,10 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
* context factory.
|
||||
*/
|
||||
public DefaultLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
|
||||
this.setContextSource(contextSource);
|
||||
this.setGroupSearchBase(groupSearchBase);
|
||||
Assert.notNull(contextSource, "contextSource must not be null");
|
||||
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
|
||||
ldapTemplate.setSearchControls(searchControls);
|
||||
setGroupSearchBase(groupSearchBase);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -226,20 +226,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
}
|
||||
|
||||
protected ContextSource getContextSource() {
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ContextSource}
|
||||
*
|
||||
* @param contextSource supplies the contexts used to search for user roles.
|
||||
*/
|
||||
private void setContextSource(ContextSource contextSource) {
|
||||
Assert.notNull(contextSource, "contextSource must not be null");
|
||||
this.contextSource = contextSource;
|
||||
|
||||
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
|
||||
ldapTemplate.setSearchControls(searchControls);
|
||||
return ldapTemplate.getContextSource();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,17 +144,10 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
checkIfValidList(this.providers);
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
exceptionMappings.putAll(additionalExceptionMappings);
|
||||
}
|
||||
|
||||
private void checkIfValidList(List listToCheck) {
|
||||
if ((listToCheck == null) || (listToCheck.size() == 0)) {
|
||||
throw new IllegalArgumentException("A list of AuthenticationProviders is required");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to authenticate the passed {@link Authentication} object.
|
||||
* <p>
|
||||
@@ -174,7 +167,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
* @throws AuthenticationException if authentication fails.
|
||||
*/
|
||||
public Authentication doAuthentication(Authentication authentication) throws AuthenticationException {
|
||||
Iterator iter = providers.iterator();
|
||||
Iterator iter = getProviders().iterator();
|
||||
|
||||
Class toTest = authentication.getClass();
|
||||
|
||||
@@ -273,7 +266,11 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
}
|
||||
|
||||
public List getProviders() {
|
||||
return this.providers;
|
||||
if (providers == null || providers.size() == 0) {
|
||||
throw new IllegalArgumentException("A list of AuthenticationProviders is required");
|
||||
}
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,8 +300,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
* AuthenticationProvider instance.
|
||||
*/
|
||||
public void setProviders(List providers) {
|
||||
checkIfValidList(providers);
|
||||
|
||||
Assert.notEmpty(providers, "A list of AuthenticationProviders is required");
|
||||
Iterator iter = providers.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
|
||||
+13
-15
@@ -15,30 +15,28 @@
|
||||
|
||||
package org.springframework.security.providers.anonymous;
|
||||
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.providers.AuthenticationProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.providers.AuthenticationProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation that validates {@link
|
||||
* org.springframework.security.providers.anonymous.AnonymousAuthenticationToken}s.<p>To be successfully validated, the
|
||||
* {@link org.springframework.security.providers.anonymous.AnonymousAuthenticationToken#getKeyHash()} must match this class'
|
||||
* {@link #getKey()}.</p>
|
||||
* An {@link AuthenticationProvider} implementation that validates {@link AnonymousAuthenticationToken}s.
|
||||
* <p>
|
||||
* To be successfully validated, the {@link AnonymousAuthenticationToken#getKeyHash()} must match this class'
|
||||
* {@link #getKey()}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AnonymousAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AnonymousAuthenticationProvider.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@@ -47,7 +45,7 @@ public class AnonymousAuthenticationProvider implements AuthenticationProvider,
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(key, "A Key is required");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
}
|
||||
|
||||
+5
-3
@@ -45,7 +45,7 @@ import java.security.cert.X509Certificate;
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @deprecated superceded by the preauth provider. Use the X.509 authentication support in org.springframework.security.ui.preauth.x509 instead
|
||||
* or namespace support via the <x509 /> element.
|
||||
* or namespace support via the <x509 /> element.
|
||||
* @version $Id$
|
||||
*/
|
||||
public class X509AuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
||||
@@ -61,7 +61,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(userCache, "An x509UserCache must be set");
|
||||
Assert.notNull(x509AuthoritiesPopulator, "An X509AuthoritiesPopulator must be set");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
@@ -101,7 +101,9 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi
|
||||
UserDetails user = userCache.getUserFromCache(clientCertificate);
|
||||
|
||||
if (user == null) {
|
||||
logger.debug("Authenticating with certificate " + clientCertificate);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authenticating with certificate " + clientCertificate);
|
||||
}
|
||||
user = x509AuthoritiesPopulator.getUserDetails(clientCertificate);
|
||||
userCache.putUserInCache(clientCertificate, user);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,11 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
|
||||
private Properties exceptionMappings = new Properties();
|
||||
|
||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||
/**
|
||||
* Delay use of NullRememberMeServices until initialization so that namespace has a chance to inject
|
||||
* the RememberMeServices implementation into custom implementations.
|
||||
*/
|
||||
private RememberMeServices rememberMeServices = null;
|
||||
|
||||
private TargetUrlResolver targetUrlResolver = new TargetUrlResolverImpl();
|
||||
|
||||
@@ -218,11 +222,13 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
|
||||
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultTargetUrl), defaultTargetUrl + " isn't a valid redirect URL");
|
||||
// Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(authenticationFailureUrl), authenticationFailureUrl + " isn't a valid redirect URL");
|
||||
Assert.notNull(authenticationManager, "authenticationManager must be specified");
|
||||
Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
|
||||
Assert.notNull(targetUrlResolver, "targetUrlResolver cannot be null");
|
||||
|
||||
if (rememberMeServices == null) {
|
||||
rememberMeServices = new NullRememberMeServices();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+24
-14
@@ -35,6 +35,7 @@ import org.springframework.security.ui.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.security.ui.SpringSecurityFilter;
|
||||
import org.springframework.security.ui.rememberme.NullRememberMeServices;
|
||||
import org.springframework.security.ui.rememberme.RememberMeServices;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -91,7 +92,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
private AuthenticationManager authenticationManager;
|
||||
private RememberMeServices rememberMeServices;
|
||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||
private boolean ignoreFailure = false;
|
||||
private String credentialsCharset = "UTF-8";
|
||||
|
||||
@@ -105,10 +106,10 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
}
|
||||
}
|
||||
|
||||
public void doFilterHttp(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain)
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
String header = httpRequest.getHeader("Authorization");
|
||||
String header = request.getHeader("Authorization");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authorization header: " + header);
|
||||
@@ -116,7 +117,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
if ((header != null) && header.startsWith("Basic ")) {
|
||||
byte[] base64Token = header.substring(6).getBytes("UTF-8");
|
||||
String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(httpRequest));
|
||||
String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(request));
|
||||
|
||||
String username = "";
|
||||
String password = "";
|
||||
@@ -130,7 +131,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
if (authenticationIsRequired(username)) {
|
||||
UsernamePasswordAuthenticationToken authRequest =
|
||||
new UsernamePasswordAuthenticationToken(username, password);
|
||||
authRequest.setDetails(authenticationDetailsSource.buildDetails(httpRequest));
|
||||
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
|
||||
|
||||
Authentication authResult;
|
||||
|
||||
@@ -144,14 +145,14 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
if (rememberMeServices != null) {
|
||||
rememberMeServices.loginFail(httpRequest, httpResponse);
|
||||
}
|
||||
rememberMeServices.loginFail(request, response);
|
||||
|
||||
onUnsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
if (ignoreFailure) {
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
authenticationEntryPoint.commence(httpRequest, httpResponse, failed);
|
||||
authenticationEntryPoint.commence(request, response, failed);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -164,13 +165,13 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authResult);
|
||||
|
||||
if (rememberMeServices != null) {
|
||||
rememberMeServices.loginSuccess(httpRequest, httpResponse, authResult);
|
||||
}
|
||||
rememberMeServices.loginSuccess(request, response, authResult);
|
||||
|
||||
onSuccessfulAuthentication(request, response, authResult);
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private boolean authenticationIsRequired(String username) {
|
||||
@@ -202,6 +203,14 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authResult) throws IOException {
|
||||
}
|
||||
|
||||
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
}
|
||||
|
||||
protected AuthenticationEntryPoint getAuthenticationEntryPoint() {
|
||||
return authenticationEntryPoint;
|
||||
@@ -233,6 +242,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
}
|
||||
|
||||
public void setRememberMeServices(RememberMeServices rememberMeServices) {
|
||||
Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -34,10 +34,10 @@ import javax.servlet.http.HttpSession;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecurityContextLogoutHandler implements LogoutHandler {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private boolean invalidateHttpSession = true;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Requires the request to be passed in.
|
||||
*
|
||||
@@ -69,6 +69,6 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
|
||||
*/
|
||||
public void setInvalidateHttpSession(boolean invalidateHttpSession) {
|
||||
this.invalidateHttpSession = invalidateHttpSession;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
@@ -25,6 +25,13 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Base class for processing filters that handle pre-authenticated authentication requests. Subclasses must implement
|
||||
* the getPreAuthenticatedPrincipal() and getPreAuthenticatedCredentials() methods.
|
||||
* <p>
|
||||
* By default, the filter chain will proceed when an authentication attempt fails in order to allow other
|
||||
* authentication mechanisms to process the request. To reject the credentials immediately, set the
|
||||
* <tt>continueFilterChainOnUnsuccessfulAuthentication</tt> flag to false. The exception raised by the
|
||||
* <tt>AuthenticationManager</tt> will the be re-thrown. Note that this will not affect cases where the principal
|
||||
* returned by {@link #getPreAuthenticatedPrincipal} is null, when the chain will still proceed as normal.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ruud Senden
|
||||
@@ -38,6 +45,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
private AuthenticationManager authenticationManager = null;
|
||||
|
||||
private boolean continueFilterChainOnUnsuccessfulAuthentication = true;
|
||||
|
||||
/**
|
||||
* Check whether all required properties have been set.
|
||||
@@ -88,6 +97,10 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
|
||||
successfulAuthentication(request, response, authResult);
|
||||
} catch (AuthenticationException failed) {
|
||||
unsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
if (!continueFilterChainOnUnsuccessfulAuthentication) {
|
||||
throw failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,8 +156,19 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
public void setContinueFilterChainOnUnsuccessfulAuthentication(boolean shouldContinue) {
|
||||
continueFilterChainOnUnsuccessfulAuthentication = shouldContinue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to extract the principal information from the current request
|
||||
*/
|
||||
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Override to extract the credentials (if applicable) from the current request. Some implementations
|
||||
* may return a dummy value.
|
||||
*/
|
||||
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
|
||||
}
|
||||
|
||||
+21
-17
@@ -32,14 +32,14 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
public static final String SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY = "SPRING_SECURITY_REMEMBER_ME_COOKIE";
|
||||
public static final String DEFAULT_PARAMETER = "_spring_security_remember_me";
|
||||
|
||||
private static final String DELIMITER = ":";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
//~ Instance fields ================================================================================================
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
@@ -49,7 +49,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
private String cookieName = SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
|
||||
private String parameter = DEFAULT_PARAMETER;
|
||||
private String parameter = DEFAULT_PARAMETER;
|
||||
private boolean alwaysRemember;
|
||||
private String key;
|
||||
private int tokenValiditySeconds = 1209600; // 14 days
|
||||
@@ -232,14 +232,14 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
}
|
||||
|
||||
String paramValue = request.getParameter(parameter);
|
||||
|
||||
|
||||
if (paramValue != null) {
|
||||
if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on") ||
|
||||
paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on") ||
|
||||
paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Did not send remember-me cookie (principal did not set parameter '" + parameter + "')");
|
||||
}
|
||||
@@ -309,6 +309,10 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
|
||||
protected String getCookieName() {
|
||||
return cookieName;
|
||||
}
|
||||
|
||||
public void setAlwaysRemember(boolean alwaysRemember) {
|
||||
this.alwaysRemember = alwaysRemember;
|
||||
}
|
||||
@@ -316,11 +320,11 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
/**
|
||||
* Sets the name of the parameter which should be checked for to see if a remember-me has been requested
|
||||
* during a login request. This should be the same name you assign to the checkbox in your login form.
|
||||
*
|
||||
*
|
||||
* @param parameter the HTTP request parameter
|
||||
*/
|
||||
public void setParameter(String parameter) {
|
||||
Assert.hasText(parameter, "Parameter name cannot be null");
|
||||
Assert.hasText(parameter, "Parameter name cannot be null");
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@@ -333,7 +337,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
Assert.notNull(userDetailsService, "UserDetailsService canot be null");
|
||||
Assert.notNull(userDetailsService, "UserDetailsService canot be null");
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@@ -357,8 +361,8 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
return authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource cannot be null");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource cannot be null");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -304,8 +304,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
|
||||
logger.debug("Switch User failed", failed);
|
||||
|
||||
if (switchFailureUrl != null) {
|
||||
switchFailureUrl = request.getContextPath() + switchFailureUrl;
|
||||
response.sendRedirect(response.encodeRedirectURL(switchFailureUrl));
|
||||
sendRedirect(request, response, switchFailureUrl);
|
||||
} else {
|
||||
response.getWriter().print("Switch user failed: " + failed.getMessage());
|
||||
response.flushBuffer();
|
||||
|
||||
+2
@@ -25,6 +25,8 @@ import org.springframework.dao.DataAccessException;
|
||||
* instead of only the directly assigned authorities.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
* @deprecated use a {@link RoleHierarchyVoter} instead of populating the user Authentication object
|
||||
* with the additional authorities.
|
||||
*/
|
||||
public class UserDetailsServiceWrapper implements UserDetailsService {
|
||||
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ import org.springframework.security.userdetails.UserDetails;
|
||||
* delegated to the <tt>UserDetails</tt> implementation.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
* @deprecated use a {@link RoleHierarchyVoter} instead.
|
||||
*/
|
||||
public class UserDetailsWrapper implements UserDetails {
|
||||
|
||||
|
||||
@@ -47,23 +47,53 @@ import javax.sql.DataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves user details (username, password, enabled flag, and authorities) from a JDBC location.
|
||||
* <tt>UserDetailsServiceRetrieves</tt> implementation which retrieves the user details
|
||||
* (username, password, enabled flag, and authorities) from a database using JDBC queries.
|
||||
*
|
||||
* <h3>Default Schema</h3>
|
||||
* A default database schema is assumed, with two tables "users" and "authorities".
|
||||
*
|
||||
* <h4>The Users table</h4>
|
||||
*
|
||||
* This table contains the login name, password and enabled status of the user.
|
||||
*
|
||||
* <table>
|
||||
* <tr><th>Column</th></tr>
|
||||
* <tr><td>username</td></tr>
|
||||
* <tr><td>password</td></tr>
|
||||
* <tr><td>enabled</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <h4>The Authorities Table</h4>
|
||||
*
|
||||
* <table>
|
||||
* <tr><th>Column</th></tr>
|
||||
* <tr><td>username</td></tr>
|
||||
* <tr><td>authority</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* If you are using an existing schema you will have to set the queries <tt>usersByUsernameQuery</tt> and
|
||||
* <tt>authoritiesByUsernameQuery</tt> to match your database setup
|
||||
* (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link #DEF_AUTHORITIES_BY_USERNAME_QUERY}).
|
||||
*
|
||||
* <p>
|
||||
* A default database structure is assumed, (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link
|
||||
* #DEF_AUTHORITIES_BY_USERNAME_QUERY}, which most users of this class will need to override, if using an existing
|
||||
* scheme. This may be done by setting the default query strings used.
|
||||
* <p>
|
||||
* In order to minimise backward compatibility issues, this DAO does not recognise the expiration of user
|
||||
* In order to minimise backward compatibility issues, this implementation doesn't recognise the expiration of user
|
||||
* accounts or the expiration of user credentials. However, it does recognise and honour the user enabled/disabled
|
||||
* column.
|
||||
* <p>
|
||||
* column. This should map to a <tt>boolean</tt> type in the result set (the SQL type will depend on the
|
||||
* database you are using). All the other columns map to <tt>String</tt>s.
|
||||
*
|
||||
* <h3>Group Support</h3>
|
||||
* Support for group-based authorities can be enabled by setting the <tt>enableGroups</tt> property to <tt>true</tt>
|
||||
* (you may also then wish to set <tt>enableAuthorities</tt> to <tt>false</tt> to disable loading of authorities
|
||||
* directly). With this approach, authorities are allocated to groups and a user's authorities are determined based
|
||||
* on the groups they are a member of. The net result is the same (a UserDetails containing a set of
|
||||
* <tt>GrantedAuthority</tt>s is loaded), but the different persistence strategy may be more suitable for the
|
||||
* administration of some applications.
|
||||
*
|
||||
* <p>
|
||||
* When groups are being used, the tables "groups", "group_members" and "group_authorities" are used. See
|
||||
* {@link #DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY} for the default query which is used to load the group authorities.
|
||||
* Again you can customize this by setting the <tt>groupAuthoritiesByUsernameQuery</tt> property, but the format of
|
||||
* the rows returned should match the default.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author colin sampaleanu
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
|
||||
public Object executeWithContext(DirContext dirCtx) throws NamingException {
|
||||
LdapContext ctx = (LdapContext) dirCtx;
|
||||
ctx.removeFromEnvironment("com.sun.jndi.ldap.connect.pool");
|
||||
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, LdapUtils.getFullDn(dn, ctx).toUrl());
|
||||
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, LdapUtils.getFullDn(dn, ctx).toString());
|
||||
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, oldPassword);
|
||||
// TODO: reconnect doesn't appear to actually change the credentials
|
||||
try {
|
||||
|
||||
@@ -107,6 +107,7 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
/** Compiled pattern version of the filter chain map */
|
||||
private Map filterChainMap;
|
||||
private UrlMatcher matcher = new AntUrlPathMatcher();
|
||||
private boolean stripQueryStringFromUrls = true;
|
||||
private DefaultFilterInvocationDefinitionSource fids;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -116,8 +117,8 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
if (fids != null) {
|
||||
Assert.isNull(uncompiledFilterChainMap, "Set the filterChainMap or FilterInvocationDefinitionSource but not both");
|
||||
FIDSToFilterChainMapConverter converter = new FIDSToFilterChainMapConverter(fids, applicationContext);
|
||||
setMatcher(converter.getMatcher());
|
||||
setFilterChainMap(converter.getFilterChainMap());
|
||||
setMatcher(converter.getMatcher());
|
||||
setFilterChainMap(converter.getFilterChainMap());
|
||||
fids = null;
|
||||
}
|
||||
|
||||
@@ -181,6 +182,16 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
* @return an ordered array of Filters defining the filter chain
|
||||
*/
|
||||
public List getFilters(String url) {
|
||||
if (stripQueryStringFromUrls) {
|
||||
// String query string - see SEC-953
|
||||
int firstQuestionMarkIndex = url.indexOf("?");
|
||||
|
||||
if (firstQuestionMarkIndex != -1) {
|
||||
url = url.substring(0, firstQuestionMarkIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Iterator filterChains = filterChainMap.entrySet().iterator();
|
||||
|
||||
while (filterChains.hasNext()) {
|
||||
@@ -319,6 +330,14 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to 'true', the query string will be stripped from the request URL before
|
||||
* attempting to find a matching filter chain. This is the default value.
|
||||
*/
|
||||
public void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) {
|
||||
this.stripQueryStringFromUrls = stripQueryStringFromUrls;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("FilterChainProxy[");
|
||||
|
||||
@@ -2,18 +2,22 @@ package org.springframework.security.util;
|
||||
|
||||
/**
|
||||
* Utilities for working with Strings and text.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class TextUtils {
|
||||
|
||||
public static String escapeEntities(String s) {
|
||||
if (s == null || s.length() == 0) {
|
||||
return s;
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
|
||||
for (int i=0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
|
||||
if(c == '<') {
|
||||
sb.append("<");
|
||||
} else if (c == '>') {
|
||||
@@ -22,12 +26,14 @@ public abstract class TextUtils {
|
||||
sb.append(""");
|
||||
} else if (c == '\'') {
|
||||
sb.append("'");
|
||||
} else if (c == '&') {
|
||||
sb.append("&");
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.springframework.security.vote;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.userdetails.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extended RoleVoter which uses a {@link RoleHierarchy} definition to determine the
|
||||
* roles allocated to the current user before voting.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class RoleHierarchyVoter extends RoleVoter {
|
||||
private RoleHierarchy roleHierarchy = null;
|
||||
|
||||
public RoleHierarchyVoter(RoleHierarchy roleHierarchy) {
|
||||
Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the <tt>RoleHierarchy</tt> to obtain the complete set of user authorities.
|
||||
*/
|
||||
GrantedAuthority[] extractAuthorities(Authentication authentication) {
|
||||
return roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,7 @@ public class RoleVoter implements AccessDecisionVoter {
|
||||
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
|
||||
int result = ACCESS_ABSTAIN;
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
GrantedAuthority[] authorities = extractAuthorities(authentication);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attribute = (ConfigAttribute) iter.next();
|
||||
@@ -102,7 +103,6 @@ public class RoleVoter implements AccessDecisionVoter {
|
||||
if (this.supports(attribute)) {
|
||||
result = ACCESS_DENIED;
|
||||
|
||||
GrantedAuthority[] authorities = authentication.getAuthorities();
|
||||
// Attempt to find a matching granted authority
|
||||
for (int i = 0; i < authorities.length; i++) {
|
||||
if (attribute.getAttribute().equals(authorities[i].getAuthority())) {
|
||||
@@ -114,4 +114,8 @@ public class RoleVoter implements AccessDecisionVoter {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GrantedAuthority[] extractAuthorities(Authentication authentication) {
|
||||
return authentication.getAuthorities();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
|
||||
|
||||
+15
-10
@@ -46,6 +46,7 @@ password-encoder.attlist &=
|
||||
ref | (hash? & base64?)
|
||||
|
||||
salt-source =
|
||||
## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.
|
||||
element salt-source {user-property | system-wide}
|
||||
user-property =
|
||||
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
|
||||
@@ -69,8 +70,8 @@ ldap-server.attlist &= (url | port)?
|
||||
ldap-server.attlist &=
|
||||
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
|
||||
attribute manager-dn {xsd:string}?
|
||||
## The password for the manager DN.
|
||||
ldap-server.attlist &=
|
||||
## The password for the manager DN.
|
||||
attribute manager-password {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## Explicitly specifies an ldif file resource to load into an embedded LDAP server
|
||||
@@ -88,12 +89,13 @@ group-search-filter-attribute =
|
||||
## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
|
||||
attribute group-search-filter {xsd:string}
|
||||
group-search-base-attribute =
|
||||
## Search base for group membership searches. Defaults to "ou=groups".
|
||||
## Search base for group membership searches. Defaults to "" (searching from the root).
|
||||
attribute group-search-base {xsd:string}
|
||||
user-search-filter-attribute =
|
||||
## The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.
|
||||
attribute user-search-filter {xsd:string}
|
||||
user-search-base-attribute =
|
||||
## Search base for user searches. Defaults to "".
|
||||
## Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.
|
||||
attribute user-search-base {xsd:string}
|
||||
group-role-attribute-attribute =
|
||||
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".
|
||||
@@ -191,6 +193,7 @@ global-method-security.attlist &=
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
|
||||
custom-after-invocation-provider =
|
||||
## Used to decorate an AfterInvocationProvider to specify that it should be used with method security.
|
||||
element custom-after-invocation-provider {empty}
|
||||
|
||||
protect-pointcut =
|
||||
@@ -258,7 +261,7 @@ intercept-url.attlist &=
|
||||
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
|
||||
attribute filters {"none"}?
|
||||
intercept-url.attlist &=
|
||||
## Used to specify that a URL must be accessed over http or https
|
||||
## Used to specify that a URL must be accessed over http or https, or that there is no preference.
|
||||
attribute requires-channel {"http" | "https" | "any"}?
|
||||
|
||||
logout =
|
||||
@@ -333,12 +336,13 @@ concurrent-session-control =
|
||||
## Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have.
|
||||
element concurrent-session-control {concurrent-sessions.attlist, empty}
|
||||
concurrent-sessions.attlist &=
|
||||
## The maximum number of sessions a single user can have open at the same time. Defaults to "1".
|
||||
attribute max-sessions {xsd:positiveInteger}?
|
||||
concurrent-sessions.attlist &=
|
||||
## The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller.
|
||||
## The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because they have logged in again.
|
||||
attribute expired-url {xsd:string}?
|
||||
concurrent-sessions.attlist &=
|
||||
## Specifies that an exception should be raised when a user attempts to login twice. The default behaviour is to expire the original session.
|
||||
## Specifies that an exception should be raised when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session.
|
||||
attribute exception-if-maximum-exceeded {boolean}?
|
||||
concurrent-sessions.attlist &=
|
||||
## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration
|
||||
@@ -371,7 +375,7 @@ remember-me-services-ref =
|
||||
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
|
||||
attribute services-ref {xsd:string}?
|
||||
remember-me-data-source-ref =
|
||||
## DataSource bean for the database that contains the token
|
||||
## DataSource bean for the database that contains the token repository schema.
|
||||
data-source-ref
|
||||
|
||||
anonymous =
|
||||
@@ -396,9 +400,9 @@ port-mappings.attlist &= empty
|
||||
port-mapping =
|
||||
element port-mapping {http-port, https-port}
|
||||
|
||||
http-port = attribute http {xsd:integer}
|
||||
http-port = attribute http {xsd:string}
|
||||
|
||||
https-port = attribute https {xsd:integer}
|
||||
https-port = attribute https {xsd:string}
|
||||
|
||||
|
||||
x509 =
|
||||
@@ -430,6 +434,7 @@ ap.attlist &=
|
||||
user-service-ref?
|
||||
|
||||
custom-authentication-provider =
|
||||
## Element used to decorate an AuthenticationProvider bean to add it to the internal AuthenticationManager maintained by the namespace.
|
||||
element custom-authentication-provider {cap.attlist}
|
||||
cap.attlist &= empty
|
||||
|
||||
@@ -496,6 +501,6 @@ position =
|
||||
|
||||
|
||||
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "OPENID_PROCESSING_FILTER" |"BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
|
||||
|
||||
+1468
File diff suppressed because it is too large
Load Diff
@@ -222,7 +222,7 @@
|
||||
<xs:attribute name="group-search-base" use="required" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Search base for group membership searches. Defaults to
|
||||
"ou=groups".</xs:documentation>
|
||||
"" (searching from the root).</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
AuthByAdapterProvider.incorrectKey=La actual implementación de AuthByAdapter no contiene la clave esperada
|
||||
BasicAclEntryAfterInvocationProvider.noPermission=Authentication {0} NO tiene permisos para el objeto de dominio {1}
|
||||
BasicAclEntryAfterInvocationProvider.insufficientPermission=Authentication {0} tiene permisos ACL para objeto de dominio, pero no los permisos ACL requeridos para el objeto de dominio {1}
|
||||
ConcurrentSessionControllerImpl.exceededAllowed=Sesiones máximas de {0} para esta Identificación excedidas
|
||||
ProviderManager.providerNotFound=AuthenticationProvider no encontrado para {0}
|
||||
AnonymousAuthenticationProvider.incorrectKey=El actual AnonymousAuthenticationToken no contiene la clave esperada
|
||||
CasAuthenticationProvider.incorrectKey=El actual CasAuthenticationToken no contiene la clave esperada
|
||||
CasAuthenticationProvider.noServiceTicket=No se ha podido proporcionar un billete de servicio CAS para validar
|
||||
NamedCasProxyDecider.untrusted=El proxy más cercano {0} no es confiable
|
||||
RejectProxyTickets.reject=Las entradas del proxy han sido rechazadas
|
||||
AbstractSecurityInterceptor.authenticationNotFound=El objeto Authentication no ha sido encontrado en el SecurityContext
|
||||
AbstractUserDetailsAuthenticationProvider.onlySupports=Sólo UsernamePasswordAuthenticationToken es soportada
|
||||
AbstractUserDetailsAuthenticationProvider.locked=La cuenta del usuario está bloqueada
|
||||
AbstractUserDetailsAuthenticationProvider.disabled=El usuario está deshabilitado
|
||||
AbstractUserDetailsAuthenticationProvider.expired=La cuenta del usuario ha expirado
|
||||
AbstractUserDetailsAuthenticationProvider.credentialsExpired=Las credenciales del usuario han expirado
|
||||
AbstractUserDetailsAuthenticationProvider.badCredentials=Credenciales erróneas
|
||||
X509AuthenticationProvider.certificateNull=Cerfificado nulo
|
||||
DaoX509AuthoritiesPopulator.noMatching=No se ha encontrado un patrón coincidente en subjectDN: {0}
|
||||
RememberMeAuthenticationProvider.incorrectKey=El actual RememberMeAuthenticationToken no contiene la clave esperada
|
||||
RunAsImplAuthenticationProvider.incorrectKey=El actual RunAsUserToken no contiene la clave esperada
|
||||
DigestProcessingFilter.missingMandatory=Valor digest obligatorio perdido; header recibido {0}
|
||||
DigestProcessingFilter.missingAuth=Valor digest obligatorio perdido para 'auth' QOP; header recibido {0}
|
||||
DigestProcessingFilter.incorrectRealm=Respuesta realm de nombre {0} no coincide con realm del sistema de nombre {1}
|
||||
DigestProcessingFilter.nonceExpired=Nonce ha expirado/fuera de tiempo
|
||||
DigestProcessingFilter.nonceEncoding=Nonce no está codificado en Base64; nonce recibido {0}
|
||||
DigestProcessingFilter.nonceNotTwoTokens=Nonce token debería tener dos fichas pero tenía {0}
|
||||
DigestProcessingFilter.nonceNotNumeric=Nonce token debería tener primero un token numérico, pero tenía {0}
|
||||
DigestProcessingFilter.nonceCompromised=Nonce token comprometido {0}
|
||||
DigestProcessingFilter.usernameNotFound=Usuario y nombre {0} no encontrado
|
||||
DigestProcessingFilter.incorrectResponse=Respuesta incorrecta
|
||||
JdbcDaoImpl.notFound=Usuario {0} no encontrado
|
||||
JdbcDaoImpl.noAuthority=Usuario {0} no tiene GrantedAuthority
|
||||
SwitchUserProcessingFilter.noCurrentUser=No hay usuario actual asociado con esta petición
|
||||
SwitchUserProcessingFilter.noOriginalAuthentication=No se puede encontrar el objeto Authentication original
|
||||
SwitchUserProcessingFilter.usernameNotFound=Usuario y nombre {0} no encontrado
|
||||
SwitchUserProcessingFilter.locked=La cuenta del usuario está bloqueada
|
||||
SwitchUserProcessingFilter.disabled=El usuario está deshabilitado
|
||||
SwitchUserProcessingFilter.expired=La cuenta del usuario ha expirado
|
||||
SwitchUserProcessingFilter.credentialsExpired=Las credenciales del usuario han expirado
|
||||
AbstractAccessDecisionManager.accessDenied=Acceso denegado
|
||||
LdapAuthenticationProvider.emptyUsername=Usuario y nombre no permitido
|
||||
LdapAuthenticationProvider.emptyPassword=Credenciales erróneas
|
||||
DefaultIntitalDirContextFactory.communicationFailure=No se puede conectar con el servidor LDAP
|
||||
DefaultIntitalDirContextFactory.badCredentials=Credenciales erróneas
|
||||
DefaultIntitalDirContextFactory.unexpectedException=Error al obtener el InitialDirContext debido a una excepción inesperada
|
||||
PasswordComparisonAuthenticator.badCredentials=Credenciales erróneas
|
||||
BindAuthenticator.badCredentials=Credenciales erróneas
|
||||
BindAuthenticator.failedToLoadAttributes=Credenciales erróneas
|
||||
UserDetailsService.locked=La cuenta del usuario está bloqueada
|
||||
UserDetailsService.disabled=El usuario está deshabilitado
|
||||
UserDetailsService.expired=La cuenta del usuario ha expirado
|
||||
UserDetailsService.credentialsExpired=Las credenciales del usuario han expirado
|
||||
@@ -6,12 +6,12 @@ ProviderManager.providerNotFound=\u672a\u67e5\u627e\u5230\u9488\u5bf9{0}\u7684Au
|
||||
AnonymousAuthenticationProvider.incorrectKey=\u5c55\u793a\u7684AnonymousAuthenticationToken\u4e0d\u542b\u6709\u9884\u671f\u7684key
|
||||
CasAuthenticationProvider.incorrectKey=\u5c55\u793a\u7684CasAuthenticationToken\u4e0d\u542b\u6709\u9884\u671f\u7684key
|
||||
CasAuthenticationProvider.noServiceTicket=\u672a\u80fd\u591f\u6b63\u786e\u63d0\u4f9b\u5f85\u9a8c\u8bc1\u7684CAS\u670d\u52a1\u7968\u6839
|
||||
NamedCasProxyDecider.untrusted=\u4ee3\u7406({0}) \u4e0d\u53d7\u4fe1\u4efb
|
||||
NamedCasProxyDecider.untrusted=\u4ee3\u7406({0})\u4e0d\u53d7\u4fe1\u4efb
|
||||
RejectProxyTickets.reject=Proxy\u7968\u6839\u88ab\u62d2\u7edd
|
||||
AbstractSecurityInterceptor.authenticationNotFound=\u672a\u5728SecurityContext\u4e2d\u67e5\u627e\u5230\u8ba4\u8bc1\u5bf9\u8c61
|
||||
AbstractUserDetailsAuthenticationProvider.onlySupports=\u4ec5\u4ec5\u652f\u6301UsernamePasswordAuthenticationToken
|
||||
AbstractUserDetailsAuthenticationProvider.locked=\u7528\u6237\u5e10\u53f7\u5df2\u88ab\u9501\u5b9a
|
||||
AbstractUserDetailsAuthenticationProvider.disabled=\u7528\u6237\u5df2\u88ab\u5931\u6548
|
||||
AbstractUserDetailsAuthenticationProvider.disabled=\u7528\u6237\u5df2\u5931\u6548
|
||||
AbstractUserDetailsAuthenticationProvider.expired=\u7528\u6237\u5e10\u53f7\u5df2\u8fc7\u671f
|
||||
AbstractUserDetailsAuthenticationProvider.credentialsExpired=\u7528\u6237\u51ed\u8bc1\u5df2\u8fc7\u671f
|
||||
AbstractUserDetailsAuthenticationProvider.badCredentials=\u574f\u7684\u51ed\u8bc1
|
||||
@@ -29,11 +29,13 @@ DigestProcessingFilter.nonceNotNumeric=Nonce\u4ee4\u724c\u7684\u7b2c1\u90e8\u520
|
||||
DigestProcessingFilter.nonceCompromised=Nonce\u4ee4\u724c\u5df2\u7ecf\u5b58\u5728\u95ee\u9898\u4e86\uff0c{0}
|
||||
DigestProcessingFilter.usernameNotFound=\u7528\u6237\u540d{0}\u672a\u627e\u5230
|
||||
DigestProcessingFilter.incorrectResponse=\u9519\u8bef\u7684\u54cd\u5e94\u7ed3\u679c
|
||||
JdbcDaoImpl.notFound=\u672a\u627e\u5230\u7528\u6237{0}
|
||||
JdbcDaoImpl.noAuthority=\u6ca1\u6709\u4e3a\u7528\u6237{0}\u6307\u5b9a\u89d2\u8272
|
||||
SwitchUserProcessingFilter.noCurrentUser=\u4e0d\u5b58\u5728\u5f53\u524d\u7528\u6237
|
||||
SwitchUserProcessingFilter.noOriginalAuthentication=\u4e0d\u80fd\u591f\u67e5\u627e\u5230\u539f\u5148\u7684\u5df2\u8ba4\u8bc1\u5bf9\u8c61
|
||||
SwitchUserProcessingFilter.usernameNotFound=\u7528\u6237\u540d{0}\u672a\u627e\u5230
|
||||
SwitchUserProcessingFilter.locked=\u7528\u6237\u5e10\u53f7\u5df2\u88ab\u9501\u5b9a
|
||||
SwitchUserProcessingFilter.disabled=\u7528\u6237\u5df2\u88ab\u5931\u6548
|
||||
SwitchUserProcessingFilter.disabled=\u7528\u6237\u5df2\u5931\u6548
|
||||
SwitchUserProcessingFilter.expired=\u7528\u6237\u5e10\u53f7\u5df2\u8fc7\u671f
|
||||
SwitchUserProcessingFilter.credentialsExpired=\u7528\u6237\u51ed\u8bc1\u5df2\u8fc7\u671f
|
||||
AbstractAccessDecisionManager.accessDenied=\u4e0d\u5141\u8bb8\u8bbf\u95ee
|
||||
@@ -45,4 +47,8 @@ DefaultIntitalDirContextFactory.unexpectedException=\u7531\u4e8e\u672a\u9884\u67
|
||||
PasswordComparisonAuthenticator.badCredentials=\u574f\u7684\u51ed\u8bc1
|
||||
BindAuthenticator.badCredentials=\u574f\u7684\u51ed\u8bc1
|
||||
BindAuthenticator.failedToLoadAttributes=\u574f\u7684\u51ed\u8bc1
|
||||
UserDetailsService.locked=\u7528\u6237\u5e10\u53f7\u5df2\u88ab\u9501\u5b9a
|
||||
UserDetailsService.disabled=\u7528\u6237\u5df2\u5931\u6548
|
||||
UserDetailsService.expired=\u7528\u6237\u5e10\u53f7\u5df2\u8fc7\u671f
|
||||
UserDetailsService.credentialsExpired=\u7528\u6237\u51ed\u8bc1\u5df2\u8fc7\u671f
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
package org.springframework.security;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
@@ -24,28 +26,10 @@ import junit.framework.TestCase;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GrantedAuthorityImplTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public GrantedAuthorityImplTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public GrantedAuthorityImplTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(GrantedAuthorityImplTests.class);
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testObjectEquals() throws Exception {
|
||||
public class GrantedAuthorityImplTests {
|
||||
|
||||
@Test
|
||||
public void equalsBehavesAsExpected() throws Exception {
|
||||
GrantedAuthorityImpl auth1 = new GrantedAuthorityImpl("TEST");
|
||||
GrantedAuthorityImpl auth2 = new GrantedAuthorityImpl("TEST");
|
||||
assertEquals(auth1, auth2);
|
||||
@@ -59,32 +43,52 @@ public class GrantedAuthorityImplTests extends TestCase {
|
||||
GrantedAuthorityImpl auth3 = new GrantedAuthorityImpl("NOT_EQUAL");
|
||||
assertTrue(!auth1.equals(auth3));
|
||||
|
||||
MockGrantedAuthorityImpl mock1 = new MockGrantedAuthorityImpl("TEST");
|
||||
MockGrantedAuthority mock1 = new MockGrantedAuthority("TEST");
|
||||
assertEquals(auth1, mock1);
|
||||
|
||||
MockGrantedAuthorityImpl mock2 = new MockGrantedAuthorityImpl("NOT_EQUAL");
|
||||
MockGrantedAuthority mock2 = new MockGrantedAuthority("NOT_EQUAL");
|
||||
assertTrue(!auth1.equals(mock2));
|
||||
|
||||
Integer int1 = new Integer(222);
|
||||
assertTrue(!auth1.equals(int1));
|
||||
}
|
||||
|
||||
public void testToString() {
|
||||
@Test
|
||||
public void toStringReturnsAuthorityValue() {
|
||||
GrantedAuthorityImpl auth = new GrantedAuthorityImpl("TEST");
|
||||
assertEquals("TEST", auth.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToGrantedAuthorityWithSameValueReturns0() {
|
||||
assertEquals(0, new GrantedAuthorityImpl("TEST").compareTo(new MockGrantedAuthority("TEST")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToNullReturnsNegativeOne() {
|
||||
assertEquals(-1, new GrantedAuthorityImpl("TEST").compareTo(null));
|
||||
}
|
||||
|
||||
/* SEC-899 */
|
||||
@Test
|
||||
public void compareToHandlesCustomAuthorityWhichReturnsNullFromGetAuthority() {
|
||||
assertEquals(-1, new GrantedAuthorityImpl("TEST").compareTo(new MockGrantedAuthority()));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockGrantedAuthorityImpl implements GrantedAuthority, Comparable {
|
||||
private class MockGrantedAuthority implements GrantedAuthority {
|
||||
private String role;
|
||||
|
||||
public MockGrantedAuthorityImpl(String role) {
|
||||
public MockGrantedAuthority() {
|
||||
}
|
||||
|
||||
public MockGrantedAuthority(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public int compareTo(Object o) {
|
||||
return this.role.compareTo(((GrantedAuthority)o).getAuthority());
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getAuthority() {
|
||||
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
package org.springframework.security.authoritymapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ruud Senden
|
||||
*/
|
||||
public class MapBasedAttributes2GrantedAuthoritiesMapperTest extends TestCase {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
// Set Log4j loglevel to debug to include all logstatements in tests
|
||||
Logger.getRootLogger().setLevel(Level.DEBUG);
|
||||
}
|
||||
|
||||
public final void testAfterPropertiesSetNoMap() {
|
||||
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
|
||||
try {
|
||||
mapper.afterPropertiesSet();
|
||||
fail("Expected exception not thrown");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
// Expected exception
|
||||
} catch (Exception unexpected) {
|
||||
fail("Unexpected exception: " + unexpected);
|
||||
}
|
||||
}
|
||||
|
||||
public final void testAfterPropertiesSetEmptyMap() {
|
||||
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
|
||||
mapper.setAttributes2grantedAuthoritiesMap(new HashMap());
|
||||
try {
|
||||
mapper.afterPropertiesSet();
|
||||
fail("Expected exception not thrown");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
// Expected exception
|
||||
} catch (Exception unexpected) {
|
||||
fail("Unexpected exception: " + unexpected);
|
||||
}
|
||||
}
|
||||
|
||||
public final void testAfterPropertiesSetInvalidKeyTypeMap() {
|
||||
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
|
||||
HashMap m = new HashMap();
|
||||
m.put(new Object(),"ga1");
|
||||
mapper.setAttributes2grantedAuthoritiesMap(m);
|
||||
try {
|
||||
mapper.afterPropertiesSet();
|
||||
fail("Expected exception not thrown");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
// Expected exception
|
||||
} catch (Exception unexpected) {
|
||||
fail("Unexpected exception: " + unexpected);
|
||||
}
|
||||
}
|
||||
|
||||
public final void testAfterPropertiesSetInvalidValueTypeMap1() {
|
||||
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
|
||||
HashMap m = new HashMap();
|
||||
m.put("role1",new Object());
|
||||
mapper.setAttributes2grantedAuthoritiesMap(m);
|
||||
try {
|
||||
mapper.afterPropertiesSet();
|
||||
fail("Expected exception not thrown");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
// Expected exception
|
||||
} catch (Exception unexpected) {
|
||||
fail("Unexpected exception: " + unexpected);
|
||||
}
|
||||
}
|
||||
|
||||
public final void testAfterPropertiesSetInvalidValueTypeMap2() {
|
||||
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
|
||||
HashMap m = new HashMap();
|
||||
m.put("role1",new Object[]{new String[]{"ga1","ga2"}, new Object()});
|
||||
mapper.setAttributes2grantedAuthoritiesMap(m);
|
||||
try {
|
||||
mapper.afterPropertiesSet();
|
||||
fail("Expected exception not thrown");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
// Expected exception
|
||||
} catch (Exception unexpected) {
|
||||
fail("Unexpected exception: " + unexpected);
|
||||
}
|
||||
}
|
||||
|
||||
public final void testAfterPropertiesSetValidMap() {
|
||||
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
|
||||
HashMap m = getValidAttributes2GrantedAuthoritiesMap();
|
||||
mapper.setAttributes2grantedAuthoritiesMap(m);
|
||||
try {
|
||||
mapper.afterPropertiesSet();
|
||||
} catch (Exception unexpected) {
|
||||
fail("Unexpected exception: " + unexpected);
|
||||
}
|
||||
}
|
||||
|
||||
public final void testMapping1() {
|
||||
String[] roles = { "role1" };
|
||||
String[] expectedGas = { "ga1" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping2() {
|
||||
String[] roles = { "role2" };
|
||||
String[] expectedGas = { "ga2" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping3() {
|
||||
String[] roles = { "role3" };
|
||||
String[] expectedGas = { "ga3", "ga4" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping4() {
|
||||
String[] roles = { "role4" };
|
||||
String[] expectedGas = { "ga5", "ga6" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping5() {
|
||||
String[] roles = { "role5" };
|
||||
String[] expectedGas = { "ga7", "ga8", "ga9" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping6() {
|
||||
String[] roles = { "role6" };
|
||||
String[] expectedGas = { "ga10", "ga11", "ga12" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping7() {
|
||||
String[] roles = { "role7" };
|
||||
String[] expectedGas = { "ga13", "ga14" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping8() {
|
||||
String[] roles = { "role8" };
|
||||
String[] expectedGas = { "ga13", "ga14" };
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping9() {
|
||||
String[] roles = { "role9" };
|
||||
String[] expectedGas = {};
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping10() {
|
||||
String[] roles = { "role10" };
|
||||
String[] expectedGas = {};
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMapping11() {
|
||||
String[] roles = { "role11" };
|
||||
String[] expectedGas = {};
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testNonExistingMapping() {
|
||||
String[] roles = { "nonExisting" };
|
||||
String[] expectedGas = {};
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
public final void testMappingCombination() {
|
||||
String[] roles = { "role1", "role2", "role3", "role4", "role5", "role6", "role7", "role8", "role9", "role10", "role11" };
|
||||
String[] expectedGas = { "ga1", "ga2", "ga3", "ga4", "ga5", "ga6", "ga7", "ga8", "ga9", "ga10", "ga11", "ga12", "ga13", "ga14"};
|
||||
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
|
||||
testGetGrantedAuthorities(mapper, roles, expectedGas);
|
||||
}
|
||||
|
||||
private HashMap getValidAttributes2GrantedAuthoritiesMap() {
|
||||
HashMap m = new HashMap();
|
||||
m.put("role1","ga1");
|
||||
m.put("role2",new GrantedAuthorityImpl("ga2"));
|
||||
m.put("role3",Arrays.asList(new Object[]{"ga3",new GrantedAuthorityImpl("ga4")}));
|
||||
m.put("role4","ga5,ga6");
|
||||
m.put("role5",Arrays.asList(new Object[]{"ga7","ga8",new Object[]{new GrantedAuthorityImpl("ga9")}}));
|
||||
m.put("role6",new Object[]{"ga10","ga11",new Object[]{new GrantedAuthorityImpl("ga12")}});
|
||||
m.put("role7",new String[]{"ga13","ga14"});
|
||||
m.put("role8",new String[]{"ga13","ga14",null});
|
||||
m.put("role9",null);
|
||||
m.put("role10",new Object[]{});
|
||||
m.put("role11",Arrays.asList(new Object[]{null}));
|
||||
return m;
|
||||
}
|
||||
|
||||
private MapBasedAttributes2GrantedAuthoritiesMapper getDefaultMapper() {
|
||||
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
|
||||
mapper.setAttributes2grantedAuthoritiesMap(getValidAttributes2GrantedAuthoritiesMap());
|
||||
mapper.afterPropertiesSet();
|
||||
return mapper;
|
||||
}
|
||||
|
||||
private void testGetGrantedAuthorities(Attributes2GrantedAuthoritiesMapper mapper, String[] roles, String[] expectedGas) {
|
||||
GrantedAuthority[] result = mapper.getGrantedAuthorities(roles);
|
||||
Collection resultColl = new ArrayList(result.length);
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
resultColl.add(result[i].getAuthority());
|
||||
}
|
||||
Collection expectedColl = Arrays.asList(expectedGas);
|
||||
assertTrue("Role collections do not match; result: " + resultColl + ", expected: " + expectedColl, expectedColl
|
||||
.containsAll(resultColl)
|
||||
&& resultColl.containsAll(expectedColl));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
public abstract class ConfigTestUtils {
|
||||
public static final String AUTH_PROVIDER_XML =
|
||||
" <authentication-provider>" +
|
||||
" <user-service id='us'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
" <user name='bill' password='billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />" +
|
||||
" <user name='admin' password='password' authorities='ROLE_ADMIN,ROLE_USER' />" +
|
||||
" <user name='user' password='password' authorities='ROLE_USER' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>";
|
||||
}
|
||||
+5
-5
@@ -11,7 +11,7 @@ import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
@@ -19,7 +19,7 @@ public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void customAfterInvocationProviderIsAddedToInterceptor() {
|
||||
setContext(
|
||||
@@ -27,11 +27,11 @@ public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
|
||||
"<b:bean id='aip' class='org.springframework.security.config.MockAfterInvocationProvider'>" +
|
||||
" <custom-after-invocation-provider />" +
|
||||
"</b:bean>" +
|
||||
HttpSecurityBeanDefinitionParserTests.AUTH_PROVIDER_XML
|
||||
ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
|
||||
|
||||
MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(BeanIds.METHOD_SECURITY_INTERCEPTOR);
|
||||
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
|
||||
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
|
||||
assertNotNull(apm);
|
||||
assertEquals(1, apm.getProviders().size());
|
||||
assertTrue(apm.getProviders().get(0) instanceof MockAfterInvocationProvider);
|
||||
|
||||
+14
-14
@@ -15,36 +15,36 @@ import org.springframework.security.intercept.web.FilterInvocation;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FilterInvocationDefinitionSourceParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsingMinimalConfigurationIsSuccessful() {
|
||||
setContext(
|
||||
"<filter-invocation-definition-source id='fids'>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
"</filter-invocation-definition-source>");
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
"</filter-invocation-definition-source>");
|
||||
DefaultFilterInvocationDefinitionSource fids = (DefaultFilterInvocationDefinitionSource) appContext.getBean("fids");
|
||||
ConfigAttributeDefinition cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
|
||||
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
|
||||
setContext(
|
||||
@@ -57,12 +57,12 @@ public class FilterInvocationDefinitionSourceParserTests {
|
||||
" <intercept-url pattern='/**' access='ROLE_USER'/>" +
|
||||
" </filter-invocation-definition-source>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>" + HttpSecurityBeanDefinitionParserTests.AUTH_PROVIDER_XML);
|
||||
|
||||
|
||||
"</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private FilterInvocation createFilterInvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI(null);
|
||||
|
||||
+112
-78
@@ -1,6 +1,7 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.security.config.ConfigTestUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
@@ -34,6 +35,7 @@ import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
import org.springframework.security.ui.WebAuthenticationDetails;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.logout.LogoutFilter;
|
||||
import org.springframework.security.ui.logout.LogoutHandler;
|
||||
import org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.ui.rememberme.NullRememberMeServices;
|
||||
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
@@ -55,13 +57,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public class HttpSecurityBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
static final String AUTH_PROVIDER_XML =
|
||||
" <authentication-provider>" +
|
||||
" <user-service id='us'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
" <user name='bill' password='billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>";
|
||||
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
@@ -75,7 +71,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
public void minimalConfigurationParses() {
|
||||
setContext("<http><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void httpAutoConfigSetsUpCorrectFilterList() throws Exception {
|
||||
setContext("<http auto-config='true' />" + AUTH_PROVIDER_XML);
|
||||
@@ -83,24 +79,26 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
List filterList = getFilters("/anyurl");
|
||||
|
||||
checkAutoConfigFilters(filterList);
|
||||
|
||||
assertEquals(true, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
|
||||
assertEquals(true, FieldUtils.getFieldValue(filterList.get(10), "objectDefinitionSource.stripQueryStringFromUrls"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() throws Exception {
|
||||
setContext("<http auto-config='true' /><http auto-config='true' />" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkAutoConfigFilters(List filterList) throws Exception {
|
||||
assertEquals("Expected 11 filters in chain", 11, filterList.size());
|
||||
|
||||
Iterator filters = filterList.iterator();
|
||||
|
||||
assertTrue(filters.next() instanceof HttpSessionContextIntegrationFilter);
|
||||
assertTrue(filters.next() instanceof HttpSessionContextIntegrationFilter);
|
||||
assertTrue(filters.next() instanceof LogoutFilter);
|
||||
Object authProcFilter = filters.next();
|
||||
assertTrue(authProcFilter instanceof AuthenticationProcessingFilter);
|
||||
// Check RememberMeServices has been set on AuthenticationProcessingFilter
|
||||
// Check RememberMeServices has been set on AuthenticationProcessingFilter
|
||||
Object rms = FieldUtils.getFieldValue(authProcFilter, "rememberMeServices");
|
||||
assertNotNull(rms);
|
||||
assertTrue(rms instanceof RememberMeServices);
|
||||
@@ -111,7 +109,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
assertTrue(filters.next() instanceof RememberMeProcessingFilter);
|
||||
assertTrue(filters.next() instanceof AnonymousProcessingFilter);
|
||||
assertTrue(filters.next() instanceof ExceptionTranslationFilter);
|
||||
assertTrue(filters.next() instanceof SessionFixationProtectionFilter);
|
||||
assertTrue(filters.next() instanceof SessionFixationProtectionFilter);
|
||||
Object fsiObj = filters.next();
|
||||
assertTrue(fsiObj instanceof FilterSecurityInterceptor);
|
||||
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) fsiObj;
|
||||
@@ -140,6 +138,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
// This will be matched by the default pattern ".*"
|
||||
List allFilters = getFilters("/ImCaughtByTheUniversalMatchPattern");
|
||||
checkAutoConfigFilters(allFilters);
|
||||
assertEquals(false, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
|
||||
assertEquals(false, FieldUtils.getFieldValue(allFilters.get(10), "objectDefinitionSource.stripQueryStringFromUrls"));
|
||||
}
|
||||
|
||||
@@ -153,7 +152,6 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
// These will be matched by the default pattern "/**"
|
||||
checkAutoConfigFilters(getFilters("/secure"));
|
||||
checkAutoConfigFilters(getFilters("/ImCaughtByTheUniversalMatchPattern"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -184,34 +182,34 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
"<http>" +
|
||||
" <form-login login-page='noLeadingSlash'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidDefaultTargetUrlIsDetected() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <form-login default-target-url='noLeadingSlash'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidLogoutUrlIsDetected() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <logout logout-url='noLeadingSlash'/>" +
|
||||
" <logout logout-url='noLeadingSlash'/>" +
|
||||
" <form-login />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidLogoutSuccessUrlIsDetected() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <logout logout-success-url='noLeadingSlash'/>" +
|
||||
" <logout logout-success-url='noLeadingSlash'/>" +
|
||||
" <form-login />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lowerCaseComparisonIsRespectedBySecurityFilterInvocationDefinitionSource() throws Exception {
|
||||
setContext(
|
||||
@@ -253,27 +251,27 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
public void oncePerRequestAttributeIsSupported() throws Exception {
|
||||
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
List filters = getFilters("/someurl");
|
||||
|
||||
|
||||
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) filters.get(filters.size() - 1);
|
||||
|
||||
|
||||
assertFalse(fsi.isObserveOncePerRequest());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void accessDeniedPageAttributeIsSupported() throws Exception {
|
||||
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
List filters = getFilters("/someurl");
|
||||
|
||||
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) filters.get(filters.size() - 3);
|
||||
|
||||
|
||||
assertEquals("/access-denied", FieldUtils.getFieldValue(etf, "accessDeniedHandler.errorPage"));
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=BeanDefinitionStoreException.class)
|
||||
public void invalidAccessDeniedUrlIsDetected() throws Exception {
|
||||
setContext("<http auto-config='true' access-denied-page='noLeadingSlash'/>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interceptUrlWithRequiresChannelAddsChannelFilterToStack() throws Exception {
|
||||
setContext(
|
||||
@@ -302,6 +300,24 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void portMappingsWorkWithPlaceholders() throws Exception {
|
||||
System.setProperty("http", "9080");
|
||||
System.setProperty("https", "9443");
|
||||
setContext(
|
||||
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||
" <http auto-config='true'>" +
|
||||
" <port-mappings>" +
|
||||
" <port-mapping http='${http}' https='${https}'/>" +
|
||||
" </port-mappings>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
PortMapperImpl pm = (PortMapperImpl) appContext.getBean(BeanIds.PORT_MAPPER);
|
||||
assertEquals(1, pm.getTranslatedPortMappings().size());
|
||||
assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
|
||||
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalFiltersAreTreatedCorrectly() throws Exception {
|
||||
// Decorated user-filters should be added to stack. The others should be ignored.
|
||||
@@ -312,21 +328,21 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
"</b:bean>" +
|
||||
"<b:bean id='userFilter1' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
|
||||
" <custom-filter before='SESSION_CONTEXT_INTEGRATION_FILTER'/>" +
|
||||
"</b:bean>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='userFilter2' class='org.springframework.security.util.MockFilter'>" +
|
||||
" <custom-filter position='FIRST'/>" +
|
||||
"</b:bean>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>" +
|
||||
"<b:bean id='userFilter4' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'/>"
|
||||
);
|
||||
List filters = getFilters("/someurl");
|
||||
|
||||
assertEquals(14, filters.size());
|
||||
assertTrue(filters.get(0) instanceof MockFilter);
|
||||
assertTrue(filters.get(0) instanceof MockFilter);
|
||||
assertTrue(filters.get(1) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
assertTrue(filters.get(4) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void twoFiltersWithSameOrderAreRejected() {
|
||||
setContext(
|
||||
@@ -345,7 +361,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
"<b:bean id='tokenRepo' " +
|
||||
"class='org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl'/> " + AUTH_PROVIDER_XML);
|
||||
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
|
||||
|
||||
|
||||
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
|
||||
}
|
||||
|
||||
@@ -359,11 +375,11 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
" <b:constructor-arg value='tokendb'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML);
|
||||
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
|
||||
|
||||
|
||||
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void rememberMeServiceWorksWithExternalServicesImpl() throws Exception {
|
||||
setContext(
|
||||
@@ -376,9 +392,13 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
" <b:property name='tokenValiditySeconds' value='5000'/>" +
|
||||
"</b:bean>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
|
||||
assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
|
||||
"tokenValiditySeconds"));
|
||||
|
||||
assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
|
||||
"tokenValiditySeconds"));
|
||||
// SEC-909
|
||||
LogoutHandler[] logoutHandlers = (LogoutHandler[]) FieldUtils.getFieldValue(appContext.getBean(BeanIds.LOGOUT_FILTER), "handlers");
|
||||
assertEquals(2, logoutHandlers.length);
|
||||
assertEquals(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), logoutHandlers[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -387,10 +407,10 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me key='ourkey' token-validity-seconds='10000' />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
|
||||
"tokenValiditySeconds"));
|
||||
}
|
||||
|
||||
assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
|
||||
"tokenValiditySeconds"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeServiceConfigurationParsesWithCustomUserService() {
|
||||
setContext(
|
||||
@@ -400,8 +420,8 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
"<b:bean id='userService' class='org.springframework.security.userdetails.MockUserDetailsService'/> " +
|
||||
AUTH_PROVIDER_XML);
|
||||
// AbstractRememberMeServices rememberMeServices = (AbstractRememberMeServices) appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void x509SupportAddsFilterAtExpectedPosition() throws Exception {
|
||||
setContext(
|
||||
@@ -420,11 +440,11 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
List filters = getFilters("/someurl");
|
||||
|
||||
assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
|
||||
|
||||
assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
|
||||
assertNotNull(appContext.getBean("seshRegistry"));
|
||||
assertNotNull(appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalSessionRegistryBeanIsConfiguredCorrectly() throws Exception {
|
||||
@@ -436,12 +456,12 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
AUTH_PROVIDER_XML);
|
||||
Object sessionRegistry = appContext.getBean("seshRegistry");
|
||||
Object sessionRegistryFromFilter = FieldUtils.getFieldValue(
|
||||
appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
|
||||
appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
|
||||
Object sessionRegistryFromController = FieldUtils.getFieldValue(
|
||||
appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
|
||||
appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
|
||||
Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue(
|
||||
appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
|
||||
|
||||
appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
|
||||
|
||||
assertSame(sessionRegistry, sessionRegistryFromFilter);
|
||||
assertSame(sessionRegistry, sessionRegistryFromController);
|
||||
assertSame(sessionRegistry, sessionRegistryFromFixationFilter);
|
||||
@@ -473,8 +493,8 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
" </b:property>" +
|
||||
"</b:bean>" +
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test(expected=ConcurrentLoginException.class)
|
||||
public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception {
|
||||
setContext(
|
||||
@@ -488,16 +508,16 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
req.setSession(new MockHttpSession());
|
||||
auth.setDetails(new WebAuthenticationDetails(req));
|
||||
try {
|
||||
seshController.checkAuthenticationAllowed(auth);
|
||||
seshController.checkAuthenticationAllowed(auth);
|
||||
} catch (ConcurrentLoginException e) {
|
||||
fail("First login should be allowed");
|
||||
}
|
||||
fail("First login should be allowed");
|
||||
}
|
||||
seshController.registerSuccessfulAuthentication(auth);
|
||||
req.setSession(new MockHttpSession());
|
||||
try {
|
||||
seshController.checkAuthenticationAllowed(auth);
|
||||
seshController.checkAuthenticationAllowed(auth);
|
||||
} catch (ConcurrentLoginException e) {
|
||||
fail("Second login should be allowed");
|
||||
fail("Second login should be allowed");
|
||||
}
|
||||
auth.setDetails(new WebAuthenticationDetails(req));
|
||||
seshController.registerSuccessfulAuthentication(auth);
|
||||
@@ -514,10 +534,10 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
" <b:constructor-arg value='/customlogin'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML);
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) getFilters("/someurl").get(8);
|
||||
assertTrue("ExceptionTranslationFilter should be configured with custom entry point",
|
||||
assertTrue("ExceptionTranslationFilter should be configured with custom entry point",
|
||||
etf.getAuthenticationEntryPoint() instanceof MockAuthenticationEntryPoint);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
/** SEC-742 */
|
||||
public void rememberMeServicesWorksWithoutBasicProcessingFilter() {
|
||||
@@ -538,7 +558,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
|
||||
assertFalse(filters.get(1) instanceof SessionFixationProtectionFilter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See SEC-750. If the http security post processor causes beans to be instantiated too eagerly, they way miss
|
||||
* additional processing. In this method we have a UserDetailsService which is referenced from the namespace
|
||||
@@ -557,18 +577,18 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SEC-795. Two methods that exercise the scenarios that will or won't result in a protected login page warning.
|
||||
* Check the log.
|
||||
*/
|
||||
@Test
|
||||
public void unprotectedLoginPageDoesntResultInWarning() {
|
||||
// Anonymous access configured
|
||||
// Anonymous access configured
|
||||
setContext(
|
||||
" <http>" +
|
||||
" <intercept-url pattern='/login.jsp*' access='IS_AUTHENTICATED_ANONYMOUSLY'/>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
" <anonymous />" +
|
||||
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
@@ -580,9 +600,9 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
" <anonymous />" +
|
||||
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void protectedLoginPageResultsInWarning() {
|
||||
// Protected, no anonymous filter configured.
|
||||
@@ -603,20 +623,34 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
|
||||
@Test
|
||||
public void settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() throws Exception {
|
||||
// Protected, no anonymous filter configured.
|
||||
setContext("<http auto-config='true' create-session='always'/>" + AUTH_PROVIDER_XML);
|
||||
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "forceEagerSessionCreation"));
|
||||
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "allowSessionCreation"));
|
||||
}
|
||||
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "allowSessionCreation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingCreateSessionToNeverSetsFilterPropertiesCorrectly() throws Exception {
|
||||
// Protected, no anonymous filter configured.
|
||||
setContext("<http auto-config='true' create-session='never'/>" + AUTH_PROVIDER_XML);
|
||||
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "forceEagerSessionCreation"));
|
||||
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "allowSessionCreation"));
|
||||
}
|
||||
|
||||
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "allowSessionCreation"));
|
||||
}
|
||||
|
||||
/* SEC-934 */
|
||||
@Test
|
||||
public void supportsTwoIdenticalInterceptUrls() {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <intercept-url pattern='/someurl' access='ROLE_A'/>" +
|
||||
" <intercept-url pattern='/someurl' access='ROLE_B'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
|
||||
|
||||
FilterInvocationDefinitionSource fids = fis.getObjectDefinitionSource();
|
||||
ConfigAttributeDefinition attrDef = fids.getAttributes(createFilterinvocation("/someurl", null));
|
||||
assertEquals(1, attrDef.getConfigAttributes().size());
|
||||
assertTrue(attrDef.contains(new SecurityConfig("ROLE_B")));
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
+20
-8
@@ -1,8 +1,6 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
@@ -13,6 +11,7 @@ import org.springframework.security.providers.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
@@ -51,24 +50,37 @@ public class JdbcUserServiceBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void beanIdIsParsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
assertTrue(appContext.getBean("myUserService") instanceof JdbcUserDetailsManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usernameAndGroupQueriesAreParsedCorrectly() {
|
||||
public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception {
|
||||
String userQuery = "select username, password, true from users where username = ?";
|
||||
String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1";
|
||||
setContext("<jdbc-user-service id='myUserService' " +
|
||||
"data-source-ref='dataSource' " +
|
||||
"users-by-username-query='select username,password,enabled from users where username = ?' " +
|
||||
"authorities-by-username-query='select username,authority from authorities where username = ?'/>" + DATA_SOURCE);
|
||||
"users-by-username-query='"+ userQuery +"' " +
|
||||
"authorities-by-username-query='" + authoritiesQuery + "'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
assertEquals(userQuery, FieldUtils.getFieldValue(mgr, "usersByUsernameQuery"));
|
||||
assertEquals(authoritiesQuery, FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery"));
|
||||
assertTrue(mgr.loadUserByUsername("rod") != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupQueryIsParsedCorrectly() throws Exception {
|
||||
setContext("<jdbc-user-service id='myUserService' " +
|
||||
"data-source-ref='dataSource' " +
|
||||
"group-authorities-by-username-query='blah blah'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
assertEquals("blah blah", FieldUtils.getFieldValue(mgr, "groupAuthoritiesByUsernameQuery"));
|
||||
assertTrue((Boolean)FieldUtils.getFieldValue(mgr, "enableGroups"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheRefIsparsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' cache-ref='userCache' data-source-ref='dataSource'/>"
|
||||
+ DATA_SOURCE +USER_CACHE_XML);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
CachingUserDetailsService cachingUserService =
|
||||
(CachingUserDetailsService) appContext.getBean("myUserService" + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX);
|
||||
assertSame(cachingUserService.getUserCache(), appContext.getBean("userCache"));
|
||||
|
||||
+18
-17
@@ -12,12 +12,13 @@ import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* $Id$
|
||||
*/
|
||||
public class SessionRegistryInjectionBeanPostProcessorTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
@@ -36,31 +37,31 @@ public class SessionRegistryInjectionBeanPostProcessorTests {
|
||||
"<http auto-config='true'/>" +
|
||||
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
|
||||
" <b:property name='sessionRegistry'>" +
|
||||
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>" +
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
|
||||
HttpSecurityBeanDefinitionParserTests.AUTH_PROVIDER_XML);
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
|
||||
ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void sessionRegistryIsSetOnFiltersWhenUsingCustomControllerWithNonStandardController() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'/>" +
|
||||
"<b:bean id='sc' class='org.springframework.security.config.SessionRegistryInjectionBeanPostProcessorTests$MockConcurrentSessionController'/>" +
|
||||
"<b:bean id='sessionRegistry' class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
|
||||
HttpSecurityBeanDefinitionParserTests.AUTH_PROVIDER_XML);
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
|
||||
ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
|
||||
}
|
||||
|
||||
|
||||
public static class MockConcurrentSessionController implements ConcurrentSessionController {
|
||||
public void checkAuthenticationAllowed(Authentication request) throws AuthenticationException {
|
||||
}
|
||||
public void registerSuccessfulAuthentication(Authentication authentication) {
|
||||
}
|
||||
public void checkAuthenticationAllowed(Authentication request) throws AuthenticationException {
|
||||
}
|
||||
public void registerSuccessfulAuthentication(Authentication authentication) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-214
@@ -15,14 +15,10 @@
|
||||
|
||||
package org.springframework.security.context;
|
||||
|
||||
import junit.framework.ComparisonFailure;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link SecurityContextHolder}.
|
||||
*
|
||||
@@ -30,193 +26,13 @@ import java.util.Random;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecurityContextHolderTests extends TestCase {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static int errors = 0;
|
||||
|
||||
private static final int NUM_OPS = 5;
|
||||
private static final int NUM_THREADS = 5;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public SecurityContextHolderTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SecurityContextHolderTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private void loadStartAndWaitForThreads(boolean topLevelThread, String prefix, int createThreads,
|
||||
boolean expectAllThreadsToUseIdenticalAuthentication, boolean expectChildrenToShareAuthenticationWithParent) {
|
||||
Thread[] threads = new Thread[createThreads];
|
||||
errors = 0;
|
||||
|
||||
if (topLevelThread) {
|
||||
// PARENT (TOP-LEVEL) THREAD CREATION
|
||||
if (expectChildrenToShareAuthenticationWithParent) {
|
||||
// An InheritableThreadLocal
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, true, null);
|
||||
} else {
|
||||
// Inject auth into current thread, but not child; current thread will have auth, child will also have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, true,
|
||||
prefix + "Auth_Parent_" + i);
|
||||
}
|
||||
}
|
||||
} else if (expectAllThreadsToUseIdenticalAuthentication) {
|
||||
// A global
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken("GLOBAL_USERNAME",
|
||||
"pass"));
|
||||
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread;both current thread and child will have same authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, true, true,
|
||||
"GLOBAL_USERNAME");
|
||||
} else {
|
||||
// Inject auth into current thread; current thread will have auth, child will also have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, true, true, "GLOBAL_USERNAME");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// A standard ThreadLocal
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, false, null);
|
||||
} else {
|
||||
// Inject auth into current thread, but not child; current thread will have auth, child will not have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, false,
|
||||
prefix + "Auth_Parent_" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CHILD THREAD CREATION
|
||||
if (expectChildrenToShareAuthenticationWithParent || expectAllThreadsToUseIdenticalAuthentication) {
|
||||
// The children being created are all expected to have security (ie an InheritableThreadLocal/global AND auth was injected into parent)
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
String expectedUsername = prefix;
|
||||
|
||||
if (expectAllThreadsToUseIdenticalAuthentication) {
|
||||
expectedUsername = "GLOBAL_USERNAME";
|
||||
}
|
||||
|
||||
// Don't inject auth into current thread; the current thread will obtain auth from its parent
|
||||
// NB: As topLevelThread = true, no further child threads will be created
|
||||
threads[i] = makeThread(prefix + "->child->Inherited_Auth_Child_" + i, false, false,
|
||||
expectAllThreadsToUseIdenticalAuthentication, false, expectedUsername);
|
||||
}
|
||||
} else {
|
||||
// The children being created are NOT expected to have security (ie not an InheritableThreadLocal OR auth was not injected into parent)
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
// NB: As topLevelThread = true, no further child threads will be created
|
||||
threads[i] = makeThread(prefix + "->child->Unauth_Child_" + i, false, false, false, false, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start and execute the threads
|
||||
startAndRun(threads);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(SecurityContextHolderTests.class);
|
||||
}
|
||||
|
||||
private Thread makeThread(final String threadIdentifier, final boolean topLevelThread,
|
||||
final boolean injectAuthIntoCurrentThread, final boolean expectAllThreadsToUseIdenticalAuthentication,
|
||||
final boolean expectChildrenToShareAuthenticationWithParent, final String expectedUsername) {
|
||||
final Random rnd = new Random();
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
if (injectAuthIntoCurrentThread) {
|
||||
// Set authentication in this thread
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken(
|
||||
expectedUsername, "pass"));
|
||||
|
||||
//System.out.println(threadIdentifier + " - set to " + SecurityContextHolder.getContext().getAuthentication());
|
||||
} else {
|
||||
//System.out.println(threadIdentifier + " - not set (currently " + SecurityContextHolder.getContext().getAuthentication() + ")");
|
||||
}
|
||||
|
||||
// Do some operations in current thread, checking authentication is as expected in the current thread (ie another thread doesn't change it)
|
||||
for (int i = 0; i < NUM_OPS; i++) {
|
||||
String currentUsername = (SecurityContextHolder.getContext().getAuthentication() == null)
|
||||
? null : SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
|
||||
if ((i % 7) == 0) {
|
||||
System.out.println(threadIdentifier + " at " + i + " username " + currentUsername);
|
||||
}
|
||||
|
||||
try {
|
||||
TestCase.assertEquals("Failed on iteration " + i + "; Authentication was '"
|
||||
+ currentUsername + "' but principal was expected to contain username '"
|
||||
+ expectedUsername + "'", expectedUsername, currentUsername);
|
||||
} catch (ComparisonFailure err) {
|
||||
errors++;
|
||||
throw err;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(rnd.nextInt(250));
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
|
||||
// Load some children threads, checking the authentication is as expected in the children (ie another thread doesn't change it)
|
||||
if (topLevelThread) {
|
||||
// Make four children, but we don't want the children to have any more children (so anti-nature, huh?)
|
||||
if (injectAuthIntoCurrentThread && expectChildrenToShareAuthenticationWithParent) {
|
||||
loadStartAndWaitForThreads(false, threadIdentifier, 4,
|
||||
expectAllThreadsToUseIdenticalAuthentication, true);
|
||||
} else {
|
||||
loadStartAndWaitForThreads(false, threadIdentifier, 4,
|
||||
expectAllThreadsToUseIdenticalAuthentication, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, threadIdentifier);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
||||
}
|
||||
|
||||
private void startAndRun(Thread[] threads) {
|
||||
// Start them up
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
// Wait for them to finish
|
||||
while (stillRunning(threads)) {
|
||||
try {
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean stillRunning(Thread[] threads) {
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if (threads[i].isAlive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testContextHolderGetterSetterClearer() {
|
||||
SecurityContext sc = new SecurityContextImpl();
|
||||
sc.setAuthentication(new UsernamePasswordAuthenticationToken("Foobar", "pass"));
|
||||
@@ -240,34 +56,4 @@ public class SecurityContextHolderTests extends TestCase {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSynchronizationCustomStrategyLoading() {
|
||||
SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
|
||||
assertTrue(new SecurityContextHolder().toString()
|
||||
.lastIndexOf("SecurityContextHolder[strategy='org.springframework.security.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
|
||||
public void testSynchronizationGlobal() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, true, false);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
|
||||
public void testSynchronizationInheritableThreadLocal()
|
||||
throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
|
||||
public void testSynchronizationThreadLocal() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, false);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package org.springframework.security.intercept.method;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
|
||||
/**
|
||||
* Tests for {@link MapBasedMethodDefinitionSource}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class MapBasedMethodDefinitionSourceTests {
|
||||
private final ConfigAttributeDefinition ROLE_A = new ConfigAttributeDefinition("ROLE_A");
|
||||
private final ConfigAttributeDefinition ROLE_B = new ConfigAttributeDefinition("ROLE_B");
|
||||
private MapBasedMethodDefinitionSource mds;
|
||||
private Method someMethodString;
|
||||
private Method someMethodInteger;
|
||||
|
||||
@Before
|
||||
public void initialize() throws Exception {
|
||||
mds = new MapBasedMethodDefinitionSource();
|
||||
someMethodString = MockService.class.getMethod("someMethod", String.class);
|
||||
someMethodInteger = MockService.class.getMethod("someMethod", Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wildcardedMatchIsOverwrittenByMoreSpecificMatch() {
|
||||
mds.addSecureMethod(MockService.class, "some*", ROLE_A);
|
||||
mds.addSecureMethod(MockService.class, "someMethod*", ROLE_B);
|
||||
assertEquals(ROLE_B, mds.getAttributes(someMethodInteger, MockService.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodsWithDifferentArgumentsAreMatchedCorrectly() throws Exception {
|
||||
mds.addSecureMethod(MockService.class, someMethodInteger, ROLE_A);
|
||||
mds.addSecureMethod(MockService.class, someMethodString, ROLE_B);
|
||||
|
||||
assertEquals(ROLE_A, mds.getAttributes(someMethodInteger, MockService.class));
|
||||
assertEquals(ROLE_B, mds.getAttributes(someMethodString, MockService.class));
|
||||
}
|
||||
|
||||
private class MockService {
|
||||
public void someMethod(String s) {
|
||||
}
|
||||
|
||||
public void someMethod(Integer i) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -36,7 +36,7 @@ import org.springframework.security.RunAsManager;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.intercept.method.AbstractMethodDefinitionSource;
|
||||
import org.springframework.security.intercept.method.MethodDefinitionSource;
|
||||
import org.springframework.security.intercept.method.MockMethodDefinitionSource;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
@@ -446,26 +446,26 @@ public class MethodSecurityInterceptorTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private class MockObjectDefinitionSourceWhichOnlySupportsStrings extends AbstractMethodDefinitionSource {
|
||||
private class MockObjectDefinitionSourceWhichOnlySupportsStrings implements MethodDefinitionSource {
|
||||
public Collection getConfigAttributeDefinitions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ConfigAttributeDefinition lookupAttributes(Method method) {
|
||||
public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
|
||||
throw new UnsupportedOperationException("mock method not implemented");
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
|
||||
throw new UnsupportedOperationException("mock method not implemented");
|
||||
}
|
||||
|
||||
public boolean supports(Class clazz) {
|
||||
public boolean supports(Class clazz) {
|
||||
if (String.class.isAssignableFrom(clazz)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Object object) {
|
||||
throw new UnsupportedOperationException("mock method not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
private class MockRunAsManagerWhichOnlySupportsStrings implements RunAsManager {
|
||||
|
||||
+6
@@ -12,4 +12,10 @@ public class DefaultSpringSecurityContextSourceTests {
|
||||
public void instantiationSucceeds() {
|
||||
new DefaultSpringSecurityContextSource("ldap://blah:789/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsSpacesInUrl() {
|
||||
new DefaultSpringSecurityContextSource("ldap://myhost:10389/dc=spring%20framework,dc=org");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-5
@@ -44,8 +44,7 @@ public class SpringSecurityAuthenticationSourceTests {
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void getPrincipalRejectsNonLdapUserDetailsObject() {
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken(new Object(), "password", null));
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(new Object(), "password"));
|
||||
|
||||
source.getPrincipal();
|
||||
}
|
||||
@@ -53,8 +52,7 @@ public class SpringSecurityAuthenticationSourceTests {
|
||||
@Test
|
||||
public void expectedCredentialsAreReturned() {
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken(new Object(), "password", null));
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(new Object(), "password"));
|
||||
|
||||
assertEquals("password", source.getCredentials());
|
||||
}
|
||||
@@ -66,7 +64,7 @@ public class SpringSecurityAuthenticationSourceTests {
|
||||
user.setDn(new DistinguishedName("uid=joe,ou=users"));
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken(user.createUserDetails(), null, null));
|
||||
new TestingAuthenticationToken(user.createUserDetails(), null));
|
||||
|
||||
assertEquals("uid=joe, ou=users", source.getPrincipal());
|
||||
}
|
||||
|
||||
+11
@@ -56,6 +56,17 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests
|
||||
assertEquals(new DistinguishedName("uid=bob,ou=people"), bob.getDn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchForNameWithCommaSucceeds() {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory);
|
||||
locator.setSearchSubtree(false);
|
||||
|
||||
DirContextOperations jerry = locator.searchForUser("jerry");
|
||||
assertEquals("jerry", jerry.getStringAttribute("uid"));
|
||||
|
||||
assertEquals(new DistinguishedName("cn=mouse\\, jerry,ou=people"), jerry.getDn());
|
||||
}
|
||||
|
||||
// Try some funny business with filters.
|
||||
@Test
|
||||
public void extraFilterPartToExcludeBob() throws Exception {
|
||||
|
||||
@@ -119,10 +119,11 @@ public class ProviderManagerTests {
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void startupFailsIfProviderListNotSet() throws Exception {
|
||||
public void getProvidersFailsIfProviderListNotSet() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
|
||||
mgr.afterPropertiesSet();
|
||||
mgr.getProviders();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
|
||||
+12
@@ -16,6 +16,7 @@
|
||||
package org.springframework.security.providers;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,6 +35,17 @@ public class TestingAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public TestingAuthenticationToken(Object principal, Object credentials) {
|
||||
super(null);
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
|
||||
public TestingAuthenticationToken(Object principal, Object credentials, String... authorities) {
|
||||
this(principal, credentials, AuthorityUtils.stringArrayToAuthorityArray(authorities));
|
||||
}
|
||||
|
||||
public TestingAuthenticationToken(Object principal, Object credentials, GrantedAuthority[] authorities) {
|
||||
super(authorities);
|
||||
this.principal = principal;
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
/* Copyright 2004, 2005, 2006 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 org.springframework.security.providers;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.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 static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(TestingAuthenticationTokenTests.class);
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
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 testNoArgConstructorDoesntExist() {
|
||||
Class clazz = TestingAuthenticationToken.class;
|
||||
|
||||
try {
|
||||
clazz.getDeclaredConstructor((Class[]) null);
|
||||
fail("Should have thrown NoSuchMethodException");
|
||||
} catch (NoSuchMethodException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-44
@@ -25,6 +25,7 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.MockAuthenticationManager;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.ui.rememberme.NullRememberMeServices;
|
||||
import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices;
|
||||
import org.springframework.security.ui.savedrequest.SavedRequest;
|
||||
import org.springframework.security.util.PortResolverImpl;
|
||||
@@ -76,8 +77,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
}
|
||||
|
||||
private void executeFilterInContainerSimulator(FilterConfig filterConfig, Filter filter, ServletRequest request,
|
||||
ServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
filter.init(filterConfig);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
filter.destroy();
|
||||
@@ -115,7 +115,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void testDefaultProcessesFilterUrlWithPathParameter() {
|
||||
public void testDefaultProcessesFilterUrlMatchesWithPathParameter() {
|
||||
MockHttpServletRequest request = createMockRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter();
|
||||
@@ -125,28 +125,6 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
}
|
||||
|
||||
public void testDoFilterWithNonHttpServletRequestDetected() throws Exception {
|
||||
AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
|
||||
|
||||
try {
|
||||
filter.doFilter(null, new MockHttpServletResponse(), new MockFilterChain());
|
||||
fail("Should have thrown ServletException");
|
||||
} catch (ServletException expected) {
|
||||
assertEquals("Can only process HttpServletRequest", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testDoFilterWithNonHttpServletResponseDetected() throws Exception {
|
||||
AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
|
||||
|
||||
try {
|
||||
filter.doFilter(new MockHttpServletRequest(null, null), null, new MockFilterChain());
|
||||
fail("Should have thrown ServletException");
|
||||
} catch (ServletException expected) {
|
||||
assertEquals("Can only process HttpServletResponse", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testFailedAuthenticationRedirectsAppropriately() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = createMockRequest();
|
||||
@@ -209,25 +187,20 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
assertEquals("test", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
|
||||
}
|
||||
|
||||
public void testGettersSetters() {
|
||||
public void testGettersSetters() throws Exception {
|
||||
AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager());
|
||||
filter.setDefaultTargetUrl("/default");
|
||||
filter.setFilterProcessesUrl("/p");
|
||||
filter.setAuthenticationFailureUrl("/fail");
|
||||
filter.afterPropertiesSet();
|
||||
|
||||
assertNotNull(filter.getRememberMeServices());
|
||||
filter.setRememberMeServices(new TokenBasedRememberMeServices());
|
||||
assertEquals(TokenBasedRememberMeServices.class, filter.getRememberMeServices().getClass());
|
||||
|
||||
filter.setAuthenticationFailureUrl("/x");
|
||||
assertEquals("/x", filter.getAuthenticationFailureUrl());
|
||||
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager());
|
||||
assertTrue(filter.getAuthenticationManager() != null);
|
||||
|
||||
filter.setDefaultTargetUrl("/default");
|
||||
assertEquals("/default", filter.getDefaultTargetUrl());
|
||||
|
||||
filter.setFilterProcessesUrl("/p");
|
||||
assertEquals("/p", filter.getFilterProcessesUrl());
|
||||
|
||||
filter.setAuthenticationFailureUrl("/fail");
|
||||
assertEquals("/fail", filter.getAuthenticationFailureUrl());
|
||||
}
|
||||
|
||||
@@ -602,11 +575,13 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
private boolean grantAccess;
|
||||
|
||||
public MockAbstractProcessingFilter(boolean grantAccess) {
|
||||
setRememberMeServices(new NullRememberMeServices());
|
||||
this.grantAccess = grantAccess;
|
||||
this.exceptionToThrow = new BadCredentialsException("Mock requested to do so");
|
||||
}
|
||||
|
||||
public MockAbstractProcessingFilter(AuthenticationException exceptionToThrow) {
|
||||
setRememberMeServices(new NullRememberMeServices());
|
||||
this.grantAccess = false;
|
||||
this.exceptionToThrow = exceptionToThrow;
|
||||
}
|
||||
@@ -614,8 +589,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
private MockAbstractProcessingFilter() {
|
||||
}
|
||||
|
||||
public Authentication attemptAuthentication(HttpServletRequest request)
|
||||
throws AuthenticationException {
|
||||
public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException {
|
||||
if (grantAccess) {
|
||||
return new UsernamePasswordAuthenticationToken("test", "test",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("TEST")});
|
||||
@@ -644,11 +618,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
this.expectToProceed = expectToProceed;
|
||||
}
|
||||
|
||||
private MockFilterChain() {
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
|
||||
if (expectToProceed) {
|
||||
assertTrue(true);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -74,6 +74,6 @@ public class SessionFixationProtectionFilterTests {
|
||||
}
|
||||
|
||||
private void authenticateUser() {
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass", null));
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass"));
|
||||
}
|
||||
}
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package org.springframework.security.ui.preauth;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.MockAuthenticationManager;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.MockFilterChain;
|
||||
|
||||
public class AbstractPreAuthenticatedProcessingFilterTests {
|
||||
private AbstractPreAuthenticatedProcessingFilter filter;
|
||||
|
||||
@Before
|
||||
public void createFilter() {
|
||||
filter = new AbstractPreAuthenticatedProcessingFilter() {
|
||||
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
|
||||
return "doesntmatter";
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterChainProceedsOnFailedAuthenticationByDefault() throws Exception {
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager(false));
|
||||
filter.afterPropertiesSet();
|
||||
filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain(true));
|
||||
assertNull(SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
/* SEC-881 */
|
||||
@Test(expected=BadCredentialsException.class)
|
||||
public void exceptionIsThrownOnFailedAuthenticationIfContinueFilterChainOnUnsuccessfulAuthenticationSetToFalse() throws Exception {
|
||||
filter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager(false));
|
||||
filter.afterPropertiesSet();
|
||||
filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain(false));
|
||||
assertNull(SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -160,7 +160,7 @@ public class RememberMeProcessingFilterTests extends TestCase {
|
||||
public void testOnunsuccessfulLoginIsCalledWhenProviderRejectsAuth() throws Exception {
|
||||
Authentication remembered = new TestingAuthenticationToken("remembered", "password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_REMEMBERED")});
|
||||
final Authentication failedAuth = new TestingAuthenticationToken("failed", "", null);
|
||||
final Authentication failedAuth = new TestingAuthenticationToken("failed", "");
|
||||
|
||||
RememberMeProcessingFilter filter = new RememberMeProcessingFilter() {
|
||||
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
|
||||
|
||||
+5
-1
@@ -343,7 +343,7 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
||||
public void testLoginSuccessNormalWithNonUserDetailsBasedPrincipal() {
|
||||
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
|
||||
// SEC-822
|
||||
services.setTokenValiditySeconds(5000000);
|
||||
services.setTokenValiditySeconds(500000000);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("d");
|
||||
request.addParameter(TokenBasedRememberMeServices.DEFAULT_PARAMETER, "true");
|
||||
@@ -354,6 +354,10 @@ public class TokenBasedRememberMeServicesTests extends TestCase {
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")}));
|
||||
|
||||
Cookie cookie = response.getCookie(TokenBasedRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY);
|
||||
String expiryTime = services.decodeCookie(cookie.getValue())[1];
|
||||
long expectedExpiryTime = 1000L * 500000000;
|
||||
expectedExpiryTime += System.currentTimeMillis();
|
||||
assertTrue(Long.parseLong(expiryTime) > expectedExpiryTime - 10000);
|
||||
assertNotNull(cookie);
|
||||
assertEquals(services.getTokenValiditySeconds(), cookie.getMaxAge());
|
||||
assertTrue(Base64.isArrayByteBase64(cookie.getValue().getBytes()));
|
||||
|
||||
+126
-229
@@ -15,8 +15,18 @@
|
||||
|
||||
package org.springframework.security.ui.switchuser;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.AccountExpiredException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
@@ -24,48 +34,34 @@ import org.springframework.security.CredentialsExpiredException;
|
||||
import org.springframework.security.DisabledException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.springframework.security.userdetails.User;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.MockFilterChain;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link org.springframework.security.ui.switchuser.SwitchUserProcessingFilter}.
|
||||
*
|
||||
* @author Mark St.Godard
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
public class SwitchUserProcessingFilterTests {
|
||||
|
||||
public SwitchUserProcessingFilterTests() {
|
||||
@Before
|
||||
public void authenticateCurrentUser() {
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
}
|
||||
|
||||
public SwitchUserProcessingFilterTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
|
||||
@After
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
private MockHttpServletRequest createMockSwitchRequest() {
|
||||
@@ -76,181 +72,122 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private Authentication switchToUser(String name) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, name);
|
||||
|
||||
public void testAttemptSwitchToUnknownUser() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
|
||||
return filter.attemptSwitchUser(request);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiresExitUserMatchesCorrectly() {
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setExitUserUrl("/j_spring_security_my_exit_user");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/j_spring_security_my_exit_user");
|
||||
|
||||
assertTrue(filter.requiresExitUser(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiresSwitchMatchesCorrectly() {
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setSwitchUserUrl("/j_spring_security_my_switch_user");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/j_spring_security_my_switch_user");
|
||||
|
||||
assertTrue(filter.requiresSwitchUser(request));
|
||||
}
|
||||
|
||||
@Test(expected=UsernameNotFoundException.class)
|
||||
public void attemptSwitchToUnknownUserFails() throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "user-that-doesnt-exist");
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
|
||||
try {
|
||||
Authentication result = filter.attemptSwitchUser(request);
|
||||
|
||||
fail("Should not be able to switch to unknown user");
|
||||
} catch (UsernameNotFoundException expected) {}
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
filter.attemptSwitchUser(request);
|
||||
}
|
||||
|
||||
public void testAttemptSwitchToUserThatIsDisabled() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
@Test(expected=DisabledException.class)
|
||||
public void attemptSwitchToUserThatIsDisabledFails() throws Exception {
|
||||
switchToUser("mcgarrett");
|
||||
}
|
||||
|
||||
@Test(expected=AccountExpiredException.class)
|
||||
public void attemptSwitchToUserWithAccountExpiredFails() throws Exception {
|
||||
switchToUser("wofat");
|
||||
}
|
||||
|
||||
@Test(expected=CredentialsExpiredException.class)
|
||||
public void attemptSwitchToUserWithExpiredCredentialsFails() throws Exception {
|
||||
switchToUser("steve");
|
||||
}
|
||||
|
||||
@Test(expected=UsernameNotFoundException.class)
|
||||
public void switchUserWithNullUsernameThrowsException() throws Exception {
|
||||
switchToUser(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attemptSwitchUserIsSuccessfulWithValidUser() throws Exception {
|
||||
assertNotNull(switchToUser("jacklord"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchToLockedAccountCausesRedirectToSwitchFailureUrl() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
// this user is disabled
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "mcgarrett");
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
|
||||
try {
|
||||
Authentication result = filter.attemptSwitchUser(request);
|
||||
|
||||
fail("Should not be able to switch to disabled user");
|
||||
} catch (DisabledException expected) {
|
||||
// user should be disabled
|
||||
}
|
||||
}
|
||||
|
||||
public void testAttemptSwitchToUserWithAccountExpired() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
// this user is disabled
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "wofat");
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
|
||||
try {
|
||||
Authentication result = filter.attemptSwitchUser(request);
|
||||
|
||||
fail("Should not be able to switch to user with expired account");
|
||||
} catch (AccountExpiredException expected) {
|
||||
// expected user account expired
|
||||
}
|
||||
}
|
||||
|
||||
public void testAttemptSwitchToUserWithExpiredCredentials() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
// this user is disabled
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "steve");
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
|
||||
try {
|
||||
Authentication result = filter.attemptSwitchUser(request);
|
||||
|
||||
fail("Should not be able to switch to user with expired account");
|
||||
} catch (CredentialsExpiredException expected) {
|
||||
// user credentials expired
|
||||
}
|
||||
}
|
||||
|
||||
public void testAttemptSwitchUser() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "jacklord");
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
|
||||
Authentication result = filter.attemptSwitchUser(request);
|
||||
assertTrue(result != null);
|
||||
}
|
||||
|
||||
public void testSwitchToLockedAccountCausesRedirectToSwitchFailureUrl() throws Exception {
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
MockHttpServletRequest request = createMockSwitchRequest();
|
||||
request.setRequestURI("/j_spring_security_switch_user");
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "mcgarrett");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
|
||||
// Check it with no url set
|
||||
// Check it with no url set (should get a text response)
|
||||
filter.doFilterHttp(request, response, new MockFilterChain(false));
|
||||
|
||||
assertEquals("Switch user failed: User is disabled", response.getContentAsString());
|
||||
|
||||
// Now check for the redirect
|
||||
request.setContextPath("/mywebapp");
|
||||
request.setRequestURI("/mywebapp/j_spring_security_switch_user");
|
||||
filter.setSwitchFailureUrl("/switchfailed");
|
||||
response = new MockHttpServletResponse();
|
||||
|
||||
filter.doFilterHttp(request, response, new MockFilterChain(false));
|
||||
|
||||
assertEquals("/switchfailed", response.getRedirectedUrl());
|
||||
filter.doFilterHttp(request, response, new MockFilterChain(true));
|
||||
|
||||
assertEquals("/mywebapp/switchfailed", response.getRedirectedUrl());
|
||||
assertEquals("/switchfailed", FieldUtils.getFieldValue(filter, "switchFailureUrl"));
|
||||
}
|
||||
|
||||
public void testIfSwitchUserWithNullUsernameThrowsException() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
String username = null;
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, username);
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
Authentication result = null ;
|
||||
try {
|
||||
result = filter.attemptSwitchUser(request);
|
||||
fail("UsernameNotFoundException should have been thrown");
|
||||
} catch (UsernameNotFoundException e) {
|
||||
|
||||
}
|
||||
assertFalse(result != null);
|
||||
}
|
||||
|
||||
public void testBadConfigMissingAuthenticationDao() {
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void configMissingUserDetailsServiceFails() throws Exception {
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setSwitchUserUrl("/j_spring_security_switch_user");
|
||||
filter.setExitUserUrl("/j_spring_security_exit_user");
|
||||
filter.setTargetUrl("/main.jsp");
|
||||
|
||||
try {
|
||||
filter.afterPropertiesSet();
|
||||
fail("Expect to fail due to missing 'authenticationDao'");
|
||||
} catch (Exception expected) {
|
||||
// expected exception
|
||||
}
|
||||
filter.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void testBadConfigMissingTargetUrl() {
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testBadConfigMissingTargetUrl() throws Exception {
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
filter.setSwitchUserUrl("/j_spring_security_switch_user");
|
||||
filter.setExitUserUrl("/j_spring_security_exit_user");
|
||||
|
||||
try {
|
||||
filter.afterPropertiesSet();
|
||||
fail("Expect to fail due to missing 'targetUrl'");
|
||||
} catch (Exception expected) {
|
||||
// expected exception
|
||||
}
|
||||
filter.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void testDefaultProcessesFilterUrlWithPathParameter() {
|
||||
@Test
|
||||
public void defaultProcessesFilterUrlMatchesUrlWithPathParameter() {
|
||||
MockHttpServletRequest request = createMockSwitchRequest();
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setSwitchUserUrl("/j_spring_security_switch_user");
|
||||
@@ -259,7 +196,8 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
assertTrue(filter.requiresSwitchUser(request));
|
||||
}
|
||||
|
||||
public void testExitRequestUserJackLordToDano() throws Exception {
|
||||
@Test
|
||||
public void exitUserJackLordToDanoSucceeds() throws Exception {
|
||||
// original user
|
||||
GrantedAuthority[] auths = {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")};
|
||||
UsernamePasswordAuthenticationToken source = new UsernamePasswordAuthenticationToken("dano", "hawaii50", auths);
|
||||
@@ -274,23 +212,17 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(admin);
|
||||
|
||||
// http request
|
||||
MockHttpServletRequest request = createMockSwitchRequest();
|
||||
request.setRequestURI("/j_spring_security_exit_user");
|
||||
|
||||
// http response
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
// setup filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
filter.setExitUserUrl("/j_spring_security_exit_user");
|
||||
filter.setTargetUrl("/webapp/someOtherUrl");
|
||||
|
||||
MockFilterChain chain = new MockFilterChain(true);
|
||||
|
||||
// run 'exit'
|
||||
filter.doFilter(request, response, chain);
|
||||
filter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain(false));
|
||||
|
||||
// check current user, should be back to original user (dano)
|
||||
Authentication targetAuth = SecurityContextHolder.getContext().getAuthentication();
|
||||
@@ -298,56 +230,44 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
assertEquals("dano", targetAuth.getPrincipal());
|
||||
}
|
||||
|
||||
public void testExitUserWithNoCurrentUser() throws Exception {
|
||||
@Test(expected=AuthenticationException.class)
|
||||
public void exitUserWithNoCurrentUserFails() throws Exception {
|
||||
// no current user in secure context
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
SecurityContextHolder.clearContext();
|
||||
|
||||
// http request
|
||||
MockHttpServletRequest request = createMockSwitchRequest();
|
||||
request.setRequestURI("/j_spring_security_exit_user");
|
||||
|
||||
// http response
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
// setup filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
filter.setExitUserUrl("/j_spring_security_exit_user");
|
||||
|
||||
MockFilterChain chain = new MockFilterChain(true);
|
||||
|
||||
// run 'exit', expect fail due to no current user
|
||||
try {
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
fail("Cannot exit from a user with no current user set!");
|
||||
} catch (AuthenticationException expected) {}
|
||||
filter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain(false));
|
||||
}
|
||||
|
||||
public void testRedirectToTargetUrl() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
@Test
|
||||
public void redirectToTargetUrlIsCorrect() throws Exception {
|
||||
MockHttpServletRequest request = createMockSwitchRequest();
|
||||
request.setContextPath("/webapp");
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "jacklord");
|
||||
request.setRequestURI("/webapp/j_spring_security_switch_user");
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockFilterChain chain = new MockFilterChain(true);
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setSwitchUserUrl("/j_spring_security_switch_user");
|
||||
filter.setTargetUrl("/someOtherUrl");
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
|
||||
filter.doFilter(request, response, chain);
|
||||
filter.doFilter(request, response, new MockFilterChain(false));
|
||||
|
||||
assertEquals("/webapp/someOtherUrl", response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
public void testRedirectOmitsContextPathIfUseRelativeContextSet() throws Exception {
|
||||
@Test
|
||||
public void redirectOmitsContextPathIfUseRelativeContextSet() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
@@ -358,42 +278,19 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
request.setRequestURI("/webapp/j_spring_security_switch_user");
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockFilterChain chain = new MockFilterChain(true);
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setSwitchUserUrl("/j_spring_security_switch_user");
|
||||
filter.setTargetUrl("/someOtherUrl");
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
filter.setUseRelativeContext(true);
|
||||
|
||||
filter.doFilter(request, response, chain);
|
||||
filter.doFilter(request, response, new MockFilterChain(false));
|
||||
|
||||
assertEquals("/someOtherUrl", response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
public void testRequiresExitUser() {
|
||||
// filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setExitUserUrl("/j_spring_security_exit_user");
|
||||
|
||||
// request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("/j_spring_security_exit_user");
|
||||
|
||||
assertTrue(filter.requiresExitUser(request));
|
||||
}
|
||||
|
||||
public void testRequiresSwitch() {
|
||||
// filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setSwitchUserUrl("/j_spring_security_switch_user");
|
||||
|
||||
// request
|
||||
MockHttpServletRequest request = createMockSwitchRequest();
|
||||
|
||||
assertTrue(filter.requiresSwitchUser(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchRequestFromDanoToJackLord() throws Exception {
|
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
@@ -409,7 +306,7 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
|
||||
// setup filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
filter.setSwitchUserUrl("/j_spring_security_switch_user");
|
||||
filter.setTargetUrl("/webapp/someOtherUrl");
|
||||
|
||||
@@ -425,7 +322,8 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
assertEquals("jacklord", ((User) targetAuth.getPrincipal()).getUsername());
|
||||
}
|
||||
|
||||
public void testModificationOfAuthoritiesWorks() {
|
||||
@Test
|
||||
public void modificationOfAuthoritiesWorks() {
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
@@ -433,7 +331,7 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "jacklord");
|
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
|
||||
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
|
||||
filter.setUserDetailsService(new MockUserDetailsService());
|
||||
filter.setSwitchUserAuthorityChanger(new SwitchUserAuthorityChanger() {
|
||||
public List modifyGrantedAuthorities(UserDetails targetUser, Authentication currentAuthentication, List authoritiesToBeGranted) {
|
||||
List auths = new ArrayList();
|
||||
@@ -451,11 +349,10 @@ public class SwitchUserProcessingFilterTests extends TestCase {
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockAuthenticationDaoUserJackLord implements UserDetailsService {
|
||||
private class MockUserDetailsService implements UserDetailsService {
|
||||
private String password = "hawaii50";
|
||||
|
||||
public UserDetails loadUserByUsername(String username)
|
||||
throws UsernameNotFoundException, DataAccessException {
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
// jacklord, dano (active)
|
||||
// mcgarrett (disabled)
|
||||
// wofat (account expired)
|
||||
|
||||
+8
-8
@@ -46,8 +46,8 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
|
||||
ctx.setAttributeValue("objectclass", "organizationalUnit");
|
||||
ctx.setAttributeValue("ou", "testpeople");
|
||||
template.bind("ou=testpeople", ctx, null);
|
||||
ctx.setAttributeValue("ou", "test people");
|
||||
template.bind("ou=test people", ctx, null);
|
||||
|
||||
ctx.setAttributeValue("ou", "testgroups");
|
||||
template.bind("ou=testgroups", ctx, null);
|
||||
@@ -56,13 +56,13 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||
|
||||
group.setAttributeValue("objectclass", "groupOfNames");
|
||||
group.setAttributeValue("cn", "clowns");
|
||||
group.setAttributeValue("member", "cn=nobody,ou=testpeople,dc=springframework,dc=org");
|
||||
group.setAttributeValue("member", "cn=nobody,ou=test people,dc=springframework,dc=org");
|
||||
template.bind("cn=clowns,ou=testgroups", group, null);
|
||||
|
||||
group.setAttributeValue("cn", "acrobats");
|
||||
template.bind("cn=acrobats,ou=testgroups", group, null);
|
||||
|
||||
mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=testpeople","uid"));
|
||||
mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=test people","uid"));
|
||||
mgr.setGroupSearchBase("ou=testgroups");
|
||||
mgr.setGroupRoleAttributeName("cn");
|
||||
mgr.setGroupMemberAttributeName("member");
|
||||
@@ -79,7 +79,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||
// template.unbind((String) people.next() + ",ou=testpeople");
|
||||
// }
|
||||
|
||||
template.unbind("ou=testpeople",true);
|
||||
template.unbind("ou=test people",true);
|
||||
template.unbind("ou=testgroups",true);
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
@@ -116,7 +116,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||
@Test
|
||||
public void testCreateNewUserSucceeds() {
|
||||
InetOrgPerson.Essence p = new InetOrgPerson.Essence();
|
||||
p.setCarLicense("XXX");
|
||||
p.setCarLicense("XXX");
|
||||
p.setCn(new String[] {"Joe Smeth"});
|
||||
p.setDepartmentNumber("5679");
|
||||
p.setDescription("Some description");
|
||||
@@ -130,7 +130,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||
p.setRoomNumber("500X");
|
||||
p.setSn("Smeth");
|
||||
p.setUid("joe");
|
||||
|
||||
|
||||
p.setAuthorities(TEST_AUTHORITIES);
|
||||
|
||||
mgr.createUser(p.createUserDetails());
|
||||
@@ -182,7 +182,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||
|
||||
mgr.changePassword("yossarianspassword", "yossariansnewpassword");
|
||||
|
||||
assertTrue(template.compare("uid=johnyossarian,ou=testpeople",
|
||||
assertTrue(template.compare("uid=johnyossarian,ou=test people",
|
||||
"userPassword", "yossariansnewpassword"));
|
||||
}
|
||||
|
||||
|
||||
@@ -62,20 +62,16 @@ public class FilterChainProxyTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testDetectsFilterInvocationDefinitionSourceThatDoesNotReturnAllConfigAttributes() throws Exception {
|
||||
FilterChainProxy filterChainProxy = new FilterChainProxy();
|
||||
filterChainProxy.setApplicationContext(new StaticApplicationContext());
|
||||
|
||||
try {
|
||||
filterChainProxy.setFilterInvocationDefinitionSource(new MockFilterInvocationDefinitionSource(false, false));
|
||||
filterChainProxy.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
filterChainProxy.setFilterInvocationDefinitionSource(new MockFilterInvocationDefinitionSource(false, false));
|
||||
filterChainProxy.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testDetectsIfConfigAttributeDoesNotReturnValueForGetAttributeMethod() throws Exception {
|
||||
FilterChainProxy filterChainProxy = new FilterChainProxy();
|
||||
filterChainProxy.setApplicationContext(new StaticApplicationContext());
|
||||
@@ -89,12 +85,8 @@ public class FilterChainProxyTests {
|
||||
|
||||
filterChainProxy.setFilterInvocationDefinitionSource(fids);
|
||||
|
||||
try {
|
||||
filterChainProxy.afterPropertiesSet();
|
||||
filterChainProxy.init(new MockFilterConfig());
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
filterChainProxy.afterPropertiesSet();
|
||||
filterChainProxy.init(new MockFilterConfig());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@@ -131,18 +123,18 @@ public class FilterChainProxyTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void normalOperation() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void proxyPathWithoutLowerCaseConversionShouldntMatchDifferentCasePath() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChainNonLowerCase", FilterChainProxy.class);
|
||||
assertNull(filterChainProxy.getFilters("/some/other/path/blah"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfig() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
||||
@@ -164,6 +156,24 @@ public class FilterChainProxyTests {
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathWithNoMatchHasNoFilters() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlStrippingPropertyIsRespected() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||
|
||||
// Should only match if we are stripping the query string
|
||||
String url = "/blah.bar?x=something";
|
||||
assertNotNull(filterChainProxy.getFilters(url));
|
||||
assertEquals(2, filterChainProxy.getFilters(url).size());
|
||||
filterChainProxy.setStripQueryStringFromUrls(false);
|
||||
assertNull(filterChainProxy.getFilters(url));
|
||||
}
|
||||
|
||||
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) throws Exception {
|
||||
List filters = filterChainProxy.getFilters("/foo/blah");
|
||||
assertEquals(1, filters.size());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user