Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d6d9bc9d6b | |||
| 2fa991c44f | |||
| 3ee8733261 | |||
| d5ee89bb7c | |||
| ff5bfccdba | |||
| 5b089aea16 | |||
| d7f194df78 | |||
| c56d524bd9 | |||
| af5f193ec1 | |||
| 7d79ae5424 | |||
| 3e5b65bd85 | |||
| 64b5fa0131 | |||
| fe929bf9b9 | |||
| 8a2581c939 | |||
| 55caab3bbc | |||
| 269865ca65 | |||
| 32b8009bee | |||
| 3b775d29d3 | |||
| 0401dddda8 | |||
| 358f284f42 | |||
| b403216494 | |||
| 371769740a | |||
| e38d5dfd87 | |||
| ff5666ae83 | |||
| de897ad1ac | |||
| ff785a829f | |||
| db1d8604a6 | |||
| f762920239 | |||
| 70826f1202 | |||
| ea25299bd0 | |||
| d784d854cd | |||
| 9308284bd4 | |||
| c34eb497c8 | |||
| de250d2073 | |||
| 8df56c8ac5 | |||
| 192aa25b60 | |||
| d95a5597c8 | |||
| 122e1c47ed | |||
| 64ab7e534c | |||
| ab6d29d927 | |||
| 2a510f3539 | |||
| 7c0f8b9756 | |||
| 1d9d7eb9a7 | |||
| 0cfcc0e9f1 | |||
| 373f7b648b | |||
| a5cae70949 | |||
| ecd2cc6da7 | |||
| f228d013d8 | |||
| 4de4bb8e87 | |||
| f8cded10ee | |||
| c031588975 | |||
| 36a192b70f | |||
| 980a72f9a0 | |||
| 517a7f117a | |||
| 244579faf4 | |||
| 87ba871605 | |||
| d63536cc0d | |||
| 8b5bbe3800 | |||
| cf4072c517 | |||
| 4b45e5d7c2 | |||
| 45c3084502 | |||
| 871e529840 | |||
| d1005e4cfb | |||
| 9ce0270226 | |||
| 7603ce2f97 | |||
| 859e99edf4 | |||
| 25ba269db0 | |||
| 11b448c0e0 | |||
| 08c5fe8925 | |||
| fbe3ca48f4 | |||
| 3e33b8a880 | |||
| b60c578b25 | |||
| 03981ab6a0 | |||
| e9adbd4d62 | |||
| 29d31b72d0 | |||
| 3fb1f59fde | |||
| 219d2e8962 | |||
| ff215e6750 | |||
| 6ae81d553b | |||
| 5af53da106 | |||
| 2329dadf48 | |||
| fb5eefeea5 | |||
| f269373442 | |||
| 4f6b4e4bfd | |||
| 8b2c0468ff | |||
| d17a2da9e0 | |||
| 7f38c656ca | |||
| 6493df13f8 | |||
| d4defb10fe | |||
| 59543af4fb | |||
| 332f8fe5a1 | |||
| 7a8eec11da | |||
| ff61644219 | |||
| 1fee538c7e | |||
| ae2470127c | |||
| 2a4d859812 | |||
| 15b893f9ae | |||
| de886e36fa | |||
| ad9a667b75 | |||
| f70701d55a | |||
| e1b226ee57 | |||
| af0153d833 | |||
| d78a021fe1 | |||
| e1c17450b3 | |||
| add2649397 | |||
| 781d88bd30 | |||
| 1030dca353 | |||
| b99f9d343d | |||
| c0e829a41d | |||
| 5a1258a4ca | |||
| 883b92e7bd | |||
| 301d021bf5 | |||
| 8ad2d681ab | |||
| 5cf0c84e2f | |||
| afc757e618 | |||
| c333070fe3 | |||
| fca3a2a709 | |||
| fa44c74993 | |||
| 06719053f1 | |||
| e7b6fe09e1 | |||
| 9961c7f867 | |||
| 7a2e1e13d3 | |||
| a599ef5398 | |||
| 3e808335a4 | |||
| 054e2f6c38 | |||
| 79ca0d1612 | |||
| 18a9965b80 | |||
| de179c3e46 | |||
| fc498954c6 | |||
| 014f21ee85 | |||
| 6ecfa0541f | |||
| 4984d4be65 | |||
| af3dc22586 | |||
| 26d2b03667 | |||
| e7e256a9d5 | |||
| 0df9dee9dd | |||
| 81ebd094ff | |||
| 473f6a32c6 | |||
| 8281aeb0da | |||
| e4b32b8d29 | |||
| 104716fedb | |||
| 49bec559a9 | |||
| f96fa66a60 | |||
| ef112f7967 | |||
| 341455cde4 | |||
| 2d692718e0 | |||
| 270fa92780 | |||
| 0c28845d4e | |||
| d3a0f05de9 | |||
| 348d211b8c | |||
| d1e23b3d2c | |||
| 1090072fff | |||
| 882509fb2a | |||
| 5d51b35cfa | |||
| eba18675fc | |||
| 38774ec94f | |||
| 80cd7f4acc | |||
| c184d2d8c5 | |||
| 01185475a1 | |||
| 7e63fe7357 | |||
| 8ea7487ec3 | |||
| ec81e780b2 | |||
| 599d9fea04 | |||
| a845a69cb7 | |||
| 0cf745b85f | |||
| b2e9e82727 | |||
| 63decfeb93 | |||
| 1ae167434a | |||
| 083644f2fe | |||
| eec62e9760 | |||
| c5f6cbb8f5 | |||
| 1258fa854e | |||
| e12b6afefa | |||
| 88ea87642a | |||
| 9eaa1cbbdd | |||
| aba5a22b6c | |||
| 1a4130528a | |||
| 5bb558bd6a | |||
| 993fdd7a32 | |||
| 1663142cf1 | |||
| 469f55ce05 | |||
| 4d347cfdb5 | |||
| 2cc3068de7 | |||
| 09ccc35119 | |||
| 7238097310 | |||
| 31a9fa553d | |||
| 680b2d3b74 | |||
| d2ddbc1ee3 | |||
| 35698edc04 | |||
| b5dc523041 | |||
| 0c42670431 |
+28
-2
@@ -3,13 +3,14 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.3</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.0</version>
|
||||
<version>2.0.3</version>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -44,4 +45,29 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version.osgi}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
javax.sql.*
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.acls</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides an abstract superclass for {@link Permission} implementations.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
* @see AbstractRegisteredPermission
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractPermission implements Permission {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected char code;
|
||||
protected int mask;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
protected AbstractPermission(int mask, char code) {
|
||||
this.mask = mask;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public final boolean equals(Object arg0) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public final int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return AclFormattingUtils.printBinary(mask, code);
|
||||
}
|
||||
|
||||
public final String toString() {
|
||||
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + mask + "]";
|
||||
}
|
||||
|
||||
public final int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -14,157 +14,36 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* A set of standard permissions.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* You may subclass this class to add additional permissions, or use this class as a guide
|
||||
* for creating your own permission classes.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class BasePermission implements Permission {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
public class BasePermission extends AbstractRegisteredPermission {
|
||||
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
|
||||
private static Map locallyDeclaredPermissionsByInteger = new HashMap();
|
||||
private static Map locallyDeclaredPermissionsByName = new HashMap();
|
||||
|
||||
static {
|
||||
Field[] fields = BasePermission.class.getDeclaredFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
try {
|
||||
Object fieldValue = fields[i].get(null);
|
||||
|
||||
if (BasePermission.class.isAssignableFrom(fieldValue.getClass())) {
|
||||
// Found a BasePermission static field
|
||||
BasePermission perm = (BasePermission) fieldValue;
|
||||
locallyDeclaredPermissionsByInteger.put(new Integer(perm.getMask()), perm);
|
||||
locallyDeclaredPermissionsByName.put(fields[i].getName(), perm);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private char code;
|
||||
private int mask;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
private BasePermission(int mask, char code) {
|
||||
this.mask = mask;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
||||
/**
|
||||
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
|
||||
* active bits in the passed mask.
|
||||
*
|
||||
* @param mask to build
|
||||
*
|
||||
* @return a Permission representing the requested object
|
||||
* Registers the public static permissions defined on this class. This is mandatory so
|
||||
* that the static methods will operate correctly.
|
||||
*/
|
||||
public static Permission buildFromMask(int mask) {
|
||||
if (locallyDeclaredPermissionsByInteger.containsKey(new Integer(mask))) {
|
||||
// The requested mask has an exactly match against a statically-defined BasePermission, so return it
|
||||
return (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(mask));
|
||||
}
|
||||
|
||||
// To get this far, we have to use a CumulativePermission
|
||||
CumulativePermission permission = new CumulativePermission();
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int permissionToCheck = 1 << i;
|
||||
|
||||
if ((mask & permissionToCheck) == permissionToCheck) {
|
||||
Permission p = (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(permissionToCheck));
|
||||
Assert.state(p != null,
|
||||
"Mask " + permissionToCheck + " does not have a corresponding static BasePermission");
|
||||
permission.set(p);
|
||||
}
|
||||
}
|
||||
|
||||
return permission;
|
||||
static {
|
||||
registerPermissionsFor(BasePermission.class);
|
||||
}
|
||||
|
||||
public static Permission[] buildFromMask(int[] masks) {
|
||||
if ((masks == null) || (masks.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[masks.length];
|
||||
|
||||
for (int i = 0; i < masks.length; i++) {
|
||||
permissions[i] = buildFromMask(masks[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
protected BasePermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
|
||||
public static Permission buildFromName(String name) {
|
||||
Assert.isTrue(locallyDeclaredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
|
||||
|
||||
return (Permission) locallyDeclaredPermissionsByName.get(name);
|
||||
}
|
||||
|
||||
public static Permission[] buildFromName(String[] names) {
|
||||
if ((names == null) || (names.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[names.length];
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
permissions[i] = buildFromName(names[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return AclFormattingUtils.printBinary(mask, code);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "BasePermission[" + getPattern() + "=" + mask + "]";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-38
@@ -19,20 +19,21 @@ import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.<p>Methods return
|
||||
* <code>this</code>, in order to facilitate method chaining.</p>
|
||||
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.
|
||||
*
|
||||
* <p>Methods return <code>this</code>, in order to facilitate method chaining.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CumulativePermission implements Permission {
|
||||
//~ Instance fields ================================================================================================
|
||||
public class CumulativePermission extends AbstractPermission {
|
||||
|
||||
private String pattern = THIRTY_TWO_RESERVED_OFF;
|
||||
private int mask = 0;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public CumulativePermission() {
|
||||
super(0, ' ');
|
||||
}
|
||||
|
||||
public CumulativePermission clear(Permission permission) {
|
||||
this.mask &= ~permission.getMask();
|
||||
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
|
||||
@@ -46,43 +47,16 @@ public class CumulativePermission implements Permission {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
public int getMask() {
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
public CumulativePermission set(Permission permission) {
|
||||
this.mask |= permission.getMask();
|
||||
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CumulativePermission[" + pattern + "=" + this.mask + "]";
|
||||
|
||||
public String getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link PermissionFactory}.
|
||||
*
|
||||
* <p>
|
||||
* Generally this class will be used by a {@link Permission} instance, as opposed to being dependency
|
||||
* injected into a {@link LookupStrategy} or similar. Nevertheless, the latter mode of operation is
|
||||
* fully supported (in which case your {@link Permission} implementations probably should extend
|
||||
* {@link AbstractPermission} instead of {@link AbstractRegisteredPermission}).
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public class DefaultPermissionFactory implements PermissionFactory {
|
||||
private Map registeredPermissionsByInteger = new HashMap();
|
||||
private Map registeredPermissionsByName = new HashMap();
|
||||
|
||||
/**
|
||||
* Permit registration of a {@link DefaultPermissionFactory} class. The class must provide
|
||||
* public static fields of type {@link Permission} to represent the possible permissions.
|
||||
*
|
||||
* @param clazz a {@link Permission} class with public static fields to register
|
||||
*/
|
||||
public void registerPublicPermissions(Class clazz) {
|
||||
Assert.notNull(clazz, "Class required");
|
||||
Assert.isAssignable(Permission.class, clazz);
|
||||
|
||||
Field[] fields = clazz.getFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
try {
|
||||
Object fieldValue = fields[i].get(null);
|
||||
|
||||
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
|
||||
// Found a Permission static field
|
||||
Permission perm = (Permission) fieldValue;
|
||||
String permissionName = fields[i].getName();
|
||||
|
||||
registerPermission(perm, permissionName);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPermission(Permission perm, String permissionName) {
|
||||
Assert.notNull(perm, "Permission required");
|
||||
Assert.hasText(permissionName, "Permission name required");
|
||||
|
||||
Integer mask = new Integer(perm.getMask());
|
||||
|
||||
// Ensure no existing Permission uses this integer or code
|
||||
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
|
||||
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName), "An existing Permission already provides name '" + permissionName + "'");
|
||||
|
||||
// Register the new Permission
|
||||
registeredPermissionsByInteger.put(mask, perm);
|
||||
registeredPermissionsByName.put(permissionName, perm);
|
||||
}
|
||||
|
||||
public Permission buildFromMask(int mask) {
|
||||
if (registeredPermissionsByInteger.containsKey(new Integer(mask))) {
|
||||
// The requested mask has an exactly match against a statically-defined Permission, so return it
|
||||
return (Permission) registeredPermissionsByInteger.get(new Integer(mask));
|
||||
}
|
||||
|
||||
// To get this far, we have to use a CumulativePermission
|
||||
CumulativePermission permission = new CumulativePermission();
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int permissionToCheck = 1 << i;
|
||||
|
||||
if ((mask & permissionToCheck) == permissionToCheck) {
|
||||
Permission p = (Permission) registeredPermissionsByInteger.get(new Integer(permissionToCheck));
|
||||
Assert.state(p != null, "Mask " + permissionToCheck + " does not have a corresponding static Permission");
|
||||
permission.set(p);
|
||||
}
|
||||
}
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
public Permission[] buildFromMask(int[] masks) {
|
||||
if ((masks == null) || (masks.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[masks.length];
|
||||
|
||||
for (int i = 0; i < masks.length; i++) {
|
||||
permissions[i] = buildFromMask(masks[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public Permission buildFromName(String name) {
|
||||
Assert.isTrue(registeredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
|
||||
|
||||
return (Permission) registeredPermissionsByName.get(name);
|
||||
}
|
||||
|
||||
public Permission[] buildFromName(String[] names) {
|
||||
if ((names == null) || (names.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[names.length];
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
permissions[i] = buildFromName(names[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides a simple mechanism to retrieve {@link Permission} instances from integer masks.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public interface PermissionFactory {
|
||||
|
||||
/**
|
||||
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
|
||||
* active bits in the passed mask.
|
||||
*
|
||||
* @param mask to build
|
||||
*
|
||||
* @return a Permission representing the requested object
|
||||
*/
|
||||
public abstract Permission buildFromMask(int mask);
|
||||
|
||||
}
|
||||
@@ -49,6 +49,7 @@ import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -73,7 +74,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructor accepting mandatory arguments
|
||||
*
|
||||
* @param dataSource to access the database
|
||||
@@ -97,30 +98,30 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
private static String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
Assert.isTrue(requiredRepetitions >= 1, "Must be => 1");
|
||||
|
||||
String startSql = "select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, "
|
||||
+ "ACL_ENTRY.ACE_ORDER, "
|
||||
+ "ACL_OBJECT_IDENTITY.ID as ACL_ID, "
|
||||
+ "ACL_OBJECT_IDENTITY.PARENT_OBJECT, "
|
||||
+ "ACL_OBJECT_IDENTITY.ENTRIES_INHERITING, "
|
||||
+ "ACL_ENTRY.ID as ACE_ID, "
|
||||
+ "ACL_ENTRY.MASK, "
|
||||
+ "ACL_ENTRY.GRANTING, "
|
||||
+ "ACL_ENTRY.AUDIT_SUCCESS, "
|
||||
+ "ACL_ENTRY.AUDIT_FAILURE, "
|
||||
+ "ACL_SID.PRINCIPAL as ACE_PRINCIPAL, "
|
||||
+ "ACL_SID.SID as ACE_SID, "
|
||||
+ "ACLI_SID.PRINCIPAL as ACL_PRINCIPAL, "
|
||||
+ "ACLI_SID.SID as ACL_SID, "
|
||||
+ "ACL_CLASS.CLASS "
|
||||
+ "from ACL_OBJECT_IDENTITY "
|
||||
+ "left join ACL_SID ACLI_SID on ACLI_SID.ID = ACL_OBJECT_IDENTITY.OWNER_SID "
|
||||
+ "left join ACL_CLASS on ACL_CLASS.ID = ACL_OBJECT_IDENTITY.OBJECT_ID_CLASS "
|
||||
+ "left join ACL_ENTRY on ACL_OBJECT_IDENTITY.ID = ACL_ENTRY.ACL_OBJECT_IDENTITY "
|
||||
+ "left join ACL_SID on ACL_ENTRY.SID = ACL_SID.ID "
|
||||
String startSql = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, "
|
||||
+ "acl_object_identity.id as acl_id, "
|
||||
+ "acl_object_identity.parent_object, "
|
||||
+ "acl_object_identity.entries_inheriting, "
|
||||
+ "acl_entry.id as ace_id, "
|
||||
+ "acl_entry.mask, "
|
||||
+ "acl_entry.granting, "
|
||||
+ "acl_entry.audit_success, "
|
||||
+ "acl_entry.audit_failure, "
|
||||
+ "acl_sid.principal as ace_principal, "
|
||||
+ "acl_sid.sid as ace_sid, "
|
||||
+ "acli_sid.principal as acl_principal, "
|
||||
+ "acli_sid.sid as acl_sid, "
|
||||
+ "acl_class.class "
|
||||
+ "from acl_object_identity "
|
||||
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
||||
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
|
||||
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
||||
+ "left join acl_sid on acl_entry.sid = acl_sid.id "
|
||||
+ "where ( ";
|
||||
|
||||
String endSql = ") order by ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY"
|
||||
+ " asc, ACL_ENTRY.ACE_ORDER asc";
|
||||
String endSql = ") order by acl_object_identity.object_id_identity"
|
||||
+ " asc, acl_entry.ace_order asc";
|
||||
|
||||
StringBuffer sqlStringBuffer = new StringBuffer();
|
||||
sqlStringBuffer.append(startSql);
|
||||
@@ -196,30 +197,30 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
*/
|
||||
private void convertCurrentResultIntoObject(Map acls, ResultSet rs)
|
||||
throws SQLException {
|
||||
Long id = new Long(rs.getLong("ACL_ID"));
|
||||
Long id = new Long(rs.getLong("acl_id"));
|
||||
|
||||
// If we already have an ACL for this ID, just create the ACE
|
||||
AclImpl acl = (AclImpl) acls.get(id);
|
||||
|
||||
if (acl == null) {
|
||||
// Make an AclImpl and pop it into the Map
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("CLASS"),
|
||||
new Long(rs.getLong("OBJECT_ID_IDENTITY")));
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
|
||||
new Long(rs.getLong("object_id_identity")));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("PARENT_OBJECT");
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
if (parentAclId != 0) {
|
||||
parentAcl = new StubAclParent(new Long(parentAclId));
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("ENTRIES_INHERITING");
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
Sid owner;
|
||||
|
||||
if (rs.getBoolean("ACL_PRINCIPAL")) {
|
||||
owner = new PrincipalSid(rs.getString("ACL_SID"));
|
||||
if (rs.getBoolean("acl_principal")) {
|
||||
owner = new PrincipalSid(rs.getString("acl_sid"));
|
||||
} else {
|
||||
owner = new GrantedAuthoritySid(rs.getString("ACL_SID"));
|
||||
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
|
||||
}
|
||||
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
|
||||
@@ -229,20 +230,21 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
// Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
|
||||
// It is permissable to have no ACEs in an ACL (which is detected by a null ACE_SID)
|
||||
if (rs.getString("ACE_SID") != null) {
|
||||
Long aceId = new Long(rs.getLong("ACE_ID"));
|
||||
if (rs.getString("ace_sid") != null) {
|
||||
Long aceId = new Long(rs.getLong("ace_id"));
|
||||
Sid recipient;
|
||||
|
||||
if (rs.getBoolean("ACE_PRINCIPAL")) {
|
||||
recipient = new PrincipalSid(rs.getString("ACE_SID"));
|
||||
if (rs.getBoolean("ace_principal")) {
|
||||
recipient = new PrincipalSid(rs.getString("ace_sid"));
|
||||
} else {
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ACE_SID"));
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
|
||||
}
|
||||
|
||||
Permission permission = BasePermission.buildFromMask(rs.getInt("MASK"));
|
||||
boolean granting = rs.getBoolean("GRANTING");
|
||||
boolean auditSuccess = rs.getBoolean("AUDIT_SUCCESS");
|
||||
boolean auditFailure = rs.getBoolean("AUDIT_FAILURE");
|
||||
int mask = rs.getInt("mask");
|
||||
Permission permission = convertMaskIntoPermission(mask);
|
||||
boolean granting = rs.getBoolean("granting");
|
||||
boolean auditSuccess = rs.getBoolean("audit_success");
|
||||
boolean auditFailure = rs.getBoolean("audit_failure");
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl, recipient, permission, granting,
|
||||
auditSuccess, auditFailure);
|
||||
@@ -264,6 +266,10 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
protected Permission convertMaskIntoPermission(int mask) {
|
||||
return BasePermission.buildFromMask(mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.<p>The caller is responsible
|
||||
* for optimization issues, such as selecting the identities to lookup, ensuring the cache doesn't contain them
|
||||
@@ -283,7 +289,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
// Make the "acls" map contain all requested objectIdentities
|
||||
// (including markers to each parent in the hierarchy)
|
||||
String sql = computeRepeatingSql("(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = ? and ACL_CLASS.CLASS = ?)",
|
||||
String sql = computeRepeatingSql("(acl_object_identity.object_id_identity = ? and acl_class.class = ?)",
|
||||
objectIdentities.length);
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
@@ -293,10 +299,10 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
for (int i = 0; i < objectIdentities.length; i++) {
|
||||
// Determine prepared statement values for this iteration
|
||||
String javaType = objectIdentities[i].getJavaType().getName();
|
||||
Assert.isInstanceOf(Long.class, objectIdentities[i].getIdentifier(),
|
||||
"This class requires ObjectIdentity.getIdentifier() to be a Long");
|
||||
|
||||
long id = ((Long) objectIdentities[i].getIdentifier()).longValue();
|
||||
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
|
||||
String identifier = objectIdentities[i].getIdentifier().toString();
|
||||
long id = (Long.valueOf(identifier)).longValue();
|
||||
|
||||
// Inject values
|
||||
ps.setLong((2 * i) + 1, id);
|
||||
@@ -338,7 +344,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
|
||||
String sql = computeRepeatingSql("(ACL_OBJECT_IDENTITY.ID = ?)", findNow.size());
|
||||
String sql = computeRepeatingSql("(acl_object_identity.id = ?)", findNow.size());
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
@@ -473,7 +479,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
convertCurrentResultIntoObject(acls, rs);
|
||||
|
||||
// Figure out if this row means we need to lookup another parent
|
||||
long parentId = rs.getLong("PARENT_OBJECT");
|
||||
long parentId = rs.getLong("parent_object");
|
||||
|
||||
if (parentId != 0) {
|
||||
// See if it's already in the "acls"
|
||||
|
||||
@@ -53,11 +53,11 @@ public class JdbcAclService implements AclService {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
||||
private static final String selectAclObjectWithParent = "SELECT obj.object_id_identity obj_id, class.class class "
|
||||
+ "FROM acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||
+ "WHERE obj.parent_object = parent.id AND obj.object_id_class = class.id "
|
||||
+ "AND parent.object_id_identity = ? AND parent.object_id_class = ("
|
||||
+ "SELECT id FROM acl_class WHERE acl_class.class = ?)";
|
||||
private static final String selectAclObjectWithParent = "select obj.object_id_identity as obj_id, class.class as class "
|
||||
+ "from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||
+ "select id FROM acl_class where acl_class.class = ?)";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
|
||||
+23
-19
@@ -62,23 +62,23 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
|
||||
private boolean foreignKeysInDatabase = true;
|
||||
private AclCache aclCache;
|
||||
private String deleteClassByClassNameString = "DELETE FROM acl_class WHERE class=?";
|
||||
private String deleteEntryByObjectIdentityForeignKey = "DELETE FROM acl_entry WHERE acl_object_identity=?";
|
||||
private String deleteObjectIdentityByPrimaryKey = "DELETE FROM acl_object_identity WHERE id=?";
|
||||
private String identityQuery = "call identity()";
|
||||
private String insertClass = "INSERT INTO acl_class (class) VALUES (?)";
|
||||
private String insertEntry = "INSERT INTO acl_entry "
|
||||
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
|
||||
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
||||
private String classIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_class_seq')
|
||||
private String sidIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_siq_seq')
|
||||
private String insertClass = "insert into acl_class (class) values (?)";
|
||||
private String insertEntry = "insert into acl_entry "
|
||||
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||
private String insertObjectIdentity = "INSERT INTO acl_object_identity "
|
||||
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "VALUES (?, ?, ?, ?)";
|
||||
private String insertSid = "INSERT INTO acl_sid (principal, sid) VALUES (?, ?)";
|
||||
private String selectClassPrimaryKey = "SELECT id FROM acl_class WHERE class=?";
|
||||
private String selectObjectIdentityPrimaryKey = "SELECT acl_object_identity.id FROM acl_object_identity, acl_class "
|
||||
+ "WHERE acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
|
||||
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
||||
private String insertObjectIdentity = "insert into acl_object_identity "
|
||||
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "values (?, ?, ?, ?)";
|
||||
private String insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
|
||||
private String selectClassPrimaryKey = "select id from acl_class where class=?";
|
||||
private String selectObjectIdentityPrimaryKey = "select acl_object_identity.id from acl_object_identity, acl_class "
|
||||
+ "where acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
|
||||
+ "and acl_object_identity.object_id_identity = ?";
|
||||
private String selectSidPrimaryKey = "SELECT id FROM acl_sid WHERE principal=? AND sid=?";
|
||||
private String updateObjectIdentity = "UPDATE acl_object_identity SET "
|
||||
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
|
||||
private String updateObjectIdentity = "update acl_object_identity set "
|
||||
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
@@ -177,7 +177,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
classId = new Long(jdbcTemplate.queryForLong(identityQuery));
|
||||
classId = new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
||||
}
|
||||
} else {
|
||||
classId = (Long) classIds.iterator().next();
|
||||
@@ -222,7 +222,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
jdbcTemplate.update(insertSid, new Object[] {new Boolean(principal), sidName});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
sidId = new Long(jdbcTemplate.queryForLong(identityQuery));
|
||||
sidId = new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
|
||||
}
|
||||
} else {
|
||||
sidId = (Long) sidIds.iterator().next();
|
||||
@@ -381,11 +381,15 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdentityQuery(String identityQuery) {
|
||||
public void setClassIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.identityQuery = identityQuery;
|
||||
this.classIdentityQuery = identityQuery;
|
||||
}
|
||||
|
||||
public void setSidIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.sidIdentityQuery = identityQuery;
|
||||
}
|
||||
/**
|
||||
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
|
||||
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
|
||||
|
||||
+8
-1
@@ -15,6 +15,7 @@
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import org.springframework.security.acls.IdentityUnavailableException;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -97,6 +98,12 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
/**
|
||||
* Important so caching operates properly.<P>Considers an object of the same class equal if it has the same
|
||||
* <code>classname</code> and <code>id</code> properties.</p>
|
||||
*
|
||||
* <p>
|
||||
* Note that this class uses string equality for the identifier field, which ensures it better supports
|
||||
* differences between {@link LookupStrategy} requirements and the domain object represented by this
|
||||
* <code>ObjectIdentityImpl</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param arg0 object to compare
|
||||
*
|
||||
@@ -113,7 +120,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
|
||||
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
|
||||
|
||||
if (this.getIdentifier().equals(other.getIdentifier()) && this.getJavaType().equals(other.getJavaType())) {
|
||||
if (this.getIdentifier().toString().equals(other.getIdentifier().toString()) && this.getJavaType().equals(other.getJavaType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -34,20 +34,20 @@ import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related services.
|
||||
*
|
||||
* @author $author$
|
||||
* @version $Revision$
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AclService aclService;
|
||||
private Class processDomainObjectClass = Object.class;
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
private String processConfigAttribute;
|
||||
private Permission[] requirePermission = {BasePermission.READ};
|
||||
protected AclService aclService;
|
||||
protected Class processDomainObjectClass = Object.class;
|
||||
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
protected String processConfigAttribute;
|
||||
protected Permission[] requirePermission = {BasePermission.READ};
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* Tests BasePermission and CumulativePermission.
|
||||
* Tests classes associated with Permission.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id${date}
|
||||
@@ -63,9 +63,9 @@ public class PermissionTests {
|
||||
assertEquals("CumulativePermission[...............................R=1]",
|
||||
new CumulativePermission().set(BasePermission.READ).toString());
|
||||
|
||||
System.out.println("A = " + new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
|
||||
assertEquals("CumulativePermission[...........................A....=16]",
|
||||
new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
|
||||
System.out.println("A = " + new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
|
||||
assertEquals("CumulativePermission[..........................EA....=48]",
|
||||
new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
|
||||
|
||||
System.out.println("RA = "
|
||||
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString());
|
||||
|
||||
+16
-11
@@ -12,24 +12,29 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
package sample.attributes;
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @author Cameron Braid
|
||||
* A test permission.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class BankServiceImpl implements BankService {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public float balance(String accountNumber) {
|
||||
return 42000000;
|
||||
public class SpecialPermission extends BasePermission {
|
||||
public static final Permission ENTER = new SpecialPermission(1 << 5, 'E'); // 32
|
||||
|
||||
/**
|
||||
* Registers the public static permissions defined on this class. This is mandatory so
|
||||
* that the static methods will operate correctly.
|
||||
*/
|
||||
static {
|
||||
registerPermissionsFor(SpecialPermission.class);
|
||||
}
|
||||
|
||||
public String[] listAccounts() {
|
||||
return new String[] {"1", "2", "3"};
|
||||
protected SpecialPermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
}
|
||||
+7
-23
@@ -120,7 +120,8 @@ public class BasicLookupStrategyTests {
|
||||
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
@@ -128,7 +129,7 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalFromCacheOnly() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
@@ -145,7 +146,7 @@ public class BasicLookupStrategyTests {
|
||||
@Test
|
||||
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Set a batch size to allow multiple database queries in order to retrieve all acls
|
||||
@@ -227,7 +228,7 @@ public class BasicLookupStrategyTests {
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(103));
|
||||
|
||||
@@ -260,8 +261,8 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
ObjectIdentity parent1Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(105));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(107));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(107));
|
||||
|
||||
// First lookup only child, thus populating the cache with grandParent, parent1 and child
|
||||
Permission[] checkPermission = new Permission[] { BasePermission.READ };
|
||||
@@ -290,21 +291,4 @@ public class BasicLookupStrategyTests {
|
||||
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAclsWithDifferentSerializableTypesAsObjectIdentities() throws Exception {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,1,1);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,1,1,0,0)";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(104));
|
||||
Sid[] sids = new Sid[] { new PrincipalSid("ben") };
|
||||
ObjectIdentity[] childOids = new ObjectIdentity[] { oid };
|
||||
|
||||
try {
|
||||
Map foundAcls = strategy.readAclsById(childOids, sids);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
} catch(IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
||||
@@ -337,7 +337,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
|
||||
// Remove the child and check all related database rows were removed accordingly
|
||||
jdbcMutableAclService.deleteAcl(childOid, false);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.3</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.0</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jboss</artifactId>
|
||||
<name>Spring Security - JBoss adapter</name>
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ import javax.security.auth.login.LoginException;
|
||||
* which is subsequently available from <code>java:comp/env/security/subject</code>.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Sergio Bern�
|
||||
* @author Sergio Bern
|
||||
* @version $Id:JbossSpringSecurityLoginModule.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class JbossSpringSecurityLoginModule extends AbstractServerLoginModule {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.3</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.0</version>
|
||||
<version>2.0.3</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.0</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-resin</artifactId>
|
||||
<name>Spring Security - Resin adapter</name>
|
||||
|
||||
+28
-3
@@ -3,11 +3,11 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-cas-client</artifactId>
|
||||
<name>Spring Security - CAS support</name>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -31,7 +31,7 @@
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
@@ -39,4 +39,29 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version.osgi}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.beans.*;version="${spring.version.osgi}",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.jasig.cas.client.*;version="[3.1.3, 4.0.0)"
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.cas</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -15,6 +15,11 @@
|
||||
|
||||
package org.springframework.security.ui.cas;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
|
||||
@@ -24,6 +29,7 @@ import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
@@ -38,7 +44,11 @@ import javax.servlet.http.HttpServletRequest;
|
||||
* <p>The configured <code>AuthenticationManager</code> is expected to provide a provider that can recognise
|
||||
* <code>UsernamePasswordAuthenticationToken</code>s containing this special <code>principal</code> name, and process
|
||||
* them accordingly by validation with the CAS server.</p>
|
||||
* <p><b>Do not use this class directly.</b> Instead configure <code>web.xml</code> to use the {@link
|
||||
* <p>By configuring a shared {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the CasProcessingFilter
|
||||
* one can have the CasProcessingFilter handle the proxying requirements for CAS. In addition, the URI endpoint for the proxying
|
||||
* would also need to be configured (i.e. the part after protocol, hostname, and port).
|
||||
*
|
||||
* <p><b>Do not use this class directly.</b> Instead configure <code>web.xml</code> to use the {@link
|
||||
* org.springframework.security.util.FilterToBeanProxy}.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
@@ -57,8 +67,17 @@ public class CasProcessingFilter extends AbstractProcessingFilter {
|
||||
*/
|
||||
public static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
/**
|
||||
* The last portion of the receptor url, i.e. /proxy/receptor
|
||||
*/
|
||||
private String proxyReceptorUrl;
|
||||
|
||||
/**
|
||||
* The backing storage to store ProxyGrantingTicket requests.
|
||||
*/
|
||||
private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
public Authentication attemptAuthentication(final HttpServletRequest request)
|
||||
throws AuthenticationException {
|
||||
final String username = CAS_STATEFUL_IDENTIFIER;
|
||||
@@ -87,4 +106,35 @@ public class CasProcessingFilter extends AbstractProcessingFilter {
|
||||
public int getOrder() {
|
||||
return FilterChainOrder.CAS_PROCESSING_FILTER;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden to provide proxying capabilities.
|
||||
*/
|
||||
protected boolean requiresAuthentication(final HttpServletRequest request,
|
||||
final HttpServletResponse response) {
|
||||
final String requestUri = request.getRequestURI();
|
||||
|
||||
if (CommonUtils.isEmpty(this.proxyReceptorUrl) || !requestUri.endsWith(this.proxyReceptorUrl) || this.proxyGrantingTicketStorage == null) {
|
||||
return super.requiresAuthentication(request, response);
|
||||
}
|
||||
|
||||
try {
|
||||
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
|
||||
return false;
|
||||
} catch (final IOException e) {
|
||||
return super.requiresAuthentication(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||
this.proxyReceptorUrl = proxyReceptorUrl;
|
||||
}
|
||||
|
||||
public final void setProxyGrantingTicketStorage(
|
||||
final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
|
||||
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+8
-6
@@ -30,12 +30,14 @@ import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Used by the <code>SecurityEnforcementFilter</code> to commence authentication via the JA-SIG Central
|
||||
* Authentication Service (CAS).<P>The user's browser will be redirected to the JA-SIG CAS enterprise-wide login
|
||||
* page. This page is specified by the <code>loginUrl</code> property. Once login is complete, the CAS login page will
|
||||
* Used by the <code>ExceptionTranslationFilter</code> to commence authentication via the JA-SIG Central
|
||||
* Authentication Service (CAS).
|
||||
* <p>
|
||||
* The user's browser will be redirected to the JA-SIG CAS enterprise-wide login page.
|
||||
* This page is specified by the <code>loginUrl</code> property. Once login is complete, the CAS login page will
|
||||
* redirect to the page indicated by the <code>service</code> property. The <code>service</code> is a HTTP URL
|
||||
* belonging to the current application. The <code>service</code> URL is monitored by the {@link CasProcessingFilter},
|
||||
* which will validate the CAS login was successful.</p>
|
||||
* which will validate the CAS login was successful.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
@@ -65,8 +67,8 @@ public class CasProcessingFilterEntryPoint implements AuthenticationEntryPoint,
|
||||
}
|
||||
|
||||
public void commence(final ServletRequest servletRequest, final ServletResponse servletResponse,
|
||||
final AuthenticationException authenticationException)
|
||||
throws IOException, ServletException {
|
||||
final AuthenticationException authenticationException) throws IOException, ServletException {
|
||||
|
||||
final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
final String urlEncodedService = CommonUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null, "ticket", this.encodeServiceUrlWithSessionId);
|
||||
final String redirectUrl = CommonUtils.constructRedirectUrl(this.loginUrl, "service", urlEncodedService, this.serviceProperties.isSendRenew(), false);
|
||||
|
||||
@@ -21,9 +21,10 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Stores properties related to this CAS service.
|
||||
* <p>Each web application capable of processing CAS tickets is known as a service.
|
||||
* <p>
|
||||
* Each web application capable of processing CAS tickets is known as a service.
|
||||
* This class stores the properties that are relevant to the local CAS service, being the application
|
||||
* that is being secured by Spring Security.</p>
|
||||
* that is being secured by Spring Security.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -42,7 +43,8 @@ public class ServiceProperties implements InitializingBean {
|
||||
|
||||
/**
|
||||
* Represents the service the user is authenticating to.
|
||||
* <p>This service is the callback URL belonging to the local Spring Security System for Spring secured application.
|
||||
* <p>
|
||||
* This service is the callback URL belonging to the local Spring Security System for Spring secured application.
|
||||
* For example,
|
||||
* <pre>
|
||||
* https://www.mycompany.com/application/j_spring_cas_security_check
|
||||
@@ -56,10 +58,12 @@ public class ServiceProperties implements InitializingBean {
|
||||
|
||||
/**
|
||||
* Indicates whether the <code>renew</code> parameter should be sent to the CAS login URL and CAS
|
||||
* validation URL.<p>If <code>true</code>, it will force CAS to authenticate the user again (even if the
|
||||
* validation URL.
|
||||
* <p>
|
||||
* If <code>true</code>, it will force CAS to authenticate the user again (even if the
|
||||
* user has previously authenticated). During ticket validation it will require the ticket was generated as a
|
||||
* consequence of an explicit login. High security applications would probably set this to <code>true</code>.
|
||||
* Defaults to <code>false</code>, providing automated single sign on.</p>
|
||||
* Defaults to <code>false</code>, providing automated single sign on.
|
||||
*
|
||||
* @return whether to send the <code>renew</code> parameter to CAS
|
||||
*/
|
||||
|
||||
+30
-35
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core-tiger</artifactId>
|
||||
@@ -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.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
@@ -25,20 +32,6 @@
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-support</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
@@ -61,26 +54,6 @@
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>${felix.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.springframework.bundle.security.core.tiger</Bundle-SymbolicName>
|
||||
<Export-Package>org.springframework.security.*;version=${pom.version}</Export-Package>
|
||||
<Private-Package>!org.springframework.security.*</Private-Package>
|
||||
<Implementation-Title>${pom.name}</Implementation-Title>
|
||||
<Implementation-Version>${pom.version}</Implementation-Version>
|
||||
<Import-Package>
|
||||
org.springframework*;resolution:=optional;version="[2.0,2.6)",
|
||||
*;resolution:=optional
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
<excludeDependencies>true</excludeDependencies>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
@@ -94,4 +67,26 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
javax.annotation.*;version="[1.0.0, 2.0.0)",
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.core.*;version="${spring.version.osgi}"
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.include.res>
|
||||
src/main/resources
|
||||
</spring.osgi.include.res>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.annotation</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
+36
-2
@@ -1,8 +1,12 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
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;
|
||||
@@ -11,17 +15,17 @@ 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 GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private ClassPathXmlApplicationContext appContext;
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/global-method-security.xml");
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
@@ -37,11 +41,13 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
loadContext();
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@@ -51,10 +57,38 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
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'/>"
|
||||
);
|
||||
|
||||
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() {
|
||||
setContext(
|
||||
"<global-method-security />" +
|
||||
"<global-method-security />"
|
||||
);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Logging
|
||||
#
|
||||
# $Id: log4j.properties 2385 2007-12-20 20:53:26Z luke_t $
|
||||
|
||||
log4j.rootCategory=DEBUG, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
|
||||
|
||||
log4j.category.org.springframework.security=DEBUG
|
||||
|
||||
+53
-29
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
@@ -141,34 +141,58 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version}
|
||||
</spring.osgi.export>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>${felix.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.springframework.bundle.security.core</Bundle-SymbolicName>
|
||||
<Export-Package>org.springframework.security.*;version=${pom.version}</Export-Package>
|
||||
<Private-Package>!org.springframework.security.*</Private-Package>
|
||||
<Implementation-Title>${pom.name}</Implementation-Title>
|
||||
<Implementation-Version>${pom.version}</Implementation-Version>
|
||||
<Import-Package>
|
||||
org.springframework*;resolution:=optional;version="[2.0,2.6)",
|
||||
*;resolution:=optional
|
||||
</Import-Package>
|
||||
<!--
|
||||
<Embed-Dependency>
|
||||
*;scope=compile|runtime;inline=true
|
||||
</Embed-Dependency>
|
||||
-->
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<spring.osgi.import>
|
||||
!com.ibm.websphere.security,
|
||||
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.aopalliance.*;version="[1.0.0, 2.0.0)",
|
||||
org.apache.commons.codec.*;version="[1.3.0, 2.0.0)",
|
||||
org.apache.commons.collections.*;version="[3.2.0, 4.0.0)",
|
||||
org.apache.commons.lang.*;version="[2.1.0, 3.0.0)",
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.apache.directory.server.configuration.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.apache.directory.server.core.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.apache.directory.server.protocol.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional,
|
||||
org.jaxen.*;version="[1.1.1, 2.0.0)";resolution:=optional,
|
||||
org.springframework.aop.*;version="${spring.version.osgi}",
|
||||
org.springframework.beans.*;version="${spring.version.osgi}",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.core.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.ldap.*;version="[1.2.1.A, 2.0.0)";resolution:=optional,
|
||||
org.springframework.metadata.*;version="${spring.version.osgi}",
|
||||
org.springframework.mock.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.remoting.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
org.springframework.web.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
javax.crypto.*,
|
||||
javax.naming.*,
|
||||
javax.rmi.*,
|
||||
javax.security.*,
|
||||
javax.sql.*,
|
||||
javax.xml.parsers.*,
|
||||
org.w3c.dom.*,
|
||||
org.xml.sax.*,
|
||||
*;resolution:=optional
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
<!--
|
||||
<spring.osgi.include.res>
|
||||
src/main/resources
|
||||
</spring.osgi.include.res>
|
||||
-->
|
||||
<spring.osgi.symbolic.name>org.springframework.security.core</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -158,8 +158,7 @@ public class ConfigAttributeDefinition implements Serializable {
|
||||
* Allows <code>AccessDecisionManager</code>s and other classes to loop through every configuration attribute
|
||||
* associated with a target secure object.
|
||||
*
|
||||
* @return all the configuration attributes stored by the instance, or <code>null</code> if an
|
||||
* <code>Iterator</code> is unavailable
|
||||
* @return the configuration attributes stored in this instance.
|
||||
*/
|
||||
public Collection getConfigAttributes() {
|
||||
return this.configAttributes;
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ public class SimpleAttributes2GrantedAuthoritiesMapper implements Attributes2Gra
|
||||
return attributePrefix == null ? "" : attributePrefix;
|
||||
}
|
||||
|
||||
public void seAttributePrefix(String string) {
|
||||
public void setAttributePrefix(String string) {
|
||||
attributePrefix = string;
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -158,4 +158,8 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
|
||||
public void setSessionRegistry(SessionRegistry sessionRegistry) {
|
||||
this.sessionRegistry = sessionRegistry;
|
||||
}
|
||||
|
||||
public SessionRegistry getSessionRegistry() {
|
||||
return sessionRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -21,6 +21,7 @@ import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.security.ui.SpringSecurityFilter;
|
||||
import org.springframework.security.ui.logout.LogoutHandler;
|
||||
import org.springframework.security.ui.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -60,6 +61,7 @@ public class ConcurrentSessionFilter extends SpringSecurityFilter implements Ini
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(sessionRegistry, "SessionRegistry required");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(expiredUrl), expiredUrl + " isn't a valid redirect URL");
|
||||
}
|
||||
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
|
||||
+2
-2
@@ -23,12 +23,12 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
|
||||
/** UserDetailsService bean Id. For use in a stateful context (i.e. in AuthenticationProviderBDP) */
|
||||
private String id;
|
||||
|
||||
protected abstract Class getBeanClass(Element element);
|
||||
protected abstract String getBeanClassName(Element element);
|
||||
|
||||
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClass(element));
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClassName(element));
|
||||
|
||||
doParse(element, parserContext, builder);
|
||||
|
||||
|
||||
+2
@@ -3,6 +3,7 @@ package org.springframework.security.config;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -70,6 +71,7 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
|
||||
authMgrProviderList.add(provider);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filter, BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
|
||||
return null;
|
||||
|
||||
+23
-4
@@ -1,32 +1,51 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Just registers an alias name for the default ProviderManager used by the namespace
|
||||
* Registers an alias name for the default ProviderManager used by the namespace
|
||||
* configuration, allowing users to reference it in their beans and clearly see where the name is
|
||||
* coming from.
|
||||
* coming from. Also allows the ConcurrentSessionController to be set on the ProviderManager.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
private static final String ATT_SESSION_CONTROLLER_REF = "session-controller-ref";
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
String alias = element.getAttribute(ATT_ALIAS);
|
||||
|
||||
if (!StringUtils.hasText(alias)) {
|
||||
parserContext.getReaderContext().error(ATT_ALIAS + " is required.", element );
|
||||
}
|
||||
|
||||
String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
|
||||
|
||||
if (StringUtils.hasText(sessionControllerRef)) {
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
|
||||
BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController",
|
||||
new RuntimeBeanReference(sessionControllerRef));
|
||||
RootBeanDefinition sessionRegistryInjector = new RootBeanDefinition(SessionRegistryInjectionBeanPostProcessor.class);
|
||||
sessionRegistryInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
sessionRegistryInjector.getConstructorArgumentValues().addGenericArgumentValue(sessionControllerRef);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_REGISTRY_INJECTION_POST_PROCESSOR, sessionRegistryInjector);
|
||||
}
|
||||
|
||||
parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -41,6 +41,7 @@ public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionPa
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER,
|
||||
filterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(),
|
||||
BeanIds.BASIC_AUTHENTICATION_FILTER));
|
||||
return null;
|
||||
|
||||
@@ -16,8 +16,11 @@ public abstract class BeanIds {
|
||||
/** Package protected as end users shouldn't really be using this BFPP directly */
|
||||
static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
|
||||
static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
|
||||
static final String HTTP_POST_PROCESSOR = "_httpConfigBeanFactoryPostProcessor";
|
||||
static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
|
||||
static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor";
|
||||
static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor";
|
||||
static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
|
||||
static final String FILTER_LIST = "_filterChainList";
|
||||
|
||||
public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
|
||||
public static final String USER_DETAILS_SERVICE = "_userDetailsService";
|
||||
@@ -30,6 +33,7 @@ public abstract class BeanIds {
|
||||
public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
|
||||
public static final String ACCESS_MANAGER = "_accessManager";
|
||||
public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
|
||||
public static final String AFTER_INVOCATION_MANAGER = "_afterInvocationManager";
|
||||
public static final String FORM_LOGIN_FILTER = "_formLoginFilter";
|
||||
public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint";
|
||||
public static final String OPEN_ID_FILTER = "_openIDFilter";
|
||||
@@ -49,6 +53,7 @@ public abstract class BeanIds {
|
||||
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
||||
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
||||
public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
|
||||
public static final String METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR = "_methodSecurityInterceptorPostProcessor";
|
||||
public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
|
||||
public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
|
||||
public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
|
||||
@@ -58,7 +63,8 @@ public abstract class BeanIds {
|
||||
public static final String CONTEXT_SOURCE = "_securityContextSource";
|
||||
public static final String PORT_MAPPER = "_portMapper";
|
||||
public static final String X509_FILTER = "_x509ProcessingFilter";
|
||||
public static final String X509_AUTH_PROVIDER = "_x509AuthenitcationProvider";
|
||||
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";
|
||||
|
||||
}
|
||||
|
||||
+31
-20
@@ -29,7 +29,8 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
|
||||
static final String ATT_EXPIRY_URL = "expired-url";
|
||||
static final String ATT_MAX_SESSIONS = "max-sessions";
|
||||
static final String ATT_EXCEPTION_IF_MAX_EXCEEDED = "exception-if-maximum-exceeded";
|
||||
static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
|
||||
static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
|
||||
static final String ATT_SESSION_REGISTRY_REF = "session-registry-ref";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
CompositeComponentDefinition compositeDef =
|
||||
@@ -38,25 +39,43 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
|
||||
|
||||
BeanDefinitionRegistry beanRegistry = parserContext.getRegistry();
|
||||
|
||||
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
|
||||
String sessionRegistryId = element.getAttribute(ATT_SESSION_REGISTRY_REF);
|
||||
|
||||
if (!StringUtils.hasText(sessionRegistryId)) {
|
||||
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
|
||||
beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(sessionRegistry, BeanIds.SESSION_REGISTRY));
|
||||
sessionRegistryId = BeanIds.SESSION_REGISTRY;
|
||||
} else {
|
||||
// Register the default ID as an alias so that things like session fixation filter can access it
|
||||
beanRegistry.registerAlias(sessionRegistryId, BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
|
||||
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
|
||||
if (StringUtils.hasText(registryAlias)) {
|
||||
beanRegistry.registerAlias(sessionRegistryId, registryAlias);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class);
|
||||
BeanDefinitionBuilder controllerBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
|
||||
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
|
||||
filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
|
||||
filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
|
||||
|
||||
Object source = parserContext.extractSource(element);
|
||||
filterBuilder.setSource(source);
|
||||
filterBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
controllerBuilder.setSource(source);
|
||||
controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
|
||||
String expiryUrl = element.getAttribute(ATT_EXPIRY_URL);
|
||||
|
||||
if (StringUtils.hasText(expiryUrl)) {
|
||||
ConfigUtils.validateHttpRedirect(expiryUrl, parserContext, source);
|
||||
filterBuilder.addPropertyValue("expiredUrl", expiryUrl);
|
||||
}
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder controllerBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
|
||||
controllerBuilder.setSource(source);
|
||||
controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
|
||||
|
||||
String maxSessions = element.getAttribute(ATT_MAX_SESSIONS);
|
||||
|
||||
@@ -71,22 +90,14 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
|
||||
}
|
||||
|
||||
BeanDefinition controller = controllerBuilder.getBeanDefinition();
|
||||
beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(sessionRegistry, BeanIds.SESSION_REGISTRY));
|
||||
|
||||
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
|
||||
if (StringUtils.hasText(registryAlias)) {
|
||||
beanRegistry.registerAlias(BeanIds.SESSION_REGISTRY, registryAlias);
|
||||
}
|
||||
|
||||
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_CONTROLLER, controller);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER));
|
||||
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, filterBuilder.getBeanDefinition());
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER));
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
|
||||
|
||||
BeanDefinition providerManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
providerManager.getPropertyValues().addPropertyValue("sessionController", controller);
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
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;
|
||||
@@ -11,13 +15,15 @@ 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.AuthenticationManager;
|
||||
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;
|
||||
import org.springframework.security.vote.RoleVoter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Utility methods used internally by the Spring Security namespace configuration code.
|
||||
@@ -86,45 +92,95 @@ public abstract class ConfigUtils {
|
||||
return authManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static RuntimeBeanReference getUserDetailsService(ConfigurableListableBeanFactory bf) {
|
||||
String[] services = bf.getBeanNamesForType(CachingUserDetailsService.class, false, false);
|
||||
|
||||
if (services.length == 0) {
|
||||
services = bf.getBeanNamesForType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
if (services.length == 0) {
|
||||
throw new IllegalArgumentException("No UserDetailsService registered.");
|
||||
|
||||
} else if (services.length > 1) {
|
||||
throw new IllegalArgumentException("More than one UserDetailsService registered. Please" +
|
||||
"use a specific Id in your configuration");
|
||||
}
|
||||
|
||||
return new RuntimeBeanReference(services[0]);
|
||||
}
|
||||
|
||||
private static AuthenticationManager getAuthenticationManager(ConfigurableListableBeanFactory bf) {
|
||||
Map authManagers = bf.getBeansOfType(AuthenticationManager.class);
|
||||
|
||||
if (authManagers.size() == 0) {
|
||||
throw new IllegalArgumentException("No AuthenticationManager registered. " +
|
||||
"Make sure you have configured at least one AuthenticationProvider?");
|
||||
|
||||
} else if (authManagers.size() > 1) {
|
||||
throw new IllegalArgumentException("More than one AuthenticationManager registered.");
|
||||
}
|
||||
|
||||
return (AuthenticationManager) authManagers.values().toArray()[0];
|
||||
}
|
||||
|
||||
static ManagedList getRegisteredProviders(ParserContext parserContext) {
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext);
|
||||
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
}
|
||||
|
||||
static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
|
||||
BeanDefinition manager = registerAfterInvocationProviderManagerIfNecessary(parserContext);
|
||||
return (ManagedList) manager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
}
|
||||
|
||||
private static BeanDefinition registerAfterInvocationProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||
return parserContext.getRegistry().getBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER);
|
||||
}
|
||||
|
||||
BeanDefinition manager = new RootBeanDefinition(AfterInvocationProviderManager.class);
|
||||
manager.getPropertyValues().addPropertyValue("providers", new ManagedList());
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER, manager);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
|
||||
return;
|
||||
}
|
||||
// Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
|
||||
RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
|
||||
filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
|
||||
RootBeanDefinition filterList = new RootBeanDefinition(FilterChainList.class);
|
||||
filterList.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_LIST, filterList);
|
||||
}
|
||||
|
||||
static void addHttpFilter(ParserContext pc, BeanMetadataElement filter) {
|
||||
registerFilterChainPostProcessorIfNecessary(pc);
|
||||
|
||||
RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
|
||||
|
||||
ManagedList filters;
|
||||
MutablePropertyValues pvs = filterList.getPropertyValues();
|
||||
if (pvs.contains("filters")) {
|
||||
filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
|
||||
} else {
|
||||
filters = new ManagedList();
|
||||
pvs.addPropertyValue("filters", filters);
|
||||
}
|
||||
|
||||
filters.add(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which holds the list of filters which are maintained in the context and modified by calls to
|
||||
* addHttpFilter. The post processor retrieves these before injecting the list into the FilterChainProxy.
|
||||
*/
|
||||
public static class FilterChainList {
|
||||
List filters;
|
||||
|
||||
public List getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public void setFilters(List filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the value of an XML attribute which represents a redirect URL.
|
||||
* If not empty or starting with "$" (potential placeholder), "/" or "http" it will raise an error.
|
||||
*/
|
||||
static void validateHttpRedirect(String url, ParserContext pc, Object source) {
|
||||
if (UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
|
||||
return;
|
||||
}
|
||||
pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
|
||||
}
|
||||
|
||||
static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(pc);
|
||||
PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
|
||||
|
||||
if (pv != null && pv.getValue() != null) {
|
||||
pc.getReaderContext().error("A session controller has already been set on the authentication manager. " +
|
||||
"The <concurrent-session-control> element isn't compatible with a custom session controller",
|
||||
pc.extractSource(sourceElt));
|
||||
}
|
||||
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName));
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Adds the decorated {@link org.springframework.security.afterinvocation.AfterInvocationProvider} to the
|
||||
* AfterInvocationProviderManager's list.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class CustomAfterInvocationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(holder.getBeanDefinition());
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -3,6 +3,7 @@ package org.springframework.security.config;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
@@ -16,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(holder.getBeanDefinition());
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(holder.getBeanName()));
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ abstract class Elements {
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
|
||||
public static final String INTERCEPT_METHODS = "intercept-methods";
|
||||
public static final String INTERCEPT_URL = "intercept-url";
|
||||
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
|
||||
public static final String HTTP = "http";
|
||||
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
|
||||
@@ -35,6 +36,7 @@ abstract class Elements {
|
||||
public static final String PORT_MAPPING = "port-mapping";
|
||||
public static final String CUSTOM_FILTER = "custom-filter";
|
||||
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
|
||||
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||
public static final String X509 = "x509";
|
||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
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.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class EntryPointInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (!BeanIds.EXCEPTION_TRANSLATION_FILTER.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
|
||||
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
|
||||
Object entryPoint = null;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) {
|
||||
entryPoint = beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT);
|
||||
logger.info("Using main configured AuthenticationEntryPoint.");
|
||||
} else {
|
||||
Map entryPoints = beanFactory.getBeansOfType(AuthenticationEntryPoint.class);
|
||||
Assert.isTrue(entryPoints.size() != 0, "No AuthenticationEntryPoint instances defined");
|
||||
Assert.isTrue(entryPoints.size() == 1, "More than one AuthenticationEntryPoint defined in context");
|
||||
entryPoint = entryPoints.values().toArray()[0];
|
||||
}
|
||||
|
||||
logger.info("Using bean '" + entryPoint + "' as the entry point.");
|
||||
etf.setAuthenticationEntryPoint((AuthenticationEntryPoint) entryPoint);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
+151
-48
@@ -2,7 +2,6 @@ package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -17,8 +16,21 @@ import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.config.ConfigUtils.FilterChainList;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.providers.anonymous.AnonymousProcessingFilter;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -29,70 +41,161 @@ import org.springframework.util.Assert;
|
||||
public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(!beanName.equals(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||
if(!BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) bean;
|
||||
// Set the default match
|
||||
List defaultFilterChain = orderFilters(beanFactory);
|
||||
FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST);
|
||||
|
||||
List filters = new ArrayList(filterList.getFilters());
|
||||
Collections.sort(filters, new OrderComparator());
|
||||
|
||||
logger.info("Checking sorted filter chain: " + filters);
|
||||
|
||||
for(int i=0; i < filters.size(); i++) {
|
||||
Ordered filter = (Ordered)filters.get(i);
|
||||
|
||||
if (i > 0) {
|
||||
Ordered previous = (Ordered)filters.get(i-1);
|
||||
if (filter.getOrder() == previous.getOrder()) {
|
||||
throw new SecurityConfigurationException("Filters '" + unwrapFilter(filter) + "' and '" +
|
||||
unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " +
|
||||
"please make sure the positions do not conflict with default filters. " +
|
||||
"Alternatively you can disable the default filters by removing the corresponding " +
|
||||
"child elements from <http> and avoiding the use of <http auto-config='true'>.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Filter chain...");
|
||||
for (int i=0; i < filters.size(); i++) {
|
||||
// Remove the ordered wrapper from the filter and put it back in the chain at the same position.
|
||||
Filter filter = unwrapFilter(filters.get(i));
|
||||
logger.info("[" + i + "] - " + filter);
|
||||
filters.set(i, filter);
|
||||
}
|
||||
|
||||
checkFilterStack(filters);
|
||||
|
||||
// Note that this returns a copy
|
||||
Map filterMap = filterChainProxy.getFilterChainMap();
|
||||
String allUrlsMatch = filterChainProxy.getMatcher().getUniversalMatchPattern();
|
||||
|
||||
filterMap.put(allUrlsMatch, defaultFilterChain);
|
||||
filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters);
|
||||
filterChainProxy.setFilterChainMap(filterMap);
|
||||
|
||||
logger.info("Configured filter chain(s): " + filterChainProxy);
|
||||
|
||||
checkLoginPageIsntProtected(filterChainProxy);
|
||||
|
||||
logger.info("FilterChainProxy: " + filterChainProxy);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private List orderFilters(ListableBeanFactory beanFactory) {
|
||||
Map filters = beanFactory.getBeansOfType(Filter.class);
|
||||
|
||||
Assert.notEmpty(filters, "No filters found in app context!");
|
||||
|
||||
Iterator ids = filters.keySet().iterator();
|
||||
|
||||
List orderedFilters = new ArrayList();
|
||||
|
||||
while (ids.hasNext()) {
|
||||
String id = (String) ids.next();
|
||||
Filter filter = (Filter) filters.get(id);
|
||||
|
||||
if (filter instanceof FilterChainProxy) {
|
||||
continue;
|
||||
|
||||
/**
|
||||
* Checks the filter list for possible errors and logs them
|
||||
*/
|
||||
private void checkFilterStack(List filters) {
|
||||
checkForDuplicates(HttpSessionContextIntegrationFilter.class, filters);
|
||||
checkForDuplicates(AuthenticationProcessingFilter.class, filters);
|
||||
checkForDuplicates(SessionFixationProtectionFilter.class, filters);
|
||||
checkForDuplicates(BasicProcessingFilter.class, filters);
|
||||
checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);
|
||||
checkForDuplicates(ExceptionTranslationFilter.class, filters);
|
||||
checkForDuplicates(FilterSecurityInterceptor.class, filters);
|
||||
}
|
||||
|
||||
private void checkForDuplicates(Class clazz, List filters) {
|
||||
for (int i=0; i < filters.size(); i++) {
|
||||
Filter f1 = (Filter)filters.get(i);
|
||||
if (clazz.isAssignableFrom(f1.getClass())) {
|
||||
// Found the first one, check remaining for another
|
||||
for (int j=i+1; j < filters.size(); j++) {
|
||||
Filter f2 = (Filter)filters.get(j);
|
||||
if (clazz.isAssignableFrom(f2.getClass())) {
|
||||
logger.warn("Possible error: Filters at position " + i + " and " + j + " are both " +
|
||||
"instances of " + clazz.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filters must be Spring security filters or wrapped using <custom-filter>
|
||||
if (!filter.getClass().getName().startsWith("org.springframework.security")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(filter instanceof Ordered)) {
|
||||
logger.info("Filter " + id + " doesn't implement the Ordered interface, skipping it.");
|
||||
continue;
|
||||
}
|
||||
|
||||
orderedFilters.add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks for the common error of having a login page URL protected by the security interceptor */
|
||||
private void checkLoginPageIsntProtected(FilterChainProxy fcp) {
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
|
||||
if (etf.getAuthenticationEntryPoint() instanceof AuthenticationProcessingFilterEntryPoint) {
|
||||
String loginPage =
|
||||
((AuthenticationProcessingFilterEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
|
||||
List filters = fcp.getFilters(loginPage);
|
||||
logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
|
||||
|
||||
if (filters == null || filters.isEmpty()) {
|
||||
logger.debug("Filter chain is empty for the login page");
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginPage.equals(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL) &&
|
||||
beanFactory.containsBean(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)) {
|
||||
logger.debug("Default generated login page is in use");
|
||||
return;
|
||||
}
|
||||
|
||||
FilterSecurityInterceptor fsi =
|
||||
((FilterSecurityInterceptor)beanFactory.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR));
|
||||
DefaultFilterInvocationDefinitionSource fids =
|
||||
(DefaultFilterInvocationDefinitionSource) fsi.getObjectDefinitionSource();
|
||||
ConfigAttributeDefinition cad = fids.lookupAttributes(loginPage, "POST");
|
||||
|
||||
if (cad == null) {
|
||||
logger.debug("No access attributes defined for login page URL");
|
||||
if (fsi.isRejectPublicInvocations()) {
|
||||
logger.warn("FilterSecurityInterceptor is configured to reject public invocations." +
|
||||
" Your login page may not be accessible.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Collections.sort(orderedFilters, new OrderComparator());
|
||||
|
||||
return orderedFilters;
|
||||
}
|
||||
if (!beanFactory.containsBean(BeanIds.ANONYMOUS_PROCESSING_FILTER)) {
|
||||
logger.warn("The login page is being protected by the filter chain, but you don't appear to have" +
|
||||
" anonymous authentication enabled. This is almost certainly an error.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate an anonymous access with the supplied attributes.
|
||||
AnonymousProcessingFilter anonPF = (AnonymousProcessingFilter) beanFactory.getBean(BeanIds.ANONYMOUS_PROCESSING_FILTER);
|
||||
AnonymousAuthenticationToken token =
|
||||
new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
|
||||
anonPF.getUserAttribute().getAuthorities());
|
||||
try {
|
||||
fsi.getAccessDecisionManager().decide(token, new Object(), cad);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " +
|
||||
"an error. Please check your configuration allows unauthenticated access to the configured " +
|
||||
"login page. (Simulated access was rejected: " + e + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delegate filter of a wrapper, or the unchanged filter if it isn't wrapped.
|
||||
*/
|
||||
private Filter unwrapFilter(Object filter) {
|
||||
if (filter instanceof OrderedFilterBeanDefinitionDecorator.OrderedFilterDecorator) {
|
||||
return ((OrderedFilterBeanDefinitionDecorator.OrderedFilterDecorator)filter).getDelegate();
|
||||
}
|
||||
|
||||
return (Filter) filter;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -44,8 +44,8 @@ public class FilterInvocationDefinitionSourceBeanDefinitionParser extends Abstra
|
||||
UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(element);
|
||||
boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
LinkedHashMap requestMap = new LinkedHashMap();
|
||||
HttpSecurityBeanDefinitionParser.parseInterceptUrlsForFilterInvocationRequestMap(interceptUrls, requestMap,
|
||||
LinkedHashMap requestMap =
|
||||
HttpSecurityBeanDefinitionParser.parseInterceptUrlsForFilterInvocationRequestMap(interceptUrls,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
builder.addConstructorArg(matcher);
|
||||
|
||||
+32
-4
@@ -1,5 +1,6 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
@@ -46,7 +47,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
||||
this.filterClassName = filterClassName;
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
public BeanDefinition parse(Element elt, ParserContext pc) {
|
||||
String loginUrl = null;
|
||||
String defaultTargetUrl = null;
|
||||
String authenticationFailureUrl = null;
|
||||
@@ -54,30 +55,57 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
Object source = null;
|
||||
|
||||
// Copy values from the session fixation protection filter
|
||||
final Boolean sessionFixationProtectionEnabled =
|
||||
new Boolean(pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
|
||||
Boolean migrateSessionAttributes = Boolean.FALSE;
|
||||
|
||||
if (sessionFixationProtectionEnabled.booleanValue()) {
|
||||
PropertyValue pv =
|
||||
pc.getRegistry().getBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)
|
||||
.getPropertyValues().getPropertyValue("migrateSessionAttributes");
|
||||
migrateSessionAttributes = (Boolean)pv.getValue();
|
||||
}
|
||||
|
||||
if (elt != null) {
|
||||
source = pc.extractSource(elt);
|
||||
loginUrl = elt.getAttribute(ATT_LOGIN_URL);
|
||||
ConfigUtils.validateHttpRedirect(loginUrl, pc, source);
|
||||
defaultTargetUrl = elt.getAttribute(ATT_FORM_LOGIN_TARGET_URL);
|
||||
ConfigUtils.validateHttpRedirect(defaultTargetUrl, pc, source);
|
||||
authenticationFailureUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL);
|
||||
ConfigUtils.validateHttpRedirect(authenticationFailureUrl, pc, source);
|
||||
alwaysUseDefault = elt.getAttribute(ATT_ALWAYS_USE_DEFAULT_TARGET_URL);
|
||||
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
|
||||
|
||||
if (!StringUtils.hasText(loginPage)) {
|
||||
loginPage = null;
|
||||
}
|
||||
source = parserContext.extractSource(elt);
|
||||
ConfigUtils.validateHttpRedirect(loginPage, pc, source);
|
||||
|
||||
}
|
||||
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
|
||||
filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl);
|
||||
filterBean.setSource(source);
|
||||
filterBean.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication",
|
||||
sessionFixationProtectionEnabled);
|
||||
filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes",
|
||||
migrateSessionAttributes);
|
||||
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES) );
|
||||
}
|
||||
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_REGISTRY)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("sessionRegistry",
|
||||
new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder entryPointBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class);
|
||||
|
||||
+104
-67
@@ -20,7 +20,6 @@ import org.springframework.security.intercept.method.MapBasedMethodDefinitionSou
|
||||
import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@@ -48,67 +47,26 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
parserContext.getReaderContext().error("Cannot locate '" + className + "'", element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
|
||||
// Check the required classes are present
|
||||
if (useSecured) {
|
||||
validatePresent(SECURED_METHOD_DEFINITION_SOURCE_CLASS, element, parserContext);
|
||||
validatePresent(SECURED_DEPENDENCY_CLASS, element, parserContext);
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
validatePresent(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS, element, parserContext);
|
||||
validatePresent(JSR_250_VOTER_CLASS, element, parserContext);
|
||||
}
|
||||
|
||||
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
|
||||
Map pointcutMap = new LinkedHashMap();
|
||||
List protect = DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT);
|
||||
|
||||
for (Iterator i = protect.iterator(); i.hasNext();) {
|
||||
Element childElt = (Element) i.next();
|
||||
String accessConfig = childElt.getAttribute(ATT_ACCESS);
|
||||
String expression = childElt.getAttribute(ATT_EXPRESSION);
|
||||
Assert.hasText(accessConfig, "Access configuration required for '" + childElt + "'");
|
||||
Assert.hasText(expression, "Expression required for '" + childElt + "'");
|
||||
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition(StringUtils.commaDelimitedListToStringArray(accessConfig));
|
||||
pointcutMap.put(expression, def);
|
||||
}
|
||||
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
|
||||
|
||||
// Now create and populate our ProtectPointcutBeanPostProcessor, if needed
|
||||
if (pointcutMap.size() > 0) {
|
||||
RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
|
||||
ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
ppbp.setSource(parserContext.extractSource(element));
|
||||
ppbp.getConstructorArgumentValues().addGenericArgumentValue(mapBasedMethodDefinitionSource);
|
||||
ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.PROTECT_POINTCUT_POST_PROCESSOR, ppbp);
|
||||
}
|
||||
|
||||
// Create our list of method metadata delegates
|
||||
Object source = parserContext.extractSource(element);
|
||||
// The list of method metadata delegates
|
||||
ManagedList delegates = new ManagedList();
|
||||
|
||||
boolean jsr250Enabled = registerAnnotationBasedMethodDefinitionSources(element, parserContext, delegates);
|
||||
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
|
||||
delegates.add(mapBasedMethodDefinitionSource);
|
||||
|
||||
if (useSecured) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
|
||||
Map pointcutMap = parseProtectPointcuts(parserContext,
|
||||
DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT));
|
||||
|
||||
if (pointcutMap.size() > 0) {
|
||||
registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodDefinitionSource, source);
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
// Register our DelegatingMethodDefinitionSource
|
||||
RootBeanDefinition delegatingMethodDefinitionSource = new RootBeanDefinition(DelegatingMethodDefinitionSource.class);
|
||||
delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
delegatingMethodDefinitionSource.setSource(parserContext.extractSource(element));
|
||||
delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
|
||||
registerDelegatingMethodDefinitionSource(parserContext, delegates, source);
|
||||
|
||||
// Register the applicable AccessDecisionManager, handling the special JSR 250 voter if being used
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
@@ -116,17 +74,94 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
|
||||
if (useJsr250) {
|
||||
if (jsr250Enabled) {
|
||||
ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
|
||||
}
|
||||
|
||||
accessManagerId = BeanIds.ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
|
||||
|
||||
registerAdvisor(parserContext, source);
|
||||
|
||||
// MethodSecurityInterceptor
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether JSR-250 and/or Secured annotations are enabled and adds the appropriate
|
||||
* MethodDefinitionSource delegates if required.
|
||||
*/
|
||||
private boolean registerAnnotationBasedMethodDefinitionSources(Element element, ParserContext pc, ManagedList delegates) {
|
||||
boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
|
||||
// Check the required classes are present
|
||||
if (useSecured) {
|
||||
validatePresent(SECURED_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
|
||||
validatePresent(SECURED_DEPENDENCY_CLASS, element, pc);
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
validatePresent(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
|
||||
validatePresent(JSR_250_VOTER_CLASS, element, pc);
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
return useJsr250;
|
||||
}
|
||||
|
||||
private void registerDelegatingMethodDefinitionSource(ParserContext parserContext, ManagedList delegates, Object source) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE)) {
|
||||
parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
|
||||
}
|
||||
RootBeanDefinition delegatingMethodDefinitionSource = new RootBeanDefinition(DelegatingMethodDefinitionSource.class);
|
||||
delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
delegatingMethodDefinitionSource.setSource(source);
|
||||
delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
|
||||
}
|
||||
|
||||
private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map pointcutMap,
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource, Object source) {
|
||||
RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
|
||||
ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
ppbp.setSource(source);
|
||||
ppbp.getConstructorArgumentValues().addGenericArgumentValue(mapBasedMethodDefinitionSource);
|
||||
ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.PROTECT_POINTCUT_POST_PROCESSOR, ppbp);
|
||||
}
|
||||
|
||||
private Map parseProtectPointcuts(ParserContext parserContext, List protectPointcutElts) {
|
||||
Map pointcutMap = new LinkedHashMap();
|
||||
|
||||
for (Iterator i = protectPointcutElts.iterator(); i.hasNext();) {
|
||||
Element childElt = (Element) i.next();
|
||||
String accessConfig = childElt.getAttribute(ATT_ACCESS);
|
||||
String expression = childElt.getAttribute(ATT_EXPRESSION);
|
||||
|
||||
if (!StringUtils.hasText(accessConfig)) {
|
||||
parserContext.getReaderContext().error("Access configuration required", parserContext.extractSource(childElt));
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(expression)) {
|
||||
parserContext.getReaderContext().error("Pointcut expression required", parserContext.extractSource(childElt));
|
||||
}
|
||||
|
||||
ConfigAttributeDefinition def = new ConfigAttributeDefinition(StringUtils.commaDelimitedListToStringArray(accessConfig));
|
||||
pointcutMap.put(expression, def);
|
||||
}
|
||||
|
||||
return pointcutMap;
|
||||
}
|
||||
|
||||
private void registerMethodSecurityInterceptor(ParserContext parserContext, String accessManagerId, Object source) {
|
||||
RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
|
||||
interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
interceptor.setSource(parserContext.extractSource(element));
|
||||
interceptor.setSource(source);
|
||||
|
||||
interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
|
||||
interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
@@ -134,15 +169,17 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
|
||||
|
||||
// MethodDefinitionSourceAdvisor
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
|
||||
new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
|
||||
}
|
||||
|
||||
private void registerAdvisor(ParserContext parserContext, Object source) {
|
||||
RootBeanDefinition advisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class);
|
||||
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisor.setSource(parserContext.extractSource(element));
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(interceptor);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||
advisor.setSource(source);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(BeanIds.METHOD_SECURITY_INTERCEPTOR);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
return null;
|
||||
}
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||
}
|
||||
}
|
||||
|
||||
+228
-170
@@ -97,154 +97,57 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
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";
|
||||
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
|
||||
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
|
||||
|
||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
|
||||
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
|
||||
|
||||
RuntimeBeanReference portMapperRef = new RuntimeBeanReference(BeanIds.PORT_MAPPER);
|
||||
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.FALSE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
} else {
|
||||
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterSecurityInterceptorBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
final BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
final UrlMatcher matcher = createUrlMatcher(element);
|
||||
final Object source = parserContext.extractSource(element);
|
||||
// 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();
|
||||
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
accessDeniedHandler.setErrorPage(accessDeniedPage);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
|
||||
}
|
||||
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,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
Map filterChainMap = new LinkedHashMap();
|
||||
boolean allowSessionCreation = registerHttpSessionIntegrationFilter(element, parserContext);
|
||||
|
||||
UrlMatcher matcher = createUrlMatcher(element);
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
|
||||
// Add servlet-api integration filter if required
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
provideServletApi = DEF_SERVLET_API_PROVISION;
|
||||
}
|
||||
|
||||
if ("true".equals(provideServletApi)) {
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
|
||||
new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class));
|
||||
}
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
|
||||
|
||||
// Set up the access manager and authentication manager references for http
|
||||
registerServletApiFilter(element, parserContext);
|
||||
|
||||
// Set up the access manager reference for http
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
accessManagerId = BeanIds.ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("accessDecisionManager",
|
||||
new RuntimeBeanReference(accessManagerId));
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("authenticationManager",
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext));
|
||||
|
||||
if ("true".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) {
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("observeOncePerRequest", Boolean.TRUE);
|
||||
}
|
||||
// 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);
|
||||
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
|
||||
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
LinkedHashMap channelRequestMap = new LinkedHashMap();
|
||||
LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap();
|
||||
|
||||
List interceptUrlElts = DomUtils.getChildElementsByTagName(element, "intercept-url");
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, filterInvocationDefinitionMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
registerExceptionTranslationFilter(element, parserContext, allowSessionCreation);
|
||||
|
||||
DefaultFilterInvocationDefinitionSource interceptorFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap);
|
||||
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap);
|
||||
|
||||
filterSecurityInterceptorBuilder.addPropertyValue("objectDefinitionSource", interceptorFilterInvDefSource);
|
||||
|
||||
|
||||
// Check if we need to register the channel processing beans
|
||||
if (channelRequestMap.size() > 0) {
|
||||
// At least one channel requirement has been specified
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
|
||||
new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
ManagedList channelProcessors = new ManagedList(3);
|
||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapperRef);
|
||||
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapperRef);
|
||||
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
||||
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
||||
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
||||
channelProcessors.add(secureChannelProcessor);
|
||||
channelProcessors.add(inSecureChannelProcessor);
|
||||
channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
|
||||
|
||||
registry.registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
|
||||
registry.registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
|
||||
}
|
||||
|
||||
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
|
||||
if (sessionControlElt != null) {
|
||||
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
|
||||
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
}
|
||||
|
||||
String sessionFixationAttribute = element.getAttribute(ATT_SESSION_FIXATION_PROTECTION);
|
||||
|
||||
if(!StringUtils.hasText(sessionFixationAttribute)) {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
}
|
||||
|
||||
if (!sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION)) {
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionFilter.class);
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
|
||||
if (sessionControlElt != null) {
|
||||
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
sessionFixationFilter.getBeanDefinition());
|
||||
registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
|
||||
}
|
||||
|
||||
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext));
|
||||
|
||||
boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
|
||||
|
||||
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
|
||||
sessionControlEnabled);
|
||||
|
||||
boolean autoConfig = false;
|
||||
if ("true".equals(element.getAttribute(ATT_AUTO_CONFIG))) {
|
||||
@@ -271,33 +174,176 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
new LogoutBeanDefinitionParser().parse(logoutElt, parserContext);
|
||||
}
|
||||
|
||||
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig);
|
||||
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig, allowSessionCreation);
|
||||
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509);
|
||||
if (x509Elt != null) {
|
||||
new X509BeanDefinitionParser().parse(x509Elt, parserContext);
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
|
||||
registry.registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
registry.registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
|
||||
registry.registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
|
||||
registry.registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, filterSecurityInterceptorBuilder.getBeanDefinition());
|
||||
|
||||
// Register the post processor which will tie up the loose ends in the configuration once the app context has been created and all beans are available.
|
||||
RootBeanDefinition postProcessor = new RootBeanDefinition(HttpSecurityConfigPostProcessor.class);
|
||||
// Register the post processors which will tie up the loose ends in the configuration once the app context has been created and all beans are available.
|
||||
RootBeanDefinition postProcessor = new RootBeanDefinition(EntryPointInjectionBeanPostProcessor.class);
|
||||
postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.HTTP_POST_PROCESSOR, postProcessor);
|
||||
|
||||
// Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
|
||||
RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
|
||||
filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
|
||||
registry.registerBeanDefinition(BeanIds.ENTRY_POINT_INJECTION_POST_PROCESSOR, postProcessor);
|
||||
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 parseBasicFormLoginAndOpenID(Element element, ParserContext parserContext, boolean autoConfig) {
|
||||
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("filterChainMap", filterChainMap);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
|
||||
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);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.FALSE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
sessionCreationAllowed = false;
|
||||
} else {
|
||||
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
|
||||
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
|
||||
private void registerServletApiFilter(Element element, ParserContext pc) {
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
provideServletApi = DEF_SERVLET_API_PROVISION;
|
||||
}
|
||||
|
||||
if ("true".equals(provideServletApi)) {
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
|
||||
new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class));
|
||||
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);
|
||||
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));
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", new Boolean(allowSessionCreation));
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
accessDeniedHandler.setErrorPage(accessDeniedPage);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
|
||||
}
|
||||
|
||||
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 =
|
||||
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",
|
||||
new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
|
||||
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap);
|
||||
channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
ManagedList channelProcessors = new ManagedList(3);
|
||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||
RuntimeBeanReference portMapper = new RuntimeBeanReference(BeanIds.PORT_MAPPER);
|
||||
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
||||
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
||||
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
||||
channelProcessors.add(secureChannelProcessor);
|
||||
channelProcessors.add(inSecureChannelProcessor);
|
||||
channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
|
||||
|
||||
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.rootBeanDefinition(SessionFixationProtectionFilter.class);
|
||||
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,
|
||||
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;
|
||||
@@ -308,12 +354,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String realm = element.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
}
|
||||
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext);
|
||||
}
|
||||
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
|
||||
}
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
|
||||
|
||||
@@ -321,7 +367,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(formLoginElt, parserContext);
|
||||
parser.parse(formLoginElt, pc);
|
||||
formLoginFilter = parser.getFilterBean();
|
||||
formLoginEntryPoint = parser.getEntryPointBean();
|
||||
formLoginPage = parser.getLoginPage();
|
||||
@@ -333,7 +379,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(openIDLoginElt, parserContext);
|
||||
parser.parse(openIDLoginElt, pc);
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
openIDLoginPage = parser.getLoginPage();
|
||||
@@ -348,23 +394,26 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(openIDProvider);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
|
||||
ConfigUtils.getRegisteredProviders(pc).add(new RuntimeBeanReference(BeanIds.OPEN_ID_PROVIDER));
|
||||
}
|
||||
|
||||
boolean needLoginPage = false;
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
needLoginPage = true;
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
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;
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
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.
|
||||
@@ -382,8 +431,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
}
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_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.
|
||||
@@ -391,33 +441,39 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
|
||||
|
||||
if (StringUtils.hasText(customEntryPoint)) {
|
||||
parserContext.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
|
||||
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) {
|
||||
parserContext.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
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) {
|
||||
parserContext.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise use OpenID
|
||||
// Otherwise use OpenID if enabled
|
||||
if (openIDFilter != null && formLoginFilter == null) {
|
||||
parserContext.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
parserContext.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 ",
|
||||
parserContext.extractSource(element));
|
||||
// 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 ",
|
||||
pc.extractSource(element));
|
||||
}
|
||||
|
||||
static UrlMatcher createUrlMatcher(Element element) {
|
||||
@@ -512,9 +568,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
static void parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, Map filterInvocationDefinitionMap,
|
||||
boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
|
||||
static LinkedHashMap parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap();
|
||||
|
||||
Iterator urlEltsIterator = urlElts.iterator();
|
||||
ConfigAttributeEditor editor = new ConfigAttributeEditor();
|
||||
|
||||
@@ -544,6 +600,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
filterInvocationDefinitionMap.put(new RequestKey(path, method), editor.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return filterInvocationDefinitionMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
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.RootBeanDefinition;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Responsible for tying up the HTTP security configuration once all the beans are registered.
|
||||
* This class does not actually instantiate any beans (for example, it should not call {@link BeanFactory#getBean(String)}).
|
||||
* All the wiring up should be done using bean definitions or bean references to avoid this. This approach should avoid any
|
||||
* conflict with other processors.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor, Ordered {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
injectUserDetailsServiceIntoRememberMeServices(beanFactory);
|
||||
injectUserDetailsServiceIntoX509Provider(beanFactory);
|
||||
injectUserDetailsServiceIntoOpenIDProvider(beanFactory);
|
||||
injectAuthenticationEntryPointIntoExceptionTranslationFilter(beanFactory);
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoRememberMeServices(ConfigurableListableBeanFactory bf) {
|
||||
try {
|
||||
BeanDefinition rememberMeServices = bf.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
|
||||
PropertyValue pv = rememberMeServices.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService",
|
||||
ConfigUtils.getUserDetailsService(bf));
|
||||
} else {
|
||||
RuntimeBeanReference cachingUserService = getCachingUserService(bf, pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService", cachingUserService);
|
||||
}
|
||||
}
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoX509Provider(ConfigurableListableBeanFactory bf) {
|
||||
try {
|
||||
BeanDefinition x509AuthProvider = bf.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER);
|
||||
PropertyValue pv = x509AuthProvider.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
BeanDefinitionBuilder preAuthUserService = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsByNameServiceWrapper.class);
|
||||
preAuthUserService.addPropertyValue("userDetailsService", ConfigUtils.getUserDetailsService(bf));
|
||||
x509AuthProvider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService",
|
||||
preAuthUserService.getBeanDefinition());
|
||||
} else {
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
RuntimeBeanReference cachingUserService = getCachingUserService(bf, userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", cachingUserService);
|
||||
}
|
||||
}
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoOpenIDProvider(ConfigurableListableBeanFactory beanFactory) {
|
||||
try {
|
||||
BeanDefinition openIDProvider = beanFactory.getBeanDefinition(BeanIds.OPEN_ID_PROVIDER);
|
||||
PropertyValue pv = openIDProvider.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
openIDProvider.getPropertyValues().addPropertyValue("userDetailsService",
|
||||
ConfigUtils.getUserDetailsService(beanFactory));
|
||||
}
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeBeanReference getCachingUserService(ConfigurableListableBeanFactory bf, 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 (bf.containsBeanDefinition(cachingId)) {
|
||||
return new RuntimeBeanReference(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the entry point that should be used in ExceptionTranslationFilter. If an entry point has been
|
||||
* set during parsing of form, openID and basic authentication information, or via a custom reference
|
||||
* (using <tt>custom-entry-point</tt>, then that will be used. Otherwise there
|
||||
* must be a single entry point bean and that will be used.
|
||||
*
|
||||
* Todo: this could probably be more easily be done in a BeanPostProcessor for ExceptionTranslationFilter.
|
||||
*
|
||||
*/
|
||||
private void injectAuthenticationEntryPointIntoExceptionTranslationFilter(ConfigurableListableBeanFactory beanFactory) {
|
||||
logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
|
||||
|
||||
BeanDefinition etf =
|
||||
beanFactory.getBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
|
||||
String entryPoint = null;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) {
|
||||
entryPoint = BeanIds.MAIN_ENTRY_POINT;
|
||||
logger.info("Using main configured AuthenticationEntryPoint set to " + BeanIds.MAIN_ENTRY_POINT);
|
||||
} else {
|
||||
String[] entryPoints = beanFactory.getBeanNamesForType(AuthenticationEntryPoint.class);
|
||||
Assert.isTrue(entryPoints.length != 0, "No AuthenticationEntryPoint instances defined");
|
||||
Assert.isTrue(entryPoints.length == 1, "More than one AuthenticationEntryPoint defined in context");
|
||||
entryPoint = entryPoints[0];
|
||||
}
|
||||
|
||||
logger.info("Using bean '" + entryPoint + "' as the entry point.");
|
||||
etf.getPropertyValues().addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(entryPoint));
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE + 1;
|
||||
}
|
||||
}
|
||||
+11
-9
@@ -1,10 +1,8 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
@@ -17,26 +15,30 @@ public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
static final String ATT_USERS_BY_USERNAME_QUERY = "users-by-username-query";
|
||||
static final String ATT_AUTHORITIES_BY_USERNAME_QUERY = "authorities-by-username-query";
|
||||
static final String ATT_GROUP_AUTHORITIES_QUERY = "group-authorities-by-username-query";
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return JdbcUserDetailsManager.class;
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager";
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
// TODO: Set authenticationManager property
|
||||
String dataSource = element.getAttribute(ATT_DATA_SOURCE);
|
||||
// An explicit dataSource was specified, so use it
|
||||
|
||||
if (dataSource != null) {
|
||||
builder.addPropertyReference("dataSource", dataSource);
|
||||
} else {
|
||||
// TODO: Have some sensible fallback if dataSource not specified, eg autowire
|
||||
throw new BeanDefinitionStoreException(ATT_DATA_SOURCE + " is required for "
|
||||
+ Elements.JDBC_USER_SERVICE );
|
||||
parserContext.getReaderContext().error(ATT_DATA_SOURCE + " is required for "
|
||||
+ Elements.JDBC_USER_SERVICE, parserContext.extractSource(element));
|
||||
}
|
||||
|
||||
String usersQuery = element.getAttribute(ATT_USERS_BY_USERNAME_QUERY);
|
||||
String authoritiesQuery = element.getAttribute(ATT_AUTHORITIES_BY_USERNAME_QUERY);
|
||||
String groupAuthoritiesQuery = element.getAttribute(ATT_GROUP_AUTHORITIES_QUERY);
|
||||
String rolePrefix = element.getAttribute(ATT_ROLE_PREFIX);
|
||||
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
builder.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(usersQuery)) {
|
||||
builder.addPropertyValue("usersByUsernameQuery", usersQuery);
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.ldap.SpringSecurityContextSource;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.security.ldap.SpringSecurityContextSource;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
@@ -17,35 +16,56 @@ import java.util.Map;
|
||||
*/
|
||||
class LdapConfigUtils {
|
||||
|
||||
/** Checks for the presence of a ContextSource instance */
|
||||
/**
|
||||
* Checks for the presence of a ContextSource instance. Also supplies the standard reference to any
|
||||
* unconfigured <ldap-authentication-provider> or <ldap-user-service> beans. This is
|
||||
* necessary in cases where the user has given the server a specific Id, but hasn't used
|
||||
* the server-ref attribute to link this to the other ldap definitions. See SEC-799.
|
||||
*/
|
||||
private static class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ordered {
|
||||
/** If set to true, a bean parser has indicated that the default context source name needs to be set */
|
||||
private boolean defaultNameRequired;
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) throws BeansException {
|
||||
Map beans = bf.getBeansOfType(SpringSecurityContextSource.class);
|
||||
String[] sources = bf.getBeanNamesForType(SpringSecurityContextSource.class);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
if (sources.length == 0) {
|
||||
throw new SecurityConfigurationException("No SpringSecurityContextSource instances found. Have you " +
|
||||
"added an <" + Elements.LDAP_SERVER + " /> element to your application context?");
|
||||
}
|
||||
|
||||
// else if (beans.size() > 1) {
|
||||
// throw new SecurityConfigurationException("More than one SpringSecurityContextSource instance found. " +
|
||||
// "Please specify a specific server id when configuring your <" + Elements.LDAP_PROVIDER + "> " +
|
||||
// "or <" + Elements.LDAP_USER_SERVICE + ">.");
|
||||
// }
|
||||
|
||||
if (!bf.containsBean(BeanIds.CONTEXT_SOURCE) && defaultNameRequired) {
|
||||
if (sources.length > 1) {
|
||||
throw new SecurityConfigurationException("More than one SpringSecurityContextSource instance found. " +
|
||||
"Please specify a specific server id using the 'server-ref' attribute when configuring your <" +
|
||||
Elements.LDAP_PROVIDER + "> " + "or <" + Elements.LDAP_USER_SERVICE + ">.");
|
||||
}
|
||||
|
||||
bf.registerAlias(sources[0], BeanIds.CONTEXT_SOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultNameRequired(boolean defaultNameRequired) {
|
||||
this.defaultNameRequired = defaultNameRequired;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return LOWEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
|
||||
static void registerPostProcessorIfNecessary(BeanDefinitionRegistry registry) {
|
||||
|
||||
static void registerPostProcessorIfNecessary(BeanDefinitionRegistry registry, boolean defaultNameRequired) {
|
||||
if (registry.containsBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR)) {
|
||||
if (defaultNameRequired) {
|
||||
BeanDefinition bd = registry.getBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR);
|
||||
bd.getPropertyValues().addPropertyValue("defaultNameRequired", Boolean.valueOf(defaultNameRequired));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR,
|
||||
new RootBeanDefinition(ContextSourceSettingPostProcessor.class));
|
||||
BeanDefinition bd = new RootBeanDefinition(ContextSourceSettingPostProcessor.class);
|
||||
registry.registerBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR, bd);
|
||||
bd.getPropertyValues().addPropertyValue("defaultNameRequired", Boolean.valueOf(defaultNameRequired));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-27
@@ -1,11 +1,8 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.security.providers.ldap.LdapAuthenticationProvider;
|
||||
import org.springframework.security.providers.ldap.authenticator.BindAuthenticator;
|
||||
import org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
@@ -27,14 +24,19 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String ATT_USER_DN_PATTERN = "user-dn-pattern";
|
||||
private static final String ATT_USER_PASSWORD= "password-attribute";
|
||||
private static final String ATT_USER_PASSWORD = "password-attribute";
|
||||
private static final String ATT_HASH = PasswordEncoderParser.ATT_HASH;
|
||||
|
||||
private static final String DEF_USER_SEARCH_FILTER="uid={0}";
|
||||
private static final String DEF_USER_SEARCH_FILTER = "uid={0}";
|
||||
|
||||
private static final String PROVIDER_CLASS = "org.springframework.security.providers.ldap.LdapAuthenticationProvider";
|
||||
private static final String BIND_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.BindAuthenticator";
|
||||
private static final String PASSWD_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator";
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
RuntimeBeanReference contextSource = LdapUserServiceBeanDefinitionParser.parseServerReference(elt, parserContext);
|
||||
|
||||
RootBeanDefinition searchBean = LdapUserServiceBeanDefinitionParser.parseSearchBean(elt, parserContext);
|
||||
BeanDefinition searchBean = LdapUserServiceBeanDefinitionParser.parseSearchBean(elt, parserContext);
|
||||
String userDnPattern = elt.getAttribute(ATT_USER_DN_PATTERN);
|
||||
|
||||
String[] userDnPatternArray = new String[0];
|
||||
@@ -44,49 +46,62 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
// TODO: Validate the pattern and make sure it is a valid DN.
|
||||
} else if (searchBean == null) {
|
||||
logger.info("No search information or DN pattern specified. Using default search filter '" + DEF_USER_SEARCH_FILTER + "'");
|
||||
searchBean = new RootBeanDefinition(FilterBasedLdapUserSearch.class);
|
||||
searchBean.setSource(elt);
|
||||
searchBean.getConstructorArgumentValues().addIndexedArgumentValue(0, "");
|
||||
searchBean.getConstructorArgumentValues().addIndexedArgumentValue(1, DEF_USER_SEARCH_FILTER);
|
||||
searchBean.getConstructorArgumentValues().addIndexedArgumentValue(2, contextSource);
|
||||
BeanDefinitionBuilder searchBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(LdapUserServiceBeanDefinitionParser.LDAP_SEARCH_CLASS);
|
||||
searchBeanBuilder.setSource(elt);
|
||||
searchBeanBuilder.addConstructorArg("");
|
||||
searchBeanBuilder.addConstructorArg(DEF_USER_SEARCH_FILTER);
|
||||
searchBeanBuilder.addConstructorArg(contextSource);
|
||||
searchBean = searchBeanBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
RootBeanDefinition authenticator = new RootBeanDefinition(BindAuthenticator.class);
|
||||
BeanDefinitionBuilder authenticatorBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(BIND_AUTH_CLASS);
|
||||
Element passwordCompareElt = DomUtils.getChildElementByTagName(elt, Elements.LDAP_PASSWORD_COMPARE);
|
||||
|
||||
if (passwordCompareElt != null) {
|
||||
authenticator = new RootBeanDefinition(PasswordComparisonAuthenticator.class);
|
||||
authenticatorBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(PASSWD_AUTH_CLASS);
|
||||
|
||||
String passwordAttribute = passwordCompareElt.getAttribute(ATT_USER_PASSWORD);
|
||||
if (StringUtils.hasText(passwordAttribute)) {
|
||||
authenticator.getPropertyValues().addPropertyValue("passwordAttributeName", passwordAttribute);
|
||||
authenticatorBuilder.addPropertyValue("passwordAttributeName", passwordAttribute);
|
||||
}
|
||||
|
||||
Element passwordEncoderElement = DomUtils.getChildElementByTagName(passwordCompareElt, Elements.PASSWORD_ENCODER);
|
||||
String hash = passwordCompareElt.getAttribute(ATT_HASH);
|
||||
|
||||
if (passwordEncoderElement != null) {
|
||||
if (StringUtils.hasText(hash)) {
|
||||
parserContext.getReaderContext().warning("Attribute 'hash' cannot be used with 'password-encoder' and " +
|
||||
"will be ignored.", parserContext.extractSource(elt));
|
||||
}
|
||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElement, parserContext);
|
||||
authenticator.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||
authenticatorBuilder.addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||
|
||||
if (pep.getSaltSource() != null) {
|
||||
parserContext.getReaderContext().warning("Salt source information isn't valid when used with LDAP", passwordEncoderElement);
|
||||
parserContext.getReaderContext().warning("Salt source information isn't valid when used with LDAP",
|
||||
passwordEncoderElement);
|
||||
}
|
||||
} else if (StringUtils.hasText(hash)) {
|
||||
Class encoderClass = (Class) PasswordEncoderParser.ENCODER_CLASSES.get(hash);
|
||||
authenticatorBuilder.addPropertyValue("passwordEncoder", new RootBeanDefinition(encoderClass));
|
||||
}
|
||||
}
|
||||
|
||||
authenticator.getConstructorArgumentValues().addGenericArgumentValue(contextSource);
|
||||
authenticator.getPropertyValues().addPropertyValue("userDnPatterns", userDnPatternArray);
|
||||
authenticatorBuilder.addConstructorArg(contextSource);
|
||||
authenticatorBuilder.addPropertyValue("userDnPatterns", userDnPatternArray);
|
||||
|
||||
if (searchBean != null) {
|
||||
authenticator.getPropertyValues().addPropertyValue("userSearch", searchBean);
|
||||
authenticatorBuilder.addPropertyValue("userSearch", searchBean);
|
||||
}
|
||||
|
||||
RootBeanDefinition ldapProvider = new RootBeanDefinition(LdapAuthenticationProvider.class);
|
||||
ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(authenticator);
|
||||
ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry());
|
||||
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider);
|
||||
BeanDefinitionBuilder ldapProvider = BeanDefinitionBuilder.rootBeanDefinition(PROVIDER_CLASS);
|
||||
ldapProvider.addConstructorArg(authenticatorBuilder.getBeanDefinition());
|
||||
ldapProvider.addConstructorArg(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
ldapProvider.addPropertyValue("userDetailsContextMapper",
|
||||
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
|
||||
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider.getBeanDefinition());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+28
-17
@@ -1,6 +1,10 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
@@ -8,7 +12,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
@@ -20,7 +23,9 @@ import org.apache.commons.logging.LogFactory;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
private static final String CONTEXT_SOURCE_CLASS="org.springframework.security.ldap.DefaultSpringSecurityContextSource";
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Defines the Url of the ldap server to use. If not specified, an embedded apache DS instance will be created */
|
||||
private static final String ATT_URL = "url";
|
||||
@@ -53,7 +58,8 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (!StringUtils.hasText(url)) {
|
||||
contextSource = createEmbeddedServer(elt, parserContext);
|
||||
} else {
|
||||
contextSource = new RootBeanDefinition(DefaultSpringSecurityContextSource.class);
|
||||
contextSource = new RootBeanDefinition();
|
||||
contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
|
||||
contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
|
||||
}
|
||||
|
||||
@@ -92,17 +98,22 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
*/
|
||||
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
BeanDefinitionBuilder configuration = BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.configuration.MutableServerStartupConfiguration");
|
||||
BeanDefinitionBuilder partition = BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration");
|
||||
BeanDefinitionBuilder configuration =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.configuration.MutableServerStartupConfiguration");
|
||||
BeanDefinitionBuilder partition =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration");
|
||||
configuration.setSource(source);
|
||||
partition.setSource(source);
|
||||
|
||||
DirContextAdapter rootContext = new DirContextAdapter();
|
||||
rootContext.setAttributeValues("objectClass", new String[] {"top", "domain", "extensibleObject"});
|
||||
rootContext.setAttributeValue("dc", "springsecurity");
|
||||
|
||||
Attributes rootAttributes = new BasicAttributes("dc", "springsecurity");
|
||||
Attribute a = new BasicAttribute("objectClass");
|
||||
a.add("top");
|
||||
a.add("domain");
|
||||
a.add("extensibleObject");
|
||||
rootAttributes.put(a);
|
||||
|
||||
partition.addPropertyValue("name", "springsecurity");
|
||||
partition.addPropertyValue("contextEntry", rootContext.getAttributes());
|
||||
partition.addPropertyValue("contextEntry", rootAttributes);
|
||||
|
||||
String suffix = element.getAttribute(ATT_ROOT_SUFFIX);
|
||||
|
||||
@@ -131,15 +142,15 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
String url = "ldap://127.0.0.1:" + port + "/" + suffix;
|
||||
|
||||
RootBeanDefinition contextSource = new RootBeanDefinition(DefaultSpringSecurityContextSource.class);
|
||||
contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
|
||||
contextSource.getPropertyValues().addPropertyValue("userDn", "uid=admin,ou=system");
|
||||
contextSource.getPropertyValues().addPropertyValue("password", "secret");
|
||||
BeanDefinitionBuilder contextSource = BeanDefinitionBuilder.rootBeanDefinition(CONTEXT_SOURCE_CLASS);
|
||||
contextSource.addConstructorArg(url);
|
||||
contextSource.addPropertyValue("userDn", "uid=admin,ou=system");
|
||||
contextSource.addPropertyValue("password", "secret");
|
||||
|
||||
RootBeanDefinition apacheContainer = new RootBeanDefinition("org.springframework.security.config.ApacheDSContainer", null, null);
|
||||
apacheContainer.setSource(source);
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(configuration.getBeanDefinition());
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(contextSource);
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(contextSource.getBeanDefinition());
|
||||
|
||||
String ldifs = element.getAttribute(ATT_LDIF_FILE);
|
||||
if (!StringUtils.hasText(ldifs)) {
|
||||
@@ -157,6 +168,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.EMBEDDED_APACHE_DS, apacheContainer);
|
||||
|
||||
return contextSource;
|
||||
return (RootBeanDefinition) contextSource.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
+53
-23
@@ -1,8 +1,5 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.userdetails.ldap.LdapUserDetailsService;
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -17,7 +14,7 @@ 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 = "";
|
||||
@@ -27,9 +24,20 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
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";
|
||||
|
||||
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";
|
||||
public static final String LDAP_USER_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.LdapUserDetailsMapper";
|
||||
public static final String LDAP_AUTHORITIES_POPULATOR_CLASS = "org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return LdapUserDetailsService.class;
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.ldap.LdapUserDetailsService";
|
||||
}
|
||||
|
||||
protected void doParse(Element elt, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
@@ -40,8 +48,7 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
|
||||
builder.addConstructorArg(parseSearchBean(elt, parserContext));
|
||||
builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext));
|
||||
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry());
|
||||
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
|
||||
@@ -61,33 +68,48 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
return null;
|
||||
}
|
||||
|
||||
RootBeanDefinition search = new RootBeanDefinition(FilterBasedLdapUserSearch.class);
|
||||
search.setSource(source);
|
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(0, userSearchBase);
|
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(1, userSearchFilter);
|
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(2, parseServerReference(elt, parserContext));
|
||||
BeanDefinitionBuilder searchBuilder = BeanDefinitionBuilder.rootBeanDefinition(LDAP_SEARCH_CLASS);
|
||||
searchBuilder.setSource(source);
|
||||
searchBuilder.addConstructorArg(userSearchBase);
|
||||
searchBuilder.addConstructorArg(userSearchFilter);
|
||||
searchBuilder.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
|
||||
return search;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -96,16 +118,24 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
groupSearchBase = DEF_GROUP_SEARCH_BASE;
|
||||
}
|
||||
|
||||
RootBeanDefinition populator = new RootBeanDefinition(DefaultLdapAuthoritiesPopulator.class);
|
||||
BeanDefinitionBuilder populator = BeanDefinitionBuilder.rootBeanDefinition(LDAP_AUTHORITIES_POPULATOR_CLASS);
|
||||
populator.setSource(parserContext.extractSource(elt));
|
||||
populator.getConstructorArgumentValues().addIndexedArgumentValue(0, parseServerReference(elt, parserContext));
|
||||
populator.getConstructorArgumentValues().addIndexedArgumentValue(1, groupSearchBase);
|
||||
populator.getPropertyValues().addPropertyValue("groupSearchFilter", groupSearchFilter);
|
||||
populator.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
populator.addConstructorArg(groupSearchBase);
|
||||
populator.addPropertyValue("groupSearchFilter", groupSearchFilter);
|
||||
populator.addPropertyValue("searchSubtree", Boolean.TRUE);
|
||||
|
||||
if (StringUtils.hasLength(groupRoleAttribute)) {
|
||||
populator.getPropertyValues().addPropertyValue("groupRoleAttribute", groupRoleAttribute);
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
if ("none".equals(rolePrefix)) {
|
||||
rolePrefix = "";
|
||||
}
|
||||
populator.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
|
||||
return populator;
|
||||
if (StringUtils.hasLength(groupRoleAttribute)) {
|
||||
populator.addPropertyValue("groupRoleAttribute", groupRoleAttribute);
|
||||
}
|
||||
|
||||
return (RootBeanDefinition) populator.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
+8
-4
@@ -31,15 +31,18 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String logoutSuccessUrl = null;
|
||||
String invalidateSession = null;
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
|
||||
|
||||
if (element != null) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
builder.setSource(source);
|
||||
logoutUrl = element.getAttribute(ATT_LOGOUT_URL);
|
||||
ConfigUtils.validateHttpRedirect(logoutUrl, parserContext, source);
|
||||
logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL);
|
||||
ConfigUtils.validateHttpRedirect(logoutSuccessUrl, parserContext, source);
|
||||
invalidateSession = element.getAttribute(ATT_INVALIDATE_SESSION);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
|
||||
builder.setSource(parserContext.extractSource(element));
|
||||
|
||||
if (!StringUtils.hasText(logoutUrl)) {
|
||||
logoutUrl = DEF_LOGOUT_URL;
|
||||
}
|
||||
@@ -70,7 +73,8 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
builder.addConstructorArg(handlers);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, builder.getBeanDefinition());
|
||||
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.AfterInvocationManager;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor which sets the AfterInvocationManager on the default MethodSecurityInterceptor,
|
||||
* if one has been configured.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public class MethodSecurityInterceptorPostProcessor implements BeanPostProcessor, BeanFactoryAware{
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(!BeanIds.METHOD_SECURITY_INTERCEPTOR.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
MethodSecurityInterceptor interceptor = (MethodSecurityInterceptor) bean;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||
logger.debug("Setting AfterInvocationManaer on MethodSecurityInterceptor");
|
||||
interceptor.setAfterInvocationManager((AfterInvocationManager)
|
||||
beanFactory.getBean(BeanIds.AFTER_INVOCATION_MANAGER));
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
+15
-6
@@ -9,8 +9,8 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
@@ -22,8 +22,8 @@ import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Replaces a Spring bean of type "Filter" with a wrapper class which implements the <tt>Ordered</tt>
|
||||
* interface. This allows user to add their own filter to the security chain. If the user's filter
|
||||
* 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.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
@@ -39,16 +39,17 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
Element elt = (Element)node;
|
||||
String order = getOrder(elt, parserContext);
|
||||
|
||||
BeanDefinition filter = holder.getBeanDefinition();
|
||||
BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator");
|
||||
wrapper.addConstructorArg(holder.getBeanName());
|
||||
wrapper.addConstructorArg(filter);
|
||||
wrapper.addConstructorArg(new RuntimeBeanReference(holder.getBeanName()));
|
||||
|
||||
if (StringUtils.hasText(order)) {
|
||||
wrapper.addPropertyValue("order", order);
|
||||
}
|
||||
|
||||
return new BeanDefinitionHolder(wrapper.getBeanDefinition(), holder.getBeanName());
|
||||
ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,5 +120,13 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
public String getBeanName() {
|
||||
return beanName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
|
||||
}
|
||||
|
||||
Filter getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ public class PasswordEncoderParser {
|
||||
static final String ATT_BASE_64 = "base64";
|
||||
static final String OPT_HASH_PLAINTEXT = "plaintext";
|
||||
static final String OPT_HASH_SHA = "sha";
|
||||
static final String OPT_HASH_SHA256 = "sha-256";
|
||||
static final String OPT_HASH_MD4 = "md4";
|
||||
static final String OPT_HASH_MD5 = "md5";
|
||||
static final String OPT_HASH_LDAP_SHA = "{sha}";
|
||||
@@ -45,6 +46,7 @@ public class PasswordEncoderParser {
|
||||
ENCODER_CLASSES = new HashMap();
|
||||
ENCODER_CLASSES.put(OPT_HASH_PLAINTEXT, PlaintextPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA256, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_MD4, Md4PasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_MD5, Md5PasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_LDAP_SHA, LdapShaPasswordEncoder.class);
|
||||
@@ -74,6 +76,11 @@ public class PasswordEncoderParser {
|
||||
} else {
|
||||
Class beanClass = (Class) ENCODER_CLASSES.get(hash);
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
|
||||
|
||||
if (OPT_HASH_SHA256.equals(hash)) {
|
||||
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new Integer(256));
|
||||
}
|
||||
|
||||
beanDefinition.setSource(parserContext.extractSource(element));
|
||||
if (useBase64) {
|
||||
if (BaseDigestPasswordEncoder.class.isAssignableFrom(beanClass)) {
|
||||
|
||||
+69
-40
@@ -23,12 +23,14 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_KEY = "key";
|
||||
static final String DEF_KEY = "doesNotMatter";
|
||||
static final String DEF_KEY = "SpringSecured";
|
||||
|
||||
static final String ATT_DATA_SOURCE = "data-source";
|
||||
static final String ATT_DATA_SOURCE = "data-source-ref";
|
||||
static final String ATT_SERVICES_REF = "services-ref";
|
||||
static final String ATT_TOKEN_REPOSITORY = "token-repository-ref";
|
||||
static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
static final String ATT_TOKEN_VALIDITY = "token-validity-seconds";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
@@ -37,73 +39,100 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String key = null;
|
||||
Object source = null;
|
||||
String userServiceRef = null;
|
||||
String rememberMeServicesRef = null;
|
||||
String tokenValiditySeconds = null;
|
||||
|
||||
if (element != null) {
|
||||
tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY);
|
||||
dataSource = element.getAttribute(ATT_DATA_SOURCE);
|
||||
key = element.getAttribute(ATT_KEY);
|
||||
userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF);
|
||||
tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY);
|
||||
source = parserContext.extractSource(element);
|
||||
}
|
||||
|
||||
RootBeanDefinition filter = new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
RootBeanDefinition services = new RootBeanDefinition(PersistentTokenBasedRememberMeServices.class);
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
key = DEF_KEY;
|
||||
}
|
||||
|
||||
RootBeanDefinition services = null;
|
||||
|
||||
boolean dataSourceSet = StringUtils.hasText(dataSource);
|
||||
boolean tokenRepoSet = StringUtils.hasText(tokenRepository);
|
||||
|
||||
boolean servicesRefSet = StringUtils.hasText(rememberMeServicesRef);
|
||||
boolean userServiceSet = StringUtils.hasText(userServiceRef);
|
||||
boolean tokenValiditySet = StringUtils.hasText(tokenValiditySeconds);
|
||||
|
||||
if (servicesRefSet && (dataSourceSet || tokenRepoSet || userServiceSet || tokenValiditySet)) {
|
||||
parserContext.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes "
|
||||
+ ATT_TOKEN_REPOSITORY + "," + ATT_DATA_SOURCE + ", " + ATT_USER_SERVICE_REF + " or " + ATT_TOKEN_VALIDITY, source);
|
||||
}
|
||||
|
||||
if (dataSourceSet && tokenRepoSet) {
|
||||
parserContext.getReaderContext().error("Specify tokenRepository or dataSource but not both", element);
|
||||
parserContext.getReaderContext().error("Specify " + ATT_TOKEN_REPOSITORY + " or " +
|
||||
ATT_DATA_SOURCE +" but not both", source);
|
||||
}
|
||||
|
||||
boolean isPersistent = dataSourceSet | tokenRepoSet;
|
||||
|
||||
if (isPersistent) {
|
||||
Object tokenRepo;
|
||||
services = new RootBeanDefinition(PersistentTokenBasedRememberMeServices.class);
|
||||
|
||||
if (tokenRepoSet) {
|
||||
tokenRepo = new RuntimeBeanReference(tokenRepository);
|
||||
} else {
|
||||
tokenRepo = new RootBeanDefinition(JdbcTokenRepositoryImpl.class);
|
||||
((BeanDefinition)tokenRepo).getPropertyValues().addPropertyValue(ATT_DATA_SOURCE,
|
||||
((BeanDefinition)tokenRepo).getPropertyValues().addPropertyValue("dataSource",
|
||||
new RuntimeBeanReference(dataSource));
|
||||
}
|
||||
services.getPropertyValues().addPropertyValue("tokenRepository", tokenRepo);
|
||||
} else {
|
||||
isPersistent = false;
|
||||
} else if (!servicesRefSet) {
|
||||
services = new RootBeanDefinition(TokenBasedRememberMeServices.class);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(key) && !isPersistent) {
|
||||
key = DEF_KEY;
|
||||
if (services != null) {
|
||||
if (userServiceSet) {
|
||||
services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
}
|
||||
|
||||
if (tokenValiditySet) {
|
||||
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", new Integer(tokenValiditySeconds));
|
||||
}
|
||||
services.setSource(source);
|
||||
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
} else {
|
||||
parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
|
||||
}
|
||||
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
|
||||
|
||||
filter.setSource(source);
|
||||
services.setSource(source);
|
||||
provider.setSource(source);
|
||||
|
||||
if (StringUtils.hasText(userServiceRef)) {
|
||||
services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
}
|
||||
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
providers.add(provider);
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
|
||||
|
||||
registerProvider(parserContext, source, key);
|
||||
|
||||
registerFilter(parserContext, source);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void registerFilter(ParserContext pc, Object source) {
|
||||
RootBeanDefinition filter = new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
filter.setSource(source);
|
||||
filter.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostPro
|
||||
logger.info("Setting RememberMeServices on bean " + beanName);
|
||||
pf.setRememberMeServices(getRememberMeServices());
|
||||
}
|
||||
} else if (beanName.equals(BeanIds.BASIC_AUTHENTICATION_FILTER)) {
|
||||
} else if (BeanIds.BASIC_AUTHENTICATION_FILTER.equals(beanName)) {
|
||||
// NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request.
|
||||
// Most of the time a user won't present such a parameter with their BASIC authentication request.
|
||||
// In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to
|
||||
|
||||
@@ -30,5 +30,6 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_FILTER, new OrderedFilterBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_PROVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AFTER_INVOCATION_PROVIDER, new CustomAfterInvocationProviderBeanDefinitionDecorator());
|
||||
}
|
||||
}
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionController;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionControllerImpl;
|
||||
import org.springframework.security.concurrent.SessionRegistry;
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Registered by the <tt>AuthenticationManagerBeanDefinitionParser</tt> if an external
|
||||
* ConcurrentSessionController is set (and hence an external SessionRegistry).
|
||||
* Its responsibility is to set the SessionRegistry on namespace-registered beans which require access
|
||||
* to it.
|
||||
* <p>
|
||||
* It will attempt to read the registry directly from the registered controller. If that fails, it will look in
|
||||
* the application context for a registered SessionRegistry bean.
|
||||
*
|
||||
* See SEC-879.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.3
|
||||
*/
|
||||
class SessionRegistryInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ListableBeanFactory beanFactory;
|
||||
private SessionRegistry sessionRegistry;
|
||||
private final String controllerBeanName;
|
||||
|
||||
SessionRegistryInjectionBeanPostProcessor(String controllerBeanName) {
|
||||
this.controllerBeanName = controllerBeanName;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.FORM_LOGIN_FILTER.equals(beanName) ||
|
||||
BeanIds.OPEN_ID_FILTER.equals(beanName)) {
|
||||
((AbstractProcessingFilter) bean).setSessionRegistry(getSessionRegistry());
|
||||
} else if (BeanIds.SESSION_FIXATION_PROTECTION_FILTER.equals(beanName)) {
|
||||
((SessionFixationProtectionFilter)bean).setSessionRegistry(getSessionRegistry());
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private SessionRegistry getSessionRegistry() {
|
||||
if (sessionRegistry != null) {
|
||||
return sessionRegistry;
|
||||
}
|
||||
|
||||
logger.info("Attempting to read SessionRegistry from registered ConcurrentSessionController bean");
|
||||
|
||||
ConcurrentSessionController controller = (ConcurrentSessionController) beanFactory.getBean(controllerBeanName);
|
||||
|
||||
if (controller instanceof ConcurrentSessionControllerImpl) {
|
||||
sessionRegistry = ((ConcurrentSessionControllerImpl)controller).getSessionRegistry();
|
||||
|
||||
return sessionRegistry;
|
||||
}
|
||||
|
||||
logger.info("ConcurrentSessionController is not a standard implementation. SessionRegistry could not be read from it. Looking for it in the context.");
|
||||
|
||||
List sessionRegs = new ArrayList(beanFactory.getBeansOfType(SessionRegistry.class).values());
|
||||
|
||||
if (sessionRegs.size() == 0) {
|
||||
throw new SecurityConfigurationException("concurrent-session-controller-ref was set but no SessionRegistry could be obtained from the application context.");
|
||||
}
|
||||
|
||||
if (sessionRegs.size() > 1) {
|
||||
logger.warn("More than one SessionRegistry instance in application context. Possible configuration errors may result.");
|
||||
}
|
||||
|
||||
sessionRegistry = (SessionRegistry) sessionRegs.get(0);
|
||||
|
||||
return sessionRegistry;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
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;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.ui.rememberme.AbstractRememberMeServices;
|
||||
import org.springframework.security.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @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 void injectUserDetailsServiceIntoRememberMeServices(AbstractRememberMeServices services) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
services.setUserDetailsService(getUserDetailsService());
|
||||
} else {
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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.
|
||||
*/
|
||||
UserDetailsService getUserDetailsService() {
|
||||
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.");
|
||||
|
||||
} else if (beans.size() > 1) {
|
||||
throw new SecurityConfigurationException("More than one UserDetailsService registered. Please " +
|
||||
"use a specific Id in your configuration");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -6,7 +6,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.security.userdetails.memory.InMemoryDaoImpl;
|
||||
import org.springframework.security.userdetails.memory.UserMap;
|
||||
import org.springframework.security.userdetails.User;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
@@ -33,8 +32,8 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
||||
static final String ATT_DISABLED = "disabled";
|
||||
static final String ATT_LOCKED = "locked";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return InMemoryDaoImpl.class;
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.memory.InMemoryDaoImpl";
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
+2
-1
@@ -45,8 +45,8 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(provider);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_AUTH_PROVIDER, provider);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(BeanIds.X509_AUTH_PROVIDER));
|
||||
|
||||
String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
@@ -62,6 +62,7 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
|
||||
filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, filterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.X509_FILTER));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+21
-7
@@ -28,6 +28,8 @@ import javax.servlet.http.HttpSession;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.security.AuthenticationTrustResolver;
|
||||
import org.springframework.security.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.ui.SpringSecurityFilter;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
|
||||
@@ -150,6 +152,8 @@ public class HttpSessionContextIntegrationFilter extends SpringSecurityFilter im
|
||||
* method.
|
||||
*/
|
||||
private boolean cloneFromHttpSession = false;
|
||||
|
||||
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
public boolean isCloneFromHttpSession() {
|
||||
return cloneFromHttpSession;
|
||||
@@ -176,6 +180,8 @@ public class HttpSessionContextIntegrationFilter extends SpringSecurityFilter im
|
||||
throw new IllegalArgumentException(
|
||||
"If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
|
||||
}
|
||||
|
||||
contextObject = generateNewContext();
|
||||
}
|
||||
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
@@ -320,7 +326,8 @@ public class HttpSessionContextIntegrationFilter extends SpringSecurityFilter im
|
||||
|
||||
/**
|
||||
* Stores the supplied security context in the session (if available) and if it has changed since it was
|
||||
* set at the start of the request.
|
||||
* set at the start of the request. If the AuthenticationTrustResolver identifies the current user as
|
||||
* anonymous, then the context will not be stored.
|
||||
*
|
||||
* @param securityContext the context object obtained from the SecurityContextHolder after the request has
|
||||
* been processed by the filter chain. SecurityContextHolder.getContext() cannot be used to obtain
|
||||
@@ -356,7 +363,7 @@ public class HttpSessionContextIntegrationFilter extends SpringSecurityFilter im
|
||||
+ "(because the allowSessionCreation property is false) - SecurityContext thus not "
|
||||
+ "stored for next request");
|
||||
}
|
||||
} else if (!contextObject.equals(securityContext)) {
|
||||
} else if (!contextObject.equals(securityContext)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("HttpSession being created as SecurityContextHolder contents are non-default");
|
||||
}
|
||||
@@ -376,11 +383,18 @@ public class HttpSessionContextIntegrationFilter extends SpringSecurityFilter im
|
||||
// If HttpSession exists, store current SecurityContextHolder contents but only if
|
||||
// the SecurityContext has actually changed (see JIRA SEC-37)
|
||||
if (httpSession != null && securityContext.hashCode() != contextHashBeforeChainExecution) {
|
||||
httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, securityContext);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SecurityContext stored to HttpSession: '" + securityContext + "'");
|
||||
}
|
||||
// See SEC-766
|
||||
if (authenticationTrustResolver.isAnonymous(securityContext.getAuthentication())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SecurityContext contents are anonymous - context will not be stored in HttpSession. ");
|
||||
}
|
||||
} else {
|
||||
httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, securityContext);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SecurityContext stored to HttpSession: '" + securityContext + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ import java.util.Collection;
|
||||
* interceptor. It will also implement the proper handling of secure object invocations, namely:
|
||||
* <ol>
|
||||
* <li>Obtain the {@link Authentication} object from the {@link SecurityContextHolder}.</li>
|
||||
* <li>Determine if the request relates to a secured or public invocation by ooking up the secure object request
|
||||
* <li>Determine if the request relates to a secured or public invocation by looking up the secure object request
|
||||
* against the {@link ObjectDefinitionSource}.</li>
|
||||
* <li>For an invocation that is secured (there is a
|
||||
* <code>ConfigAttributeDefinition</code> for the secure object invocation):
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
}
|
||||
|
||||
public void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
|
||||
Assert.hasText(pointcutExpression, "An AspecTJ pointcut expression is required");
|
||||
Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
|
||||
Assert.notNull(definition, "ConfigAttributeDefinition required");
|
||||
pointcutMap.put(pointcutExpression, definition);
|
||||
|
||||
|
||||
+52
-9
@@ -23,13 +23,18 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.security.intercept.method.MethodDefinitionSource;
|
||||
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 <code>MethodSecurityInterceptor</code> run and find out itself that it has no work to do.
|
||||
* public (ie non-secure) methods.
|
||||
* <p>
|
||||
* 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
|
||||
* {@link org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator}, which makes
|
||||
@@ -42,22 +47,47 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor {
|
||||
public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private MethodDefinitionSource attributeSource;
|
||||
private MethodSecurityInterceptor interceptor;
|
||||
private Pointcut pointcut;
|
||||
private Pointcut pointcut = new MethodDefinitionSourcePointcut();
|
||||
private BeanFactory beanFactory;
|
||||
private String adviceBeanName;
|
||||
private final Object adviceMonitor = new Object();
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* @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");
|
||||
|
||||
this.interceptor = advice;
|
||||
|
||||
Assert.notNull(advice.getObjectDefinitionSource(), "Cannot construct a MethodDefinitionSourceAdvisor using a MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
|
||||
|
||||
this.attributeSource = advice.getObjectDefinitionSource();
|
||||
this.pointcut = new MethodDefinitionSourcePointcut();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* (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.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -67,7 +97,20 @@ public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor {
|
||||
}
|
||||
|
||||
public Advice getAdvice() {
|
||||
return interceptor;
|
||||
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;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
+3
-3
@@ -78,7 +78,7 @@ public class DefaultFilterInvocationDefinitionSource implements FilterInvocation
|
||||
DefaultFilterInvocationDefinitionSource(UrlMatcher urlMatcher) {
|
||||
this.urlMatcher = urlMatcher;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the internal request map from the supplied map. The key elements should be of type {@link RequestKey},
|
||||
* which contains a URL path and an optional HTTP method (may be null). The path stored in the key will depend on
|
||||
@@ -179,7 +179,7 @@ public class DefaultFilterInvocationDefinitionSource implements FilterInvocation
|
||||
* @return the <code>ConfigAttributeDefinition</code> that applies to the specified <code>FilterInvocation</code>
|
||||
* or null if no match is foud
|
||||
*/
|
||||
protected ConfigAttributeDefinition lookupAttributes(String url, String method) {
|
||||
public ConfigAttributeDefinition lookupAttributes(String url, String method) {
|
||||
if (stripQueryStringFromUrls) {
|
||||
// Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
|
||||
int firstQuestionMarkIndex = url.indexOf("?");
|
||||
@@ -252,7 +252,7 @@ public class DefaultFilterInvocationDefinitionSource implements FilterInvocation
|
||||
return urlMatcher.requiresLowerCaseUrl();
|
||||
}
|
||||
|
||||
protected void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) {
|
||||
public void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) {
|
||||
this.stripQueryStringFromUrls = stripQueryStringFromUrls;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.springframework.security.intercept.web;
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class RequestKey {
|
||||
private String url;
|
||||
@@ -47,10 +48,10 @@ public class RequestKey {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method == null && key.method != null) {
|
||||
return false;
|
||||
if (method == null) {
|
||||
return key.method == null;
|
||||
}
|
||||
|
||||
|
||||
return method.equals(key.method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ package org.springframework.security.ldap;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.security.ldap.LdapDataAccessException;
|
||||
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
|
||||
|
||||
@@ -42,7 +40,6 @@ public interface LdapAuthoritiesPopulator {
|
||||
*
|
||||
* @return the granted authorities for the given user.
|
||||
*
|
||||
* @throws LdapDataAccessException if there is a problem accessing the directory.
|
||||
*/
|
||||
GrantedAuthority[] getGrantedAuthorities(DirContextOperations userData, String username);
|
||||
}
|
||||
|
||||
+11
-3
@@ -22,6 +22,7 @@ import org.springframework.ldap.core.ContextSource;
|
||||
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.util.Assert;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -135,9 +136,16 @@ 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) {
|
||||
|
||||
String formattedFilter = MessageFormat.format(filter, 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());
|
||||
}
|
||||
|
||||
String formattedFilter = MessageFormat.format(filter, encodedParams);
|
||||
logger.debug("Using filter: " + formattedFilter);
|
||||
|
||||
final HashSet set = new HashSet();
|
||||
|
||||
|
||||
+10
-6
@@ -69,13 +69,13 @@ import java.util.Set;
|
||||
* <pre>
|
||||
* <bean id="ldapAuthoritiesPopulator"
|
||||
* class="org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
|
||||
* <constructor-arg><ref local="contextSource"/></constructor-arg>
|
||||
* <constructor-arg><value>ou=groups</value></constructor-arg>
|
||||
* <property name="groupRoleAttribute"><value>ou</value></property>
|
||||
* <constructor-arg ref="contextSource"/>
|
||||
* <constructor-arg value="ou=groups"/>
|
||||
* <property name="groupRoleAttribute" value="ou"/>
|
||||
* <!-- the following properties are shown with their default values -->
|
||||
* <property name="searchSubTree"><value>false</value></property>
|
||||
* <property name="rolePrefix"><value>ROLE_</value></property>
|
||||
* <property name="convertToUpperCase"><value>true</value></property>
|
||||
* <property name="searchSubTree" value="false"/>
|
||||
* <property name="rolePrefix" value="ROLE_"/>
|
||||
* <property name="convertToUpperCase" value="true"/>
|
||||
* </bean>
|
||||
* </pre>
|
||||
* A search for roles for user "uid=ben,ou=people,dc=springframework,dc=org" would return the single granted authority
|
||||
@@ -284,6 +284,10 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
this.groupSearchFilter = groupSearchFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix which will be prepended to the values loaded from the directory.
|
||||
* Defaults to "ROLE_" for compatibility with <tt>RoleVoter/tt>.
|
||||
*/
|
||||
public void setRolePrefix(String rolePrefix) {
|
||||
Assert.notNull(rolePrefix, "rolePrefix must not be null");
|
||||
this.rolePrefix = rolePrefix;
|
||||
|
||||
+7
-2
@@ -158,7 +158,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
Assert.hasLength(loginContextName, "loginContextName must be set on " + getClass());
|
||||
|
||||
configureJaas(loginConfig);
|
||||
|
||||
|
||||
Assert.notNull(Configuration.getConfiguration(),
|
||||
"As per http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html "
|
||||
+ "\"If a Configuration object was set via the Configuration.setConfiguration method, then that object is "
|
||||
@@ -246,6 +246,9 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
*/
|
||||
protected void configureJaas(Resource loginConfig) throws IOException {
|
||||
configureJaasUsingLoop();
|
||||
|
||||
// Overcome issue in SEC-760
|
||||
Configuration.getConfiguration().refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,7 +378,9 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
* @param token The {@link UsernamePasswordAuthenticationToken} being processed
|
||||
*/
|
||||
protected void publishSuccessEvent(UsernamePasswordAuthenticationToken token) {
|
||||
applicationEventPublisher.publishEvent(new JaasAuthenticationSuccessEvent(token));
|
||||
if (applicationEventPublisher != null) {
|
||||
applicationEventPublisher.publishEvent(new JaasAuthenticationSuccessEvent(token));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-1
@@ -88,7 +88,6 @@ public class PreAuthenticatedAuthenticationProvider implements AuthenticationPro
|
||||
result.setDetails(authentication.getDetails());
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,4 +122,14 @@ public class PreAuthenticatedAuthenticationProvider implements AuthenticationPro
|
||||
public void setThrowExceptionWhenTokenRejected(boolean throwExceptionWhenTokenRejected) {
|
||||
this.throwExceptionWhenTokenRejected = throwExceptionWhenTokenRejected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy which will be used to validate the loaded <tt>UserDetails</tt> object
|
||||
* for the user. Defaults to an {@link AccountStatusUserDetailsChecker}.
|
||||
* @param userDetailsChecker
|
||||
*/
|
||||
public void setUserDetailsChecker(UserDetailsChecker userDetailsChecker) {
|
||||
Assert.notNull(userDetailsChecker, "userDetailsChacker cannot be null");
|
||||
this.userDetailsChecker = userDetailsChecker;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.springframework.security.token;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link Token}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public class DefaultToken implements Token {
|
||||
private String key;
|
||||
private long keyCreationTime;
|
||||
private String extendedInformation;
|
||||
|
||||
public DefaultToken(String key, long keyCreationTime, String extendedInformation) {
|
||||
Assert.hasText(key, "Key required");
|
||||
Assert.notNull(extendedInformation, "Extended information cannot be null");
|
||||
this.key = key;
|
||||
this.keyCreationTime = keyCreationTime;
|
||||
this.extendedInformation = extendedInformation;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public long getKeyCreationTime() {
|
||||
return keyCreationTime;
|
||||
}
|
||||
|
||||
public String getExtendedInformation() {
|
||||
return extendedInformation;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj != null && obj instanceof DefaultToken) {
|
||||
DefaultToken rhs = (DefaultToken) obj;
|
||||
return this.key.equals(rhs.key) && this.keyCreationTime == rhs.keyCreationTime && this.extendedInformation.equals(rhs.extendedInformation);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int code = 979;
|
||||
code = code * key.hashCode();
|
||||
code = code * new Long(keyCreationTime).hashCode();
|
||||
code = code * extendedInformation.hashCode();
|
||||
return code;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "DefaultToken[key=" + new String(key) + "; creation=" + new Date(keyCreationTime) + "; extended=" + extendedInformation + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
package org.springframework.security.token;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.util.Sha512DigestUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link TokenService} that is compatible with clusters and across machine restarts,
|
||||
* without requiring database persistence.
|
||||
*
|
||||
* <p>
|
||||
* Keys are produced in the format:
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Base64(creationTime + ":" + hex(pseudoRandomNumber) + ":" + extendedInformation + ":" +
|
||||
* Sha512Hex(creationTime + ":" + hex(pseudoRandomNumber) + ":" + extendedInformation + ":" + serverSecret) )
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* In the above, <code>creationTime</code>, <code>tokenKey</code> and <code>extendedInformation</code>
|
||||
* are equal to that stored in {@link Token}. The <code>Sha512Hex</code> includes the same payload,
|
||||
* plus a <code>serverSecret</code>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The <code>serverSecret</code> varies every millisecond. It relies on two static server-side secrets. The first
|
||||
* is a password, and the second is a server integer. Both of these must remain the same for any issued keys
|
||||
* to subsequently be recognised. The applicable <code>serverSecret</code> in any millisecond is computed by
|
||||
* <code>password</code> + ":" + (<code>creationTime</code> % <code>serverInteger</code>). This approach
|
||||
* further obfuscates the actual server secret and renders attempts to compute the server secret more
|
||||
* limited in usefulness (as any false tokens would be forced to have a <code>creationTime</code> equal
|
||||
* to the computed hash). Recall that framework features depending on token services should reject tokens
|
||||
* that are relatively old in any event.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A further consideration of this class is the requirement for cryptographically strong pseudo-random numbers.
|
||||
* To this end, the use of {@link SecureRandomFactoryBean} is recommended to inject the property.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This implementation uses UTF-8 encoding internally for string manipulation.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
*
|
||||
*/
|
||||
public class KeyBasedPersistenceTokenService implements TokenService, InitializingBean {
|
||||
private int pseudoRandomNumberBits = 256;
|
||||
private String serverSecret;
|
||||
private Integer serverInteger;
|
||||
private SecureRandom secureRandom;
|
||||
|
||||
public Token allocateToken(String extendedInformation) {
|
||||
Assert.notNull(extendedInformation, "Must provided non-null extendedInformation (but it can be empty)");
|
||||
long creationTime = new Date().getTime();
|
||||
String serverSecret = computeServerSecretApplicableAt(creationTime);
|
||||
String pseudoRandomNumber = generatePseudoRandomNumber();
|
||||
String content = new Long(creationTime).toString() + ":" + pseudoRandomNumber + ":" + extendedInformation;
|
||||
|
||||
// Compute key
|
||||
String sha512Hex = Sha512DigestUtils.shaHex(content + ":" + serverSecret);
|
||||
String keyPayload = content + ":" + sha512Hex;
|
||||
String key = convertToString(Base64.encodeBase64(convertToBytes(keyPayload)));
|
||||
|
||||
return new DefaultToken(key, creationTime, extendedInformation);
|
||||
}
|
||||
|
||||
public Token verifyToken(String key) {
|
||||
if (key == null || "".equals(key)) {
|
||||
return null;
|
||||
}
|
||||
String[] tokens = StringUtils.delimitedListToStringArray(convertToString(Base64.decodeBase64(convertToBytes(key))), ":");
|
||||
Assert.isTrue(tokens.length >= 4, "Expected 4 or more tokens but found " + tokens.length);
|
||||
|
||||
long creationTime;
|
||||
try {
|
||||
creationTime = Long.decode(tokens[0]).longValue();
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IllegalArgumentException("Expected number but found " + tokens[0]);
|
||||
}
|
||||
|
||||
String serverSecret = computeServerSecretApplicableAt(creationTime);
|
||||
String pseudoRandomNumber = tokens[1];
|
||||
|
||||
// Permit extendedInfo to itself contain ":" characters
|
||||
StringBuffer extendedInfo = new StringBuffer();
|
||||
for (int i = 2; i < tokens.length-1; i++) {
|
||||
if (i > 2) {
|
||||
extendedInfo.append(":");
|
||||
}
|
||||
extendedInfo.append(tokens[i]);
|
||||
}
|
||||
|
||||
String sha1Hex = tokens[tokens.length-1];
|
||||
|
||||
// Verification
|
||||
String content = new Long(creationTime).toString() + ":" + pseudoRandomNumber + ":" + extendedInfo.toString();
|
||||
String expectedSha512Hex = Sha512DigestUtils.shaHex(content + ":" + serverSecret);
|
||||
Assert.isTrue(expectedSha512Hex.equals(sha1Hex), "Key verification failure");
|
||||
|
||||
return new DefaultToken(key, creationTime, extendedInfo.toString());
|
||||
}
|
||||
|
||||
private byte[] convertToBytes(String input) {
|
||||
try {
|
||||
return input.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String convertToString(byte[] bytes) {
|
||||
try {
|
||||
return new String(bytes, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a pseduo random number (hex encoded)
|
||||
*/
|
||||
private String generatePseudoRandomNumber() {
|
||||
byte[] randomizedBits = new byte[pseudoRandomNumberBits];
|
||||
secureRandom.nextBytes(randomizedBits);
|
||||
return new String(Hex.encodeHex(randomizedBits));
|
||||
}
|
||||
|
||||
private String computeServerSecretApplicableAt(long time) {
|
||||
return serverSecret + ":" + new Long(time % serverInteger.intValue()).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serverSecret the new secret, which can contain a ":" if desired (never being sent to the client)
|
||||
*/
|
||||
public void setServerSecret(String serverSecret) {
|
||||
this.serverSecret = serverSecret;
|
||||
}
|
||||
|
||||
public void setSecureRandom(SecureRandom secureRandom) {
|
||||
this.secureRandom = secureRandom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pseudoRandomNumberBits changes the number of bits issued (must be >= 0; defaults to 256)
|
||||
*/
|
||||
public void setPseudoRandomNumberBits(int pseudoRandomNumberBits) {
|
||||
Assert.isTrue(pseudoRandomNumberBits >= 0, "Must have a positive pseudo random number bit size");
|
||||
this.pseudoRandomNumberBits = pseudoRandomNumberBits;
|
||||
}
|
||||
|
||||
public void setServerInteger(Integer serverInteger) {
|
||||
this.serverInteger = serverInteger;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasText(serverSecret, "Server secret required");
|
||||
Assert.notNull(serverInteger, "Server integer required");
|
||||
Assert.notNull(secureRandom, "SecureRandom instance required");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.springframework.security.token;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Creates a {@link SecureRandom} instance.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.1
|
||||
*
|
||||
*/
|
||||
public class SecureRandomFactoryBean implements FactoryBean {
|
||||
|
||||
private String algorithm = "SHA1PRNG";
|
||||
private Resource seed;
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
SecureRandom rnd = SecureRandom.getInstance(algorithm);
|
||||
|
||||
if (seed != null) {
|
||||
// Seed specified, so use it
|
||||
byte[] seedBytes = FileCopyUtils.copyToByteArray(seed.getInputStream());
|
||||
rnd.setSeed(seedBytes);
|
||||
} else {
|
||||
// Request the next bytes, thus eagerly incurring the expense of default seeding
|
||||
rnd.nextBytes(new byte[1]);
|
||||
}
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return SecureRandom.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the Pseudo Random Number Generator (PRNG) algorithm to be nominated. Defaults to
|
||||
* SHA1PRNG.
|
||||
*
|
||||
* @param algorithm to use (mandatory)
|
||||
*/
|
||||
public void setAlgorithm(String algorithm) {
|
||||
Assert.hasText(algorithm, "Algorithm required");
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the user to specify a resource which will act as a seed for the {@link SecureRandom}
|
||||
* instance. Specifically, the resource will be read into an {@link InputStream} and those
|
||||
* bytes presented to the {@link SecureRandom#setSeed(byte[])} method. Note that this will
|
||||
* simply supplement, rather than replace, the existing seed. As such, it is always safe to
|
||||
* set a seed using this method (it never reduces randomness).
|
||||
*
|
||||
* @param seed to use, or <code>null</code> if no additional seeding is needed
|
||||
*/
|
||||
public void setSeed(Resource seed) {
|
||||
this.seed = seed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.springframework.security.token;
|
||||
|
||||
|
||||
/**
|
||||
* A token issued by {@link TokenService}.
|
||||
*
|
||||
* <p>
|
||||
* It is important that the keys assigned to tokens are sufficiently randomised and secured that
|
||||
* they can serve as identifying a unique user session. Implementations of {@link TokenService}
|
||||
* are free to use encryption or encoding strategies of their choice. It is strongly recommended that
|
||||
* keys are of sufficient length to balance safety against persistence cost. In relation to persistence
|
||||
* cost, it is strongly recommended that returned keys are small enough for encoding in a cookie.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public interface Token {
|
||||
|
||||
/**
|
||||
* Obtains the randomised, secure key assigned to this token. Presentation of this token to
|
||||
* {@link TokenService} will always return a <code>Token</code> that is equal to the original
|
||||
* <code>Token</code> issued for that key.
|
||||
*
|
||||
* @return a key with appropriate randomness and security.
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* The time the token key was initially created is available from this method. Note that a given
|
||||
* token must never have this creation time changed. If necessary, a new token can be
|
||||
* requested from the {@link TokenService} to replace the original token.
|
||||
*
|
||||
* @return the time this token key was created, in the same format as specified by {@link Date#getTime()).
|
||||
*/
|
||||
long getKeyCreationTime();
|
||||
|
||||
/**
|
||||
* Obtains the extended information associated within the token, which was presented when the token
|
||||
* was first created.
|
||||
*
|
||||
* @return the user-specified extended information, if any
|
||||
*/
|
||||
String getExtendedInformation();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.springframework.security.token;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a mechanism to allocate and rebuild secure, randomised tokens.
|
||||
*
|
||||
* <p>
|
||||
* Implementations are solely concern with issuing a new {@link Token} on demand. The
|
||||
* issued <code>Token</code> may contain user-specified extended information. The token also
|
||||
* contains a cryptographically strong, byte array-based key. This permits the token to be
|
||||
* used to identify a user session, if desired. The key can subsequently be re-presented
|
||||
* to the <code>TokenService</code> for verification and reconstruction of a <code>Token</code>
|
||||
* equal to the original <code>Token</code>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Given the tightly-focused behaviour provided by this interface, it can serve as a building block
|
||||
* for more sophisticated token-based solutions. For example, authentication systems that depend on
|
||||
* stateless session keys. These could, for instance, place the username inside the user-specified
|
||||
* extended information associated with the key). It is important to recognise that we do not intend
|
||||
* for this interface to be expanded to provide such capabilities directly.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.1
|
||||
*
|
||||
*/
|
||||
public interface TokenService {
|
||||
/**
|
||||
* Forces the allocation of a new {@link Token}.
|
||||
*
|
||||
* @param the extended information desired in the token (cannot be <code>null</code>, but can be empty)
|
||||
* @return a new token that has not been issued previously, and is guaranteed to be recognised
|
||||
* by this implementation's {@link #verifyToken(String)} at any future time.
|
||||
*/
|
||||
Token allocateToken(String extendedInformation);
|
||||
|
||||
/**
|
||||
* Permits verification the <{@link Token#getKey()} was issued by this <code>TokenService</code> and
|
||||
* reconstructs the corresponding <code>Token</code>.
|
||||
*
|
||||
* @param key as obtained from {@link Token#getKey()} and created by this implementation
|
||||
* @return the token, or <code>null</code> if the token was not issued by this <code>TokenService</code>
|
||||
*/
|
||||
Token verifyToken(String key);
|
||||
}
|
||||
@@ -21,7 +21,9 @@ import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
import org.springframework.security.util.RedirectUtils;
|
||||
import org.springframework.security.util.SessionUtils;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
|
||||
import org.springframework.security.concurrent.SessionRegistry;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.event.authentication.InteractiveAuthenticationSuccessEvent;
|
||||
@@ -43,10 +45,6 @@ import org.springframework.util.Assert;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -210,13 +208,18 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
private boolean allowSessionCreation = true;
|
||||
|
||||
private boolean serverSideRedirect = false;
|
||||
|
||||
private SessionRegistry sessionRegistry;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
|
||||
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");
|
||||
@@ -355,7 +358,7 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
}
|
||||
|
||||
if (invalidateSessionOnSuccessfulAuthentication) {
|
||||
SessionUtils.startNewSessionIfRequired(request, migrateInvalidatedSessionAttributes, null);
|
||||
SessionUtils.startNewSessionIfRequired(request, migrateInvalidatedSessionAttributes, sessionRegistry);
|
||||
}
|
||||
|
||||
String targetUrl = determineTargetUrl(request);
|
||||
@@ -567,5 +570,13 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
*/
|
||||
public void setServerSideRedirect(boolean serverSideRedirect) {
|
||||
this.serverSideRedirect = serverSideRedirect;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The session registry needs to be set if session fixation attack protection is in use (and concurrent
|
||||
* session control is enabled).
|
||||
*/
|
||||
public void setSessionRegistry(SessionRegistry sessionRegistry) {
|
||||
this.sessionRegistry = sessionRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void handle(ServletRequest request, ServletResponse response, AccessDeniedException accessDeniedException)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
if (errorPage != null) {
|
||||
// Put exception into request scope (perhaps of use to a view)
|
||||
((HttpServletRequest) request).setAttribute(SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY,
|
||||
@@ -80,7 +80,7 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
|
||||
*/
|
||||
public void setErrorPage(String errorPage) {
|
||||
if ((errorPage != null) && !errorPage.startsWith("/")) {
|
||||
throw new IllegalArgumentException("ErrorPage must begin with '/'");
|
||||
throw new IllegalArgumentException("errorPage must begin with '/'");
|
||||
}
|
||||
|
||||
this.errorPage = errorPage;
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class AuthenticationDetailsSourceImpl implements AuthenticationDetailsSou
|
||||
Constructor constructor = null;
|
||||
for (int i = 0; i < constructors.length; i++) {
|
||||
Class[] parameterTypes = constructors[i].getParameterTypes();
|
||||
if (parameterTypes.length == 1 && (object == null || parameterTypes[i].isInstance(object))) {
|
||||
if (parameterTypes.length == 1 && (object == null || parameterTypes[0].isInstance(object))) {
|
||||
constructor = constructors[i];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,7 @@ public abstract class FilterChainOrder {
|
||||
|
||||
public static final int CHANNEL_FILTER = FILTER_CHAIN_FIRST;
|
||||
public static final int CONCURRENT_SESSION_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int HTTP_SESSION_CONTEXT_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int SESSION_FIXATION_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int HTTP_SESSION_CONTEXT_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int LOGOUT_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int X509_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int PRE_AUTH_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
@@ -37,6 +36,7 @@ public abstract class FilterChainOrder {
|
||||
public static final int ANONYMOUS_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int EXCEPTION_TRANSLATION_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int NTLM_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int SESSION_FIXATION_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int FILTER_SECURITY_INTERCEPTOR = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
public static final int SWITCH_USER_FILTER = FILTER_CHAIN_FIRST + INTERVAL * i++;
|
||||
|
||||
@@ -46,7 +46,6 @@ public abstract class FilterChainOrder {
|
||||
filterNameToOrder.put("FIRST", new Integer(Integer.MIN_VALUE));
|
||||
filterNameToOrder.put("CHANNEL_FILTER", new Integer(CHANNEL_FILTER));
|
||||
filterNameToOrder.put("CONCURRENT_SESSION_FILTER", new Integer(CONCURRENT_SESSION_FILTER));
|
||||
filterNameToOrder.put("SESSION_CONTEXT_INTEGRATION_FILTER", new Integer(HTTP_SESSION_CONTEXT_FILTER));
|
||||
filterNameToOrder.put("LOGOUT_FILTER", new Integer(LOGOUT_FILTER));
|
||||
filterNameToOrder.put("X509_FILTER", new Integer(X509_FILTER));
|
||||
filterNameToOrder.put("PRE_AUTH_FILTER", new Integer(PRE_AUTH_FILTER));
|
||||
@@ -59,6 +58,7 @@ public abstract class FilterChainOrder {
|
||||
filterNameToOrder.put("ANONYMOUS_FILTER", new Integer(ANONYMOUS_FILTER));
|
||||
filterNameToOrder.put("EXCEPTION_TRANSLATION_FILTER", new Integer(EXCEPTION_TRANSLATION_FILTER));
|
||||
filterNameToOrder.put("NTLM_FILTER", new Integer(NTLM_FILTER));
|
||||
filterNameToOrder.put("SESSION_CONTEXT_INTEGRATION_FILTER", new Integer(HTTP_SESSION_CONTEXT_FILTER));
|
||||
filterNameToOrder.put("FILTER_SECURITY_INTERCEPTOR", new Integer(FILTER_SECURITY_INTERCEPTOR));
|
||||
filterNameToOrder.put("SWITCH_USER_FILTER", new Integer(SWITCH_USER_FILTER));
|
||||
filterNameToOrder.put("LAST", new Integer(Integer.MAX_VALUE));
|
||||
|
||||
+20
-97
@@ -6,24 +6,23 @@ import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationTrustResolver;
|
||||
import org.springframework.security.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.concurrent.SessionRegistry;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.context.SecurityContext;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.SessionUtils;
|
||||
|
||||
/**
|
||||
* Detects that a user has been authenticated since the start of the request and starts a new session.
|
||||
* <p>
|
||||
* This is essentially a generalization of the functionality that was implemented for SEC-399. Additionally, it will
|
||||
* update the configured SessionRegistry if one is in use, thus preventing problems when used with Spring Security's
|
||||
* concurrent session control.
|
||||
* <p>
|
||||
* If the response has already been committed when the filter checks the authentication state, then it isn't possible
|
||||
* to create a new session and the filter will print a warning to that effect.
|
||||
* This is essentially a generalization of the functionality that was implemented for SEC-399.
|
||||
* Additionally, it will update the configured SessionRegistry if one is in use, thus preventing problems when used
|
||||
* with Spring Security's concurrent session control.
|
||||
*
|
||||
* @author Martin Algesten
|
||||
* @author Luke Taylor
|
||||
@@ -55,22 +54,17 @@ public class SessionFixationProtectionFilter extends SpringSecurityFilter {
|
||||
}
|
||||
|
||||
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
|
||||
|
||||
if (isAuthenticated()) {
|
||||
// We don't have to worry about session fixation attack if already authenticated
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
SecurityContext sessionSecurityContext =
|
||||
(SecurityContext) session.getAttribute(HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY);
|
||||
|
||||
SessionFixationProtectionResponseWrapper wrapper =
|
||||
new SessionFixationProtectionResponseWrapper(response, request);
|
||||
try {
|
||||
chain.doFilter(request, wrapper);
|
||||
} finally {
|
||||
if (!wrapper.isNewSessionStarted()) {
|
||||
startNewSessionIfRequired(request, response);
|
||||
}
|
||||
if (sessionSecurityContext == null && isAuthenticated()) {
|
||||
// The user has been authenticated during the current request, so do the session migration
|
||||
startNewSessionIfRequired(request, response);
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private boolean isAuthenticated() {
|
||||
@@ -92,83 +86,12 @@ public class SessionFixationProtectionFilter extends SpringSecurityFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the an initially unauthenticated request completes or a redirect or sendError occurs.
|
||||
* Called when the a user wasn't authenticated at the start of the request but has been during it
|
||||
* <p>
|
||||
* If the user is now authenticated, a new session will be created, the session attributes copied to it (if
|
||||
* <tt>migrateSessionAttributes</tt> is set and the sessionRegistry updated with the new session information.
|
||||
* A new session will be created, the session attributes copied to it (if
|
||||
* <tt>migrateSessionAttributes</tt> is set) and the sessionRegistry updated with the new session information.
|
||||
*/
|
||||
protected void startNewSessionIfRequired(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (isAuthenticated()) {
|
||||
if (request.getSession(false) != null && response.isCommitted()) {
|
||||
logger.warn("Response is already committed. Unable to create new session.");
|
||||
}
|
||||
|
||||
SessionUtils.startNewSessionIfRequired(request, migrateSessionAttributes, sessionRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Response wrapper to handle the situation where we need to migrate the session after a redirect or sendError.
|
||||
* Similar in function to Martin Algesten's OnRedirectUpdateSessionResponseWrapper used in
|
||||
* HttpSessionContextIntegrationFilter.
|
||||
* <p>
|
||||
* Only used to wrap the response if the conditions are right at the start of the request to potentially
|
||||
* require starting a new session, i.e. that the user isn't authenticated and a session existed to begin with.
|
||||
*/
|
||||
class SessionFixationProtectionResponseWrapper extends HttpServletResponseWrapper {
|
||||
private HttpServletRequest request;
|
||||
private boolean newSessionStarted;
|
||||
|
||||
SessionFixationProtectionResponseWrapper(HttpServletResponse response, HttpServletRequest request) {
|
||||
super(response);
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure a new session is created before calling the
|
||||
* superclass <code>sendError()</code>
|
||||
*/
|
||||
public void sendError(int sc) throws IOException {
|
||||
startNewSession();
|
||||
super.sendError(sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure a new session is created before calling the
|
||||
* superclass <code>sendError()</code>
|
||||
*/
|
||||
public void sendError(int sc, String msg) throws IOException {
|
||||
startNewSession();
|
||||
super.sendError(sc, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure a new session is created before calling the
|
||||
* superclass <code>sendRedirect()</code>
|
||||
*/
|
||||
public void sendRedirect(String location) throws IOException {
|
||||
startNewSession();
|
||||
super.sendRedirect(location);
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
startNewSession();
|
||||
super.flushBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls <code>startNewSessionIfRequired()</code>
|
||||
*/
|
||||
private void startNewSession() {
|
||||
if (newSessionStarted) {
|
||||
return;
|
||||
}
|
||||
startNewSessionIfRequired(request, this);
|
||||
newSessionStarted = true;
|
||||
}
|
||||
|
||||
boolean isNewSessionStarted() {
|
||||
return newSessionStarted;
|
||||
}
|
||||
protected void startNewSessionIfRequired(HttpServletRequest request, HttpServletResponse response) {
|
||||
SessionUtils.startNewSessionIfRequired(request, migrateSessionAttributes, sessionRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,6 @@ public abstract class SpringSecurityFilter implements Filter, Ordered {
|
||||
protected abstract void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException;
|
||||
|
||||
public String toString() {
|
||||
return getClass() + "[ order=" + getOrder() + "; ]";
|
||||
return getClass().getName() + "[ order=" + getOrder() + "; ]";
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import org.springframework.security.ui.savedrequest.SavedRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation for {@link TargetUrlResolver}
|
||||
* <p>
|
||||
@@ -46,11 +47,10 @@ public class TargetUrlResolverImpl implements TargetUrlResolver {
|
||||
/**
|
||||
* If <code>true</code>, will only use <code>SavedRequest</code> to determine the target URL on successful
|
||||
* authentication if the request that caused the authentication request was a GET.
|
||||
* It will return null for a POST/PUT request.
|
||||
* In most cases it's meaningless to redirect to a URL generated by a POST/PUT request.
|
||||
* Defaults to true.
|
||||
* It will then return null for a POST/PUT request.
|
||||
* Defaults to false.
|
||||
*/
|
||||
private boolean justUseSavedRequestOnGet = true;
|
||||
private boolean justUseSavedRequestOnGet = false;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.acegisecurity.ui.TargetUrlResolver#determineTargetUrl(org.acegisecurity.ui.savedrequest.SavedRequest, javax.servlet.http.HttpServletRequest, org.acegisecurity.Authentication)
|
||||
|
||||
+14
-4
@@ -93,6 +93,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
private AuthenticationManager authenticationManager;
|
||||
private RememberMeServices rememberMeServices;
|
||||
private boolean ignoreFailure = false;
|
||||
private String credentialsCharset = "UTF-8";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -114,8 +115,8 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
}
|
||||
|
||||
if ((header != null) && header.startsWith("Basic ")) {
|
||||
String base64Token = header.substring(6);
|
||||
String token = new String(Base64.decodeBase64(base64Token.getBytes()));
|
||||
byte[] base64Token = header.substring(6).getBytes("UTF-8");
|
||||
String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(httpRequest));
|
||||
|
||||
String username = "";
|
||||
String password = "";
|
||||
@@ -172,7 +173,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
}
|
||||
|
||||
private boolean authenticationIsRequired(String username) {
|
||||
private boolean authenticationIsRequired(String username) {
|
||||
// Only reauthenticate if username doesn't match SecurityContextHolder and user isn't authenticated
|
||||
// (see SEC-53)
|
||||
Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
|
||||
@@ -235,7 +236,16 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
public void setCredentialsCharset(String credentialsCharset) {
|
||||
Assert.hasText(credentialsCharset, "credentialsCharset cannot be null or empty");
|
||||
this.credentialsCharset = credentialsCharset;
|
||||
}
|
||||
|
||||
protected String getCredentialsCharset(HttpServletRequest httpRequest) {
|
||||
return credentialsCharset;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return FilterChainOrder.BASIC_PROCESSING_FILTER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ui.SpringSecurityFilter;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.security.util.RedirectUtils;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -58,6 +59,7 @@ public class LogoutFilter extends SpringSecurityFilter {
|
||||
public LogoutFilter(String logoutSuccessUrl, LogoutHandler[] handlers) {
|
||||
Assert.notEmpty(handlers, "LogoutHandlers are required");
|
||||
this.logoutSuccessUrl = logoutSuccessUrl;
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(logoutSuccessUrl), logoutSuccessUrl + " isn't a valid redirect URL");
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
@@ -130,7 +132,7 @@ public class LogoutFilter extends SpringSecurityFilter {
|
||||
String targetUrl = request.getParameter("logoutSuccessUrl");
|
||||
|
||||
if(!StringUtils.hasLength(targetUrl)) {
|
||||
targetUrl = logoutSuccessUrl;
|
||||
targetUrl = getLogoutSuccessUrl();
|
||||
}
|
||||
|
||||
if (!StringUtils.hasLength(targetUrl)) {
|
||||
@@ -161,9 +163,14 @@ public class LogoutFilter extends SpringSecurityFilter {
|
||||
|
||||
public void setFilterProcessesUrl(String filterProcessesUrl) {
|
||||
Assert.hasText(filterProcessesUrl, "FilterProcessesUrl required");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
|
||||
this.filterProcessesUrl = filterProcessesUrl;
|
||||
}
|
||||
|
||||
protected String getLogoutSuccessUrl() {
|
||||
return logoutSuccessUrl;
|
||||
}
|
||||
|
||||
protected String getFilterProcessesUrl() {
|
||||
return filterProcessesUrl;
|
||||
}
|
||||
|
||||
+163
-152
@@ -24,171 +24,182 @@ import org.apache.commons.logging.LogFactory;
|
||||
* @since 2.0
|
||||
*/
|
||||
final class WASSecurityHelper {
|
||||
private static final Log logger = LogFactory.getLog(WASSecurityHelper.class);
|
||||
private static final Log logger = LogFactory.getLog(WASSecurityHelper.class);
|
||||
|
||||
private static final String USER_REGISTRY = "UserRegistry";
|
||||
private static final String USER_REGISTRY = "UserRegistry";
|
||||
|
||||
private static Method getRunAsSubject = null;
|
||||
private static Method getRunAsSubject = null;
|
||||
|
||||
private static Method getWSCredentialFromSubject = null;
|
||||
private static Method getGroupsForUser = null;
|
||||
|
||||
private static Method getGroupsForUser = null;
|
||||
private static Method getSecurityName = null;
|
||||
|
||||
private static Method getSecurityName = null;
|
||||
// SEC-803
|
||||
private static Class wsCredentialClass = null;
|
||||
|
||||
/**
|
||||
* Get the security name for the given subject.
|
||||
*
|
||||
* @param subject
|
||||
* The subject for which to retrieve the security name
|
||||
* @return String the security name for the given subject
|
||||
*/
|
||||
private static final String getSecurityName(final Subject subject) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Determining Websphere security name for subject " + subject);
|
||||
}
|
||||
String userSecurityName = null;
|
||||
if (subject != null) {
|
||||
// SEC-803
|
||||
Object credential = subject.getPublicCredentials(getWSCredentialClass()).iterator().next();
|
||||
if (credential != null) {
|
||||
userSecurityName = (String)invokeMethod(getSecurityNameMethod(),credential,null);
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Websphere security name is " + userSecurityName + " for subject " + subject);
|
||||
}
|
||||
return userSecurityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security name for the given subject.
|
||||
*
|
||||
* @param subject
|
||||
* The subject for which to retrieve the security name
|
||||
* @return String the security name for the given subject
|
||||
*/
|
||||
private static final String getSecurityName(final Subject subject) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Determining Websphere security name for subject " + subject);
|
||||
}
|
||||
String userSecurityName = null;
|
||||
if (subject != null) {
|
||||
Object credential = invokeMethod(getWSCredentialFromSubjectMethod(),null,new Object[]{subject});
|
||||
if (credential != null) {
|
||||
userSecurityName = (String)invokeMethod(getSecurityNameMethod(),credential,null);
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Websphere security name is " + userSecurityName + " for subject " + subject);
|
||||
}
|
||||
return userSecurityName;
|
||||
}
|
||||
/**
|
||||
* Get the current RunAs subject.
|
||||
*
|
||||
* @return Subject the current RunAs subject
|
||||
*/
|
||||
private static final Subject getRunAsSubject() {
|
||||
logger.debug("Retrieving WebSphere RunAs subject");
|
||||
// get Subject: WSSubject.getCallerSubject ();
|
||||
return (Subject) invokeMethod(getRunAsSubjectMethod(), null, new Object[] {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current RunAs subject.
|
||||
*
|
||||
* @return Subject the current RunAs subject
|
||||
*/
|
||||
private static final Subject getRunAsSubject() {
|
||||
logger.debug("Retrieving WebSphere RunAs subject");
|
||||
// get Subject: WSSubject.getCallerSubject ();
|
||||
return (Subject) invokeMethod(getRunAsSubjectMethod(), null, new Object[] {});
|
||||
}
|
||||
/**
|
||||
* Get the WebSphere group names for the given subject.
|
||||
*
|
||||
* @param subject
|
||||
* The subject for which to retrieve the WebSphere group names
|
||||
* @return the WebSphere group names for the given subject
|
||||
*/
|
||||
private static final String[] getWebSphereGroups(final Subject subject) {
|
||||
return getWebSphereGroups(getSecurityName(subject));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WebSphere group names for the given subject.
|
||||
*
|
||||
* @param subject
|
||||
* The subject for which to retrieve the WebSphere group names
|
||||
* @return the WebSphere group names for the given subject
|
||||
*/
|
||||
private static final String[] getWebSphereGroups(final Subject subject) {
|
||||
return getWebSphereGroups(getSecurityName(subject));
|
||||
}
|
||||
/**
|
||||
* Get the WebSphere group names for the given security name.
|
||||
*
|
||||
* @param securityName
|
||||
* The securityname for which to retrieve the WebSphere group names
|
||||
* @return the WebSphere group names for the given security name
|
||||
*/
|
||||
private static final String[] getWebSphereGroups(final String securityName) {
|
||||
Context ic = null;
|
||||
try {
|
||||
// TODO: Cache UserRegistry object
|
||||
ic = new InitialContext();
|
||||
Object objRef = ic.lookup(USER_REGISTRY);
|
||||
Object userReg = PortableRemoteObject.narrow(objRef, Class.forName ("com.ibm.websphere.security.UserRegistry"));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Determining WebSphere groups for user " + securityName + " using WebSphere UserRegistry " + userReg);
|
||||
}
|
||||
final Collection groups = (Collection) invokeMethod(getGroupsForUserMethod(), userReg, new Object[]{ securityName });
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Groups for user " + securityName + ": " + groups.toString());
|
||||
}
|
||||
String[] result = new String[groups.size()];
|
||||
return (String[]) groups.toArray(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("Exception occured while looking up groups for user", e);
|
||||
throw new RuntimeException("Exception occured while looking up groups for user", e);
|
||||
} finally {
|
||||
try {
|
||||
ic.close();
|
||||
} catch (NamingException e) {
|
||||
logger.debug("Exception occured while closing context", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WebSphere group names for the given security name.
|
||||
*
|
||||
* @param securityName
|
||||
* The securityname for which to retrieve the WebSphere group names
|
||||
* @return the WebSphere group names for the given security name
|
||||
*/
|
||||
private static final String[] getWebSphereGroups(final String securityName) {
|
||||
Context ic = null;
|
||||
try {
|
||||
// TODO: Cache UserRegistry object
|
||||
ic = new InitialContext();
|
||||
Object objRef = ic.lookup(USER_REGISTRY);
|
||||
Object userReg = PortableRemoteObject.narrow(objRef, Class.forName ("com.ibm.websphere.security.UserRegistry"));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Determining WebSphere groups for user " + securityName + " using WebSphere UserRegistry " + userReg);
|
||||
}
|
||||
final Collection groups = (Collection) invokeMethod(getGroupsForUserMethod(), userReg, new Object[]{ securityName });
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Groups for user " + securityName + ": " + groups.toString());
|
||||
}
|
||||
String[] result = new String[groups.size()];
|
||||
return (String[]) groups.toArray(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("Exception occured while looking up groups for user", e);
|
||||
throw new RuntimeException("Exception occured while looking up groups for user", e);
|
||||
} finally {
|
||||
try {
|
||||
ic.close();
|
||||
} catch (NamingException e) {
|
||||
logger.debug("Exception occured while closing context", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public static final String[] getGroupsForCurrentUser() {
|
||||
return getWebSphereGroups(getRunAsSubject());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public static final String[] getGroupsForCurrentUser() {
|
||||
return getWebSphereGroups(getRunAsSubject());
|
||||
}
|
||||
public static final String getCurrentUserName() {
|
||||
return getSecurityName(getRunAsSubject());
|
||||
}
|
||||
|
||||
private static final Object invokeMethod(Method method, Object instance, Object[] args)
|
||||
{
|
||||
try {
|
||||
return method.invoke(instance,args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.error("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+ Arrays.asList(args)+")",e);
|
||||
throw new RuntimeException("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.error("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
throw new RuntimeException("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
} catch (InvocationTargetException e) {
|
||||
logger.error("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
throw new RuntimeException("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String getCurrentUserName() {
|
||||
return getSecurityName(getRunAsSubject());
|
||||
}
|
||||
|
||||
private static final Object invokeMethod(Method method, Object instance, Object[] args)
|
||||
{
|
||||
try {
|
||||
return method.invoke(instance,args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.error("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+ Arrays.asList(args)+")",e);
|
||||
throw new RuntimeException("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.error("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
throw new RuntimeException("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
} catch (InvocationTargetException e) {
|
||||
logger.error("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
throw new RuntimeException("Error while invoking method "+method.getClass().getName()+"."+method.getName()+"("+Arrays.asList(args)+")",e);
|
||||
}
|
||||
}
|
||||
private static final Method getMethod(String className, String methodName, String[] parameterTypeNames) {
|
||||
try {
|
||||
Class c = Class.forName(className);
|
||||
final int len = parameterTypeNames.length;
|
||||
Class[] parameterTypes = new Class[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
parameterTypes[i] = Class.forName(parameterTypeNames[i]);
|
||||
}
|
||||
return c.getDeclaredMethod(methodName, parameterTypes);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("Required class"+className+" not found");
|
||||
throw new RuntimeException("Required class"+className+" not found",e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
logger.error("Required method "+methodName+" with parameter types ("+ Arrays.asList(parameterTypeNames) +") not found on class "+className);
|
||||
throw new RuntimeException("Required class"+className+" not found",e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Method getMethod(String className, String methodName, String[] parameterTypeNames) {
|
||||
try {
|
||||
Class c = Class.forName(className);
|
||||
final int len = parameterTypeNames.length;
|
||||
Class[] parameterTypes = new Class[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
parameterTypes[i] = Class.forName(parameterTypeNames[i]);
|
||||
}
|
||||
return c.getDeclaredMethod(methodName, parameterTypes);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("Required class"+className+" not found");
|
||||
throw new RuntimeException("Required class"+className+" not found",e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
logger.error("Required method "+methodName+" with parameter types ("+ Arrays.asList(parameterTypeNames) +") not found on class "+className);
|
||||
throw new RuntimeException("Required class"+className+" not found",e);
|
||||
}
|
||||
}
|
||||
private static final Method getRunAsSubjectMethod() {
|
||||
if (getRunAsSubject == null) {
|
||||
getRunAsSubject = getMethod("com.ibm.websphere.security.auth.WSSubject", "getRunAsSubject", new String[] {});
|
||||
}
|
||||
return getRunAsSubject;
|
||||
}
|
||||
|
||||
private static final Method getRunAsSubjectMethod() {
|
||||
if (getRunAsSubject == null) {
|
||||
getRunAsSubject = getMethod("com.ibm.websphere.security.auth.WSSubject", "getRunAsSubject", new String[] {});
|
||||
}
|
||||
return getRunAsSubject;
|
||||
}
|
||||
private static final Method getGroupsForUserMethod() {
|
||||
if (getGroupsForUser == null) {
|
||||
getGroupsForUser = getMethod("com.ibm.websphere.security.UserRegistry", "getGroupsForUser", new String[] { "java.lang.String" });
|
||||
}
|
||||
return getGroupsForUser;
|
||||
}
|
||||
|
||||
private static final Method getWSCredentialFromSubjectMethod() {
|
||||
if (getWSCredentialFromSubject == null) {
|
||||
getWSCredentialFromSubject = getMethod("com.ibm.ws.security.auth.SubjectHelper", "getWSCredentialFromSubject",
|
||||
new String[] { "javax.security.auth.Subject" });
|
||||
}
|
||||
return getWSCredentialFromSubject;
|
||||
}
|
||||
|
||||
private static final Method getGroupsForUserMethod() {
|
||||
if (getGroupsForUser == null) {
|
||||
getGroupsForUser = getMethod("com.ibm.websphere.security.UserRegistry", "getGroupsForUser", new String[] { "java.lang.String" });
|
||||
}
|
||||
return getGroupsForUser;
|
||||
}
|
||||
|
||||
private static final Method getSecurityNameMethod() {
|
||||
if (getSecurityName == null) {
|
||||
getSecurityName = getMethod("com.ibm.websphere.security.cred.WSCredential", "getSecurityName", new String[] {});
|
||||
}
|
||||
return getSecurityName;
|
||||
}
|
||||
private static final Method getSecurityNameMethod() {
|
||||
if (getSecurityName == null) {
|
||||
getSecurityName = getMethod("com.ibm.websphere.security.cred.WSCredential", "getSecurityName", new String[] {});
|
||||
}
|
||||
return getSecurityName;
|
||||
}
|
||||
|
||||
// SEC-803
|
||||
private static final Class getWSCredentialClass() {
|
||||
if (wsCredentialClass == null) {
|
||||
wsCredentialClass = getClass("com.ibm.websphere.security.cred.WSCredential");
|
||||
}
|
||||
return wsCredentialClass;
|
||||
}
|
||||
|
||||
private static final Class getClass(String className) {
|
||||
try {
|
||||
return Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("Required class " + className + " not found");
|
||||
throw new RuntimeException("Required class " + className + " not found",e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
package org.springframework.security.ui.preauth.websphere;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -68,8 +69,8 @@ public class WebSpherePreAuthenticatedAuthenticationDetailsSource extends Authen
|
||||
String[] webSphereGroups = WASSecurityHelper.getGroupsForCurrentUser();
|
||||
GrantedAuthority[] userGas = webSphereGroups2GrantedAuthoritiesMapper.getGrantedAuthorities(webSphereGroups);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("WebSphere groups [" + ArrayUtils.toString(webSphereGroups) + "] mapped to Granted Authorities: ["
|
||||
+ ArrayUtils.toString(userGas) + "]");
|
||||
LOG.debug("WebSphere groups: " + Arrays.asList(webSphereGroups) + " mapped to Granted Authorities: "
|
||||
+ Arrays.asList(userGas));
|
||||
}
|
||||
return userGas;
|
||||
}
|
||||
|
||||
+13
@@ -313,7 +313,14 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
this.alwaysRemember = alwaysRemember;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@@ -326,6 +333,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
Assert.notNull(userDetailsService, "UserDetailsService canot be null");
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@@ -348,4 +356,9 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
protected AuthenticationDetailsSource getAuthenticationDetailsSource() {
|
||||
return authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource cannot be null");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -152,7 +152,7 @@ public class TokenBasedRememberMeServices extends AbstractRememberMeServices {
|
||||
}
|
||||
|
||||
int tokenLifetime = calculateLoginLifetime(request, successfulAuthentication);
|
||||
long expiryTime = System.currentTimeMillis() + 1000*tokenLifetime;
|
||||
long expiryTime = System.currentTimeMillis() + 1000L*tokenLifetime;
|
||||
|
||||
String signatureValue = makeTokenSignature(expiryTime, username, password);
|
||||
|
||||
|
||||
+2
-1
@@ -22,6 +22,7 @@ import org.springframework.security.providers.UsernamePasswordAuthenticationToke
|
||||
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.security.util.TextUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -72,7 +73,7 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
|
||||
HttpSession session = request.getSession(false);
|
||||
|
||||
if (session != null || getAllowSessionCreation()) {
|
||||
request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, username);
|
||||
request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextUtils.escapeEntities(username));
|
||||
}
|
||||
|
||||
// Allow subclasses to set the "details" property
|
||||
|
||||
+6
-3
@@ -23,6 +23,7 @@ import org.springframework.security.ui.rememberme.AbstractRememberMeServices;
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DefaultLoginPageGeneratingFilter extends SpringSecurityFilter {
|
||||
public static final String DEFAULT_LOGIN_PAGE_URL = "/spring_security_login";
|
||||
@@ -71,11 +72,13 @@ public class DefaultLoginPageGeneratingFilter extends SpringSecurityFilter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
if (isLoginUrlRequest(request)) {
|
||||
response.getOutputStream().print(generateLoginPageHtml(request));
|
||||
String loginPageHtml = generateLoginPageHtml(request);
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
response.setContentLength(loginPageHtml.length());
|
||||
response.getOutputStream().print(loginPageHtml);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
* references a set of the reachable lower roles.
|
||||
*/
|
||||
private void buildRolesReachableInOneStepMap() {
|
||||
String parsingRegex = "(\\s*(\\w+)\\s*\\>\\s*(\\w+))";
|
||||
String parsingRegex = "(\\s*([^\\s>]+)\\s*\\>\\s*([^\\s>]+))";
|
||||
Pattern pattern = Pattern.compile(parsingRegex);
|
||||
|
||||
Matcher roleHierarchyMatcher = pattern.matcher(roleHierarchyStringRepresentation);
|
||||
|
||||
+107
-282
@@ -15,19 +15,17 @@ import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsManager;
|
||||
import org.springframework.security.userdetails.GroupManager;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.object.MappingSqlQuery;
|
||||
import org.springframework.jdbc.object.SqlQuery;
|
||||
import org.springframework.jdbc.object.SqlUpdate;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -116,28 +114,6 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
private String groupAuthoritiesSql = DEF_GROUP_AUTHORITIES_QUERY_SQL;
|
||||
private String deleteGroupAuthoritySql = DEF_DELETE_GROUP_AUTHORITY_SQL;
|
||||
|
||||
private SqlUpdate insertUser;
|
||||
private SqlUpdate deleteUser;
|
||||
private SqlUpdate updateUser;
|
||||
private SqlUpdate insertAuthority;
|
||||
private SqlUpdate deleteUserAuthorities;
|
||||
private SqlQuery userExistsQuery;
|
||||
private SqlUpdate changePassword;
|
||||
|
||||
private SqlQuery findAllGroupsQuery;
|
||||
private SqlQuery findUsersInGroupQuery;
|
||||
private SqlUpdate insertGroup;
|
||||
private SqlQuery findGroupIdQuery;
|
||||
private SqlUpdate insertGroupAuthority;
|
||||
private SqlUpdate deleteGroup;
|
||||
private SqlUpdate deleteGroupMembers;
|
||||
private SqlUpdate deleteGroupAuthorities;
|
||||
private SqlUpdate renameGroup;
|
||||
private SqlUpdate insertGroupMember;
|
||||
private SqlUpdate deleteGroupMember;
|
||||
private SqlQuery groupAuthoritiesQuery;
|
||||
private SqlUpdate deleteGroupAuthority;
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
private UserCache userCache = new NullUserCache();
|
||||
@@ -150,43 +126,36 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
"not be performed.");
|
||||
}
|
||||
|
||||
insertUser = new InsertUser(getDataSource());
|
||||
deleteUser = new DeleteUser(getDataSource());
|
||||
updateUser = new UpdateUser(getDataSource());
|
||||
insertAuthority = new InsertAuthority(getDataSource());
|
||||
deleteUserAuthorities = new DeleteUserAuthorities(getDataSource());
|
||||
userExistsQuery = new UserExistsQuery(getDataSource());
|
||||
changePassword = new ChangePassword(getDataSource());
|
||||
|
||||
findAllGroupsQuery = new AllGroupsQuery(getDataSource());
|
||||
findUsersInGroupQuery = new GroupMembersQuery(getDataSource());
|
||||
insertGroup = new InsertGroup(getDataSource());
|
||||
findGroupIdQuery = new FindGroupIdQuery(getDataSource());
|
||||
insertGroupAuthority = new InsertGroupAuthority(getDataSource());
|
||||
deleteGroup = new DeleteGroup(getDataSource());
|
||||
deleteGroupAuthorities = new DeleteGroupAuthorities(getDataSource());
|
||||
deleteGroupMembers = new DeleteGroupMembers(getDataSource());
|
||||
renameGroup = new RenameGroup(getDataSource());
|
||||
insertGroupMember = new InsertGroupMember(getDataSource());
|
||||
deleteGroupMember = new DeleteGroupMember (getDataSource());
|
||||
groupAuthoritiesQuery = new GroupAuthoritiesByGroupNameMapping(getDataSource());
|
||||
deleteGroupAuthority = new DeleteGroupAuthority(getDataSource());
|
||||
|
||||
super.initDao();
|
||||
}
|
||||
|
||||
//~ UserDetailsManager implementation ==============================================================================
|
||||
|
||||
public void createUser(UserDetails user) {
|
||||
public void createUser(final UserDetails user) {
|
||||
validateUserDetails(user);
|
||||
insertUser.update(new Object[] {user.getUsername(), user.getPassword(), Boolean.valueOf(user.isEnabled())});
|
||||
getJdbcTemplate().update(createUserSql, new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, user.getUsername());
|
||||
ps.setString(2, user.getPassword());
|
||||
ps.setBoolean(3, user.isEnabled());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
insertUserAuthorities(user);
|
||||
}
|
||||
|
||||
public void updateUser(UserDetails user) {
|
||||
public void updateUser(final UserDetails user) {
|
||||
validateUserDetails(user);
|
||||
updateUser.update(new Object[] {user.getPassword(), Boolean.valueOf(user.isEnabled()), user.getUsername()});
|
||||
deleteUserAuthorities.update(user.getUsername());
|
||||
getJdbcTemplate().update(updateUserSql, new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, user.getPassword());
|
||||
ps.setBoolean(2, user.isEnabled());
|
||||
ps.setString(3, user.getUsername());
|
||||
}
|
||||
});
|
||||
|
||||
deleteUserAuthorities(user.getUsername());
|
||||
insertUserAuthorities(user);
|
||||
|
||||
userCache.removeUserFromCache(user.getUsername());
|
||||
@@ -194,15 +163,20 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
|
||||
private void insertUserAuthorities(UserDetails user) {
|
||||
for (int i=0; i < user.getAuthorities().length; i++) {
|
||||
insertAuthority.update(user.getUsername(), user.getAuthorities()[i].getAuthority());
|
||||
getJdbcTemplate().update(createAuthoritySql,
|
||||
new Object[] {user.getUsername(), user.getAuthorities()[i].getAuthority()});
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteUser(String username) {
|
||||
deleteUserAuthorities.update(username);
|
||||
deleteUser.update(username);
|
||||
deleteUserAuthorities(username);
|
||||
getJdbcTemplate().update(deleteUserSql, new Object[] {username});
|
||||
userCache.removeUserFromCache(username);
|
||||
}
|
||||
|
||||
private void deleteUserAuthorities(String username) {
|
||||
getJdbcTemplate().update(deleteUserAuthoritiesSql, new Object[] {username});
|
||||
}
|
||||
|
||||
public void changePassword(String oldPassword, String newPassword) throws AuthenticationException {
|
||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
|
||||
@@ -226,7 +200,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
|
||||
logger.debug("Changing password for user '"+ username + "'");
|
||||
|
||||
changePassword.update(new String[] {newPassword, username});
|
||||
getJdbcTemplate().update(changePasswordSql, new String[] {newPassword, username});
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(currentUser, newPassword));
|
||||
|
||||
@@ -244,10 +218,10 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
}
|
||||
|
||||
public boolean userExists(String username) {
|
||||
List users = userExistsQuery.execute(username);
|
||||
List users = getJdbcTemplate().queryForList(userExistsSql, new Object[] {username});
|
||||
|
||||
if (users.size() > 1) {
|
||||
throw new IllegalStateException("More than one user found with name '" + username + "'");
|
||||
throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
|
||||
}
|
||||
|
||||
return users.size() == 1;
|
||||
@@ -256,26 +230,33 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
//~ GroupManager implementation ====================================================================================
|
||||
|
||||
public String[] findAllGroups() {
|
||||
return (String[]) findAllGroupsQuery.execute().toArray(new String[0]);
|
||||
return (String[]) getJdbcTemplate().queryForList(findAllGroupsSql, String.class).toArray(new String[0]);
|
||||
}
|
||||
|
||||
public String[] findUsersInGroup(String groupName) {
|
||||
Assert.hasText(groupName);
|
||||
return (String[]) findUsersInGroupQuery.execute(groupName).toArray(new String[0]);
|
||||
return (String[]) getJdbcTemplate().queryForList(findUsersInGroupSql, new String[] {groupName}, String.class).toArray(new String[0]);
|
||||
}
|
||||
|
||||
public void createGroup(String groupName, GrantedAuthority[] authorities) {
|
||||
public void createGroup(final String groupName, final GrantedAuthority[] authorities) {
|
||||
Assert.hasText(groupName);
|
||||
Assert.notNull(authorities);
|
||||
|
||||
logger.debug("Creating new group '" + groupName + "' with authorities " +
|
||||
AuthorityUtils.authorityArrayToSet(authorities));
|
||||
|
||||
insertGroup.update(groupName);
|
||||
Integer id = (Integer) findGroupIdQuery.findObject(groupName);
|
||||
getJdbcTemplate().update(insertGroupSql, new String[] {groupName});
|
||||
|
||||
final int groupId = findGroupId(groupName);
|
||||
|
||||
for (int i=0; i < authorities.length; i++) {
|
||||
insertGroupAuthority.update( new Object[] {id, authorities[i].getAuthority()});
|
||||
final String authority = authorities[i].getAuthority();
|
||||
getJdbcTemplate().update(insertGroupAuthoritySql, new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setInt(1, groupId);
|
||||
ps.setString(2, authority);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,10 +264,15 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
logger.debug("Deleting group '" + groupName + "'");
|
||||
Assert.hasText(groupName);
|
||||
|
||||
int id = ((Integer) findGroupIdQuery.findObject(groupName)).intValue();
|
||||
deleteGroupMembers.update(id);
|
||||
deleteGroupAuthorities.update(id);
|
||||
deleteGroup.update(id);
|
||||
final int id = findGroupId(groupName);
|
||||
PreparedStatementSetter groupIdPSS = new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setInt(1, id);
|
||||
}
|
||||
};
|
||||
getJdbcTemplate().update(deleteGroupMembersSql, groupIdPSS);
|
||||
getJdbcTemplate().update(deleteGroupAuthoritiesSql, groupIdPSS);
|
||||
getJdbcTemplate().update(deleteGroupSql, groupIdPSS);
|
||||
}
|
||||
|
||||
public void renameGroup(String oldName, String newName) {
|
||||
@@ -294,54 +280,90 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
Assert.hasText(oldName);
|
||||
Assert.hasText(newName);
|
||||
|
||||
renameGroup.update(newName, oldName);
|
||||
getJdbcTemplate().update(renameGroupSql, new String[] {newName, oldName});
|
||||
}
|
||||
|
||||
public void addUserToGroup(String username, String groupName) {
|
||||
public void addUserToGroup(final String username, final String groupName) {
|
||||
logger.debug("Adding user '" + username + "' to group '" + groupName + "'");
|
||||
Assert.hasText(username);
|
||||
Assert.hasText(groupName);
|
||||
|
||||
Integer id = (Integer) findGroupIdQuery.findObject(groupName);
|
||||
final int id = findGroupId(groupName);
|
||||
getJdbcTemplate().update(insertGroupMemberSql, new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setInt(1, id);
|
||||
ps.setString(2, username);
|
||||
}
|
||||
});
|
||||
|
||||
insertGroupMember.update(new Object[] {id, username});
|
||||
userCache.removeUserFromCache(username);
|
||||
}
|
||||
|
||||
public void removeUserFromGroup(String username, String groupName) {
|
||||
public void removeUserFromGroup(final String username, final String groupName) {
|
||||
logger.debug("Removing user '" + username + "' to group '" + groupName + "'");
|
||||
Assert.hasText(username);
|
||||
Assert.hasText(groupName);
|
||||
|
||||
Integer id = (Integer) findGroupIdQuery.findObject(groupName);
|
||||
final int id = findGroupId(groupName);
|
||||
|
||||
getJdbcTemplate().update(deleteGroupMemberSql, new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setInt(1, id);
|
||||
ps.setString(2, username);
|
||||
}
|
||||
});
|
||||
|
||||
deleteGroupMember.update(new Object[] {id, username});
|
||||
userCache.removeUserFromCache(username);
|
||||
}
|
||||
|
||||
public GrantedAuthority[] findGroupAuthorities(String groupName) {
|
||||
logger.debug("Loading authorities for group '" + groupName + "'");
|
||||
Assert.hasText(groupName);
|
||||
|
||||
List authorities = getJdbcTemplate().query(groupAuthoritiesSql, new String[] {groupName}, new RowMapper() {
|
||||
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
String roleName = getRolePrefix() + rs.getString(3);
|
||||
GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
|
||||
|
||||
return (GrantedAuthority[]) groupAuthoritiesQuery.execute(groupName).toArray(new GrantedAuthority[0]);
|
||||
return authority;
|
||||
}
|
||||
});
|
||||
|
||||
return (GrantedAuthority[]) authorities.toArray(new GrantedAuthority[0]);
|
||||
}
|
||||
|
||||
public void removeGroupAuthority(String groupName, GrantedAuthority authority) {
|
||||
public void removeGroupAuthority(String groupName, final GrantedAuthority authority) {
|
||||
logger.debug("Removing authority '" + authority + "' from group '" + groupName + "'");
|
||||
Assert.hasText(groupName);
|
||||
Assert.notNull(authority);
|
||||
|
||||
Integer id = (Integer) findGroupIdQuery.findObject(groupName);
|
||||
deleteGroupAuthority.update(new Object[] {id, authority});
|
||||
final int id = findGroupId(groupName);
|
||||
|
||||
getJdbcTemplate().update(deleteGroupAuthoritySql, new PreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setInt(1, id);
|
||||
ps.setString(2, authority.getAuthority());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addGroupAuthority(String groupName, GrantedAuthority authority) {
|
||||
public void addGroupAuthority(final String groupName, final GrantedAuthority authority) {
|
||||
logger.debug("Adding authority '" + authority + "' to group '" + groupName + "'");
|
||||
Assert.hasText(groupName);
|
||||
Assert.notNull(authority);
|
||||
|
||||
Integer id = (Integer) findGroupIdQuery.findObject(groupName);
|
||||
insertGroupAuthority.update(new Object[] {id, authority.getAuthority()});
|
||||
final int id = findGroupId(groupName);
|
||||
getJdbcTemplate().update(insertGroupAuthoritySql, new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setInt(1, id);
|
||||
ps.setString(2, authority.getAuthority());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int findGroupId(String group) {
|
||||
return getJdbcTemplate().queryForInt(findGroupIdSql, new Object[] {group});
|
||||
}
|
||||
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
@@ -411,201 +433,4 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||
Assert.hasText(authorities[i].getAuthority(), "getAuthority() method must return a non-empty string");
|
||||
}
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class InsertUser extends SqlUpdate {
|
||||
|
||||
public InsertUser(DataSource ds) {
|
||||
super(ds, createUserSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
declareParameter(new SqlParameter(Types.BOOLEAN));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteUser extends SqlUpdate {
|
||||
public DeleteUser(DataSource ds) {
|
||||
super(ds, deleteUserSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class InsertAuthority extends SqlUpdate {
|
||||
public InsertAuthority(DataSource ds) {
|
||||
super(ds, createAuthoritySql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteUserAuthorities extends SqlUpdate {
|
||||
public DeleteUserAuthorities(DataSource ds) {
|
||||
super(ds, deleteUserAuthoritiesSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateUser extends SqlUpdate {
|
||||
public UpdateUser(DataSource ds) {
|
||||
super(ds, updateUserSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
declareParameter(new SqlParameter(Types.BOOLEAN));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class ChangePassword extends SqlUpdate {
|
||||
public ChangePassword(DataSource ds) {
|
||||
super(ds, changePasswordSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class UserExistsQuery extends MappingSqlQuery {
|
||||
public UserExistsQuery(DataSource ds) {
|
||||
super(ds, userExistsSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
|
||||
protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return rs.getString(1);
|
||||
}
|
||||
}
|
||||
|
||||
private class AllGroupsQuery extends MappingSqlQuery {
|
||||
public AllGroupsQuery(DataSource ds) {
|
||||
super(ds, findAllGroupsSql);
|
||||
compile();
|
||||
}
|
||||
|
||||
protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return rs.getString(1);
|
||||
}
|
||||
}
|
||||
|
||||
private class GroupMembersQuery extends MappingSqlQuery {
|
||||
public GroupMembersQuery(DataSource ds) {
|
||||
super(ds, findUsersInGroupSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
|
||||
protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return rs.getString(1);
|
||||
}
|
||||
}
|
||||
|
||||
private class InsertGroup extends SqlUpdate {
|
||||
public InsertGroup(DataSource ds) {
|
||||
super(ds, insertGroupSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class FindGroupIdQuery extends MappingSqlQuery {
|
||||
public FindGroupIdQuery(DataSource ds) {
|
||||
super(ds, findGroupIdSql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
compile();
|
||||
}
|
||||
|
||||
protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return new Integer(rs.getInt(1));
|
||||
}
|
||||
}
|
||||
|
||||
private class InsertGroupAuthority extends SqlUpdate {
|
||||
public InsertGroupAuthority(DataSource ds) {
|
||||
super(ds, insertGroupAuthoritySql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
protected class DeleteGroup extends SqlUpdate {
|
||||
public DeleteGroup(DataSource ds) {
|
||||
super(ds, deleteGroupSql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteGroupMembers extends SqlUpdate {
|
||||
public DeleteGroupMembers(DataSource ds) {
|
||||
super(ds, deleteGroupMembersSql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
protected class DeleteGroupAuthorities extends SqlUpdate {
|
||||
public DeleteGroupAuthorities(DataSource ds) {
|
||||
super(ds, deleteGroupAuthoritiesSql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class RenameGroup extends SqlUpdate {
|
||||
public RenameGroup(DataSource ds) {
|
||||
super(ds, renameGroupSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
protected class InsertGroupMember extends SqlUpdate {
|
||||
public InsertGroupMember(DataSource ds) {
|
||||
super(ds, insertGroupMemberSql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteGroupMember extends SqlUpdate {
|
||||
public DeleteGroupMember(DataSource ds) {
|
||||
super(ds, deleteGroupMemberSql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
private class GroupAuthoritiesByGroupNameMapping extends MappingSqlQuery {
|
||||
protected GroupAuthoritiesByGroupNameMapping(DataSource ds) {
|
||||
super(ds, groupAuthoritiesSql);
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
|
||||
protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
|
||||
String roleName = getRolePrefix() + rs.getString(3);
|
||||
GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
|
||||
|
||||
return authority;
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteGroupAuthority extends SqlUpdate {
|
||||
public DeleteGroupAuthority(DataSource ds) {
|
||||
super(ds, deleteGroupAuthoritySql);
|
||||
declareParameter(new SqlParameter(Types.INTEGER));
|
||||
declareParameter(new SqlParameter(Types.VARCHAR));
|
||||
compile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user