Compare commits
196 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 902b8c1a5e | |||
| 915b2acf73 | |||
| c3f5f4686e | |||
| 4c9a13a755 | |||
| dc201b7989 | |||
| fb227b5433 | |||
| aa489f7ff6 | |||
| 70d5ba536e | |||
| d50184deda | |||
| 5c4f4cbe4d | |||
| b192680df3 | |||
| 95d0e08059 | |||
| 4f993d95b5 | |||
| 4c832fc946 | |||
| 5945abb10a | |||
| 8c224f39dc | |||
| f0a6b7ca27 | |||
| 0350c2833e | |||
| 7406e03306 | |||
| ca3c1979b8 | |||
| c9facdd993 | |||
| d2e6343295 | |||
| 31338a7bdb | |||
| 7714c5cd02 | |||
| 5ed5590268 | |||
| 5dd6b4a77a | |||
| 5118e0b86e | |||
| 21f2991ab4 | |||
| 3679227b11 | |||
| 25e17c1568 | |||
| 9847366d5e | |||
| 7cb472f105 | |||
| 863b36962b | |||
| bbfb3da9c7 | |||
| b1af3d00ee | |||
| daa7f3f64e | |||
| 7a3135f0f9 | |||
| 82163e2546 | |||
| 2d27b28199 | |||
| 714ee3e960 | |||
| ee74c4ced2 | |||
| 102027a44c | |||
| 799a43d72e | |||
| 3dc4158f7d | |||
| 62f70f17ff | |||
| 4b0fbe1606 | |||
| a8bce41876 | |||
| cea1f4499f | |||
| c19a5ffd73 | |||
| 594ee9515e | |||
| a087e828a6 | |||
| 5238ba0e26 | |||
| 887e3361d2 | |||
| a24570ae06 | |||
| ba719dc0e1 | |||
| 28e70db8f2 | |||
| 84031c6001 | |||
| ca2af8bc59 | |||
| 6f59805ef3 | |||
| f359bed596 | |||
| 0f1ae574ab | |||
| cb7a94af88 | |||
| 9b8d2719a6 | |||
| 73b67da3a8 | |||
| b5546d1d29 | |||
| 70ca0d1a39 | |||
| 7a5a062cd0 | |||
| 977da0da1f | |||
| dfbc938e99 | |||
| d5f1f6cbff | |||
| a2cdbab50c | |||
| 1833b234a5 | |||
| 6c97fccc91 | |||
| 2888f2b86f | |||
| 04d42211b1 | |||
| 6a87a5f1a1 | |||
| f6b21880a2 | |||
| 198d5d0482 | |||
| acee3e2593 | |||
| b87dabe1ac | |||
| f509193604 | |||
| 11a091f051 | |||
| 8e48658efb | |||
| afd556412e | |||
| 187a530760 | |||
| 1b6587a5d4 | |||
| ece824fca2 | |||
| e3644e2d27 | |||
| b3943ac268 | |||
| 537d8f108a | |||
| d0bada2bad | |||
| 952af853ac | |||
| 4dea140331 | |||
| bb3a973fcb | |||
| 522e8db5da | |||
| 8f71f6febf | |||
| 69a1fb76d3 | |||
| 156a6924fa | |||
| d53db3ba13 | |||
| 90304f64c6 | |||
| 6349359b77 | |||
| e80853b698 | |||
| 82d105cbc3 | |||
| e88f47a96a | |||
| 979ea63980 | |||
| 0bdc9c176b | |||
| 80fd238c3a | |||
| 5c597c8cde | |||
| ec7b9703a6 | |||
| 71b2af31ee | |||
| fc75b69ab8 | |||
| 6141ef79b3 | |||
| 3cfe23f60d | |||
| 82d140ffb1 | |||
| 1563491322 | |||
| b688bb69ee | |||
| 36f008643d | |||
| cbdf77e991 | |||
| 399e921d14 | |||
| c458311d2d | |||
| d6f408e8bf | |||
| 1739628e6a | |||
| 8e68fa1334 | |||
| 82cd72768d | |||
| 161710cc87 | |||
| dc1b652512 | |||
| ed9411c660 | |||
| e58f982351 | |||
| 072b73354f | |||
| 443231d1e8 | |||
| 45674a16ea | |||
| a1b124def5 | |||
| f6abc24ed6 | |||
| 1a9b7e1b6f | |||
| 8b5c70951d | |||
| c891ab45ec | |||
| 657a69b906 | |||
| 3b8fbe8bee | |||
| 4ad85cdfdf | |||
| 845c50a1c3 | |||
| 25d222208d | |||
| 9b0c21dfef | |||
| 8301bd6276 | |||
| 1872d94aa1 | |||
| 46611872db | |||
| b6cbdde0cb | |||
| 71e1702224 | |||
| 80ccd2b285 | |||
| 02c1f02f2a | |||
| 21a664b2eb | |||
| 9a2d0c2cb5 | |||
| 73b62497a3 | |||
| 09aba3906c | |||
| 57cfff6f5c | |||
| b7b6b2bac7 | |||
| 8602ae3863 | |||
| 8737fe3acb | |||
| 27faad3402 | |||
| aaa7bd90b2 | |||
| 295e0ded18 | |||
| 304f12fb63 | |||
| 8cbe232fbf | |||
| 5ac106808e | |||
| 8c605516b3 | |||
| e6e168f127 | |||
| 6d6c2d31ef | |||
| 8f6aecac9b | |||
| 0760bb947b | |||
| 9d2e2ca11d | |||
| 6354c7e052 | |||
| 42cdaa0ce2 | |||
| eda60b72b1 | |||
| 0d198d42ae | |||
| f000aaa7e8 | |||
| 634e340d80 | |||
| 4c8e9e2d7e | |||
| e518adbef1 | |||
| 59b69f6f48 | |||
| b8e50c0933 | |||
| 677576ea8b | |||
| 91153df78d | |||
| 1b0ac9c785 | |||
| 8c9159f273 | |||
| 4c8b0faa88 | |||
| 5a5b62e2cb | |||
| 6ac8588144 | |||
| 5690f1c581 | |||
| 87cf27ab7c | |||
| 41e06152b3 | |||
| a7e21318bf | |||
| bc6aae132b | |||
| b46ae6ac62 | |||
| 317da55cd0 | |||
| 9e751e22c8 | |||
| 4d65b35827 | |||
| 9831980bc2 |
+5
-1
@@ -1,4 +1,7 @@
|
||||
target/
|
||||
*/src/*/java/META-INF
|
||||
*/src/META-INF/
|
||||
*/src/*/java/META-INF/
|
||||
.classpath
|
||||
.springBeans
|
||||
.project
|
||||
@@ -6,12 +9,13 @@ target/
|
||||
.settings/
|
||||
.idea/
|
||||
out/
|
||||
bin/
|
||||
intellij/
|
||||
build/
|
||||
*.log
|
||||
*.log.*
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.gradle/
|
||||
gradle.properties
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
@@ -12,6 +11,4 @@ dependencies {
|
||||
testCompile "org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context-support:$springVersion",
|
||||
"org.springframework:spring-test:$springVersion"
|
||||
|
||||
testRuntime "hsqldb:hsqldb:$hsqlVersion"
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>@pomVersion@</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<name>Spring Security - ACL module</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>8.3-603.jdbc3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -20,7 +20,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.access.AuthorizationServiceException;
|
||||
@@ -146,10 +145,14 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return (attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute());
|
||||
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
|
||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
|
||||
|
||||
for(ConfigAttribute attr : attributes) {
|
||||
|
||||
@@ -174,7 +177,7 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
try {
|
||||
Class<?> clazz = domainObject.getClass();
|
||||
Method method = clazz.getMethod(internalMethod, new Class[0]);
|
||||
domainObject = method.invoke(domainObject);
|
||||
domainObject = method.invoke(domainObject, new Object[0]);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()
|
||||
+ "' does not provide the requested internalMethod: " + internalMethod);
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.access.PermissionCacheOptimizer;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* Batch loads ACLs for collections of objects to allow optimised filtering.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.1
|
||||
*/
|
||||
public class AclPermissionCacheOptimizer implements PermissionCacheOptimizer {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private final AclService aclService;
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
private ObjectIdentityRetrievalStrategy oidRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
|
||||
public AclPermissionCacheOptimizer(AclService aclService) {
|
||||
this.aclService = aclService;
|
||||
}
|
||||
|
||||
public void cachePermissionsFor(Authentication authentication, Collection<?> objects) {
|
||||
if (objects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ObjectIdentity> oidsToCache = new ArrayList<ObjectIdentity>(objects.size());
|
||||
|
||||
for (Object domainObject : objects) {
|
||||
if (domainObject == null) {
|
||||
continue;
|
||||
}
|
||||
ObjectIdentity oid = oidRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
oidsToCache.add(oid);
|
||||
}
|
||||
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Eagerly loading Acls for " + oidsToCache.size() + " objects");
|
||||
}
|
||||
|
||||
aclService.readAclsById(oidsToCache, sids);
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
this.oidRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final AclService aclService;
|
||||
private AclService aclService;
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
@@ -70,30 +70,24 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
List<Permission> requiredPermission = resolvePermission(permission);
|
||||
|
||||
final boolean debug = logger.isDebugEnabled();
|
||||
|
||||
if (debug) {
|
||||
logger.debug("Checking permission '" + permission + "' for object '" + oid + "'");
|
||||
}
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
Acl acl = aclService.readAclById(oid, sids);
|
||||
|
||||
if (acl.isGranted(requiredPermission, sids, false)) {
|
||||
if (debug) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Access is granted");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
|
||||
}
|
||||
|
||||
} catch (NotFoundException nfe) {
|
||||
if (debug) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning false - no ACLs apply for this principal");
|
||||
}
|
||||
}
|
||||
@@ -117,7 +111,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
if (permission instanceof String) {
|
||||
String permString = (String)permission;
|
||||
Permission p;
|
||||
Permission p = null;
|
||||
|
||||
try {
|
||||
p = permissionFactory.buildFromName(permString);
|
||||
|
||||
+5
-3
@@ -43,12 +43,12 @@ import org.springframework.util.Assert;
|
||||
public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected final AclService aclService;
|
||||
protected AclService aclService;
|
||||
protected Class<?> processDomainObjectClass = Object.class;
|
||||
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
protected String processConfigAttribute;
|
||||
protected final List<Permission> requirePermission;
|
||||
protected List<Permission> requirePermission = Arrays.asList(BasePermission.READ);
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -78,9 +78,11 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
// Obtain the SIDs applicable to the principal
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
Acl acl = null;
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
Acl acl = aclService.readAclById(objectIdentity, sids);
|
||||
acl = aclService.readAclById(objectIdentity, sids);
|
||||
|
||||
return acl.isGranted(requirePermission, sids, false);
|
||||
} catch (NotFoundException ignore) {
|
||||
|
||||
+3
-1
@@ -75,7 +75,9 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
|
||||
if (returnedObject == null) {
|
||||
logger.debug("Return object is null, skipping");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Return object is null, skipping");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+8
-4
@@ -65,7 +65,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
|
||||
this(aclService, "AFTER_ACL_READ", requirePermission);
|
||||
super(aclService, "AFTER_ACL_READ", requirePermission);
|
||||
}
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
|
||||
@@ -81,13 +81,17 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
||||
if (returnedObject == null) {
|
||||
// AclManager interface contract prohibits nulls
|
||||
// As they have permission to null/nothing, grant access
|
||||
logger.debug("Return object is null, skipping");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Return object is null, skipping");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
|
||||
logger.debug("Return object is not applicable for this provider, skipping");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Return object is not applicable for this provider, skipping");
|
||||
}
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
@@ -104,7 +108,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
||||
|
||||
logger.debug("Denying access");
|
||||
|
||||
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
|
||||
throw new AccessDeniedException(messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
|
||||
new Object[] {authentication.getName(), returnedObject},
|
||||
"Authentication {0} has NO permissions to the domain object {1}"));
|
||||
}
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ class ArrayFilterer<T> implements Filterer<T> {
|
||||
}
|
||||
|
||||
public T next() {
|
||||
if (!hasNext()) {
|
||||
if (hasNext() == false) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return list[index++];
|
||||
|
||||
+8
-3
@@ -37,9 +37,12 @@ class CollectionFilterer<T> implements Filterer<T> {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Collection<T> collection;
|
||||
private Collection<T> collection;
|
||||
|
||||
private final Set<T> removeList;
|
||||
// collectionIter offers significant performance optimisations (as
|
||||
// per security-developer mailing list conversation 19/5/05)
|
||||
private Iterator<T> collectionIter;
|
||||
private Set<T> removeList;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -85,7 +88,9 @@ class CollectionFilterer<T> implements Filterer<T> {
|
||||
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
return collection.iterator();
|
||||
collectionIter = collection.iterator();
|
||||
|
||||
return collectionIter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,7 @@ public abstract class AbstractPermission implements Permission {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected final char code;
|
||||
protected char code;
|
||||
protected int mask;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
+4
-4
@@ -33,13 +33,13 @@ import java.io.Serializable;
|
||||
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Acl acl;
|
||||
private Acl acl;
|
||||
private Permission permission;
|
||||
private final Serializable id;
|
||||
private final Sid sid;
|
||||
private Serializable id;
|
||||
private Sid sid;
|
||||
private boolean auditFailure = false;
|
||||
private boolean auditSuccess = false;
|
||||
private final boolean granting;
|
||||
private boolean granting;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
|
||||
+10
-17
@@ -41,9 +41,9 @@ import org.springframework.util.Assert;
|
||||
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final GrantedAuthority gaGeneralChanges;
|
||||
private final GrantedAuthority gaModifyAuditing;
|
||||
private final GrantedAuthority gaTakeOwnership;
|
||||
private GrantedAuthority gaGeneralChanges;
|
||||
private GrantedAuthority gaModifyAuditing;
|
||||
private GrantedAuthority gaTakeOwnership;
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
@@ -52,23 +52,16 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
|
||||
* can be held to always permit ACL changes.
|
||||
*
|
||||
* @param auths the <code>GrantedAuthority</code>s that have
|
||||
* @param auths an array of <code>GrantedAuthority</code>s that have
|
||||
* special permissions (index 0 is the authority needed to change
|
||||
* ownership, index 1 is the authority needed to modify auditing details,
|
||||
* index 2 is the authority needed to change other ACL and ACE details) (required)
|
||||
* <p>
|
||||
* Alternatively, a single value can be supplied for all three permissions.
|
||||
*/
|
||||
public AclAuthorizationStrategyImpl(GrantedAuthority... auths) {
|
||||
Assert.isTrue(auths != null && (auths.length == 3 || auths.length == 1),
|
||||
"One or three GrantedAuthority instances required");
|
||||
if (auths.length == 3) {
|
||||
gaTakeOwnership = auths[0];
|
||||
gaModifyAuditing = auths[1];
|
||||
gaGeneralChanges = auths[2];
|
||||
} else {
|
||||
gaTakeOwnership = gaModifyAuditing = gaGeneralChanges = auths[0];
|
||||
}
|
||||
public AclAuthorizationStrategyImpl(GrantedAuthority[] auths) {
|
||||
Assert.isTrue(auths != null && auths.length == 3, "GrantedAuthority[] with three elements required");
|
||||
this.gaTakeOwnership = auths[0];
|
||||
this.gaModifyAuditing = auths[1];
|
||||
this.gaGeneralChanges = auths[2];
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -91,7 +84,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
}
|
||||
|
||||
// Not authorized by ACL ownership; try via adminstrative permissions
|
||||
GrantedAuthority requiredAuthority;
|
||||
GrantedAuthority requiredAuthority = null;
|
||||
|
||||
if (changeType == CHANGE_AUDITING) {
|
||||
requiredAuthority = this.gaModifyAuditing;
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.OwnershipAcl;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.UnloadedSidException;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -42,8 +41,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
|
||||
private Acl parentAcl;
|
||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private transient PermissionGrantingStrategy permissionGrantingStrategy;
|
||||
private final List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
|
||||
private transient AuditLogger auditLogger;
|
||||
private List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
|
||||
private ObjectIdentity objectIdentity;
|
||||
private Serializable id;
|
||||
private Sid owner; // OwnershipAcl
|
||||
@@ -70,48 +69,39 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
this.objectIdentity = objectIdentity;
|
||||
this.id = id;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
|
||||
this(objectIdentity, id, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger),
|
||||
parentAcl, loadedSids, entriesInheriting, owner);
|
||||
this.auditLogger = auditLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor, which should be used by persistence tools that do not
|
||||
* provide field-level access features.
|
||||
*
|
||||
* @param objectIdentity the object identity this ACL relates to
|
||||
* @param id the primary key assigned to this ACL
|
||||
* @param aclAuthorizationStrategy authorization strategy
|
||||
* @param grantingStrategy the {@code PermissionGrantingStrategy} which will be used by the {@code isGranted()} method
|
||||
* @param parentAcl the parent (may be may be {@code null})
|
||||
* @param loadedSids the loaded SIDs if only a subset were loaded (may be {@code null})
|
||||
* @param objectIdentity the object identity this ACL relates to (required)
|
||||
* @param id the primary key assigned to this ACL (required)
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
* @param auditLogger audit logger (required)
|
||||
* @param parentAcl the parent (may be <code>null</code>)
|
||||
* @param loadedSids the loaded SIDs if only a subset were loaded (may be
|
||||
* <code>null</code>)
|
||||
* @param entriesInheriting if ACEs from the parent should inherit into
|
||||
* this ACL
|
||||
* @param owner the owner (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
|
||||
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(owner, "Owner required");
|
||||
|
||||
Assert.notNull(auditLogger, "AuditLogger required");
|
||||
this.objectIdentity = objectIdentity;
|
||||
this.id = id;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.auditLogger = auditLogger;
|
||||
this.parentAcl = parentAcl; // may be null
|
||||
this.loadedSids = loadedSids; // may be null
|
||||
this.entriesInheriting = entriesInheriting;
|
||||
this.owner = owner;
|
||||
this.permissionGrantingStrategy = grantingStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,11 +168,35 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the {@link PermissionGrantingStrategy}.
|
||||
* Determines authorization. The order of the <code>permission</code> and <code>sid</code> arguments is
|
||||
* <em>extremely important</em>! The method will iterate through each of the <code>permission</code>s in the order
|
||||
* specified. For each iteration, all of the <code>sid</code>s will be considered, again in the order they are
|
||||
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
|
||||
* matches that <code>permission:sid</code> combination. When the <em>first full match</em> is found (ie an ACE
|
||||
* that has the SID currently being searched for and the exact permission bit mask being search for), the grant or
|
||||
* deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return
|
||||
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the next <code>permission</code>
|
||||
* iteration will be performed. If each permission indicates to deny access, the first deny ACE found will be
|
||||
* considered the reason for the failure (as it was the first match found, and is therefore the one most logically
|
||||
* requiring changes - although not always). If absolutely no matching ACE was found at all for any permission,
|
||||
* the parent ACL will be tried (provided that there is a parent and {@link #isEntriesInheriting()} is
|
||||
* <code>true</code>. The parent ACL will also scan its parent and so on. If ultimately no matching ACE is found,
|
||||
* a <code>NotFoundException</code> will be thrown and the caller will need to decide how to handle the permission
|
||||
* check. Similarly, if any of the SID arguments presented to the method were not loaded by the ACL,
|
||||
* <code>UnloadedSidException</code> will be thrown.
|
||||
*
|
||||
* @param permission the exact permissions to scan for (order is important)
|
||||
* @param sids the exact SIDs to scan for (order is important)
|
||||
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no auditing
|
||||
* will be undertaken
|
||||
*
|
||||
* @return <code>true</code> if one of the permissions has been granted, <code>false</code> if one of the
|
||||
* permissions has been specifically revoked
|
||||
*
|
||||
* @throws NotFoundException if an exact ACE for one of the permission bit masks and SID combination could not be
|
||||
* found
|
||||
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the ACL was only loaded for a
|
||||
* subset of SIDs
|
||||
* @see DefaultPermissionGrantingStrategy
|
||||
*/
|
||||
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
@@ -193,7 +207,64 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
throw new UnloadedSidException("ACL was not loaded for one or more SID");
|
||||
}
|
||||
|
||||
return permissionGrantingStrategy.isGranted(this, permission, sids, administrativeMode);
|
||||
AccessControlEntry firstRejection = null;
|
||||
|
||||
for (Permission p : permission) {
|
||||
for (Sid sid: sids) {
|
||||
// Attempt to find exact match for this permission mask and SID
|
||||
boolean scanNextSid = true;
|
||||
|
||||
for (AccessControlEntry ace : aces ) {
|
||||
|
||||
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
|
||||
// Found a matching ACE, so its authorization decision will prevail
|
||||
if (ace.isGranting()) {
|
||||
// Success
|
||||
if (!administrativeMode) {
|
||||
auditLogger.logIfNeeded(true, ace);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Failure for this permission, so stop search
|
||||
// We will see if they have a different permission
|
||||
// (this permission is 100% rejected for this SID)
|
||||
if (firstRejection == null) {
|
||||
// Store first rejection for auditing reasons
|
||||
firstRejection = ace;
|
||||
}
|
||||
|
||||
scanNextSid = false; // helps break the loop
|
||||
|
||||
break; // exit aces loop
|
||||
}
|
||||
}
|
||||
|
||||
if (!scanNextSid) {
|
||||
break; // exit SID for loop (now try next permission)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstRejection != null) {
|
||||
// We found an ACE to reject the request at this point, as no
|
||||
// other ACEs were found that granted a different permission
|
||||
if (!administrativeMode) {
|
||||
auditLogger.logIfNeeded(false, firstRejection);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// No matches have been found so far
|
||||
if (isEntriesInheriting() && (parentAcl != null)) {
|
||||
// We have a parent, so let them try to find a matching ACE
|
||||
return parentAcl.isGranted(permission, sids, false);
|
||||
} else {
|
||||
// We either have no parent, or we're the uppermost parent
|
||||
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
@@ -249,6 +320,39 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
return parentAcl;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("AclImpl[");
|
||||
sb.append("id: ").append(this.id).append("; ");
|
||||
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
|
||||
sb.append("owner: ").append(this.owner).append("; ");
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (AccessControlEntry ace : aces) {
|
||||
count++;
|
||||
|
||||
if (count == 1) {
|
||||
sb.append("\r\n");
|
||||
}
|
||||
|
||||
sb.append(ace).append("\r\n");
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
sb.append("no ACEs; ");
|
||||
}
|
||||
|
||||
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
|
||||
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
|
||||
sb.append("; ");
|
||||
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
|
||||
sb.append("auditLogger: ").append(this.auditLogger);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void updateAce(int aceIndex, Permission permission)
|
||||
throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
@@ -275,15 +379,15 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
if (obj instanceof AclImpl) {
|
||||
AclImpl rhs = (AclImpl) obj;
|
||||
if (this.aces.equals(rhs.aces)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl !=null && this.parentAcl.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity != null && this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null) || (this.id != null && this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null) || (this.owner != null && this.owner.equals(rhs.owner))) {
|
||||
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||
return true;
|
||||
}
|
||||
if (this.loadedSids.size() == rhs.loadedSids.size()) {
|
||||
if (this.loadedSids != null && (this.loadedSids.size() == rhs.loadedSids.size())) {
|
||||
for (int i = 0; i < this.loadedSids.size(); i++) {
|
||||
if (!this.loadedSids.get(i).equals(rhs.loadedSids.get(i))) {
|
||||
return false;
|
||||
@@ -301,37 +405,4 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("AclImpl[");
|
||||
sb.append("id: ").append(this.id).append("; ");
|
||||
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
|
||||
sb.append("owner: ").append(this.owner).append("; ");
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (AccessControlEntry ace : aces) {
|
||||
count++;
|
||||
|
||||
if (count == 1) {
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
sb.append(ace).append("\n");
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
sb.append("no ACEs; ");
|
||||
}
|
||||
|
||||
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
|
||||
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
|
||||
sb.append("; ");
|
||||
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
|
||||
sb.append("permissionGrantingStrategy: ").append(this.permissionGrantingStrategy);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -64,19 +64,18 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
|
||||
Field[] fields = clazz.getFields();
|
||||
|
||||
for (Field field : fields) {
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
try {
|
||||
Object fieldValue = field.get(null);
|
||||
Object fieldValue = fields[i].get(null);
|
||||
|
||||
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
|
||||
// Found a Permission static field
|
||||
Permission perm = (Permission) fieldValue;
|
||||
String permissionName = field.getName();
|
||||
String permissionName = fields[i].getName();
|
||||
|
||||
registerPermission(perm, permissionName);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +83,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
Assert.notNull(perm, "Permission required");
|
||||
Assert.hasText(permissionName, "Permission name required");
|
||||
|
||||
Integer mask = Integer.valueOf(perm.getMask());
|
||||
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);
|
||||
@@ -98,7 +97,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
public Permission buildFromMask(int mask) {
|
||||
if (registeredPermissionsByInteger.containsKey(Integer.valueOf(mask))) {
|
||||
// The requested mask has an exact match against a statically-defined Permission, so return it
|
||||
return registeredPermissionsByInteger.get(Integer.valueOf(mask));
|
||||
return registeredPermissionsByInteger.get(new Integer(mask));
|
||||
}
|
||||
|
||||
// To get this far, we have to use a CumulativePermission
|
||||
|
||||
-119
@@ -1,119 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
public class DefaultPermissionGrantingStrategy implements PermissionGrantingStrategy {
|
||||
|
||||
private final transient AuditLogger auditLogger;
|
||||
|
||||
/**
|
||||
* Creates an instance with the logger which will be used to record granting and denial of requested permissions.
|
||||
*/
|
||||
public DefaultPermissionGrantingStrategy(AuditLogger auditLogger) {
|
||||
Assert.notNull(auditLogger, "auditLogger cannot be null");
|
||||
this.auditLogger = auditLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines authorization. The order of the <code>permission</code> and <code>sid</code> arguments is
|
||||
* <em>extremely important</em>! The method will iterate through each of the <code>permission</code>s in the order
|
||||
* specified. For each iteration, all of the <code>sid</code>s will be considered, again in the order they are
|
||||
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
|
||||
* matches that <code>permission:sid</code> combination. When the <em>first full match</em> is found (ie an ACE
|
||||
* that has the SID currently being searched for and the exact permission bit mask being search for), the grant or
|
||||
* deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return
|
||||
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the next <code>permission</code>
|
||||
* iteration will be performed. If each permission indicates to deny access, the first deny ACE found will be
|
||||
* considered the reason for the failure (as it was the first match found, and is therefore the one most logically
|
||||
* requiring changes - although not always). If absolutely no matching ACE was found at all for any permission,
|
||||
* the parent ACL will be tried (provided that there is a parent and {@link Acl#isEntriesInheriting()} is
|
||||
* <code>true</code>. The parent ACL will also scan its parent and so on. If ultimately no matching ACE is found,
|
||||
* a <code>NotFoundException</code> will be thrown and the caller will need to decide how to handle the permission
|
||||
* check. Similarly, if any of the SID arguments presented to the method were not loaded by the ACL,
|
||||
* <code>UnloadedSidException</code> will be thrown.
|
||||
*
|
||||
* @param permission the exact permissions to scan for (order is important)
|
||||
* @param sids the exact SIDs to scan for (order is important)
|
||||
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no auditing
|
||||
* will be undertaken
|
||||
*
|
||||
* @return <code>true</code> if one of the permissions has been granted, <code>false</code> if one of the
|
||||
* permissions has been specifically revoked
|
||||
*
|
||||
* @throws NotFoundException if an exact ACE for one of the permission bit masks and SID combination could not be
|
||||
* found
|
||||
*/
|
||||
public boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
throws NotFoundException {
|
||||
|
||||
final List<AccessControlEntry> aces = acl.getEntries();
|
||||
|
||||
AccessControlEntry firstRejection = null;
|
||||
|
||||
for (Permission p : permission) {
|
||||
for (Sid sid: sids) {
|
||||
// Attempt to find exact match for this permission mask and SID
|
||||
boolean scanNextSid = true;
|
||||
|
||||
for (AccessControlEntry ace : aces ) {
|
||||
|
||||
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
|
||||
// Found a matching ACE, so its authorization decision will prevail
|
||||
if (ace.isGranting()) {
|
||||
// Success
|
||||
if (!administrativeMode) {
|
||||
auditLogger.logIfNeeded(true, ace);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Failure for this permission, so stop search
|
||||
// We will see if they have a different permission
|
||||
// (this permission is 100% rejected for this SID)
|
||||
if (firstRejection == null) {
|
||||
// Store first rejection for auditing reasons
|
||||
firstRejection = ace;
|
||||
}
|
||||
|
||||
scanNextSid = false; // helps break the loop
|
||||
|
||||
break; // exit aces loop
|
||||
}
|
||||
}
|
||||
|
||||
if (!scanNextSid) {
|
||||
break; // exit SID for loop (now try next permission)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstRejection != null) {
|
||||
// We found an ACE to reject the request at this point, as no
|
||||
// other ACEs were found that granted a different permission
|
||||
if (!administrativeMode) {
|
||||
auditLogger.logIfNeeded(false, firstRejection);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// No matches have been found so far
|
||||
if (acl.isEntriesInheriting() && (acl.getParentAcl() != null)) {
|
||||
// We have a parent, so let them try to find a matching ACE
|
||||
return acl.getParentAcl().isGranted(permission, sids, false);
|
||||
} else {
|
||||
// We either have no parent, or we're the uppermost parent
|
||||
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+7
-21
@@ -23,48 +23,34 @@ import net.sf.ehcache.Element;
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
|
||||
*
|
||||
* <p>
|
||||
* Designed to handle the transient fields in {@link AclImpl}. Note that this implementation assumes all
|
||||
* {@link AclImpl} instances share the same {@link PermissionGrantingStrategy} and {@link AclAuthorizationStrategy}
|
||||
* instances.
|
||||
* {@link AclImpl} instances share the same {@link AuditLogger} and {@link AclAuthorizationStrategy} instance.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class EhCacheBasedAclCache implements AclCache {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Ehcache cache;
|
||||
private PermissionGrantingStrategy permissionGrantingStrategy;
|
||||
private Ehcache cache;
|
||||
private AuditLogger auditLogger;
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* @deprecated use the second constructor which injects the strategy objects. See SEC-1498.
|
||||
*/
|
||||
@Deprecated
|
||||
public EhCacheBasedAclCache(Ehcache cache) {
|
||||
Assert.notNull(cache, "Cache required");
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public EhCacheBasedAclCache(Ehcache cache, PermissionGrantingStrategy permissionGrantingStrategy,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy) {
|
||||
Assert.notNull(cache, "Cache required");
|
||||
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
this.cache = cache;
|
||||
this.permissionGrantingStrategy = permissionGrantingStrategy;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void evictFromCache(Serializable pk) {
|
||||
@@ -129,7 +115,7 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
if (this.aclAuthorizationStrategy == null) {
|
||||
if (acl instanceof AclImpl) {
|
||||
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", acl);
|
||||
this.permissionGrantingStrategy = (PermissionGrantingStrategy) FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", acl);
|
||||
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +130,7 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
if (value instanceof AclImpl) {
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
|
||||
FieldUtils.setProtectedFieldValue("auditLogger", value, this.auditLogger);
|
||||
}
|
||||
|
||||
if (value.getParentAcl() != null) {
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.springframework.util.Assert;
|
||||
public class GrantedAuthoritySid implements Sid {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final String grantedAuthority;
|
||||
private String grantedAuthority;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
|
||||
try {
|
||||
Method method = typeClass.getMethod("getId", new Class[] {});
|
||||
result = method.invoke(object);
|
||||
result = method.invoke(object, new Object[] {});
|
||||
} catch (Exception e) {
|
||||
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.util.Assert;
|
||||
public class PrincipalSid implements Sid {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final String principal;
|
||||
private String principal;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public List<Sid> getSids(Authentication authentication) {
|
||||
Collection<? extends GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
Collection<GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
List<Sid> sids = new ArrayList<Sid>(authorities.size() + 1);
|
||||
|
||||
sids.add(new PrincipalSid(authentication));
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
@@ -37,7 +38,6 @@ import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.AuditLogger;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PermissionFactory;
|
||||
@@ -49,7 +49,6 @@ import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.UnloadedSidException;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
@@ -107,11 +106,11 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
private final AclCache aclCache;
|
||||
private final PermissionGrantingStrategy grantingStrategy;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private AclCache aclCache;
|
||||
private AuditLogger auditLogger;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
private int batchSize = 50;
|
||||
|
||||
private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
|
||||
@@ -131,28 +130,19 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
* @param dataSource to access the database
|
||||
* @param aclCache the cache where fully-loaded elements can be stored
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
*
|
||||
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
|
||||
this(dataSource, aclCache, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger));
|
||||
}
|
||||
|
||||
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
Assert.notNull(aclCache, "AclCache required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(grantingStrategy, "grantingStrategy required");
|
||||
Assert.notNull(auditLogger, "AuditLogger required");
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.aclCache = aclCache;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.grantingStrategy = grantingStrategy;
|
||||
this.auditLogger = auditLogger;
|
||||
fieldAces.setAccessible(true);
|
||||
fieldAcl.setAccessible(true);
|
||||
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -405,7 +395,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
// Now we have the parent (if there is one), create the true AclImpl
|
||||
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), (Long) inputAcl.getId(), aclAuthorizationStrategy,
|
||||
grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
|
||||
@@ -476,8 +466,8 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
|
||||
private final Map<Serializable, Acl> acls;
|
||||
private final List<Sid> sids;
|
||||
private Map<Serializable, Acl> acls;
|
||||
private List<Sid> sids;
|
||||
|
||||
public ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs cannot be null");
|
||||
@@ -494,8 +484,9 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
* @param rs The {@link ResultSet} to be processed
|
||||
* @return a list of parent IDs remaining to be looked up (may be empty, but never <tt>null</tt>)
|
||||
* @throws SQLException
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
public Set<Long> extractData(ResultSet rs) throws SQLException {
|
||||
public Set<Long> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
Set<Long> parentIdsToLookup = new HashSet<Long>(); // Set of parent_id Longs
|
||||
|
||||
while (rs.next()) {
|
||||
@@ -564,7 +555,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
|
||||
}
|
||||
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
|
||||
entriesInheriting, owner);
|
||||
|
||||
acls.put(id, acl);
|
||||
@@ -603,7 +594,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
|
||||
private class StubAclParent implements Acl {
|
||||
private final Long id;
|
||||
private Long id;
|
||||
|
||||
public StubAclParent(Long id) {
|
||||
this.id = id;
|
||||
|
||||
@@ -56,8 +56,8 @@ public class JdbcAclService implements AclService {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected final JdbcTemplate jdbcTemplate;
|
||||
private final LookupStrategy lookupStrategy;
|
||||
protected JdbcTemplate jdbcTemplate;
|
||||
private LookupStrategy lookupStrategy;
|
||||
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
@@ -109,9 +109,10 @@ public class JdbcAclService implements AclService {
|
||||
Map<ObjectIdentity, Acl> result = lookupStrategy.readAclsById(objects, sids);
|
||||
|
||||
// Check every requested object identity was found (throw NotFoundException if needed)
|
||||
for (ObjectIdentity oid : objects) {
|
||||
if (!result.containsKey(oid)) {
|
||||
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
|
||||
for (int i = 0; i < objects.size(); i++) {
|
||||
if (!result.containsKey(objects.get(i))) {
|
||||
throw new NotFoundException("Unable to find ACL information for object identity '"
|
||||
+ objects.get(i) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-11
@@ -61,7 +61,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private boolean foreignKeysInDatabase = true;
|
||||
private final AclCache aclCache;
|
||||
private AclCache aclCache;
|
||||
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()";
|
||||
@@ -194,7 +194,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
Assert.notNull(sid, "Sid required");
|
||||
|
||||
String sidName;
|
||||
String sidName = null;
|
||||
boolean sidIsPrincipal = true;
|
||||
|
||||
if (sid instanceof PrincipalSid) {
|
||||
@@ -214,7 +214,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
}
|
||||
|
||||
if (allowCreate) {
|
||||
jdbcTemplate.update(insertSid, Boolean.valueOf(sidIsPrincipal), sidName);
|
||||
jdbcTemplate.update(insertSid, new Object[] {Boolean.valueOf(sidIsPrincipal), sidName});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
|
||||
}
|
||||
@@ -229,8 +229,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
if (deleteChildren) {
|
||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (ObjectIdentity child : children) {
|
||||
deleteAcl(child, true);
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
deleteAcl(children.get(i), true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -263,7 +263,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @param oidPrimaryKey the rows in acl_entry to delete
|
||||
*/
|
||||
protected void deleteEntries(Long oidPrimaryKey) {
|
||||
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey, oidPrimaryKey);
|
||||
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
|
||||
new Object[] {oidPrimaryKey});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +277,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
*/
|
||||
protected void deleteObjectIdentity(Long oidPrimaryKey) {
|
||||
// Delete the acl_object_identity row
|
||||
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, oidPrimaryKey);
|
||||
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -290,7 +291,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
*/
|
||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
try {
|
||||
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey, oid.getType(), oid.getIdentifier()));
|
||||
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
|
||||
new Object[] {oid.getType(), oid.getIdentifier()}));
|
||||
} catch (DataAccessException notFound) {
|
||||
return null;
|
||||
}
|
||||
@@ -324,8 +326,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (ObjectIdentity child : children) {
|
||||
clearCacheIncludingChildren(child);
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
clearCacheIncludingChildren(children.get(i));
|
||||
}
|
||||
}
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
@@ -354,7 +356,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
|
||||
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
|
||||
int count = jdbcTemplate.update(updateObjectIdentity,
|
||||
parentId, ownerSid, Boolean.valueOf(acl.isEntriesInheriting()), acl.getId());
|
||||
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
|
||||
|
||||
if (count != 1) {
|
||||
throw new NotFoundException("Unable to locate ACL to update");
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Allow customization of the logic for determining whether a permission or permissions are granted to a particular
|
||||
* sid or sids by an {@link Acl}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0.2
|
||||
*/
|
||||
public interface PermissionGrantingStrategy {
|
||||
|
||||
/**
|
||||
* Returns true if the the supplied strategy decides that the supplied {@code Acl} grants access
|
||||
* based on the supplied list of permissions and sids.
|
||||
*/
|
||||
boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode);
|
||||
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public class AclPermissionCacheOptimizerTests {
|
||||
|
||||
@Test
|
||||
public void eagerlyLoadsRequiredAcls() throws Exception {
|
||||
AclService service = mock(AclService.class);
|
||||
AclPermissionCacheOptimizer pco = new AclPermissionCacheOptimizer(service);
|
||||
ObjectIdentityRetrievalStrategy oidStrat = mock(ObjectIdentityRetrievalStrategy.class);
|
||||
SidRetrievalStrategy sidStrat = mock(SidRetrievalStrategy.class);
|
||||
pco.setObjectIdentityRetrievalStrategy(oidStrat);
|
||||
pco.setSidRetrievalStrategy(sidStrat);
|
||||
Object[] dos = {new Object(), null, new Object()};
|
||||
ObjectIdentity[] oids = {new ObjectIdentityImpl("A", "1"), new ObjectIdentityImpl("A", "2")};
|
||||
when(oidStrat.getObjectIdentity(dos[0])).thenReturn(oids[0]);
|
||||
when(oidStrat.getObjectIdentity(dos[2])).thenReturn(oids[1]);
|
||||
|
||||
pco.cachePermissionsFor(mock(Authentication.class), Arrays.asList(dos));
|
||||
|
||||
// AclService should be invoked with the list of required Oids
|
||||
verify(service).readAclsById(eq(Arrays.asList(oids)), any(List.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresEmptyCollection() {
|
||||
AclService service = mock(AclService.class);
|
||||
AclPermissionCacheOptimizer pco = new AclPermissionCacheOptimizer(service);
|
||||
ObjectIdentityRetrievalStrategy oids = mock(ObjectIdentityRetrievalStrategy.class);
|
||||
SidRetrievalStrategy sids = mock(SidRetrievalStrategy.class);
|
||||
pco.setObjectIdentityRetrievalStrategy(oids);
|
||||
pco.setSidRetrievalStrategy(sids);
|
||||
|
||||
pco.cachePermissionsFor(mock(Authentication.class), Collections.emptyList());
|
||||
|
||||
verifyZeroInteractions(service, sids, oids);
|
||||
}
|
||||
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.acls.model.*;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public class AclEntryAfterInvocationCollectionFilteringProviderTests {
|
||||
@Test
|
||||
public void objectsAreRemovedIfPermissionDenied() throws Exception {
|
||||
AclService service = mock(AclService.class);
|
||||
Acl acl = mock(Acl.class);
|
||||
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(false);
|
||||
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
|
||||
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(service, Arrays.asList(mock(Permission.class)));
|
||||
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
|
||||
provider.setProcessDomainObjectClass(Object.class);
|
||||
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
|
||||
|
||||
Object returned = provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), new ArrayList(Arrays.asList(new Object(), new Object())));
|
||||
assertTrue(returned instanceof List);
|
||||
assertTrue(((List)returned).isEmpty());
|
||||
returned = provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "AFTER_ACL_COLLECTION_READ"), new Object[] {new Object(), new Object()});
|
||||
assertTrue(returned instanceof Object[]);
|
||||
assertTrue(((Object[])returned).length == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessIsGrantedIfNoAttributesDefined() throws Exception {
|
||||
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
|
||||
Object returned = new Object();
|
||||
|
||||
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), Collections.<ConfigAttribute>emptyList(), returned));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullReturnObjectIsIgnored() throws Exception {
|
||||
AclService service = mock(AclService.class);
|
||||
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(service, Arrays.asList(mock(Permission.class)));
|
||||
|
||||
assertNull(provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null));
|
||||
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
|
||||
}
|
||||
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.acls.model.*;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public class AclEntryAfterInvocationProviderTests {
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void rejectsMissingPermissions() throws Exception {
|
||||
try {
|
||||
new AclEntryAfterInvocationProvider(mock(AclService.class), null);
|
||||
fail("Exception expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
new AclEntryAfterInvocationProvider(mock(AclService.class), Collections.<Permission>emptyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessIsAllowedIfPermissionIsGranted() {
|
||||
AclService service = mock(AclService.class);
|
||||
Acl acl = mock(Acl.class);
|
||||
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(true);
|
||||
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
|
||||
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
|
||||
provider.setMessageSource(new SpringSecurityMessageSource());
|
||||
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
|
||||
provider.setProcessDomainObjectClass(Object.class);
|
||||
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
|
||||
Object returned = new Object();
|
||||
|
||||
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_READ"), returned));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessIsGrantedIfNoAttributesDefined() throws Exception {
|
||||
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
|
||||
Object returned = new Object();
|
||||
|
||||
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), Collections.<ConfigAttribute>emptyList(), returned));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessIsGrantedIfObjectTypeNotSupported() throws Exception {
|
||||
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
|
||||
provider.setProcessDomainObjectClass(String.class);
|
||||
// Not a String
|
||||
Object returned = new Object();
|
||||
|
||||
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_READ"), returned));
|
||||
}
|
||||
|
||||
|
||||
@Test(expected= AccessDeniedException.class)
|
||||
public void accessIsDeniedIfPermissionIsNotGranted() {
|
||||
AclService service = mock(AclService.class);
|
||||
Acl acl = mock(Acl.class);
|
||||
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(false);
|
||||
// Try a second time with no permissions found
|
||||
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenThrow(new NotFoundException(""));
|
||||
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
|
||||
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
|
||||
provider.setProcessConfigAttribute("MY_ATTRIBUTE");
|
||||
provider.setMessageSource(new SpringSecurityMessageSource());
|
||||
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
|
||||
provider.setProcessDomainObjectClass(Object.class);
|
||||
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
|
||||
try {
|
||||
provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object());
|
||||
fail();
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
// Second scenario with no acls found
|
||||
provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullReturnObjectIsIgnored() throws Exception {
|
||||
AclService service = mock(AclService.class);
|
||||
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
|
||||
|
||||
assertNull(provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null));
|
||||
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
|
||||
}
|
||||
}
|
||||
+22
-18
@@ -1,8 +1,10 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
@@ -16,6 +18,7 @@ import org.springframework.security.acls.model.Sid;
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AccessControlImplEntryTests {
|
||||
Mockery jmock = new JUnit4Mockery();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -32,7 +35,7 @@ public class AccessControlImplEntryTests {
|
||||
|
||||
// Check Sid field is present
|
||||
try {
|
||||
new AccessControlEntryImpl(null, mock(Acl.class), null,
|
||||
new AccessControlEntryImpl(null, jmock.mock(Acl.class), null,
|
||||
BasePermission.ADMINISTRATION, true, true, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
@@ -41,7 +44,7 @@ public class AccessControlImplEntryTests {
|
||||
|
||||
// Check Permission field is present
|
||||
try {
|
||||
new AccessControlEntryImpl(null, mock(Acl.class), new PrincipalSid("johndoe"), null,
|
||||
new AccessControlEntryImpl(null, jmock.mock(Acl.class), new PrincipalSid("johndoe"), null,
|
||||
true, true, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
@@ -51,11 +54,11 @@ public class AccessControlImplEntryTests {
|
||||
|
||||
@Test
|
||||
public void testAccessControlEntryImplGetters() {
|
||||
Acl mockAcl = mock(Acl.class);
|
||||
Acl mockAcl = jmock.mock(Acl.class);
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
// Create a sample entry
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
// and check every get() method
|
||||
@@ -70,31 +73,32 @@ public class AccessControlImplEntryTests {
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
final Acl mockAcl = mock(Acl.class);
|
||||
final ObjectIdentity oid = mock(ObjectIdentity.class);
|
||||
|
||||
when(mockAcl.getObjectIdentity()).thenReturn(oid);
|
||||
final Acl mockAcl = jmock.mock(Acl.class);
|
||||
final ObjectIdentity oid = jmock.mock(ObjectIdentity.class);
|
||||
jmock.checking(new Expectations() {{
|
||||
allowing(mockAcl).getObjectIdentity(); will(returnValue(oid));
|
||||
}});
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
assertFalse(ace.equals(null));
|
||||
assertFalse(ace.equals(Long.valueOf(100)));
|
||||
assertFalse(ace.equals(new Long(100)));
|
||||
assertTrue(ace.equals(ace));
|
||||
assertTrue(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
|
||||
assertTrue(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(2), mockAcl, sid,
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(2), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, new PrincipalSid("scott"),
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, new PrincipalSid("scott"),
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.WRITE, true,
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.WRITE, true,
|
||||
true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, false, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, false, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, false)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,37 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.*;
|
||||
import org.springframework.security.acls.model.*;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jmock.Mockery;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AlreadyExistsException;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.AuditableAcl;
|
||||
import org.springframework.security.acls.model.ChildrenExistException;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.MutableAclService;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.OwnershipAcl;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -30,8 +49,8 @@ public class AclImplTests {
|
||||
private static final List<Sid> BEN = Arrays.asList((Sid)new PrincipalSid("ben"));
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("joe", "ignored", "ROLE_ADMINISTRATOR");
|
||||
AclAuthorizationStrategy authzStrategy;
|
||||
PermissionGrantingStrategy pgs;
|
||||
Mockery jmockCtx = new Mockery();
|
||||
AclAuthorizationStrategy mockAuthzStrategy;
|
||||
AuditLogger mockAuditLogger;
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(TARGET_CLASS, 100);
|
||||
|
||||
@@ -40,9 +59,8 @@ public class AclImplTests {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
authzStrategy = mock(AclAuthorizationStrategy.class);
|
||||
mockAuditLogger = mock(AuditLogger.class);
|
||||
pgs = new DefaultPermissionGrantingStrategy(mockAuditLogger);
|
||||
mockAuthzStrategy = mock(AclAuthorizationStrategy.class);
|
||||
mockAuditLogger = mock(AuditLogger.class);;
|
||||
auth.setAuthenticated(true);
|
||||
}
|
||||
|
||||
@@ -54,26 +72,25 @@ public class AclImplTests {
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullObjectIdentity() throws Exception {
|
||||
try {
|
||||
new AclImpl(null, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
new AclImpl(null, 1, authzStrategy, mockAuditLogger);
|
||||
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullId() throws Exception {
|
||||
try {
|
||||
new AclImpl(objectIdentity, null, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
new AclImpl(objectIdentity, null, authzStrategy, mockAuditLogger);
|
||||
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullAclAuthzStrategy() throws Exception {
|
||||
try {
|
||||
@@ -85,9 +102,20 @@ public class AclImplTests {
|
||||
new AclImpl(objectIdentity, 1, null, mockAuditLogger);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullAuditLogger() throws Exception {
|
||||
try {
|
||||
new AclImpl(objectIdentity, 1, mockAuthzStrategy, null, null, null, true, new PrincipalSid("joe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
new AclImpl(objectIdentity, 1, mockAuthzStrategy, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertAceRejectsNullParameters() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid(
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
try {
|
||||
acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
|
||||
@@ -105,7 +133,7 @@ public class AclImplTests {
|
||||
|
||||
@Test
|
||||
public void insertAceAddsElementAtCorrectIndex() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Insert one permission
|
||||
@@ -141,7 +169,7 @@ public class AclImplTests {
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void insertAceFailsForNonExistentElement() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity,1, authzStrategy, pgs, null, null, true, new PrincipalSid(
|
||||
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
@@ -154,7 +182,8 @@ public class AclImplTests {
|
||||
|
||||
@Test
|
||||
public void deleteAceKeepsInitialOrdering() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity,1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Add several permissions
|
||||
@@ -185,10 +214,11 @@ public class AclImplTests {
|
||||
|
||||
@Test
|
||||
public void deleteAceFailsForNonExistentElement() throws Exception {
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity, (1), strategy, pgs, null, null, true, new PrincipalSid(
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
MutableAcl acl = new AclImpl(objectIdentity, (1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
try {
|
||||
acl.deleteAce(99);
|
||||
@@ -200,7 +230,8 @@ public class AclImplTests {
|
||||
|
||||
@Test
|
||||
public void isGrantingRejectsEmptyParameters() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
Sid ben = new PrincipalSid("ben");
|
||||
try {
|
||||
acl.isGranted(new ArrayList<Permission>(0), Arrays.asList(ben) , false);
|
||||
@@ -224,7 +255,8 @@ public class AclImplTests {
|
||||
ObjectIdentity rootOid = new ObjectIdentityImpl(TARGET_CLASS, 100);
|
||||
|
||||
// Create an ACL which owner is not the authenticated principal
|
||||
MutableAcl rootAcl = new AclImpl(rootOid, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
|
||||
MutableAcl rootAcl = new AclImpl(rootOid, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
|
||||
"joe"));
|
||||
|
||||
// Grant some permissions
|
||||
rootAcl.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), false);
|
||||
@@ -267,12 +299,16 @@ public class AclImplTests {
|
||||
ObjectIdentity childOid2 = new ObjectIdentityImpl(TARGET_CLASS, 104);
|
||||
|
||||
// Create ACLs
|
||||
PrincipalSid joe = new PrincipalSid("joe");
|
||||
MutableAcl grandParentAcl = new AclImpl(grandParentOid, 1, authzStrategy, pgs, null, null, false, joe);
|
||||
MutableAcl parentAcl1 = new AclImpl(parentOid1, 2, authzStrategy, pgs, null, null, true, joe);
|
||||
MutableAcl parentAcl2 = new AclImpl(parentOid2, 3, authzStrategy, pgs, null, null, true, joe);
|
||||
MutableAcl childAcl1 = new AclImpl(childOid1, 4, authzStrategy, pgs, null, null, true, joe);
|
||||
MutableAcl childAcl2 = new AclImpl(childOid2, 4, authzStrategy, pgs, null, null, false, joe);
|
||||
MutableAcl grandParentAcl = new AclImpl(grandParentOid, 1, mockAuthzStrategy, mockAuditLogger, null, null, false,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl parentAcl1 = new AclImpl(parentOid1, 2, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl parentAcl2 = new AclImpl(parentOid2, 3, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl childAcl1 = new AclImpl(childOid1, 4, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl childAcl2 = new AclImpl(childOid2, 4, mockAuthzStrategy, mockAuditLogger, null, null, false,
|
||||
new PrincipalSid("joe"));
|
||||
|
||||
// Create hierarchies
|
||||
childAcl2.setParent(childAcl1);
|
||||
@@ -330,7 +366,8 @@ public class AclImplTests {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_GENERAL");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
|
||||
"joe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
@@ -347,7 +384,7 @@ public class AclImplTests {
|
||||
acl.updateAce(1, BasePermission.DELETE);
|
||||
acl.updateAce(2, BasePermission.READ);
|
||||
|
||||
// Check the change was successfully made
|
||||
// Check the change was successfuly made
|
||||
assertEquals(acl.getEntries().get(0).getPermission(), BasePermission.CREATE);
|
||||
assertEquals(acl.getEntries().get(1).getPermission(), BasePermission.DELETE);
|
||||
assertEquals(acl.getEntries().get(2).getPermission(), BasePermission.READ);
|
||||
@@ -358,7 +395,8 @@ public class AclImplTests {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_AUDITING", "ROLE_GENERAL");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
|
||||
"joe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
@@ -383,13 +421,16 @@ public class AclImplTests {
|
||||
|
||||
@Test
|
||||
public void gettersAndSettersAreConsistent() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_GENERAL");
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, (100));
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, (101));
|
||||
MutableAcl acl = new AclImpl(identity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
MutableAcl parentAcl = new AclImpl(identity2, 2, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
MutableAcl acl = new AclImpl(identity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl parentAcl = new AclImpl(identity2, 2, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MockAclService service = new MockAclService();
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
@@ -408,14 +449,14 @@ public class AclImplTests {
|
||||
acl.setEntriesInheriting(false);
|
||||
assertFalse(acl.isEntriesInheriting());
|
||||
|
||||
acl.setOwner(new PrincipalSid("ben"));
|
||||
((OwnershipAcl) acl).setOwner(new PrincipalSid("ben"));
|
||||
assertEquals(acl.getOwner(), new PrincipalSid("ben"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSidLoadedBehavesAsExpected() throws Exception {
|
||||
List<Sid> loadedSids = Arrays.asList(new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_IGNORED"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, loadedSids, true,
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, loadedSids, true,
|
||||
new PrincipalSid("joe"));
|
||||
|
||||
assertTrue(acl.isSidLoaded(loadedSids));
|
||||
@@ -431,19 +472,22 @@ public class AclImplTests {
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void insertAceRaisesNotFoundExceptionForIndexLessThanZero() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
acl.insertAce(-1, mock(Permission.class), mock(Sid.class), true);
|
||||
}
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void deleteAceRaisesNotFoundExceptionForIndexLessThanZero() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
acl.deleteAce(-1);
|
||||
}
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void insertAceRaisesNotFoundExceptionForIndexGreaterThanSize() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
// Insert at zero, OK.
|
||||
acl.insertAce(0, mock(Permission.class), mock(Sid.class), true);
|
||||
// Size is now 1
|
||||
@@ -453,12 +497,23 @@ public class AclImplTests {
|
||||
// SEC-1151
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void deleteAceRaisesNotFoundExceptionForIndexEqualToSize() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
acl.insertAce(0, mock(Permission.class), mock(Sid.class), true);
|
||||
// Size is now 1
|
||||
acl.deleteAce(1);
|
||||
}
|
||||
|
||||
// SEC-1795
|
||||
@Test
|
||||
public void changingParentIsSuccessful() throws Exception {
|
||||
AclImpl parentAcl = new AclImpl(objectIdentity, 1L, mockAuthzStrategy, mockAuditLogger);
|
||||
AclImpl childAcl = new AclImpl(objectIdentity, 2L, mockAuthzStrategy, mockAuditLogger);
|
||||
AclImpl changeParentAcl = new AclImpl(objectIdentity, 3L, mockAuthzStrategy, mockAuditLogger);
|
||||
|
||||
childAcl.setParent(parentAcl);
|
||||
childAcl.setParent(changeParentAcl);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
|
||||
+60
-59
@@ -1,8 +1,8 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.*;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
@@ -10,7 +10,8 @@ import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
@@ -19,31 +20,28 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AclImplementationSecurityCheckTests {
|
||||
public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
protected void setUp() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
protected void tearDown() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecurityCheckNoACEs() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password","ROLE_GENERAL","ROLE_AUDITING","ROLE_OWNERSHIP");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
@@ -52,43 +50,43 @@ public class AclImplementationSecurityCheckTests {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
|
||||
// Create another authorization strategy
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_ONE"), new SimpleGrantedAuthority("ROLE_TWO"),
|
||||
new SimpleGrantedAuthority("ROLE_THREE"));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_THREE") });
|
||||
Acl acl2 = new AclImpl(identity, new Long(1), aclAuthorizationStrategy2, new ConsoleAuditLogger());
|
||||
// Check access in case the principal has no authorization rights
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
fail("It should have thrown NotFoundException");
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
fail("It should have thrown NotFoundException");
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
fail("It should have thrown NotFoundException");
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecurityCheckWithMultipleACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
// Let's give the principal the ADMINISTRATION permission, without
|
||||
// granting access
|
||||
@@ -103,13 +101,13 @@ public class AclImplementationSecurityCheckTests {
|
||||
// nor granting access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
fail("It should have thrown AccessDeniedException");
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
fail("It should have thrown AccessDeniedException");
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
@@ -120,7 +118,7 @@ public class AclImplementationSecurityCheckTests {
|
||||
// (false) will deny this access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
fail("It should have thrown AccessDeniedException");
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
@@ -140,58 +138,58 @@ public class AclImplementationSecurityCheckTests {
|
||||
aclFirstAllow.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
assertTrue(true);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
fail("It shouldn't have thrown AccessDeniedException");
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
|
||||
// Create an ACL with no ACE
|
||||
MutableAcl aclNoACE = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
fail("It should have thrown NotFoundException");
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
// and still grant access for CHANGE_GENERAL
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
assertTrue(true);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
fail("It shouldn't have thrown NotFoundException");
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecurityCheckWithInheritableACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100);
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_ONE"), new SimpleGrantedAuthority("ROLE_TWO"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
// Let's give the principal an ADMINISTRATION permission, with granting
|
||||
// access
|
||||
MutableAcl parentAcl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
MutableAcl parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
parentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
MutableAcl childAcl = new AclImpl(identity, 2, aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
MutableAcl childAcl = new AclImpl(identity, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
// Check against the 'child' acl, which doesn't offer any authorization
|
||||
// rights on CHANGE_OWNERSHIP
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
fail("It should have thrown NotFoundException");
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Link the child with its parent and test again against the
|
||||
@@ -200,60 +198,63 @@ public class AclImplementationSecurityCheckTests {
|
||||
childAcl.setEntriesInheriting(true);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
assertTrue(true);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
fail("It shouldn't have thrown NotFoundException");
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
|
||||
// Create a root parent and link it to the middle parent
|
||||
MutableAcl rootParentAcl = new AclImpl(identity, 1, aclAuthorizationStrategy,
|
||||
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
parentAcl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
rootParentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
parentAcl.setEntriesInheriting(true);
|
||||
parentAcl.setParent(rootParentAcl);
|
||||
childAcl.setParent(parentAcl);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
assertTrue(true);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
fail("It shouldn't have thrown NotFoundException");
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testSecurityCheckPrincipalOwner() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_ONE");
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_ONE"),
|
||||
new GrantedAuthorityImpl("ROLE_ONE") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100);
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
Acl acl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
|
||||
false, new PrincipalSid(auth));
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
fail("It shouldn't have thrown AccessDeniedException");
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
fail("It shouldn't have thrown AccessDeniedException");
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
fail("It shouldn't have thrown AccessDeniedException");
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -19,17 +21,29 @@ import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
*/
|
||||
public class AuditLoggerTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
private Mockery jmock = new JUnit4Mockery();
|
||||
private PrintStream console;
|
||||
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
private ConsoleAuditLogger logger;
|
||||
private AuditableAccessControlEntry ace;
|
||||
private Expectations aceRequiresAudit;
|
||||
private Expectations aceDoesntRequireAudit;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
logger = new ConsoleAuditLogger();
|
||||
ace = mock(AuditableAccessControlEntry.class);
|
||||
ace = jmock.mock(AuditableAccessControlEntry.class);
|
||||
aceRequiresAudit = new Expectations() {{
|
||||
allowing(ace).isAuditSuccess(); will(returnValue(true));
|
||||
allowing(ace).isAuditFailure(); will(returnValue(true));
|
||||
}};
|
||||
aceDoesntRequireAudit = new Expectations() {{
|
||||
allowing(ace).isAuditSuccess(); will(returnValue(false));
|
||||
allowing(ace).isAuditFailure(); will(returnValue(false));
|
||||
}};
|
||||
|
||||
console = System.out;
|
||||
System.setOut(new PrintStream(bytes));
|
||||
}
|
||||
@@ -42,36 +56,35 @@ public class AuditLoggerTests {
|
||||
|
||||
@Test
|
||||
public void nonAuditableAceIsIgnored() {
|
||||
AccessControlEntry ace = mock(AccessControlEntry.class);
|
||||
AccessControlEntry ace = jmock.mock(AccessControlEntry.class);
|
||||
logger.logIfNeeded(true, ace);
|
||||
assertEquals(0, bytes.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successIsNotLoggedIfAceDoesntRequireSuccessAudit() throws Exception {
|
||||
when(ace.isAuditSuccess()).thenReturn(false);
|
||||
jmock.checking(aceDoesntRequireAudit);
|
||||
logger.logIfNeeded(true, ace);
|
||||
assertEquals(0, bytes.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successIsLoggedIfAceRequiresSuccessAudit() throws Exception {
|
||||
when(ace.isAuditSuccess()).thenReturn(true);
|
||||
|
||||
jmock.checking(aceRequiresAudit);
|
||||
logger.logIfNeeded(true, ace);
|
||||
assertTrue(bytes.toString().startsWith("GRANTED due to ACE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failureIsntLoggedIfAceDoesntRequireFailureAudit() throws Exception {
|
||||
when(ace.isAuditFailure()).thenReturn(false);
|
||||
jmock.checking(aceDoesntRequireAudit);
|
||||
logger.logIfNeeded(false, ace);
|
||||
assertEquals(0, bytes.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failureIsLoggedIfAceRequiresFailureAudit() throws Exception {
|
||||
when(ace.isAuditFailure()).thenReturn(true);
|
||||
jmock.checking(aceRequiresAudit);
|
||||
logger.logIfNeeded(false, ace);
|
||||
assertTrue(bytes.toString().startsWith("DENIED due to ACE"));
|
||||
}
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ public class ObjectIdentityImplTests {
|
||||
@Test
|
||||
public void longAndIntegerIdsWithSameValueAreEqualAndHaveSameHashcode() {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(Object.class, new Long(5));
|
||||
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, Integer.valueOf(5));
|
||||
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, new Integer(5));
|
||||
|
||||
assertEquals(obj, obj2);
|
||||
assertEquals(obj.hashCode(), obj2.hashCode());
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ public class ObjectIdentityRetrievalStrategyImplTests extends TestCase {
|
||||
|
||||
public void testObjectIdentityCreation() throws Exception {
|
||||
MockIdDomainObject domain = new MockIdDomainObject();
|
||||
domain.setId(Integer.valueOf(1));
|
||||
domain.setId(new Integer(1));
|
||||
|
||||
ObjectIdentityRetrievalStrategy retStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
ObjectIdentity identity = retStrategy.getObjectIdentity(domain);
|
||||
|
||||
+41
-33
@@ -1,10 +1,19 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import org.junit.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -14,7 +23,6 @@ import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
|
||||
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
@@ -25,11 +33,10 @@ import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Tests {@link BasicLookupStrategy}
|
||||
*
|
||||
@@ -93,9 +100,10 @@ public class BasicLookupStrategyTests {
|
||||
@Before
|
||||
public void initializeBeans() {
|
||||
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache());
|
||||
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
|
||||
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy,
|
||||
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
|
||||
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"), new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"),
|
||||
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy, new ConsoleAuditLogger());
|
||||
strategy.setPermissionFactory(new DefaultPermissionFactory());
|
||||
}
|
||||
|
||||
@@ -120,7 +128,7 @@ public class BasicLookupStrategyTests {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(102));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(102));
|
||||
|
||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
@@ -128,7 +136,7 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalFromCacheOnly() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(100));
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||
|
||||
@@ -145,11 +153,11 @@ public class BasicLookupStrategyTests {
|
||||
@Test
|
||||
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(101));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||
|
||||
// Set a batch size to allow multiple database queries in order to retrieve all acls
|
||||
this.strategy.setBatchSize(1);
|
||||
((BasicLookupStrategy) this.strategy).setBatchSize(1);
|
||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
}
|
||||
@@ -184,36 +192,36 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
// Check each entry
|
||||
Assert.assertTrue(topParent.isEntriesInheriting());
|
||||
Assert.assertEquals(topParent.getId(), Long.valueOf(1));
|
||||
Assert.assertEquals(topParent.getId(), new Long(1));
|
||||
Assert.assertEquals(topParent.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(topParent.getEntries().get(0).getId(), Long.valueOf(1));
|
||||
Assert.assertEquals(topParent.getEntries().get(0).getId(), new Long(1));
|
||||
Assert.assertEquals(topParent.getEntries().get(0).getPermission(), BasePermission.READ);
|
||||
Assert.assertEquals(topParent.getEntries().get(0).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditSuccess());
|
||||
Assert.assertTrue((topParent.getEntries().get(0)).isGranting());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isGranting());
|
||||
|
||||
Assert.assertEquals(topParent.getEntries().get(1).getId(), Long.valueOf(2));
|
||||
Assert.assertEquals(topParent.getEntries().get(1).getId(), new Long(2));
|
||||
Assert.assertEquals(topParent.getEntries().get(1).getPermission(), BasePermission.WRITE);
|
||||
Assert.assertEquals(topParent.getEntries().get(1).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditSuccess());
|
||||
Assert.assertFalse(topParent.getEntries().get(1).isGranting());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isGranting());
|
||||
|
||||
Assert.assertTrue(middleParent.isEntriesInheriting());
|
||||
Assert.assertEquals(middleParent.getId(), Long.valueOf(2));
|
||||
Assert.assertEquals(middleParent.getId(), new Long(2));
|
||||
Assert.assertEquals(middleParent.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(middleParent.getEntries().get(0).getId(), Long.valueOf(3));
|
||||
Assert.assertEquals(middleParent.getEntries().get(0).getId(), new Long(3));
|
||||
Assert.assertEquals(middleParent.getEntries().get(0).getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(middleParent.getEntries().get(0).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditSuccess());
|
||||
Assert.assertTrue(middleParent.getEntries().get(0).isGranting());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isGranting());
|
||||
|
||||
Assert.assertTrue(child.isEntriesInheriting());
|
||||
Assert.assertEquals(child.getId(), Long.valueOf(3));
|
||||
Assert.assertEquals(child.getId(), new Long(3));
|
||||
Assert.assertEquals(child.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(child.getEntries().get(0).getId(), Long.valueOf(4));
|
||||
Assert.assertEquals(child.getEntries().get(0).getId(), new Long(4));
|
||||
Assert.assertEquals(child.getEntries().get(0).getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(child.getEntries().get(0).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditFailure());
|
||||
@@ -226,21 +234,21 @@ public class BasicLookupStrategyTests {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,103,1,1,1);";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102));
|
||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(103));
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(103));
|
||||
|
||||
// Retrieve the child
|
||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(childOid), null);
|
||||
|
||||
// Check that the child and all its parents were retrieved
|
||||
Assert.assertNotNull(map.get(childOid));
|
||||
Assert.assertEquals(childOid, map.get(childOid).getObjectIdentity());
|
||||
Assert.assertEquals(childOid, ((Acl) map.get(childOid)).getObjectIdentity());
|
||||
Assert.assertNotNull(map.get(middleParentOid));
|
||||
Assert.assertEquals(middleParentOid, map.get(middleParentOid).getObjectIdentity());
|
||||
Assert.assertEquals(middleParentOid, ((Acl) map.get(middleParentOid)).getObjectIdentity());
|
||||
Assert.assertNotNull(map.get(topParentOid));
|
||||
Assert.assertEquals(topParentOid, map.get(topParentOid).getObjectIdentity());
|
||||
Assert.assertEquals(topParentOid, ((Acl) map.get(topParentOid)).getObjectIdentity());
|
||||
|
||||
// The second parent shouldn't have been retrieved
|
||||
Assert.assertNull(map.get(middleParent2Oid));
|
||||
@@ -260,8 +268,8 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
|
||||
ObjectIdentity parent1Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(105));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(107));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(107));
|
||||
|
||||
// First lookup only child, thus populating the cache with grandParent, parent1 and child
|
||||
List<Permission> checkPermission = Arrays.asList(BasePermission.READ);
|
||||
@@ -271,7 +279,7 @@ public class BasicLookupStrategyTests {
|
||||
strategy.setBatchSize(6);
|
||||
Map<ObjectIdentity, Acl> foundAcls = strategy.readAclsById(childOids, sids);
|
||||
|
||||
Acl foundChildAcl = foundAcls.get(childOid);
|
||||
Acl foundChildAcl = (Acl) foundAcls.get(childOid);
|
||||
Assert.assertNotNull(foundChildAcl);
|
||||
Assert.assertTrue(foundChildAcl.isGranted(checkPermission, sids, false));
|
||||
|
||||
@@ -285,7 +293,7 @@ public class BasicLookupStrategyTests {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
|
||||
Acl foundParent2Acl = foundAcls.get(parent2Oid);
|
||||
Acl foundParent2Acl = (Acl) foundAcls.get(parent2Oid);
|
||||
Assert.assertNotNull(foundParent2Acl);
|
||||
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
|
||||
}
|
||||
|
||||
+45
-39
@@ -2,10 +2,22 @@ package org.springframework.security.acls.jdbc;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import org.junit.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
@@ -16,18 +28,11 @@ import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Tests {@link EhCacheBasedAclCache}
|
||||
*
|
||||
@@ -122,11 +127,11 @@ public class EhCacheBasedAclCacheTests {
|
||||
// SEC-527
|
||||
@Test
|
||||
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
// Serialization test
|
||||
File file = File.createTempFile("SEC_TEST", ".object");
|
||||
@@ -145,7 +150,7 @@ public class EhCacheBasedAclCacheTests {
|
||||
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
|
||||
assertEquals(null, retrieved1);
|
||||
|
||||
Object retrieved2 = FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", retrieved);
|
||||
Object retrieved2 = FieldUtils.getProtectedFieldValue("auditLogger", retrieved);
|
||||
assertEquals(null, retrieved2);
|
||||
}
|
||||
|
||||
@@ -154,11 +159,11 @@ public class EhCacheBasedAclCacheTests {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
myCache.putInCache(acl);
|
||||
@@ -168,29 +173,29 @@ public class EhCacheBasedAclCacheTests {
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
assertEquals(myCache.getFromCache(Long.valueOf(1)), acl);
|
||||
assertEquals(myCache.getFromCache(new Long(1)), acl);
|
||||
assertEquals(myCache.getFromCache(identity), acl);
|
||||
|
||||
// Put another object in cache
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
|
||||
MutableAcl acl2 = new AclImpl(identity2, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||
MutableAcl acl2 = new AclImpl(identity2, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
myCache.putInCache(acl2);
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
// Try to evict an entry that doesn't exist
|
||||
myCache.evictFromCache(Long.valueOf(3));
|
||||
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102)));
|
||||
myCache.evictFromCache(new Long(3));
|
||||
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, new Long(102)));
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
myCache.evictFromCache(Long.valueOf(1));
|
||||
myCache.evictFromCache(new Long(1));
|
||||
assertEquals(cache.getSize(), 2);
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
|
||||
// Check the second object inserted
|
||||
assertEquals(myCache.getFromCache(Long.valueOf(2)), acl2);
|
||||
assertEquals(myCache.getFromCache(new Long(2)), acl2);
|
||||
assertEquals(myCache.getFromCache(identity2), acl2);
|
||||
|
||||
myCache.evictFromCache(identity2);
|
||||
@@ -203,17 +208,18 @@ public class EhCacheBasedAclCacheTests {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(1));
|
||||
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
MutableAcl parentAcl = new AclImpl(identityParent, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(1));
|
||||
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, new Long(2));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
MutableAcl parentAcl = new AclImpl(identityParent, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
|
||||
@@ -234,17 +240,17 @@ public class EhCacheBasedAclCacheTests {
|
||||
}
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(1));
|
||||
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(new Long(1));
|
||||
// For the checks on transient fields, we need to be sure that the object is being loaded from the cache,
|
||||
// not from the ehcache spool or elsewhere...
|
||||
assertFalse(acl == aclFromCache);
|
||||
assertEquals(acl, aclFromCache);
|
||||
// SEC-951 check transient fields are set on parent
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "aclAuthorizationStrategy"));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "permissionGrantingStrategy"));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "auditLogger"));
|
||||
assertEquals(acl, myCache.getFromCache(identity));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache, "aclAuthorizationStrategy"));
|
||||
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(2));
|
||||
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(new Long(2));
|
||||
assertEquals(parentAcl, parentAclFromCache);
|
||||
assertNotNull(FieldUtils.getFieldValue(parentAclFromCache, "aclAuthorizationStrategy"));
|
||||
assertEquals(parentAcl, myCache.getFromCache(identityParent));
|
||||
|
||||
+2
-3
@@ -4,7 +4,6 @@ import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -54,8 +53,8 @@ public class SidRetrievalStrategyTests {
|
||||
@Test
|
||||
public void roleHierarchyIsUsedWhenSet() throws Exception {
|
||||
RoleHierarchy rh = mock(RoleHierarchy.class);
|
||||
List rhAuthorities = AuthorityUtils.createAuthorityList("D");
|
||||
when(rh.getReachableGrantedAuthorities(anyCollection())).thenReturn(rhAuthorities);
|
||||
List<GrantedAuthority> rhAuthorities = AuthorityUtils.createAuthorityList("D");
|
||||
when(rh.getReachableGrantedAuthorities(anyList())).thenReturn(rhAuthorities);
|
||||
SidRetrievalStrategy strat = new SidRetrievalStrategyImpl(rh);
|
||||
|
||||
List<Sid> sids = strat.getSids(authentication);
|
||||
|
||||
@@ -2,13 +2,14 @@ package org.springframework.security.acls.sid;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
|
||||
public class SidTests extends TestCase {
|
||||
|
||||
@@ -108,7 +109,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
GrantedAuthority ga = new SimpleGrantedAuthority(null);
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl(null);
|
||||
new GrantedAuthoritySid(ga);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
@@ -117,7 +118,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
new GrantedAuthoritySid(ga);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
@@ -141,15 +142,15 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testGrantedAuthoritySidEquals() throws Exception {
|
||||
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
Assert.assertFalse(gaSid.equals(null));
|
||||
Assert.assertFalse(gaSid.equals("DIFFERENT_TYPE_OBJECT"));
|
||||
Assert.assertTrue(gaSid.equals(gaSid));
|
||||
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(ga)));
|
||||
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_TEST"))));
|
||||
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_NOT_EQUAL"))));
|
||||
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST"))));
|
||||
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_NOT_EQUAL"))));
|
||||
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid("ROLE_TEST")));
|
||||
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid("ROLE_NOT_EQUAL")));
|
||||
}
|
||||
@@ -158,26 +159,26 @@ public class SidTests extends TestCase {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
|
||||
Assert.assertTrue(principalSid.hashCode() == "johndoe".hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() == new String("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() == new PrincipalSid("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid("scott").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
|
||||
}
|
||||
|
||||
public void testGrantedAuthoritySidHashCode() throws Exception {
|
||||
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
Assert.assertTrue(gaSid.hashCode() == "ROLE_TEST".hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() == new String("ROLE_TEST").hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() == new GrantedAuthoritySid("ROLE_TEST").hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid("ROLE_TEST_2").hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_TEST_2")).hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST_2")).hashCode());
|
||||
}
|
||||
|
||||
public void testGetters() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
PrincipalSid principalSid = new PrincipalSid(authentication);
|
||||
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
Assert.assertTrue("johndoe".equals(principalSid.getPrincipal()));
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
</list>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
|
||||
|
||||
<root level="${root.level}:-WARN">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
+13
-12
@@ -5,18 +5,19 @@ Bundle-Name: Spring Security Acls
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-Version: ${version}
|
||||
Bundle-ManifestVersion: 2
|
||||
Ignored-Existing-Headers:
|
||||
Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
|
||||
org.springframework.security.core.*;version="[${version}, 3.2.0)",
|
||||
org.springframework.security.access.*;version="[${version}, 3.2.0)",
|
||||
org.springframework.security.util.*;version="[${version}, 3.2.0)",
|
||||
org.springframework.context.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
|
||||
org.springframework.dao.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
|
||||
org.springframework.jdbc.core.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
|
||||
org.springframework.util.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
Import-Template:
|
||||
org.aopalliance.*;version="${aopAllianceRange}",
|
||||
org.apache.commons.logging.*;version="${cloggingRange}",
|
||||
org.springframework.security.core.*;version="${secRange}",
|
||||
org.springframework.security.access.*;version="${secRange}",
|
||||
org.springframework.security.util.*;version="${secRange}",
|
||||
org.springframework.context.*;version="${springRange}";resolution:=optional,
|
||||
org.springframework.dao.*;version="${springRange}";resolution:=optional,
|
||||
org.springframework.jdbc.core.*;version="${springRange}";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="${springRange}";resolution:=optional,
|
||||
org.springframework.util.*;version="${springRange}";resolution:=optional,
|
||||
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
|
||||
javax.sql.*;version="0";resolution:=optional
|
||||
|
||||
@@ -3,6 +3,4 @@ dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion"
|
||||
|
||||
testCompile 'aopalliance:aopalliance:1.0'
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>@pomVersion@</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<name>Spring Security - Aspects</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>@pomVersion@</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>aspectj-maven-plugin</artifactId>
|
||||
<version>1.2</version>
|
||||
<dependencies>
|
||||
<!--
|
||||
NB: You must use Maven 2.0.9 or above or these
|
||||
are ignored (see MNG-2972)
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
<version>1.6.8</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+4
-35
@@ -1,10 +1,6 @@
|
||||
package org.springframework.security.access.intercept.aspectj.aspect;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -18,12 +14,8 @@ import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
|
||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
||||
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
|
||||
@@ -82,33 +74,15 @@ public class AnnotationSecurityAspectTests {
|
||||
// SEC-1262
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
|
||||
configureForElAnnotations();
|
||||
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||
prePostSecured.denyAllMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postFilterIsApplied() throws Exception {
|
||||
configureForElAnnotations();
|
||||
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||
List<String> objects = prePostSecured.postFilterMethod();
|
||||
assertEquals(2, objects.size());
|
||||
assertTrue(objects.contains("apple"));
|
||||
assertTrue(objects.contains("aubergine"));
|
||||
}
|
||||
|
||||
private void configureForElAnnotations() {
|
||||
DefaultMethodSecurityExpressionHandler eh = new DefaultMethodSecurityExpressionHandler();
|
||||
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
|
||||
new ExpressionBasedAnnotationAttributeFactory(eh)));
|
||||
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
|
||||
AffirmativeBased adm = new AffirmativeBased();
|
||||
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
|
||||
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
|
||||
adm.setDecisionVoters(Arrays.asList(voters));
|
||||
interceptor.setAccessDecisionManager(adm);
|
||||
AfterInvocationProviderManager aim = new AfterInvocationProviderManager();
|
||||
aim.setProviders(Arrays.asList(new PostInvocationAdviceProvider(new ExpressionBasedPostInvocationAdvice(eh))));
|
||||
interceptor.setAfterInvocationManager(aim);
|
||||
prePostSecured.denyAllMethod();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +92,7 @@ interface SecuredInterface {
|
||||
}
|
||||
|
||||
class SecuredImpl implements SecuredInterface {
|
||||
|
||||
// Not really secured because AspectJ doesn't inherit annotations from interfaces
|
||||
public void securedMethod() {
|
||||
}
|
||||
@@ -128,14 +103,8 @@ class SecuredImpl implements SecuredInterface {
|
||||
}
|
||||
|
||||
class PrePostSecured {
|
||||
|
||||
@PreAuthorize("denyAll")
|
||||
public void denyAllMethod() {
|
||||
}
|
||||
|
||||
@PostFilter("filterObject.startsWith('a')")
|
||||
public List<String> postFilterMethod() {
|
||||
ArrayList<String> objects = new ArrayList<String>();
|
||||
objects.addAll(Arrays.asList(new String[] {"apple", "banana", "aubergine", "orange"}));
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -9,6 +9,8 @@ Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
org.aspectj.*;version="[1.6.0, 1.7.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
|
||||
org.springframework.security.core.*;version="[${version}, 3.2.0)"
|
||||
org.aspectj.*;version="${aspectjRange}";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="${cloggingRange}",
|
||||
org.springframework.security.core.*;version="${secRange}",
|
||||
org.springframework.security.access.intercept.aspectj;version="${secRange}",
|
||||
org.springframework.beans.factory;version="${springRange}"
|
||||
|
||||
+38
-59
@@ -1,40 +1,34 @@
|
||||
apply plugin: 'base'
|
||||
|
||||
description = 'Spring Security'
|
||||
allprojects {
|
||||
version = '3.1.0.M2'
|
||||
releaseBuild = version.endsWith('RELEASE')
|
||||
snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
ext.releaseBuild = version.endsWith('RELEASE')
|
||||
ext.snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
|
||||
group = 'org.springframework.security'
|
||||
|
||||
repositories {
|
||||
mavenRepo name:'Local', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||
mavenCentral()
|
||||
mavenRepo name: 'SpringSource Milestone Repo', urls: 'http://repository.springsource.com/maven/bundles/milestone'
|
||||
mavenRepo name: 'SpringSource Maven Snapshot Repo', urls: 'http://maven.springframework.org/snapshot/'
|
||||
mavenRepo name: 'SpringSource Enterprise Release', urls: 'http://repository.springsource.com/maven/bundles/release'
|
||||
mavenRepo name: 'SpringSource Enterprise External', urls: 'http://repository.springsource.com/maven/bundles/external'
|
||||
// mavenRepo(name: 'Spock Snapshots', urls: 'http://m2repo.spockframework.org/snapshots')
|
||||
}
|
||||
}
|
||||
|
||||
// Set up different subproject lists for individual configuration
|
||||
javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'faq' && project.name != 'manual' }
|
||||
sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
|
||||
itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
|
||||
coreModuleProjects = javaProjects - sampleProjects - itestProjects
|
||||
aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj')]
|
||||
|
||||
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'faq' && project.name != 'manual' }
|
||||
ext.sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
|
||||
ext.itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
|
||||
ext.coreModuleProjects = javaProjects - sampleProjects - itestProjects
|
||||
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj')]
|
||||
configure(javaProjects) {
|
||||
apply from: "$rootDir/gradle/javaprojects.gradle"
|
||||
}
|
||||
|
||||
configure(coreModuleProjects) {
|
||||
apply from: "$rootDir/gradle/bundlor.gradle"
|
||||
apply from: "$rootDir/gradle/maven-deployment.gradle"
|
||||
apply from: "$rootDir/gradle/emma.gradle"
|
||||
// Gives better names in structure101 jar diagram
|
||||
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
|
||||
sourceSets.main.output.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
|
||||
apply plugin: 'bundlor'
|
||||
bundlor.expansions = bundlorProperties
|
||||
apply from: "$rootDir/gradle/maven-deployment.gradle"
|
||||
apply plugin: 'emma'
|
||||
}
|
||||
|
||||
task coreBuild {
|
||||
@@ -42,55 +36,40 @@ task coreBuild {
|
||||
}
|
||||
|
||||
configure (aspectjProjects) {
|
||||
apply from: "$rootDir/gradle/aspectj.gradle"
|
||||
apply plugin: 'aspectj'
|
||||
}
|
||||
|
||||
apply from: "$rootDir/gradle/dist.gradle"
|
||||
// Task for creating the distro zip
|
||||
|
||||
apply plugin: 'idea'
|
||||
|
||||
configure(javaProjects) {
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
ideaModule {
|
||||
downloadJavadoc=false
|
||||
excludeDirs.add(buildDir)
|
||||
gradleCacheVariable = 'GRADLE_CACHE'
|
||||
outputDir = "$rootProject.projectDir/intellij/out" as File
|
||||
testOutputDir = "$rootProject.projectDir/intellij/testOut" as File
|
||||
whenConfigured { module ->
|
||||
def allClasses = module.dependencies.findAll() { dep ->
|
||||
if (dep instanceof org.gradle.plugins.idea.model.ModuleLibrary
|
||||
&& dep.classes.find { path ->
|
||||
path.url.matches('.*jcl-over-slf4j.*') ||
|
||||
path.url.matches('.*servlet-api.*') ||
|
||||
path.url.matches('.*jsp-api.*')
|
||||
}) {
|
||||
dep.scope = 'COMPILE'
|
||||
dep.exported = false
|
||||
}
|
||||
}
|
||||
task dist(type: Zip) {
|
||||
dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' || task.name.endsWith('Zip') }
|
||||
classifier = 'dist'
|
||||
evaluationDependsOn(':docs')
|
||||
def zipRootDir = "${project.name}-$version"
|
||||
into(zipRootDir) {
|
||||
from(rootDir) {
|
||||
include '*.txt'
|
||||
}
|
||||
into('docs') {
|
||||
with(project(':docs').apiSpec)
|
||||
with(project(':docs:manual').spec)
|
||||
}
|
||||
into('dist') {
|
||||
from coreModuleProjects.collect {project -> project.libsDir }
|
||||
from project(':spring-security-samples-tutorial').libsDir
|
||||
from project(':spring-security-samples-contacts').libsDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ideaModule {
|
||||
excludeDirs += file('.gradle')
|
||||
excludeDirs += file('buildSrc/build')
|
||||
excludeDirs += file('buildSrc/.gradle')
|
||||
artifacts {
|
||||
archives dist
|
||||
archives project(':docs').docsZip
|
||||
archives project(':docs').schemaZip
|
||||
}
|
||||
|
||||
ideaProject {
|
||||
javaVersion = '1.6'
|
||||
subprojects = [rootProject] + javaProjects
|
||||
withXml { node ->
|
||||
// Use git
|
||||
def vcsConfig = node.component.find { it.'@name' == 'VcsDirectoryMappings' }
|
||||
vcsConfig.mapping[0].'@vcs' = 'Git'
|
||||
}
|
||||
}
|
||||
apply from: "$rootDir/gradle/ide-integration.gradle"
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '0.9'
|
||||
gradleVersion = '1.1'
|
||||
}
|
||||
|
||||
+22
-6
@@ -1,10 +1,15 @@
|
||||
apply plugin: 'groovy'
|
||||
|
||||
repositories {
|
||||
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||
mavenCentral()
|
||||
mavenRepo name: 'GAE', urls:'http://maven-gae-plugin.googlecode.com/svn/repository'
|
||||
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
|
||||
maven {
|
||||
name = 'SpringSource Enterprise Release'
|
||||
url = 'http://repository.springsource.com/maven/bundles/release'
|
||||
}
|
||||
maven {
|
||||
name = 'SpringSource Enterprise External'
|
||||
url = 'http://repository.springsource.com/maven/bundles/external'
|
||||
}
|
||||
}
|
||||
|
||||
// Docbook Plugin
|
||||
@@ -19,9 +24,10 @@ dependencies {
|
||||
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
|
||||
groovy localGroovy()
|
||||
compile gradleApi(),
|
||||
'org.apache.xerces:resolver:2.9.1',
|
||||
'org.apache.xerces:xercesImpl:2.9.1',
|
||||
'xml-resolver:xml-resolver:1.2',
|
||||
'xerces:xercesImpl:2.9.1',
|
||||
'saxon:saxon:6.5.3',
|
||||
'net.java.dev.jets3t:jets3t:0.6.1',
|
||||
fopDeps
|
||||
|
||||
runtime 'net.sf.xslthl:xslthl:2.0.1',
|
||||
@@ -30,7 +36,17 @@ dependencies {
|
||||
|
||||
// GAE
|
||||
dependencies {
|
||||
compile 'com.google.appengine:appengine-tools-api:1.3.7'
|
||||
compile 'com.google.appengine:appengine-tools-sdk:1.4.2'
|
||||
}
|
||||
|
||||
dependencies{
|
||||
compile "emma:emma:2.0.5312"
|
||||
}
|
||||
|
||||
// Bundlor
|
||||
dependencies {
|
||||
compile 'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RELEASE',
|
||||
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RELEASE'
|
||||
}
|
||||
|
||||
task ide(type: Copy) {
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.tasks.*;
|
||||
import org.gradle.api.tasks.bundling.Tar;
|
||||
import org.gradle.api.tasks.bundling.Compression;
|
||||
|
||||
/**
|
||||
* Extends the Tar task, uploading the created archive to a remote directory, unpacking and deleting it.
|
||||
* Requires Ant ssh (jsch) support.
|
||||
*/
|
||||
class TarUpload extends Tar {
|
||||
@Input
|
||||
String remoteDir
|
||||
Login login
|
||||
@Input
|
||||
String host
|
||||
|
||||
TarUpload() {
|
||||
compression = Compression.BZIP2
|
||||
if (project.configurations.findByName('antjsch') == null) {
|
||||
project.configurations.add('antjsch')
|
||||
project.dependencies {
|
||||
antjsch 'org.apache.ant:ant-jsch:1.8.1'
|
||||
}
|
||||
def classpath = project.configurations.antjsch.asPath
|
||||
project.ant {
|
||||
taskdef(name: 'scp', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', classpath: classpath)
|
||||
taskdef(name: 'sshexec', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', classpath: classpath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void copy() {
|
||||
super.copy();
|
||||
upload();
|
||||
}
|
||||
|
||||
def upload() {
|
||||
String username = login.username
|
||||
String password = login.password
|
||||
String host = login.host
|
||||
project.ant {
|
||||
scp(file: archivePath, todir: "$username@$host:$remoteDir", password: password)
|
||||
sshexec(host: host, username: username, password: password, command: "cd $remoteDir && tar -xjf $archiveName")
|
||||
sshexec(host: host, username: username, password: password, command: "rm $remoteDir/$archiveName")
|
||||
}
|
||||
}
|
||||
|
||||
void setLogin(Login login) {
|
||||
dependsOn(login)
|
||||
this.login = login
|
||||
this.host = login.host
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores login information for a remote host.
|
||||
*/
|
||||
class Login extends DefaultTask {
|
||||
@Input
|
||||
String host
|
||||
String username
|
||||
String password
|
||||
|
||||
@TaskAction
|
||||
login() {
|
||||
def console = System.console()
|
||||
if (console) {
|
||||
username = console.readLine("\nPlease enter the ssh username for host '$host': ")
|
||||
password = new String(console.readPassword("Please enter the ssh password for '$host': "))
|
||||
} else {
|
||||
logger.error "Unable to access System.console()."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package aspectj
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
|
||||
import org.gradle.plugins.ide.eclipse.GenerateEclipseProject
|
||||
import org.gradle.plugins.ide.eclipse.GenerateEclipseClasspath
|
||||
import org.gradle.plugins.ide.eclipse.EclipsePlugin
|
||||
import org.gradle.plugins.ide.eclipse.model.BuildCommand
|
||||
import org.gradle.plugins.ide.eclipse.model.ProjectDependency
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
class AspectJPlugin implements Plugin<Project> {
|
||||
|
||||
void apply(Project project) {
|
||||
if (!project.hasProperty('aspectjVersion')) {
|
||||
throw new GradleException("You must set the property 'aspectjVersion' before applying the aspectj plugin")
|
||||
}
|
||||
|
||||
if (project.configurations.findByName('ajtools') == null) {
|
||||
project.configurations.add('ajtools')
|
||||
project.dependencies {
|
||||
ajtools "org.aspectj:aspectjtools:${project.aspectjVersion}"
|
||||
compile "org.aspectj:aspectjrt:${project.aspectjVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
if (project.configurations.findByName('aspectpath') == null) {
|
||||
project.configurations.add('aspectpath')
|
||||
}
|
||||
|
||||
project.tasks.add(name: 'compileJava', overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
|
||||
dependsOn project.processResources
|
||||
sourceSet = project.sourceSets.main
|
||||
inputs.files(sourceSet.java.srcDirs)
|
||||
outputs.dir(sourceSet.output.classesDir)
|
||||
aspectPath = project.configurations.aspectpath
|
||||
}
|
||||
|
||||
project.tasks.add(name: 'compileTestJava', overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
|
||||
dependsOn project.processTestResources, project.compileJava, project.jar
|
||||
sourceSet = project.sourceSets.test
|
||||
inputs.files(sourceSet.java.srcDirs)
|
||||
outputs.dir(sourceSet.output.classesDir)
|
||||
aspectPath = project.files(project.configurations.aspectpath, project.jar.archivePath)
|
||||
}
|
||||
|
||||
project.tasks.withType(GenerateEclipseProject) {
|
||||
project.eclipse.project.file.whenMerged { p ->
|
||||
p.natures.add(0, 'org.eclipse.ajdt.ui.ajnature')
|
||||
p.buildCommands = [new BuildCommand('org.eclipse.ajdt.core.ajbuilder')]
|
||||
}
|
||||
}
|
||||
|
||||
project.tasks.withType(GenerateEclipseClasspath) {
|
||||
project.eclipse.classpath.file.whenMerged { classpath ->
|
||||
def entries = classpath.entries.findAll { it instanceof ProjectDependency}.findAll { entry ->
|
||||
def projectPath = entry.path.replaceAll('/',':')
|
||||
println projectPath
|
||||
project.rootProject.allprojects.find{ p->
|
||||
if(p.plugins.findPlugin(EclipsePlugin)) {
|
||||
println " checking " + p.eclipse.project.name
|
||||
return p.eclipse.project.name == projectPath && p.plugins.findPlugin(AspectJPlugin)
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
entries.each { entry->
|
||||
entry.entryAttributes.put('org.eclipse.ajdt.aspectpath','org.eclipse.ajdt.aspectpath')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Ajc extends DefaultTask {
|
||||
SourceSet sourceSet
|
||||
FileCollection aspectPath
|
||||
|
||||
Ajc() {
|
||||
logging.captureStandardOutput(LogLevel.INFO)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
def compile() {
|
||||
logger.info("Running ajc ...")
|
||||
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: project.configurations.ajtools.asPath)
|
||||
ant.iajc(classpath: sourceSet.compileClasspath.asPath, fork: 'true', destDir: sourceSet.output.classesDir.absolutePath,
|
||||
source: project.convention.plugins.java.sourceCompatibility,
|
||||
target: project.convention.plugins.java.targetCompatibility,
|
||||
aspectPath: aspectPath.asPath, sourceRootCopyFilter: '**/*.java', showWeaveInfo: 'true') {
|
||||
sourceroots {
|
||||
sourceSet.java.srcDirs.each {
|
||||
pathelement(location: it.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package bundlor
|
||||
|
||||
import com.springsource.bundlor.ClassPath
|
||||
import com.springsource.bundlor.ManifestGenerator
|
||||
import com.springsource.bundlor.ManifestWriter
|
||||
import com.springsource.bundlor.blint.ManifestValidator
|
||||
import com.springsource.bundlor.blint.support.DefaultManifestValidatorContributorsFactory
|
||||
import com.springsource.bundlor.blint.support.StandardManifestValidator
|
||||
import com.springsource.bundlor.support.DefaultManifestGeneratorContributorsFactory
|
||||
import com.springsource.bundlor.support.StandardManifestGenerator
|
||||
import com.springsource.bundlor.support.classpath.FileSystemClassPath
|
||||
import com.springsource.bundlor.support.manifestwriter.FileSystemManifestWriter
|
||||
import com.springsource.bundlor.support.properties.EmptyPropertiesSource
|
||||
import com.springsource.bundlor.support.properties.FileSystemPropertiesSource
|
||||
import com.springsource.bundlor.support.properties.PropertiesPropertiesSource
|
||||
import com.springsource.bundlor.support.properties.PropertiesSource
|
||||
import com.springsource.bundlor.util.BundleManifestUtils
|
||||
import com.springsource.util.parser.manifest.ManifestContents
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
class BundlorPlugin implements Plugin<Project> {
|
||||
void apply(Project project) {
|
||||
Task bundlor = project.tasks.add('bundlor', Bundlor.class)
|
||||
bundlor.setDescription('Generates OSGi manifest using bundlor tool')
|
||||
bundlor.dependsOn(project.classes)
|
||||
project.jar.dependsOn bundlor
|
||||
}
|
||||
}
|
||||
|
||||
public class Bundlor extends DefaultTask {
|
||||
@InputFile
|
||||
@Optional
|
||||
File manifestTemplate
|
||||
|
||||
@OutputDirectory
|
||||
File bundlorDir = new File("${project.buildDir}/bundlor")
|
||||
|
||||
@OutputFile
|
||||
File manifest = project.file("${bundlorDir}/META-INF/MANIFEST.MF")
|
||||
|
||||
@Input
|
||||
Map<String,String> expansions = [:]
|
||||
|
||||
@InputFile
|
||||
@Optional
|
||||
File osgiProfile
|
||||
|
||||
@InputFiles
|
||||
@Optional
|
||||
FileCollection inputPaths
|
||||
|
||||
@Input
|
||||
boolean failOnWarnings = false
|
||||
|
||||
Bundlor() {
|
||||
manifestTemplate = new File(project.projectDir, 'template.mf')
|
||||
|
||||
if (!manifestTemplate.exists()) {
|
||||
logger.info("No bundlor template for project " + project.name)
|
||||
manifestTemplate = null
|
||||
}
|
||||
|
||||
inputPaths = project.files(project.sourceSets.main.output.classesDir)
|
||||
|
||||
if (manifestTemplate != null) {
|
||||
project.jar.manifest.from manifest
|
||||
project.jar.inputs.files manifest
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void createManifest() {
|
||||
if (manifestTemplate == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
logging.captureStandardOutput(LogLevel.INFO)
|
||||
|
||||
project.mkdir(bundlorDir)
|
||||
|
||||
//String inputPath = project.sourceSets.main.classesDir
|
||||
|
||||
List<ClassPath> inputClassPath = [] as List;
|
||||
|
||||
ManifestWriter manifestWriter = new FileSystemManifestWriter(project.file(bundlorDir.absolutePath));
|
||||
ManifestContents mfTemplate = BundleManifestUtils.getManifest(manifestTemplate);
|
||||
|
||||
inputPaths.each {f ->
|
||||
inputClassPath.add(new FileSystemClassPath(f))
|
||||
}
|
||||
|
||||
// Must be a better way of doing this...
|
||||
Properties p = new Properties()
|
||||
expansions.each {entry ->
|
||||
p.setProperty(entry.key, entry.value as String)
|
||||
}
|
||||
|
||||
PropertiesSource expansionProps = new PropertiesPropertiesSource(p)
|
||||
PropertiesSource osgiProfileProps = osgiProfile == null ? new EmptyPropertiesSource() :
|
||||
new FileSystemPropertiesSource(osgiProfile);
|
||||
|
||||
ManifestGenerator manifestGenerator = new StandardManifestGenerator(
|
||||
DefaultManifestGeneratorContributorsFactory.create(expansionProps, osgiProfileProps));
|
||||
|
||||
ManifestContents mf = manifestGenerator.generate(mfTemplate, inputClassPath.toArray(new ClassPath[inputClassPath.size()]));
|
||||
|
||||
try {
|
||||
manifestWriter.write(mf);
|
||||
} finally {
|
||||
manifestWriter.close();
|
||||
}
|
||||
|
||||
ManifestValidator manifestValidator = new StandardManifestValidator(DefaultManifestValidatorContributorsFactory.create());
|
||||
|
||||
List<String> warnings = manifestValidator.validate(mf);
|
||||
|
||||
if (warnings.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
logger.warn("Bundlor Warnings:");
|
||||
for (String warning : warnings) {
|
||||
logger.warn(" " + warning);
|
||||
}
|
||||
|
||||
if (failOnWarnings) {
|
||||
throw new GradleException("Bundlor returned warnings. Please fix manifest template at " + manifestTemplate.absolutePath + " and try again.")
|
||||
}
|
||||
}
|
||||
|
||||
def inputPath(FileCollection paths) {
|
||||
inputPaths = project.files(inputPaths, paths)
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class Docbook extends DefaultTask {
|
||||
factory.setXIncludeAware(XIncludeAware);
|
||||
docsDir.mkdirs();
|
||||
|
||||
File srcFile = new File(sourceDirectory, sourceFileName);
|
||||
File srcFile = new File(filterDocbookSources(sourceDirectory), sourceFileName);
|
||||
String outputFilename = srcFile.getName().substring(0, srcFile.getName().length() - 4) + suffix + '.' + extension;
|
||||
|
||||
File outputFile = new File(getDocsDir(), outputFilename);
|
||||
@@ -135,6 +135,32 @@ public class Docbook extends DefaultTask {
|
||||
postTransform(outputFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sourceDir directory of unfiltered sources
|
||||
* @return directory of filtered sources
|
||||
* @author Chris Beams
|
||||
*/
|
||||
private File filterDocbookSources(File sourceDir) {
|
||||
def docbookWorkDir = new File("${project.buildDir}/reference-work")
|
||||
|
||||
docbookWorkDir.mkdirs()
|
||||
|
||||
// copy everything but springsecurity.xml
|
||||
project.copy {
|
||||
into(docbookWorkDir)
|
||||
from(sourceDir) { exclude '**/springsecurity.xml' }
|
||||
}
|
||||
// copy index.xml and expand ${...} variables along the way
|
||||
// e.g.: ${version} needs to be replaced in the header
|
||||
project.copy {
|
||||
into(docbookWorkDir)
|
||||
from(sourceDir) { include '**/springsecurity.xml' }
|
||||
expand(version: "${project.version}")
|
||||
}
|
||||
|
||||
return docbookWorkDir
|
||||
}
|
||||
|
||||
private void extractHighlightFiles(File toDir) {
|
||||
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader();
|
||||
URL[] urls = cl.getURLs();
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package emma;
|
||||
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.Input
|
||||
import com.vladium.emma.instr.InstrProcessor
|
||||
import com.vladium.emma.report.ReportProcessor
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import com.vladium.util.XProperties;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
class EmmaPlugin implements Plugin<Project> {
|
||||
|
||||
void apply(Project project) {
|
||||
Project rootProject = project.rootProject
|
||||
def emmaMetaDataFile = "${rootProject.buildDir}/emma/emma.em"
|
||||
def emmaCoverageFile = "${rootProject.buildDir}/emma/emma.ec"
|
||||
|
||||
if (project.configurations.findByName('emma_rt') == null) {
|
||||
project.configurations.add('emma_rt')
|
||||
project.dependencies {
|
||||
emma_rt 'emma:emma:2.0.5312'
|
||||
}
|
||||
}
|
||||
|
||||
project.task('emmaInstrument') {
|
||||
dependsOn project.classes
|
||||
|
||||
doFirst {
|
||||
InstrProcessor processor = InstrProcessor.create ();
|
||||
String[] classesDirPath = [project.sourceSets.main.output.classesDir.absolutePath]
|
||||
|
||||
processor.setInstrPath(classesDirPath, false);
|
||||
processor.setOutMode(InstrProcessor.OutMode.OUT_MODE_COPY);
|
||||
processor.setInstrOutDir("${project.buildDir}/emma/classes");
|
||||
processor.setMetaOutFile(emmaMetaDataFile);
|
||||
processor.setMetaOutMerge(true);
|
||||
//processor.setInclExclFilter (null);
|
||||
processor.run();
|
||||
}
|
||||
}
|
||||
|
||||
// Modify test tasks in the project to generate coverage data
|
||||
project.afterEvaluate {
|
||||
if (project.hasProperty('coverage') && ['on','true'].contains(project.properties.coverage)) {
|
||||
project.tasks.withType(Test.class).each { task ->
|
||||
task.dependsOn project.emmaInstrument
|
||||
task.configure() {
|
||||
jvmArgs '-Dsec.log.level=DEBUG', "-Demma.coverage.out.file=$emmaCoverageFile"
|
||||
jvmArgs '-Demma.verbosity.level=quiet'
|
||||
}
|
||||
task.doFirst {
|
||||
classpath = project.files("${project.buildDir}/emma/classes") + project.configurations.emma_rt + classpath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Task> reportTasks = rootProject.getTasksByName('coverageReport', false) as List;
|
||||
CoverageReport task;
|
||||
|
||||
if (reportTasks.isEmpty()) {
|
||||
task = rootProject.tasks.add('coverageReport', CoverageReport.class);
|
||||
task.dataPath = [emmaMetaDataFile, emmaCoverageFile];
|
||||
} else {
|
||||
task = reportTasks[0];
|
||||
}
|
||||
|
||||
task.modules.add(project);
|
||||
}
|
||||
}
|
||||
|
||||
class CoverageReport extends DefaultTask {
|
||||
@Input
|
||||
List<Project> modules = [];
|
||||
|
||||
@Input
|
||||
String[] dataPath;
|
||||
|
||||
@TaskAction
|
||||
void generateReport() {
|
||||
def buildDir = project.rootProject.buildDir
|
||||
|
||||
if (!buildDir.exists()) {
|
||||
throw new GradleException("No coverage data. Run gradle with -Pcoverage=on if using coverageReport");
|
||||
}
|
||||
|
||||
ReportProcessor processor = ReportProcessor.create ();
|
||||
processor.setDataPath(dataPath)
|
||||
|
||||
def srcPath = []
|
||||
modules.each {module->
|
||||
module.sourceSets.main.java.srcDirs.each {
|
||||
srcPath.add(it.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
processor.setSourcePath(srcPath as String[]);
|
||||
|
||||
|
||||
def types = ['txt', 'html']
|
||||
processor.setReportTypes(types as String[]);
|
||||
XProperties properties = new XProperties();
|
||||
properties.setProperty('report.html.out.file', "$buildDir/emma/coverage.html");
|
||||
properties.setProperty('report.txt.out.file', "$buildDir/emma/coverage.txt");
|
||||
processor.setPropertyOverrides(properties)
|
||||
|
||||
processor.run()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
implementation-class=aspectj.AspectJPlugin
|
||||
@@ -0,0 +1 @@
|
||||
implementation-class=bundlor.BundlorPlugin
|
||||
@@ -0,0 +1 @@
|
||||
implementation-class=emma.EmmaPlugin
|
||||
+3
-2
@@ -4,9 +4,10 @@ dependencies {
|
||||
project(':spring-security-web'),
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.jasig.cas.client:cas-client-core:3.1.11",
|
||||
"org.jasig.cas:cas-client-core:3.1.9",
|
||||
"net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||
|
||||
provided 'javax.servlet:servlet-api:2.5'
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>@pomVersion@</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-cas-client</artifactId>
|
||||
<name>Spring Security - CAS support</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>3.1.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+5
-15
@@ -31,8 +31,6 @@ import org.springframework.security.cas.web.CasAuthenticationFilter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.*;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -53,16 +51,14 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService;
|
||||
private AuthenticationUserDetailsService authenticationUserDetailsService;
|
||||
|
||||
private final UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
|
||||
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache();
|
||||
private String key;
|
||||
private TicketValidator ticketValidator;
|
||||
private ServiceProperties serviceProperties;
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -135,8 +131,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
|
||||
final UserDetails userDetails = loadUserByAssertion(assertion);
|
||||
userDetailsChecker.check(userDetails);
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
|
||||
authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(), userDetails.getAuthorities(), userDetails, assertion);
|
||||
} catch (final TicketValidationException e) {
|
||||
throw new BadCredentialsException(e.getMessage(), e);
|
||||
}
|
||||
@@ -155,7 +150,6 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
/**
|
||||
* @deprecated as of 3.0. Use the {@link org.springframework.security.cas.authentication.CasAuthenticationProvider#setAuthenticationUserDetailsService(org.springframework.security.core.userdetails.AuthenticationUserDetailsService)} instead.
|
||||
*/
|
||||
@@ -163,7 +157,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
this.authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService);
|
||||
}
|
||||
|
||||
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService) {
|
||||
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService authenticationUserDetailsService) {
|
||||
this.authenticationUserDetailsService = authenticationUserDetailsService;
|
||||
}
|
||||
|
||||
@@ -199,11 +193,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
public boolean supports(final Class<?> authentication) {
|
||||
public boolean supports(final Class<? extends Object> authentication) {
|
||||
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)) ||
|
||||
(CasAuthenticationToken.class.isAssignableFrom(authentication)) ||
|
||||
(CasAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
||||
|
||||
+18
-7
@@ -15,17 +15,23 @@
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Caches tickets using a Spring IoC defined <a href="http://ehcache.sourceforge.net">EHCACHE</a>.
|
||||
* Caches tickets using a Spring IoC defined <A HREF="http://ehcache.sourceforge.net">EHCACHE</a>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
@@ -45,13 +51,18 @@ public class EhCacheBasedTicketCache implements StatelessTicketCache, Initializi
|
||||
}
|
||||
|
||||
public CasAuthenticationToken getByTicketId(final String serviceTicket) {
|
||||
final Element element = cache.get(serviceTicket);
|
||||
try {
|
||||
final Element element = cache.get(serviceTicket);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache hit: " + (element != null) + "; service ticket: " + serviceTicket);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache hit: " + (element != null) + "; service ticket: " + serviceTicket);
|
||||
}
|
||||
|
||||
return element == null ? null : (CasAuthenticationToken) element.getValue();
|
||||
|
||||
} catch (CacheException cacheException) {
|
||||
throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());
|
||||
}
|
||||
|
||||
return element == null ? null : (CasAuthenticationToken) element.getValue();
|
||||
}
|
||||
|
||||
public Ehcache getCache() {
|
||||
|
||||
+9
-6
@@ -14,10 +14,13 @@
|
||||
*/
|
||||
package org.springframework.security.cas.userdetails;
|
||||
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
|
||||
import org.springframework.util.Assert;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
/**
|
||||
* Abstract class for using the provided CAS assertion to construct a new User object. This generally is most
|
||||
@@ -26,11 +29,11 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class AbstractCasAssertionUserDetailsService
|
||||
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
|
||||
public abstract class AbstractCasAssertionUserDetailsService implements AuthenticationUserDetailsService {
|
||||
|
||||
public final UserDetails loadUserDetails(final CasAssertionAuthenticationToken token) {
|
||||
return loadUserDetails(token.getAssertion());
|
||||
public final UserDetails loadUserDetails(final Authentication token) throws UsernameNotFoundException {
|
||||
Assert.isInstanceOf(CasAssertionAuthenticationToken.class, token, "The provided token MUST be an instance of CasAssertionAuthenticationToken.class");
|
||||
return loadUserDetails(((CasAssertionAuthenticationToken) token).getAssertion());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-4
@@ -17,7 +17,7 @@ package org.springframework.security.cas.userdetails;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.util.Assert;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
@@ -36,7 +36,7 @@ public final class GrantedAuthorityFromAssertionAttributesUserDetailsService ext
|
||||
|
||||
private static final String NON_EXISTENT_PASSWORD_VALUE = "NO_PASSWORD";
|
||||
|
||||
private final String[] attributes;
|
||||
private String[] attributes;
|
||||
|
||||
private boolean convertToUpperCase = true;
|
||||
|
||||
@@ -62,11 +62,11 @@ public final class GrantedAuthorityFromAssertionAttributesUserDetailsService ext
|
||||
final List list = (List) value;
|
||||
|
||||
for (final Object o : list) {
|
||||
grantedAuthorities.add(new SimpleGrantedAuthority(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString()));
|
||||
grantedAuthorities.add(new GrantedAuthorityImpl(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString()));
|
||||
}
|
||||
|
||||
} else {
|
||||
grantedAuthorities.add(new SimpleGrantedAuthority(this.convertToUpperCase ? value.toString().toUpperCase() : value.toString()));
|
||||
grantedAuthorities.add(new GrantedAuthorityImpl(this.convertToUpperCase ? value.toString().toUpperCase() : value.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-13
@@ -54,6 +54,7 @@ import org.springframework.security.web.authentication.AbstractAuthenticationPro
|
||||
* By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
@@ -89,7 +90,13 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
|
||||
throws AuthenticationException {
|
||||
throws AuthenticationException, IOException {
|
||||
// if the request is a proxy request process it and return null to indicate the request has been processed
|
||||
if(isProxyRequest(request)) {
|
||||
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
|
||||
return null;
|
||||
}
|
||||
|
||||
final String username = CAS_STATEFUL_IDENTIFIER;
|
||||
String password = request.getParameter(this.artifactParameter);
|
||||
|
||||
@@ -108,18 +115,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
* 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);
|
||||
}
|
||||
return isProxyRequest(request) || super.requiresAuthentication(request, response);
|
||||
}
|
||||
|
||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||
@@ -134,4 +130,14 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
public final void setServiceProperties(final ServiceProperties serviceProperties) {
|
||||
this.artifactParameter = serviceProperties.getArtifactParameter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is eligible to be processed as a proxy request.
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private boolean isProxyRequest(final HttpServletRequest request) {
|
||||
final String requestUri = request.getRequestURI();
|
||||
return this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl) && requestUri.endsWith(this.proxyReceptorUrl);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-8
@@ -18,26 +18,28 @@ package org.springframework.security.cas.authentication;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.jasig.cas.client.validation.AssertionImpl;
|
||||
import org.jasig.cas.client.validation.TicketValidationException;
|
||||
import org.jasig.cas.client.validation.TicketValidator;
|
||||
import org.junit.*;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.web.CasAuthenticationFilter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationProvider}.
|
||||
@@ -45,7 +47,6 @@ import java.util.*;
|
||||
* @author Ben Alex
|
||||
* @author Scott Battaglia
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CasAuthenticationProviderTests {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -96,8 +97,8 @@ public class CasAuthenticationProviderTests {
|
||||
CasAuthenticationToken casResult = (CasAuthenticationToken) result;
|
||||
assertEquals(makeUserDetailsFromAuthoritiesPopulator(), casResult.getPrincipal());
|
||||
assertEquals("ST-123", casResult.getCredentials());
|
||||
assertTrue(casResult.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_A")));
|
||||
assertTrue(casResult.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_B")));
|
||||
assertTrue(casResult.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_A")));
|
||||
assertTrue(casResult.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_B")));
|
||||
assertEquals(cap.getKey().hashCode(), casResult.getKeyHash());
|
||||
assertEquals("details", casResult.getDetails());
|
||||
|
||||
@@ -254,7 +255,8 @@ public class CasAuthenticationProviderTests {
|
||||
cap.setServiceProperties(makeServiceProperties());
|
||||
cap.afterPropertiesSet();
|
||||
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password", "ROLE_A");
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
|
||||
assertFalse(cap.supports(TestingAuthenticationToken.class));
|
||||
|
||||
// Try it anyway
|
||||
|
||||
+6
-5
@@ -15,18 +15,19 @@
|
||||
|
||||
package org.springframework.security.cas.authentication;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.jasig.cas.client.validation.AssertionImpl;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationToken}.
|
||||
*
|
||||
@@ -107,8 +108,8 @@ public class CasAuthenticationTokenTests extends TestCase {
|
||||
assertEquals("key".hashCode(), token.getKeyHash());
|
||||
assertEquals(makeUserDetails(), token.getPrincipal());
|
||||
assertEquals("Password", token.getCredentials());
|
||||
assertTrue(token.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ONE")));
|
||||
assertTrue(token.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_TWO")));
|
||||
assertTrue(token.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_ONE")));
|
||||
assertTrue(token.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_TWO")));
|
||||
assertEquals(assertion, token.getAssertion());
|
||||
assertEquals(makeUserDetails().getUsername(), token.getUserDetails().getUsername());
|
||||
}
|
||||
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
package org.springframework.security.cas.userdetails;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests {
|
||||
|
||||
@Test
|
||||
public void correctlyExtractsNamedAttributesFromAssertionAndConvertsThemToAuthorities() {
|
||||
GrantedAuthorityFromAssertionAttributesUserDetailsService uds =
|
||||
new GrantedAuthorityFromAssertionAttributesUserDetailsService(new String[] {"a", "b", "c", "d"});
|
||||
uds.setConvertToUpperCase(false);
|
||||
Assertion assertion = mock(Assertion.class);
|
||||
AttributePrincipal principal = mock(AttributePrincipal.class);
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
attributes.put("a", Arrays.asList("role_a1", "role_a2"));
|
||||
attributes.put("b", "role_b");
|
||||
attributes.put("c", "role_c");
|
||||
attributes.put("d", null);
|
||||
attributes.put("someother", "unused");
|
||||
when(assertion.getPrincipal()).thenReturn(principal);
|
||||
when(principal.getAttributes()).thenReturn(attributes);
|
||||
when(principal.getName()).thenReturn("somebody");
|
||||
CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "ticket");
|
||||
UserDetails user = uds.loadUserDetails(token);
|
||||
Set<String> roles = AuthorityUtils.authorityListToSet(user.getAuthorities());
|
||||
assertTrue(roles.size() == 4);
|
||||
assertTrue(roles.contains("role_a1"));
|
||||
assertTrue(roles.contains("role_a2"));
|
||||
assertTrue(roles.contains("role_b"));
|
||||
assertTrue(roles.contains("role_c"));
|
||||
}
|
||||
}
|
||||
+60
-9
@@ -16,7 +16,9 @@
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.junit.Test;
|
||||
@@ -24,7 +26,6 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
|
||||
@@ -33,22 +34,20 @@ import org.springframework.security.core.AuthenticationException;
|
||||
* Tests {@link CasAuthenticationFilter}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class CasAuthenticationFilterTests {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void testGettersSetters() {
|
||||
public void testGetters() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
assertEquals("/j_spring_cas_security_check", filter.getFilterProcessesUrl());
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl("/someurl");
|
||||
filter.setServiceProperties(new ServiceProperties());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalOperation() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/j_spring_cas_security_check");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
|
||||
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
@@ -58,8 +57,6 @@ public class CasAuthenticationFilterTests {
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(filter.requiresAuthentication(request, new MockHttpServletResponse()));
|
||||
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertTrue(result != null);
|
||||
}
|
||||
@@ -75,4 +72,58 @@ public class CasAuthenticationFilterTests {
|
||||
|
||||
filter.attemptAuthentication(new MockHttpServletRequest(), new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationFilterProcessUrl() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI(filter.getFilterProcessesUrl());
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationProxyRequest() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
request.setRequestURI("/other");
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateProxyUrl() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
assertNull(filter.attemptAuthentication(request, response));
|
||||
}
|
||||
|
||||
// SEC-1592
|
||||
@Test
|
||||
public void testChainNotInvokedForProxy() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
|
||||
filter.doFilter(request,response,chain);
|
||||
verifyZeroInteractions(chain);
|
||||
}
|
||||
}
|
||||
|
||||
+22
-25
@@ -15,43 +15,40 @@
|
||||
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.cas.SamlServiceProperties;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link ServiceProperties}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ServicePropertiesTests {
|
||||
public class ServicePropertiesTests extends TestCase {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void detectsMissingService() throws Exception {
|
||||
public void testDetectsMissingLoginFormUrl() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGettersSetters() throws Exception {
|
||||
ServiceProperties[] sps = {new ServiceProperties(), new SamlServiceProperties()};
|
||||
for(ServiceProperties sp : sps) {
|
||||
sp.setSendRenew(false);
|
||||
assertFalse(sp.isSendRenew());
|
||||
sp.setSendRenew(true);
|
||||
assertTrue(sp.isSendRenew());
|
||||
sp.setArtifactParameter("notticket");
|
||||
assertEquals("notticket", sp.getArtifactParameter());
|
||||
sp.setServiceParameter("notservice");
|
||||
assertEquals("notservice", sp.getServiceParameter());
|
||||
|
||||
sp.setService("https://mycompany.com/service");
|
||||
assertEquals("https://mycompany.com/service", sp.getService());
|
||||
|
||||
try {
|
||||
sp.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("service must be specified.", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGettersSetters() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.setSendRenew(false);
|
||||
assertFalse(sp.isSendRenew());
|
||||
sp.setSendRenew(true);
|
||||
assertTrue(sp.isSendRenew());
|
||||
|
||||
sp.setService("https://mycompany.com/service");
|
||||
assertEquals("https://mycompany.com/service", sp.getService());
|
||||
|
||||
sp.afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -9,14 +9,14 @@ Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
|
||||
org.jasig.cas.client.*;version="[3.1.1, 3.2.0)",
|
||||
org.springframework.security.core.*;version="[${version}, 3.2.0)",
|
||||
org.springframework.security.authentication.*;version="[${version}, 3.2.0)",
|
||||
org.springframework.security.web.*;version="[${version}, 3.2.0)",
|
||||
org.springframework.beans.factory;version="[${spring.version}, 3.2.0)",
|
||||
org.springframework.context.*;version="[${spring.version}, 3.2.0)",
|
||||
org.springframework.dao;version="[${spring.version}, 3.2.0)",
|
||||
org.springframework.util;version="[${spring.version}, 3.2.0)",
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="${cloggingRange}",
|
||||
org.jasig.cas.client.*;version="${casRange}",
|
||||
org.springframework.security.core.*;version="${secRange}",
|
||||
org.springframework.security.authentication.*;version="${secRange}",
|
||||
org.springframework.security.web.*;version="${secRange}",
|
||||
org.springframework.beans.factory;version="${springRange}",
|
||||
org.springframework.context.*;version="${springRange}",
|
||||
org.springframework.dao;version="${springRange}",
|
||||
org.springframework.util;version="${springRange}",
|
||||
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
|
||||
javax.servlet.*;version="0"
|
||||
|
||||
+12
-28
@@ -1,55 +1,39 @@
|
||||
// Config Module build file
|
||||
|
||||
apply plugin: 'groovy'
|
||||
|
||||
compileTestJava.dependsOn(':spring-security-core:compileTestJava')
|
||||
|
||||
configurations {
|
||||
// GRADLE-1124
|
||||
compile.extendsFrom = []
|
||||
testCompile.extendsFrom groovy
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
project(':spring-security-web'),
|
||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion"
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion"
|
||||
|
||||
provided "javax.servlet:servlet-api:2.5"
|
||||
|
||||
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.4'
|
||||
|
||||
testCompile project(':spring-security-ldap'),
|
||||
project(':spring-security-openid'),
|
||||
'org.openid4java:openid4java-nodeps:0.9.5',
|
||||
project(':spring-security-core').sourceSets.test.classes,
|
||||
project(':spring-security-core').sourceSets.test.output,
|
||||
'javax.annotation:jsr250-api:1.0',
|
||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
||||
"org.springframework:spring-expression:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
'org.spockframework:spock-core:0.4-groovy-1.7',
|
||||
'org.spockframework:spock-core:0.6-groovy-1.8',
|
||||
"org.slf4j:jcl-over-slf4j:$slf4jVersion"
|
||||
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
}
|
||||
|
||||
|
||||
testRuntime "hsqldb:hsqldb:$hsqlVersion",
|
||||
"cglib:cglib-nodep:2.2"
|
||||
}
|
||||
|
||||
task ldapTests(type: Test) {
|
||||
jvmArgs = ['-ea', '-Xmx500m', "-DapacheDSWorkDir=${buildDir}/apacheDSWork"]
|
||||
include ("**/ldap/**")
|
||||
maxParallelForks = 1
|
||||
// GRADLE-1090
|
||||
testClassesDir = sourceSets.test.classesDir
|
||||
classpath = sourceSets.test.runtimeClasspath
|
||||
testReport = false
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn ldapTests
|
||||
exclude ("**/ldap/**")
|
||||
integrationTest {
|
||||
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
pushd src/main/resources/org/springframework/security/config/
|
||||
|
||||
echo "Converting rnc file to xsd ..."
|
||||
java -jar ~/bin/trang.jar spring-security-3.1.rnc spring-security-3.1.xsd
|
||||
java -jar ~/bin/trang.jar spring-security-3.0.4.rnc spring-security-3.0.4.xsd
|
||||
|
||||
echo "Applying XSL transformation to xsd ..."
|
||||
xsltproc --output spring-security-3.1.xsd spring-security.xsl spring-security-3.1.xsd
|
||||
xsltproc --output spring-security-3.0.4.xsd spring-security.xsl spring-security-3.0.4.xsd
|
||||
|
||||
popd
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>@pomVersion@</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<name>Spring Security - Namespace Configuration Module</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-openid</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-jndi</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>jsr250-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package org.springframework.security.config.ldap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.ldap.authentication.BindAuthenticator;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
|
||||
import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class LdapProviderBeanDefinitionParserTests {
|
||||
InMemoryXmlApplicationContext appCtx;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appCtx != null) {
|
||||
appCtx.close();
|
||||
appCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanClassNamesAreCorrect() throws Exception {
|
||||
assertEquals(PROVIDER_CLASS, LdapAuthenticationProvider.class.getName());
|
||||
assertEquals(BIND_AUTH_CLASS, BindAuthenticator.class.getName());
|
||||
assertEquals(PASSWD_AUTH_CLASS, PasswordComparisonAuthenticator.class.getName());
|
||||
}
|
||||
|
||||
// SEC-1182
|
||||
@Test
|
||||
public void multipleProvidersAreSupported() throws Exception {
|
||||
setContext("<ldap-server url='ldap://blah:389/dc=blah'/>" +
|
||||
"<authentication-manager>" +
|
||||
" <ldap-authentication-provider group-search-filter='member={0}' />" +
|
||||
" <ldap-authentication-provider group-search-filter='uniqueMember={0}' />" +
|
||||
"</authentication-manager>");
|
||||
|
||||
ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
|
||||
assertEquals(2, authManager.getProviders().size());
|
||||
assertEquals("member={0}", FieldUtils.getFieldValue(authManager.getProviders().get(0), "authoritiesPopulator.groupSearchFilter"));
|
||||
assertEquals("uniqueMember={0}", FieldUtils.getFieldValue(authManager.getProviders().get(1), "authoritiesPopulator.groupSearchFilter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleProviderAuthenticatesCorrectly() {
|
||||
setContext("<ldap-server />" +
|
||||
"<authentication-manager>" +
|
||||
" <ldap-authentication-provider group-search-filter='member={0}' />" +
|
||||
"</authentication-manager>");
|
||||
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
Authentication auth = provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
|
||||
LdapUserDetailsImpl ben = (LdapUserDetailsImpl) auth.getPrincipal();
|
||||
|
||||
assertEquals(3, ben.getAuthorities().size());
|
||||
}
|
||||
|
||||
@Test(expected = ApplicationContextException.class)
|
||||
public void missingServerEltCausesConfigException() {
|
||||
setContext(
|
||||
"<authentication-manager>" +
|
||||
" <ldap-authentication-provider />" +
|
||||
"</authentication-manager>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsPasswordComparisonAuthentication() {
|
||||
setContext("<ldap-server /> " +
|
||||
"<authentication-manager>" +
|
||||
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
|
||||
" <password-compare />" +
|
||||
"</ldap-authentication-provider>"+
|
||||
"</authentication-manager>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void supportsPasswordComparisonAuthenticationWithHashAttribute() {
|
||||
setContext("<ldap-server /> " +
|
||||
"<authentication-manager>" +
|
||||
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
|
||||
" <password-compare password-attribute='uid' hash='plaintext'/>" +
|
||||
"</ldap-authentication-provider>" +
|
||||
"</authentication-manager>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
|
||||
setContext("<ldap-server /> " +
|
||||
"<authentication-manager>" +
|
||||
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
|
||||
" <password-compare password-attribute='uid'>" +
|
||||
" <password-encoder hash='plaintext'/>" +
|
||||
" </password-compare>" +
|
||||
"</ldap-authentication-provider>" +
|
||||
"</authentication-manager>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsNonStandardServerId() {
|
||||
setContext("<ldap-server id='myServer'/> " +
|
||||
"<authentication-manager>" +
|
||||
" <ldap-authentication-provider />" +
|
||||
"</authentication-manager>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inetOrgContextMapperIsSupported() throws Exception {
|
||||
setContext(
|
||||
"<ldap-server id='someServer' url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
|
||||
"<authentication-manager>" +
|
||||
" <ldap-authentication-provider user-details-class='inetOrgPerson'/>" +
|
||||
"</authentication-manager>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
assertTrue(FieldUtils.getFieldValue(provider, "userDetailsContextMapper") instanceof InetOrgPersonContextMapper);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appCtx = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
private LdapAuthenticationProvider getProvider() {
|
||||
ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
|
||||
assertEquals(1, authManager.getProviders().size());
|
||||
|
||||
LdapAuthenticationProvider provider = (LdapAuthenticationProvider) authManager.getProviders().get(0);
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
+27
-4
@@ -1,14 +1,31 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.ldap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class LdapServerBeanDefinitionParserTests {
|
||||
InMemoryXmlApplicationContext appCtx;
|
||||
@@ -23,7 +40,7 @@ public class LdapServerBeanDefinitionParserTests {
|
||||
|
||||
@Test
|
||||
public void embeddedServerCreationContainsExpectedContextSourceAndData() {
|
||||
appCtx = new InMemoryXmlApplicationContext("<ldap-server />");
|
||||
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif'/>");
|
||||
|
||||
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean(BeanIds.CONTEXT_SOURCE);
|
||||
|
||||
@@ -35,8 +52,8 @@ public class LdapServerBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void useOfUrlAttributeCreatesCorrectContextSource() {
|
||||
// Create second "server" with a url pointing at embedded one
|
||||
appCtx = new InMemoryXmlApplicationContext("<ldap-server port='33388'/>" +
|
||||
"<ldap-server id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
|
||||
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='33388'/>" +
|
||||
"<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
|
||||
|
||||
// Check the default context source is still there.
|
||||
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
|
||||
@@ -58,6 +75,12 @@ public class LdapServerBeanDefinitionParserTests {
|
||||
template.lookup("uid=pg,ou=gorillas");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultLdifFileIsSuccessful() {
|
||||
appCtx = new InMemoryXmlApplicationContext(
|
||||
"<ldap-server/>");
|
||||
ApacheDSContainer dsContainer = appCtx.getBean(ApacheDSContainer.class);
|
||||
|
||||
|
||||
assertEquals("classpath*:*.ldif", ReflectionTestUtils.getField(dsContainer, "ldifResources"));
|
||||
}
|
||||
}
|
||||
+22
-9
@@ -1,3 +1,15 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.ldap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@@ -23,6 +35,7 @@ import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class LdapUserServiceBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appCtx;
|
||||
@@ -47,12 +60,12 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
|
||||
@Test
|
||||
public void minimalConfigurationIsParsedOk() throws Exception {
|
||||
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
|
||||
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server ldif='classpath:test-server.ldif' url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userServiceReturnsExpectedData() throws Exception {
|
||||
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server />");
|
||||
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
@@ -67,7 +80,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
setContext("<ldap-user-service id='ldapUDS' " +
|
||||
" user-search-base='ou=otherpeople' " +
|
||||
" user-search-filter='(cn={0})' " +
|
||||
" group-search-filter='member={0}' /><ldap-server />");
|
||||
" group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails joe = uds.loadUserByUsername("Joe Smeth");
|
||||
@@ -83,7 +96,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
" group-search-filter='member={0}' role-prefix='PREFIX_'/>" +
|
||||
"<ldap-user-service id='ldapUDSNoPrefix' " +
|
||||
" user-search-filter='(uid={0})' " +
|
||||
" group-search-filter='member={0}' role-prefix='none'/><ldap-server />");
|
||||
" group-search-filter='member={0}' role-prefix='none'/><ldap-server ldif='classpath:test-server.ldif'/>");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
@@ -98,7 +111,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
|
||||
@Test
|
||||
public void differentGroupRoleAttributeWorksAsExpected() throws Exception {
|
||||
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server />");
|
||||
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
@@ -112,7 +125,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void isSupportedByAuthenticationProviderElement() {
|
||||
setContext(
|
||||
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
|
||||
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' ldif='classpath:test-server.ldif'/>" +
|
||||
"<authentication-manager>" +
|
||||
" <authentication-provider>" +
|
||||
" <ldap-user-service user-search-filter='(uid={0})' />" +
|
||||
@@ -123,7 +136,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void personContextMapperIsSupported() {
|
||||
setContext(
|
||||
"<ldap-server />" +
|
||||
"<ldap-server ldif='classpath:test-server.ldif'/>" +
|
||||
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='person'/>");
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
@@ -133,7 +146,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void inetOrgContextMapperIsSupported() {
|
||||
setContext(
|
||||
"<ldap-server id='someServer'/>" +
|
||||
"<ldap-server id='someServer' ldif='classpath:test-server.ldif'/>" +
|
||||
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='inetOrgPerson'/>");
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
@@ -143,7 +156,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void externalContextMapperIsSupported() {
|
||||
setContext(
|
||||
"<ldap-server id='someServer'/>" +
|
||||
"<ldap-server id='someServer' ldif='classpath:test-server.ldif'/>" +
|
||||
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-context-mapper-ref='mapper'/>" +
|
||||
"<b:bean id='mapper' class='"+ InetOrgPersonContextMapper.class.getName() +"'/>");
|
||||
|
||||
@@ -6,7 +6,6 @@ package org.springframework.security.config;
|
||||
* These are intended for internal use.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public abstract class BeanIds {
|
||||
private static final String PREFIX = "org.springframework.security.";
|
||||
@@ -20,7 +19,6 @@ public abstract class BeanIds {
|
||||
public static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = PREFIX + "contextSettingPostProcessor";
|
||||
|
||||
public static final String USER_DETAILS_SERVICE = PREFIX + "userDetailsService";
|
||||
public static final String USER_DETAILS_SERVICE_FACTORY = PREFIX + "userDetailsServiceFactory";
|
||||
|
||||
public static final String METHOD_ACCESS_MANAGER = PREFIX + "defaultMethodAccessManager";
|
||||
|
||||
@@ -29,6 +27,4 @@ public abstract class BeanIds {
|
||||
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
|
||||
public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer";
|
||||
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
|
||||
|
||||
public static final String DEBUG_FILTER = PREFIX + "debugFilter";
|
||||
}
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.config.debug.SecurityDebugBeanFactoryPostProcessor;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class DebugBeanDefinitionParser implements BeanDefinitionParser {
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
RootBeanDefinition debugPP = new RootBeanDefinition(SecurityDebugBeanFactoryPostProcessor.class);
|
||||
parserContext.getReaderContext().registerWithGeneratedName(debugPP);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
/**
|
||||
* Contains all the element names used by Spring Security 3 namespace support.
|
||||
* Contains all the element names used by Spring Security 2 namespace support.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
@@ -46,12 +46,9 @@ public abstract class Elements {
|
||||
public static final String CUSTOM_FILTER = "custom-filter";
|
||||
public static final String REQUEST_CACHE = "request-cache";
|
||||
public static final String X509 = "x509";
|
||||
public static final String JEE = "jee";
|
||||
public static final String FILTER_SECURITY_METADATA_SOURCE = "filter-security-metadata-source";
|
||||
public static final String METHOD_SECURITY_METADATA_SOURCE = "method-security-metadata-source";
|
||||
@Deprecated
|
||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||
public static final String DEBUG = "debug";
|
||||
public static final String HTTP_FIREWALL = "http-firewall";
|
||||
}
|
||||
|
||||
+14
-18
@@ -24,7 +24,6 @@ import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
||||
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -39,6 +38,7 @@ import org.w3c.dom.Node;
|
||||
*/
|
||||
public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
|
||||
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
|
||||
private BeanDefinitionDecorator filterChainMapBDD;
|
||||
@@ -63,8 +63,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd schema " +
|
||||
"with Spring Security 3.1. Please update your schema declarations to the 3.1 schema.", element);
|
||||
pc.getReaderContext().fatal("You must use a 3.0 schema with Spring Security 3.0." +
|
||||
"(2.0 or 3.1 versions are not valid)" +
|
||||
" Please update your schema declarations to the 3.0.3 schema (spring-security-3.0.3.xsd).", element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
BeanDefinitionParser parser = parsers.get(name);
|
||||
@@ -75,20 +76,18 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
}
|
||||
|
||||
if (parser == null) {
|
||||
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name) ||
|
||||
Elements.FILTER_CHAIN_MAP.equals(name)) {
|
||||
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
|
||||
reportMissingWebClasses(name, pc, element);
|
||||
} else {
|
||||
reportUnsupportedNodeType(name, pc, element);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return parser.parse(element, pc);
|
||||
}
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext pc) {
|
||||
BeanDefinitionDecorator decorator = null;
|
||||
String name = pc.getDelegate().getLocalName(node);
|
||||
|
||||
// We only handle elements
|
||||
@@ -108,7 +107,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
}
|
||||
}
|
||||
|
||||
reportUnsupportedNodeType(name, pc, node);
|
||||
if (decorator == null) {
|
||||
reportUnsupportedNodeType(name, pc, node);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -120,7 +121,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private void reportMissingWebClasses(String nodeName, ParserContext pc, Node node) {
|
||||
pc.getReaderContext().fatal("spring-security-web classes are not available. " +
|
||||
"You need these to use <" + nodeName + ">", node);
|
||||
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
@@ -138,11 +139,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
|
||||
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
||||
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
|
||||
parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE, new MethodSecurityMetadataSourceBeanDefinitionParser());
|
||||
|
||||
// Only load the web-namespace parsers if the web classes are available
|
||||
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
|
||||
parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());
|
||||
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
|
||||
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
|
||||
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||
@@ -153,11 +152,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
/**
|
||||
* Check that the schema location declared in the source file being parsed matches the Spring Security version.
|
||||
* The old 2.0 schema is not compatible with the 3.1 parser, so it is an error to explicitly use
|
||||
* 2.0.
|
||||
* <p>
|
||||
* There are also differences between 3.0 and 3.1 which are sufficient that we report using 3.0 as an error too.
|
||||
* It might be an error to declare spring-security.xsd as an alias, but you are only going to find that out
|
||||
* The old 2.0 schema is not compatible with the new 3.0 parser, so it is an error to explicitly use
|
||||
* 3.0. It might be an error to declare spring-security.xsd as an alias, but you are only going to find that out
|
||||
* when one of the sub parsers breaks.
|
||||
*
|
||||
* @param element the element that is to be parsed next
|
||||
@@ -169,8 +165,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-3\\.1.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-3\\.0.*xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security\\.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
|
||||
+3
-14
@@ -57,17 +57,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
if (node instanceof Element) {
|
||||
Element providerElt = (Element)node;
|
||||
if (StringUtils.hasText(providerElt.getAttribute(ATT_REF))) {
|
||||
if (providerElt.getAttributes().getLength() > 1) {
|
||||
pc.getReaderContext().error("authentication-provider element cannot be used with other attributes " +
|
||||
"when using 'ref' attribute", pc.extractSource(element));
|
||||
}
|
||||
NodeList providerChildren = providerElt.getChildNodes();
|
||||
for (int j = 0; j < providerChildren.getLength(); j++) {
|
||||
if (providerChildren.item(j) instanceof Element) {
|
||||
pc.getReaderContext().error("authentication-provider element cannot have child elements when used " +
|
||||
"with 'ref' attribute", pc.extractSource(element));
|
||||
}
|
||||
}
|
||||
providers.add(new RuntimeBeanReference(providerElt.getAttribute(ATT_REF)));
|
||||
} else {
|
||||
BeanDefinition provider = resolver.resolve(providerElt.getNamespaceURI()).parse(providerElt, pc);
|
||||
@@ -85,8 +74,8 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
|
||||
providerManagerBldr.addPropertyValue("providers", providers);
|
||||
|
||||
if ("false".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
|
||||
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", false);
|
||||
if ("true".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
|
||||
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", true);
|
||||
}
|
||||
|
||||
// Add the default event publisher
|
||||
@@ -128,7 +117,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean supports(Class<?> authentication) {
|
||||
public boolean supports(Class<? extends Object> authentication) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import org.w3c.dom.Element;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String ATT_USER_DETAILS_REF = "user-service-ref";
|
||||
private static String ATT_USER_DETAILS_REF = "user-service-ref";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class CachingUserDetailsService implements UserDetailsService {
|
||||
private UserCache userCache = new NullUserCache();
|
||||
private final UserDetailsService delegate;
|
||||
private UserDetailsService delegate;
|
||||
|
||||
CachingUserDetailsService(UserDetailsService delegate) {
|
||||
this.delegate = delegate;
|
||||
|
||||
+3
-3
@@ -55,7 +55,7 @@ public class PasswordEncoderParser {
|
||||
ENCODER_CLASSES.put(OPT_HASH_LDAP_SSHA, LdapShaPasswordEncoder.class);
|
||||
}
|
||||
|
||||
private static final Log logger = LogFactory.getLog(PasswordEncoderParser.class);
|
||||
private static Log logger = LogFactory.getLog(PasswordEncoderParser.class);
|
||||
|
||||
private BeanMetadataElement passwordEncoder;
|
||||
private BeanMetadataElement saltSource;
|
||||
@@ -69,7 +69,7 @@ public class PasswordEncoderParser {
|
||||
boolean useBase64 = false;
|
||||
|
||||
if (StringUtils.hasText(element.getAttribute(ATT_BASE_64))) {
|
||||
useBase64 = Boolean.valueOf(element.getAttribute(ATT_BASE_64)).booleanValue();
|
||||
useBase64 = new Boolean(element.getAttribute(ATT_BASE_64)).booleanValue();
|
||||
}
|
||||
|
||||
String ref = element.getAttribute(ATT_REF);
|
||||
@@ -93,7 +93,7 @@ public class PasswordEncoderParser {
|
||||
BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
|
||||
|
||||
if (OPT_HASH_SHA256.equals(hash)) {
|
||||
beanBldr.addConstructorArgValue(Integer.valueOf(256));
|
||||
beanBldr.addConstructorArgValue(new Integer(256));
|
||||
}
|
||||
|
||||
if (useBase64) {
|
||||
|
||||
+14
-10
@@ -9,12 +9,12 @@ import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.core.userdetails.memory.UserMap;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@@ -24,6 +24,7 @@ import org.w3c.dom.Element;
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
|
||||
static final String ATT_PASSWORD = "password";
|
||||
@@ -37,7 +38,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
||||
private SecureRandom random;
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return InMemoryUserDetailsManager.class.getName();
|
||||
return "org.springframework.security.core.userdetails.memory.InMemoryDaoImpl";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -53,20 +54,21 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
||||
|
||||
BeanDefinition bd = new RootBeanDefinition(PropertiesFactoryBean.class);
|
||||
bd.getPropertyValues().addPropertyValue("location", userProperties);
|
||||
builder.addConstructorArgValue(bd);
|
||||
builder.addPropertyValue("userProperties", bd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(userElts)) {
|
||||
if(CollectionUtils.isEmpty(userElts)) {
|
||||
throw new BeanDefinitionStoreException("You must supply user definitions, either with <" + ELT_USER + "> child elements or a " +
|
||||
"properties file (using the '" + ATT_PROPERTIES + "' attribute)" );
|
||||
}
|
||||
|
||||
ManagedList<BeanDefinition> users = new ManagedList<BeanDefinition>();
|
||||
BeanDefinition userMap = new RootBeanDefinition(UserMap.class);
|
||||
ManagedMap<String, BeanDefinition> users = new ManagedMap<String, BeanDefinition>();
|
||||
|
||||
for (Object elt : userElts) {
|
||||
Element userElt = (Element) elt;
|
||||
for (Iterator i = userElts.iterator(); i.hasNext();) {
|
||||
Element userElt = (Element) i.next();
|
||||
String userName = userElt.getAttribute(ATT_NAME);
|
||||
String password = userElt.getAttribute(ATT_PASSWORD);
|
||||
|
||||
@@ -89,10 +91,12 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
||||
user.addConstructorArgValue(!locked);
|
||||
user.addConstructorArgValue(authorities.getBeanDefinition());
|
||||
|
||||
users.add(user.getBeanDefinition());
|
||||
users.put(userName.toLowerCase(), user.getBeanDefinition());
|
||||
}
|
||||
|
||||
builder.addConstructorArgValue(users);
|
||||
userMap.getPropertyValues().addPropertyValue("users", users);
|
||||
|
||||
builder.addPropertyValue("userMap", userMap);
|
||||
}
|
||||
|
||||
private String generateRandomPassword() {
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
package org.springframework.security.config.debug;
|
||||
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Spring Security debugging filter.
|
||||
* <p>
|
||||
* Logs information (such as session creation) to help the user understand how requests are being handled
|
||||
* by Spring Security and provide them with other relevant information (such as when sessions are being created).
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.1
|
||||
*/
|
||||
class DebugFilter extends OncePerRequestFilter {
|
||||
private final FilterChainProxy fcp;
|
||||
private final Map<RequestMatcher, List<Filter>> filterChainMap;
|
||||
private final Logger logger = new Logger();
|
||||
|
||||
public DebugFilter(FilterChainProxy fcp) {
|
||||
this.fcp = fcp;
|
||||
this.filterChainMap = fcp.getFilterChainMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
List<Filter> filters = getFilters(request);
|
||||
logger.log("Request received for '" + UrlUtils.buildRequestUrl(request) + "':\n\n" +
|
||||
request + "\n\n" +
|
||||
"servletPath:" + request.getServletPath() + "\n" +
|
||||
"pathInfo:" + request.getPathInfo() + "\n\n" +
|
||||
formatFilters(filters));
|
||||
|
||||
fcp.doFilter(new DebugRequestWrapper(request), response, filterChain);
|
||||
}
|
||||
|
||||
String formatFilters(List<Filter> filters) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Security filter chain: ");
|
||||
if (filters == null) {
|
||||
sb.append("no match");
|
||||
} else if (filters.isEmpty()) {
|
||||
sb.append("[] empty (bypassed by security='none') ");
|
||||
} else {
|
||||
sb.append("[\n");
|
||||
for (Filter f : filters) {
|
||||
sb.append(" ").append(f.getClass().getSimpleName()).append("\n");
|
||||
}
|
||||
sb.append("]");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private List<Filter> getFilters(HttpServletRequest request) {
|
||||
for (Map.Entry<RequestMatcher, List<Filter>> entry : filterChainMap.entrySet()) {
|
||||
RequestMatcher matcher = entry.getKey();
|
||||
|
||||
if (matcher.matches(request)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class DebugRequestWrapper extends HttpServletRequestWrapper {
|
||||
private static final Logger logger = new Logger();
|
||||
|
||||
public DebugRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession() {
|
||||
boolean sessionExists = super.getSession(false) != null;
|
||||
HttpSession session = super.getSession();
|
||||
|
||||
if (!sessionExists) {
|
||||
logger.log("New HTTP session created: " + session.getId(), true);
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession(boolean create) {
|
||||
if (!create) {
|
||||
return super.getSession(create);
|
||||
}
|
||||
return getSession();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.springframework.security.config.debug;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Controls output for the Spring Security debug feature.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.1
|
||||
*/
|
||||
final class Logger {
|
||||
final static Log logger = LogFactory.getLog("Spring Security Debugger");
|
||||
|
||||
void log(String message) {
|
||||
log(message, false);
|
||||
}
|
||||
|
||||
void log(String message, boolean dumpStack) {
|
||||
StringBuilder output = new StringBuilder(256);
|
||||
output.append("\n\n************************************************************\n\n");
|
||||
output.append(message).append("\n");
|
||||
|
||||
if (dumpStack) {
|
||||
StringWriter os = new StringWriter();
|
||||
new Exception().printStackTrace(new PrintWriter(os));
|
||||
StringBuffer buffer = os.getBuffer();
|
||||
// Remove the exception in case it scares people.
|
||||
int start = buffer.indexOf("java.lang.Exception");
|
||||
buffer.replace(start, start + 19, "");
|
||||
output.append("\nCall stack: \n").append(os.toString());
|
||||
}
|
||||
|
||||
output.append("\n\n************************************************************\n\n");
|
||||
|
||||
logger.info(output.toString());
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package org.springframework.security.config.debug;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class SecurityDebugBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
Logger.logger.warn("\n\n" +
|
||||
"********************************************************************\n" +
|
||||
"********** Security debugging is enabled. *************\n" +
|
||||
"********** This may include sensitive information. *************\n" +
|
||||
"********** Do not use in a production system! *************\n" +
|
||||
"********************************************************************\n\n");
|
||||
if (beanFactory.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) != null) {
|
||||
FilterChainProxy fcp = beanFactory.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class);
|
||||
beanFactory.registerSingleton(BeanIds.DEBUG_FILTER, new DebugFilter(fcp));
|
||||
// Overwrite the filter chain alias
|
||||
beanFactory.registerAlias(BeanIds.DEBUG_FILTER, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
+119
-215
@@ -13,29 +13,24 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
|
||||
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.web.PortResolverImpl;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
|
||||
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -57,13 +52,10 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
static final String OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationFilter";
|
||||
static final String OPEN_ID_AUTHENTICATION_PROVIDER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationProvider";
|
||||
private static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
|
||||
static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
|
||||
static final String OPEN_ID_ATTRIBUTE_CLASS = "org.springframework.security.openid.OpenIDAttribute";
|
||||
private static final String OPEN_ID_ATTRIBUTE_FACTORY_CLASS = "org.springframework.security.openid.RegexBasedAxFetchListFactory";
|
||||
static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter";
|
||||
|
||||
static final String ATT_AUTH_DETAILS_SOURCE_REF = "authentication-details-source-ref";
|
||||
|
||||
private static final String ATT_AUTO_CONFIG = "auto-config";
|
||||
|
||||
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
@@ -72,13 +64,16 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
private static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
private static final String ATT_REF = "ref";
|
||||
|
||||
private static final String ATT_KEY = "key";
|
||||
|
||||
private final Element httpElt;
|
||||
private final ParserContext pc;
|
||||
private Element httpElt;
|
||||
private ParserContext pc;
|
||||
|
||||
private final boolean autoConfig;
|
||||
private final boolean allowSessionCreation;
|
||||
private final String portMapperName;
|
||||
|
||||
private RootBeanDefinition anonymousFilter;
|
||||
private BeanReference anonymousProviderRef;
|
||||
@@ -87,49 +82,31 @@ final class AuthenticationConfigBuilder {
|
||||
private BeanReference rememberMeProviderRef;
|
||||
private BeanDefinition basicFilter;
|
||||
private RuntimeBeanReference basicEntryPoint;
|
||||
private RootBeanDefinition formFilter;
|
||||
private BeanDefinition formEntryPoint;
|
||||
private RootBeanDefinition openIDFilter;
|
||||
private BeanDefinition openIDEntryPoint;
|
||||
private BeanReference openIDProviderRef;
|
||||
private String openIDProviderId;
|
||||
private String formFilterId = null;
|
||||
private String openIDFilterId = null;
|
||||
private BeanDefinition x509Filter;
|
||||
private BeanDefinition x509EntryPoint;
|
||||
private BeanReference x509ProviderRef;
|
||||
private BeanDefinition jeeFilter;
|
||||
private BeanReference jeeProviderRef;
|
||||
private RootBeanDefinition preAuthEntryPoint;
|
||||
|
||||
private String x509ProviderId;
|
||||
private BeanDefinition logoutFilter;
|
||||
private BeanDefinition loginPageGenerationFilter;
|
||||
private BeanDefinition etf;
|
||||
private final BeanReference requestCache;
|
||||
private BeanReference requestCache;
|
||||
|
||||
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
|
||||
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy) {
|
||||
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
|
||||
String portMapperName) {
|
||||
this.httpElt = element;
|
||||
this.pc = pc;
|
||||
this.requestCache = requestCache;
|
||||
this.portMapperName = portMapperName;
|
||||
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.never
|
||||
&& sessionPolicy != SessionCreationPolicy.stateless;
|
||||
|
||||
createAnonymousFilter();
|
||||
createRememberMeFilter(authenticationManager);
|
||||
createBasicFilter(authenticationManager);
|
||||
createFormLoginFilter(sessionStrategy, authenticationManager);
|
||||
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
|
||||
createX509Filter(authenticationManager);
|
||||
createJeeFilter(authenticationManager);
|
||||
createLogoutFilter();
|
||||
createLoginPageFilterIfNeeded();
|
||||
createUserDetailsServiceFactory();
|
||||
createExceptionTranslationFilter();
|
||||
|
||||
this.allowSessionCreation = allowSessionCreation;
|
||||
}
|
||||
|
||||
void createRememberMeFilter(BeanReference authenticationManager) {
|
||||
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
|
||||
|
||||
@@ -162,6 +139,7 @@ final class AuthenticationConfigBuilder {
|
||||
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
|
||||
RootBeanDefinition formFilter = null;
|
||||
|
||||
if (formLoginElt != null || autoConfig) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
@@ -176,6 +154,7 @@ final class AuthenticationConfigBuilder {
|
||||
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
|
||||
|
||||
// Id is required by login page filter
|
||||
formFilterId = pc.getReaderContext().generateBeanName(formFilter);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(formFilter, formFilterId));
|
||||
@@ -185,6 +164,7 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
||||
RootBeanDefinition openIDFilter = null;
|
||||
|
||||
if (openIDLoginElt != null) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
@@ -194,31 +174,30 @@ final class AuthenticationConfigBuilder {
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
|
||||
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
|
||||
Element attrExElt = DomUtils.getChildElementByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
|
||||
|
||||
if (!attrExElts.isEmpty()) {
|
||||
if (attrExElt != null) {
|
||||
// Set up the consumer with the required attribute list
|
||||
BeanDefinitionBuilder consumerBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_CONSUMER_CLASS);
|
||||
BeanDefinitionBuilder axFactory = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_FACTORY_CLASS);
|
||||
ManagedMap<String, ManagedList<BeanDefinition>> axMap = new ManagedMap<String, ManagedList<BeanDefinition>>();
|
||||
|
||||
for (Element attrExElt : attrExElts) {
|
||||
String identifierMatch = attrExElt.getAttribute("identifier-match");
|
||||
|
||||
if (!StringUtils.hasText(identifierMatch)) {
|
||||
if (attrExElts.size() > 1) {
|
||||
pc.getReaderContext().error("You must supply an identifier-match attribute if using more" +
|
||||
" than one " + Elements.OPENID_ATTRIBUTE_EXCHANGE + " element", attrExElt);
|
||||
}
|
||||
// Match anything
|
||||
identifierMatch = ".*";
|
||||
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition> ();
|
||||
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
|
||||
String name = attElt.getAttribute("name");
|
||||
String type = attElt.getAttribute("type");
|
||||
String required = attElt.getAttribute("required");
|
||||
String count = attElt.getAttribute("count");
|
||||
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
|
||||
attrBldr.addConstructorArgValue(name);
|
||||
attrBldr.addConstructorArgValue(type);
|
||||
if (StringUtils.hasLength(required)) {
|
||||
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
|
||||
}
|
||||
|
||||
axMap.put(identifierMatch, parseOpenIDAttributes(attrExElt));
|
||||
if (StringUtils.hasLength(count)) {
|
||||
attrBldr.addPropertyValue("count", Integer.parseInt(count));
|
||||
}
|
||||
attributes.add(attrBldr.getBeanDefinition());
|
||||
}
|
||||
axFactory.addConstructorArgValue(axMap);
|
||||
|
||||
consumerBldr.addConstructorArgValue(axFactory.getBeanDefinition());
|
||||
consumerBldr.addConstructorArgValue(attributes);
|
||||
openIDFilter.getPropertyValues().addPropertyValue("consumer", consumerBldr.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
@@ -235,43 +214,20 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private ManagedList<BeanDefinition> parseOpenIDAttributes(Element attrExElt) {
|
||||
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition> ();
|
||||
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
|
||||
String name = attElt.getAttribute("name");
|
||||
String type = attElt.getAttribute("type");
|
||||
String required = attElt.getAttribute("required");
|
||||
String count = attElt.getAttribute("count");
|
||||
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
|
||||
attrBldr.addConstructorArgValue(name);
|
||||
attrBldr.addConstructorArgValue(type);
|
||||
if (StringUtils.hasLength(required)) {
|
||||
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(count)) {
|
||||
attrBldr.addPropertyValue("count", Integer.parseInt(count));
|
||||
}
|
||||
attributes.add(attrBldr.getBeanDefinition());
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void createOpenIDProvider() {
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
||||
BeanDefinitionBuilder openIDProviderBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
|
||||
|
||||
RootBeanDefinition uds = new RootBeanDefinition();
|
||||
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
|
||||
uds.setFactoryMethodName("authenticationUserDetailsService");
|
||||
uds.getConstructorArgumentValues().addGenericArgumentValue(openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF));
|
||||
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
openIDProviderBuilder.addPropertyValue("authenticationUserDetailsService", uds);
|
||||
if (StringUtils.hasText(userService)) {
|
||||
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
|
||||
}
|
||||
|
||||
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
|
||||
openIDProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(openIDProvider));
|
||||
openIDProviderId = pc.getReaderContext().registerWithGeneratedName(openIDProvider);
|
||||
openIDProviderRef = new RuntimeBeanReference(openIDProviderId);
|
||||
}
|
||||
|
||||
private void injectRememberMeServicesRef(RootBeanDefinition bean, String rememberMeServicesId) {
|
||||
@@ -283,46 +239,41 @@ final class AuthenticationConfigBuilder {
|
||||
void createBasicFilter(BeanReference authManager) {
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt, Elements.BASIC_AUTH);
|
||||
|
||||
if (basicAuthElt == null && !autoConfig) {
|
||||
// No basic auth, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
String realm = httpElt.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
||||
RootBeanDefinition filter = null;
|
||||
|
||||
String entryPointId;
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
||||
|
||||
if (basicAuthElt != null) {
|
||||
if (StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
|
||||
String entryPointId;
|
||||
|
||||
if (basicAuthElt != null && StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
|
||||
basicEntryPoint = new RuntimeBeanReference(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
|
||||
} else {
|
||||
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(httpElt));
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||
basicEntryPoint = new RuntimeBeanReference(entryPointId);
|
||||
}
|
||||
|
||||
injectAuthenticationDetailsSource(basicAuthElt, filterBuilder);
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
if (basicEntryPoint == null) {
|
||||
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(httpElt));
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||
basicEntryPoint = new RuntimeBeanReference(entryPointId);
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
|
||||
basicFilter = filterBuilder.getBeanDefinition();
|
||||
basicFilter = filter;
|
||||
}
|
||||
|
||||
void createX509Filter(BeanReference authManager) {
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
|
||||
RootBeanDefinition filter = null;
|
||||
RootBeanDefinition entryPoint = null;
|
||||
|
||||
if (x509Elt != null) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509AuthenticationFilter.class);
|
||||
@@ -337,102 +288,37 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
|
||||
}
|
||||
|
||||
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
|
||||
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
createPrauthEntryPoint(x509Elt);
|
||||
entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(x509Elt));
|
||||
|
||||
createX509Provider();
|
||||
}
|
||||
|
||||
x509Filter = filter;
|
||||
}
|
||||
|
||||
private void injectAuthenticationDetailsSource(Element elt, BeanDefinitionBuilder filterBuilder) {
|
||||
String authDetailsSourceRef = elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
|
||||
|
||||
if (StringUtils.hasText(authDetailsSourceRef)) {
|
||||
filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef);
|
||||
}
|
||||
x509EntryPoint = entryPoint;
|
||||
}
|
||||
|
||||
private void createX509Provider() {
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
|
||||
RootBeanDefinition uds = new RootBeanDefinition();
|
||||
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
|
||||
uds.setFactoryMethodName("authenticationUserDetailsService");
|
||||
uds.getConstructorArgumentValues().addGenericArgumentValue(x509Elt.getAttribute(ATT_USER_SERVICE_REF));
|
||||
String userServiceRef = x509Elt.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", uds);
|
||||
|
||||
x509ProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(provider));
|
||||
}
|
||||
|
||||
private void createPrauthEntryPoint(Element source) {
|
||||
if (preAuthEntryPoint == null) {
|
||||
preAuthEntryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
|
||||
preAuthEntryPoint.setSource(pc.extractSource(source));
|
||||
}
|
||||
}
|
||||
|
||||
void createJeeFilter(BeanReference authManager) {
|
||||
final String ATT_MAPPABLE_ROLES = "mappable-roles";
|
||||
|
||||
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
|
||||
RootBeanDefinition filter = null;
|
||||
|
||||
if (jeeElt != null) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(J2eePreAuthenticatedProcessingFilter.class);
|
||||
filterBuilder.getRawBeanDefinition().setSource(pc.extractSource(jeeElt));
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
|
||||
BeanDefinitionBuilder adsBldr = BeanDefinitionBuilder.rootBeanDefinition(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
|
||||
adsBldr.addPropertyValue("userRoles2GrantedAuthoritiesMapper", new RootBeanDefinition(SimpleAttributes2GrantedAuthoritiesMapper.class));
|
||||
|
||||
String roles = jeeElt.getAttribute(ATT_MAPPABLE_ROLES);
|
||||
Assert.state(StringUtils.hasText(roles));
|
||||
BeanDefinitionBuilder rolesBuilder = BeanDefinitionBuilder.rootBeanDefinition(StringUtils.class);
|
||||
rolesBuilder.addConstructorArgValue(roles);
|
||||
rolesBuilder.setFactoryMethod("commaDelimitedListToSet");
|
||||
|
||||
RootBeanDefinition mappableRolesRetriever = new RootBeanDefinition(SimpleMappableAttributesRetriever.class);
|
||||
mappableRolesRetriever.getPropertyValues().addPropertyValue("mappableAttributes", rolesBuilder.getBeanDefinition());
|
||||
adsBldr.addPropertyValue("mappableRolesRetriever", mappableRolesRetriever);
|
||||
filterBuilder.addPropertyValue("authenticationDetailsSource", adsBldr.getBeanDefinition());
|
||||
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
|
||||
createPrauthEntryPoint(jeeElt);
|
||||
createJeeProvider();
|
||||
if (StringUtils.hasText(userServiceRef)) {
|
||||
RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class);
|
||||
preAuthUserService.setSource(pc.extractSource(x509Elt));
|
||||
preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService);
|
||||
}
|
||||
|
||||
jeeFilter = filter;
|
||||
x509ProviderId = pc.getReaderContext().registerWithGeneratedName(provider);
|
||||
x509ProviderRef = new RuntimeBeanReference(x509ProviderId);
|
||||
}
|
||||
|
||||
private void createJeeProvider() {
|
||||
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
|
||||
RootBeanDefinition uds;
|
||||
if (StringUtils.hasText(jeeElt.getAttribute(ATT_USER_SERVICE_REF))) {
|
||||
uds = new RootBeanDefinition();
|
||||
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
|
||||
uds.setFactoryMethodName("authenticationUserDetailsService");
|
||||
uds.getConstructorArgumentValues().addGenericArgumentValue(jeeElt.getAttribute(ATT_USER_SERVICE_REF));
|
||||
} else {
|
||||
uds = new RootBeanDefinition(PreAuthenticatedGrantedAuthoritiesUserDetailsService.class);
|
||||
}
|
||||
|
||||
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", uds);
|
||||
|
||||
jeeProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(provider));
|
||||
}
|
||||
|
||||
void createLoginPageFilterIfNeeded() {
|
||||
boolean needLoginPage = formFilter != null || openIDFilter != null;
|
||||
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
|
||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
|
||||
|
||||
@@ -443,11 +329,11 @@ final class AuthenticationConfigBuilder {
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||
|
||||
if (formFilter != null) {
|
||||
if (formFilterId != null) {
|
||||
loginPageFilter.addConstructorArgReference(formFilterId);
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
if (openIDFilterId != null) {
|
||||
loginPageFilter.addConstructorArgReference(openIDFilterId);
|
||||
}
|
||||
|
||||
@@ -526,6 +412,28 @@ final class AuthenticationConfigBuilder {
|
||||
etf = etfBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
void createRequestCache() {
|
||||
Element requestCacheElt = DomUtils.getChildElementByTagName(httpElt, Elements.REQUEST_CACHE);
|
||||
|
||||
if (requestCacheElt != null) {
|
||||
requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
|
||||
return;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
|
||||
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
|
||||
portResolver.addPropertyReference("portMapper", portMapperName);
|
||||
requestCacheBldr.addPropertyValue("createSessionAllowed", allowSessionCreation);
|
||||
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
|
||||
|
||||
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
|
||||
String id = pc.getReaderContext().generateBeanName(bean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
|
||||
|
||||
this.requestCache = new RuntimeBeanReference(id);
|
||||
}
|
||||
|
||||
|
||||
private BeanMetadataElement createAccessDeniedHandler(Element element, ParserContext pc) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
WebConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
@@ -589,18 +497,18 @@ final class AuthenticationConfigBuilder {
|
||||
"but not both.", pc.extractSource(openIDLoginElt));
|
||||
}
|
||||
|
||||
if (formFilter != null && openIDLoginPage == null) {
|
||||
if (formFilterId != null && openIDLoginPage == null) {
|
||||
return formEntryPoint;
|
||||
}
|
||||
|
||||
// Otherwise use OpenID if enabled
|
||||
if (openIDFilter != null) {
|
||||
if (openIDFilterId != null) {
|
||||
return openIDEntryPoint;
|
||||
}
|
||||
|
||||
// If X.509 or JEE have been enabled, use the preauth entry point.
|
||||
if (preAuthEntryPoint != null) {
|
||||
return preAuthEntryPoint;
|
||||
// If X.509 has been enabled, use the preauth entry point.
|
||||
if (DomUtils.getChildElementByTagName(httpElt, Elements.X509) != null) {
|
||||
return x509EntryPoint;
|
||||
}
|
||||
|
||||
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
|
||||
@@ -629,14 +537,14 @@ final class AuthenticationConfigBuilder {
|
||||
return (String) pv.getValue();
|
||||
}
|
||||
|
||||
private void createUserDetailsServiceFactory() {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY)) {
|
||||
// Multiple <http> case
|
||||
return;
|
||||
}
|
||||
RootBeanDefinition bean = new RootBeanDefinition(UserDetailsServiceFactoryBean.class);
|
||||
bean.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getReaderContext().getRegistry().registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY, bean);
|
||||
void createUserServiceInjector() {
|
||||
BeanDefinitionBuilder userServiceInjector =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
userServiceInjector.addConstructorArgValue(x509ProviderId);
|
||||
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
|
||||
userServiceInjector.addConstructorArgValue(openIDProviderId);
|
||||
userServiceInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getReaderContext().registerWithGeneratedName(userServiceInjector.getBeanDefinition());
|
||||
}
|
||||
|
||||
List<OrderDecorator> getFilters() {
|
||||
@@ -658,16 +566,12 @@ final class AuthenticationConfigBuilder {
|
||||
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
|
||||
}
|
||||
|
||||
if (jeeFilter != null) {
|
||||
filters.add(new OrderDecorator(jeeFilter, PRE_AUTH_FILTER));
|
||||
if (formFilterId != null) {
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(formFilterId), FORM_LOGIN_FILTER));
|
||||
}
|
||||
|
||||
if (formFilter != null) {
|
||||
filters.add(new OrderDecorator(formFilter, FORM_LOGIN_FILTER));
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
filters.add(new OrderDecorator(openIDFilter, OPENID_FILTER));
|
||||
if (openIDFilterId != null) {
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(openIDFilterId), OPENID_FILTER));
|
||||
}
|
||||
|
||||
if (loginPageGenerationFilter != null) {
|
||||
@@ -702,11 +606,11 @@ final class AuthenticationConfigBuilder {
|
||||
providers.add(x509ProviderRef);
|
||||
}
|
||||
|
||||
if (jeeProviderRef != null) {
|
||||
providers.add(jeeProviderRef);
|
||||
}
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
public BeanReference getRequestCache() {
|
||||
return requestCache;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ public class ChannelAttributeFactory {
|
||||
private static final String OPT_REQUIRES_HTTPS = "https";
|
||||
private static final String OPT_ANY_CHANNEL = "any";
|
||||
|
||||
public static List<ConfigAttribute> createChannelAttributes(String requiredChannel) {
|
||||
String channelConfigAttribute;
|
||||
public static final List<ConfigAttribute> createChannelAttributes(String requiredChannel) {
|
||||
String channelConfigAttribute = null;
|
||||
|
||||
if (requiredChannel.equals(OPT_REQUIRES_HTTPS)) {
|
||||
channelConfigAttribute = "REQUIRES_SECURE_CHANNEL";
|
||||
|
||||
+53
-55
@@ -2,6 +2,7 @@ package org.springframework.security.config.http;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
@@ -10,7 +11,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
@@ -20,21 +20,24 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
|
||||
public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public void validate(FilterChainProxy fcp) {
|
||||
for(List<Filter> filters : fcp.getFilterChainMap().values()) {
|
||||
checkLoginPageIsntProtected(fcp, filters);
|
||||
Map<String, List<Filter>> filterChainMap = fcp.getFilterChainMap();
|
||||
for(String pattern : fcp.getFilterChainMap().keySet()) {
|
||||
List<Filter> filters = filterChainMap.get(pattern);
|
||||
checkFilterStack(filters);
|
||||
}
|
||||
|
||||
checkLoginPageIsntProtected(fcp, filterChainMap.get(fcp.getMatcher().getUniversalMatchPattern()));
|
||||
}
|
||||
|
||||
private Object getFilter(Class<?> type, List<Filter> filters) {
|
||||
|
||||
for (Filter f : filters) {
|
||||
if (type.isAssignableFrom(f.getClass())) {
|
||||
return f;
|
||||
@@ -53,7 +56,6 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
|
||||
checkForDuplicates(SessionManagementFilter.class, filters);
|
||||
checkForDuplicates(BasicAuthenticationFilter.class, filters);
|
||||
checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);
|
||||
checkForDuplicates(JaasApiIntegrationFilter.class, filters);
|
||||
checkForDuplicates(ExceptionTranslationFilter.class, filters);
|
||||
checkForDuplicates(FilterSecurityInterceptor.class, filters);
|
||||
}
|
||||
@@ -76,60 +78,56 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
|
||||
}
|
||||
|
||||
/* Checks for the common error of having a login page URL protected by the security interceptor */
|
||||
private void checkLoginPageIsntProtected(FilterChainProxy fcp, List<Filter> filterStack) {
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter)getFilter(ExceptionTranslationFilter.class, filterStack);
|
||||
private void checkLoginPageIsntProtected(FilterChainProxy fcp, List<Filter> defaultFilters) {
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter)getFilter(ExceptionTranslationFilter.class, defaultFilters);
|
||||
|
||||
if(etf == null || !(etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint)) {
|
||||
return;
|
||||
}
|
||||
if (etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint) {
|
||||
String loginPage =
|
||||
((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
|
||||
List<Filter> filters = fcp.getFilters(loginPage);
|
||||
logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
|
||||
|
||||
String loginPage = ((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
|
||||
FilterInvocation loginRequest = new FilterInvocation(loginPage, "POST");
|
||||
List<Filter> 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 (getFilter(DefaultLoginPageGeneratingFilter.class, filters) != null) {
|
||||
logger.debug("Default generated login page is in use");
|
||||
return;
|
||||
}
|
||||
|
||||
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class, filters);
|
||||
DefaultFilterInvocationSecurityMetadataSource fids =
|
||||
(DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource();
|
||||
|
||||
Collection<ConfigAttribute> attributes = fids.getAttributes(loginRequest);
|
||||
|
||||
if (attributes == 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.");
|
||||
if (filters == null || filters.isEmpty()) {
|
||||
logger.debug("Filter chain is empty for the login page");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
AnonymousAuthenticationFilter anonPF = (AnonymousAuthenticationFilter) getFilter(AnonymousAuthenticationFilter.class, filters);
|
||||
if (anonPF == null) {
|
||||
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;
|
||||
}
|
||||
if (getFilter(DefaultLoginPageGeneratingFilter.class, filters) != null) {
|
||||
logger.debug("Default generated login page is in use");
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate an anonymous access with the supplied attributes.
|
||||
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
|
||||
anonPF.getUserAttribute().getAuthorities());
|
||||
try {
|
||||
fsi.getAccessDecisionManager().decide(token, new Object(), attributes);
|
||||
} 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 + ")");
|
||||
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class, filters);
|
||||
DefaultFilterInvocationSecurityMetadataSource fids =
|
||||
(DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource();
|
||||
Collection<ConfigAttribute> attributes = fids.lookupAttributes(loginPage, "POST");
|
||||
|
||||
if (attributes == 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;
|
||||
}
|
||||
|
||||
AnonymousAuthenticationFilter anonPF = (AnonymousAuthenticationFilter) getFilter(AnonymousAuthenticationFilter.class, filters);
|
||||
if (anonPF == null) {
|
||||
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.
|
||||
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
|
||||
anonPF.getUserAttribute().getAuthorities());
|
||||
try {
|
||||
fsi.getAccessDecisionManager().decide(token, new Object(), fids.lookupAttributes(loginPage, "POST"));
|
||||
} 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 + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,10 +1,5 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
@@ -13,11 +8,14 @@ import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.web.util.RegexUrlPathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Sets the filter chain Map for a FilterChainProxy bean declaration.
|
||||
*
|
||||
@@ -32,7 +30,11 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
|
||||
Map filterChainMap = new LinkedHashMap();
|
||||
Element elt = (Element)node;
|
||||
|
||||
MatcherType matcherType = MatcherType.fromElement(elt);
|
||||
String pathType = elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_TYPE);
|
||||
|
||||
if (HttpSecurityBeanDefinitionParser.OPT_PATH_TYPE_REGEX.equals(pathType)) {
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", new RegexUrlPathMatcher());
|
||||
}
|
||||
|
||||
List<Element> filterChainElts = DomUtils.getChildElementsByTagName(elt, Elements.FILTER_CHAIN);
|
||||
|
||||
@@ -50,19 +52,17 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
|
||||
"'must not be empty", elt);
|
||||
}
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, null);
|
||||
|
||||
if (filters.equals(HttpSecurityBeanDefinitionParser.OPT_FILTERS_NONE)) {
|
||||
filterChainMap.put(matcher, Collections.EMPTY_LIST);
|
||||
filterChainMap.put(path, Collections.EMPTY_LIST);
|
||||
} else {
|
||||
String[] filterBeanNames = StringUtils.tokenizeToStringArray(filters, ",");
|
||||
ManagedList filterChain = new ManagedList(filterBeanNames.length);
|
||||
|
||||
for (String name : filterBeanNames) {
|
||||
filterChain.add(new RuntimeBeanReference(name));
|
||||
for (int i=0; i < filterBeanNames.length; i++) {
|
||||
filterChain.add(new RuntimeBeanReference(filterBeanNames[i]));
|
||||
}
|
||||
|
||||
filterChainMap.put(matcher, filterChain);
|
||||
filterChainMap.put(path, filterChain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+31
-17
@@ -1,5 +1,8 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||
import static org.springframework.security.config.Elements.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -17,6 +20,9 @@ import org.springframework.security.web.access.expression.DefaultWebSecurityExpr
|
||||
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.RequestKey;
|
||||
import org.springframework.security.web.util.AntUrlPathMatcher;
|
||||
import org.springframework.security.web.util.UrlMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -60,11 +66,11 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
}
|
||||
|
||||
static BeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
|
||||
MatcherType matcherType = MatcherType.fromElement(elt);
|
||||
UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(elt);
|
||||
boolean useExpressions = isUseExpressions(elt);
|
||||
|
||||
ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap(
|
||||
matcherType, interceptUrls, useExpressions, pc);
|
||||
interceptUrls, useExpressions, pc);
|
||||
BeanDefinitionBuilder fidsBuilder;
|
||||
|
||||
if (useExpressions) {
|
||||
@@ -74,37 +80,33 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
if (StringUtils.hasText(expressionHandlerRef)) {
|
||||
logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation");
|
||||
} else {
|
||||
expressionHandlerRef = registerDefaultExpressionHandler(pc);
|
||||
BeanDefinition expressionHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultWebSecurityExpressionHandler.class).getBeanDefinition();
|
||||
expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
|
||||
}
|
||||
|
||||
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedFilterInvocationSecurityMetadataSource.class);
|
||||
fidsBuilder.addConstructorArgValue(matcher);
|
||||
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
|
||||
fidsBuilder.addConstructorArgReference(expressionHandlerRef);
|
||||
} else {
|
||||
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
|
||||
fidsBuilder.addConstructorArgValue(matcher);
|
||||
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
|
||||
}
|
||||
|
||||
fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
|
||||
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt));
|
||||
|
||||
return fidsBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
static String registerDefaultExpressionHandler(ParserContext pc) {
|
||||
BeanDefinition expressionHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultWebSecurityExpressionHandler.class).getBeanDefinition();
|
||||
String expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
|
||||
|
||||
return expressionHandlerRef;
|
||||
}
|
||||
|
||||
static boolean isUseExpressions(Element elt) {
|
||||
return "true".equals(elt.getAttribute(ATT_USE_EXPRESSIONS));
|
||||
}
|
||||
|
||||
private static ManagedMap<BeanDefinition, BeanDefinition>
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(MatcherType matcherType,
|
||||
List<Element> urlElts, boolean useExpressions, ParserContext parserContext) {
|
||||
private static ManagedMap<BeanDefinition, BeanDefinition> parseInterceptUrlsForFilterInvocationRequestMap(List<Element> urlElts,
|
||||
boolean useExpressions, ParserContext parserContext) {
|
||||
|
||||
ManagedMap<BeanDefinition, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<BeanDefinition, BeanDefinition>();
|
||||
|
||||
@@ -113,6 +115,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
if (!StringUtils.hasText(access)) {
|
||||
continue;
|
||||
}
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
if(OPT_FILTERS_NONE.equals(filters)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Ambiguous configuration. Cannot contain " + INTERCEPT_URL+"@" + ATT_FILTERS +
|
||||
"=\"" + OPT_FILTERS_NONE + "\" and " + INTERCEPT_URL + "@" + ATT_ACCESS,
|
||||
parserContext.extractSource(urlElt));
|
||||
}
|
||||
|
||||
String path = urlElt.getAttribute(ATT_PATTERN);
|
||||
|
||||
@@ -125,7 +134,10 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
method = null;
|
||||
}
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, method);
|
||||
BeanDefinitionBuilder keyBldr = BeanDefinitionBuilder.rootBeanDefinition(RequestKey.class);
|
||||
keyBldr.addConstructorArgValue(path);
|
||||
keyBldr.addConstructorArgValue(method);
|
||||
|
||||
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
|
||||
attributeBuilder.addConstructorArgValue(access);
|
||||
|
||||
@@ -138,11 +150,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
|
||||
}
|
||||
|
||||
if (filterInvocationDefinitionMap.containsKey(matcher)) {
|
||||
BeanDefinition key = keyBldr.getBeanDefinition();
|
||||
|
||||
if (filterInvocationDefinitionMap.containsKey(key)) {
|
||||
logger.warn("Duplicate URL defined: " + path + ". The original attribute values will be overwritten");
|
||||
}
|
||||
|
||||
filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
|
||||
filterInvocationDefinitionMap.put(key, attributeBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
return filterInvocationDefinitionMap;
|
||||
|
||||
+2
-25
@@ -29,8 +29,6 @@ public class FormLoginBeanDefinitionParser {
|
||||
private static final String ATT_FORM_LOGIN_TARGET_URL = "default-target-url";
|
||||
private static final String ATT_ALWAYS_USE_DEFAULT_TARGET_URL = "always-use-default-target";
|
||||
private static final String DEF_FORM_LOGIN_TARGET_URL = "/";
|
||||
private static final String ATT_USERNAME_PARAMETER = "username-parameter";
|
||||
private static final String ATT_PASSWORD_PARAMETER = "password-parameter";
|
||||
|
||||
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
|
||||
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL =
|
||||
@@ -65,10 +63,6 @@ public class FormLoginBeanDefinitionParser {
|
||||
String alwaysUseDefault = null;
|
||||
String successHandlerRef = null;
|
||||
String failureHandlerRef = null;
|
||||
// Only available with form-login
|
||||
String usernameParameter = null;
|
||||
String passwordParameter = null;
|
||||
String authDetailsSourceRef = null;
|
||||
|
||||
Object source = null;
|
||||
|
||||
@@ -84,27 +78,15 @@ public class FormLoginBeanDefinitionParser {
|
||||
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
|
||||
successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF);
|
||||
failureHandlerRef = elt.getAttribute(ATT_FAILURE_HANDLER_REF);
|
||||
authDetailsSourceRef = elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
|
||||
|
||||
|
||||
if (!StringUtils.hasText(loginPage)) {
|
||||
loginPage = null;
|
||||
}
|
||||
WebConfigUtils.validateHttpRedirect(loginPage, pc, source);
|
||||
usernameParameter = elt.getAttribute(ATT_USERNAME_PARAMETER);
|
||||
passwordParameter = elt.getAttribute(ATT_PASSWORD_PARAMETER);
|
||||
}
|
||||
|
||||
filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl,
|
||||
successHandlerRef, failureHandlerRef, authDetailsSourceRef);
|
||||
|
||||
if (StringUtils.hasText(usernameParameter)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("usernameParameter", usernameParameter);
|
||||
}
|
||||
if (StringUtils.hasText(passwordParameter)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("passwordParameter", passwordParameter);
|
||||
}
|
||||
|
||||
successHandlerRef, failureHandlerRef);
|
||||
filterBean.setSource(source);
|
||||
|
||||
BeanDefinitionBuilder entryPointBuilder =
|
||||
@@ -117,8 +99,7 @@ public class FormLoginBeanDefinitionParser {
|
||||
}
|
||||
|
||||
private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String alwaysUseDefault,
|
||||
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef,
|
||||
String authDetailsSourceRef) {
|
||||
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef) {
|
||||
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);
|
||||
|
||||
@@ -140,10 +121,6 @@ public class FormLoginBeanDefinitionParser {
|
||||
filterBuilder.addPropertyValue("authenticationSuccessHandler", successHandler.getBeanDefinition());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(authDetailsSourceRef)) {
|
||||
filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef);
|
||||
}
|
||||
|
||||
if (sessionStrategy != null) {
|
||||
filterBuilder.addPropertyValue("sessionAuthenticationStrategy", sessionStrategy);
|
||||
}
|
||||
|
||||
+102
-143
@@ -1,11 +1,14 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||
import static org.springframework.security.config.http.SecurityFilters.*;
|
||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||
import static org.springframework.security.config.Elements.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
@@ -22,7 +25,6 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.PortResolverImpl;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
@@ -33,19 +35,17 @@ import org.springframework.security.web.access.channel.SecureChannelProcessor;
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.access.intercept.RequestKey;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.security.web.util.AntUrlPathMatcher;
|
||||
import org.springframework.security.web.util.UrlMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -58,6 +58,9 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
class HttpConfigurationBuilder {
|
||||
private static final String ATT_CREATE_SESSION = "create-session";
|
||||
private static final String OPT_CREATE_SESSION_NEVER = "never";
|
||||
private static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired";
|
||||
private static final String OPT_CREATE_SESSION_ALWAYS = "always";
|
||||
|
||||
private static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
|
||||
private static final String OPT_SESSION_FIXATION_NO_PROTECTION = "none";
|
||||
@@ -73,60 +76,66 @@ class HttpConfigurationBuilder {
|
||||
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
private static final String ATT_ONCE_PER_REQUEST = "once-per-request";
|
||||
|
||||
private static final String ATT_REF = "ref";
|
||||
|
||||
private final Element httpElt;
|
||||
private final ParserContext pc;
|
||||
private final SessionCreationPolicy sessionPolicy;
|
||||
private final UrlMatcher matcher;
|
||||
private final Boolean convertPathsToLowerCase;
|
||||
private final boolean allowSessionCreation;
|
||||
private final List<Element> interceptUrls;
|
||||
private final MatcherType matcherType;
|
||||
|
||||
// Use ManagedMap to allow placeholder resolution
|
||||
private ManagedMap<Object, List<BeanMetadataElement>> filterChainMap;
|
||||
|
||||
private BeanDefinition cpf;
|
||||
private BeanDefinition securityContextPersistenceFilter;
|
||||
private BeanReference contextRepoRef;
|
||||
private BeanReference sessionRegistryRef;
|
||||
private BeanDefinition concurrentSessionFilter;
|
||||
private BeanDefinition requestCacheAwareFilter;
|
||||
private BeanReference sessionStrategyRef;
|
||||
private RootBeanDefinition sfpf;
|
||||
private BeanDefinition servApiFilter;
|
||||
private BeanDefinition jaasApiFilter;
|
||||
private final String portMapperName;
|
||||
private String portMapperName;
|
||||
private BeanReference fsi;
|
||||
private BeanReference requestCache;
|
||||
|
||||
public HttpConfigurationBuilder(Element element, ParserContext pc, MatcherType matcherType,
|
||||
String portMapperName, BeanReference authenticationManager) {
|
||||
|
||||
public HttpConfigurationBuilder(Element element, ParserContext pc, UrlMatcher matcher, String portMapperName) {
|
||||
this.httpElt = element;
|
||||
this.pc = pc;
|
||||
this.portMapperName = portMapperName;
|
||||
this.matcherType = matcherType;
|
||||
this.matcher = matcher;
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
allowSessionCreation = !OPT_CREATE_SESSION_NEVER.equals(element.getAttribute(ATT_CREATE_SESSION));
|
||||
}
|
||||
|
||||
void parseInterceptUrlsForEmptyFilterChains() {
|
||||
filterChainMap = new ManagedMap<Object, List<BeanMetadataElement>>();
|
||||
|
||||
for (Element urlElt : interceptUrls) {
|
||||
if (StringUtils.hasText(urlElt.getAttribute(ATT_FILTERS))) {
|
||||
pc.getReaderContext().error("The use of \"filters='none'\" is no longer supported. Please define a" +
|
||||
" separate <http> element for the pattern you want to exclude and use the attribute" +
|
||||
" \"security='none'\".", pc.extractSource(urlElt));
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
|
||||
if(!StringUtils.hasText(path)) {
|
||||
pc.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder pathBean = BeanDefinitionBuilder.rootBeanDefinition(HttpConfigurationBuilder.class);
|
||||
pathBean.setFactoryMethod("createPath");
|
||||
pathBean.addConstructorArgValue(path);
|
||||
pathBean.addConstructorArgValue(convertPathsToLowerCase);
|
||||
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
|
||||
if (StringUtils.hasText(filters)) {
|
||||
if (!filters.equals(OPT_FILTERS_NONE)) {
|
||||
pc.getReaderContext().error("Currently only 'none' is supported as the custom " +
|
||||
"filters attribute", urlElt);
|
||||
}
|
||||
|
||||
List<BeanMetadataElement> noFilters = Collections.emptyList();
|
||||
filterChainMap.put(pathBean.getBeanDefinition(), noFilters);
|
||||
}
|
||||
}
|
||||
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
|
||||
if (StringUtils.hasText(createSession)) {
|
||||
sessionPolicy = SessionCreationPolicy.valueOf(createSession);
|
||||
} else {
|
||||
sessionPolicy = SessionCreationPolicy.ifRequired;
|
||||
}
|
||||
|
||||
createSecurityContextPersistenceFilter();
|
||||
createSessionManagementFilters();
|
||||
createRequestCacheFilter();
|
||||
createServletApiFilter();
|
||||
createJaasApiFilter();
|
||||
createChannelProcessingFilter();
|
||||
createFilterSecurityInterceptor(authenticationManager);
|
||||
}
|
||||
|
||||
// Needed to account for placeholders
|
||||
@@ -134,44 +143,43 @@ class HttpConfigurationBuilder {
|
||||
return lowerCase ? path.toLowerCase() : path;
|
||||
}
|
||||
|
||||
private void createSecurityContextPersistenceFilter() {
|
||||
void createSecurityContextPersistenceFilter() {
|
||||
BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
|
||||
|
||||
String repoRef = httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
|
||||
String createSession = httpElt.getAttribute(ATT_CREATE_SESSION);
|
||||
String disableUrlRewriting = httpElt.getAttribute(ATT_DISABLE_URL_REWRITING);
|
||||
|
||||
if (StringUtils.hasText(repoRef)) {
|
||||
if (sessionPolicy == SessionCreationPolicy.always) {
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (StringUtils.hasText(createSession)) {
|
||||
pc.getReaderContext().error("If using security-context-repository-ref, the only value you can set for " +
|
||||
"'create-session' is 'always'. Other session creation logic should be handled by the " +
|
||||
"SecurityContextRepository", httpElt);
|
||||
}
|
||||
} else {
|
||||
BeanDefinitionBuilder contextRepo;
|
||||
if (sessionPolicy == SessionCreationPolicy.stateless) {
|
||||
contextRepo = BeanDefinitionBuilder.rootBeanDefinition(NullSecurityContextRepository.class);
|
||||
BeanDefinitionBuilder contextRepo = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSecurityContextRepository.class);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
} else {
|
||||
contextRepo = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSecurityContextRepository.class);
|
||||
switch (sessionPolicy) {
|
||||
case always:
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
break;
|
||||
case never:
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
break;
|
||||
default:
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
|
||||
if ("true".equals(disableUrlRewriting)) {
|
||||
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
|
||||
}
|
||||
if ("true".equals(disableUrlRewriting)) {
|
||||
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
|
||||
}
|
||||
|
||||
BeanDefinition repoBean = contextRepo.getBeanDefinition();
|
||||
repoRef = pc.getReaderContext().generateBeanName(repoBean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(repoBean, repoRef));
|
||||
|
||||
}
|
||||
|
||||
contextRepoRef = new RuntimeBeanReference(repoRef);
|
||||
@@ -180,7 +188,7 @@ class HttpConfigurationBuilder {
|
||||
securityContextPersistenceFilter = scpf.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void createSessionManagementFilters() {
|
||||
void createSessionManagementFilters() {
|
||||
Element sessionMgmtElt = DomUtils.getChildElementByTagName(httpElt, Elements.SESSION_MANAGEMENT);
|
||||
Element sessionCtrlElt = null;
|
||||
|
||||
@@ -190,11 +198,6 @@ class HttpConfigurationBuilder {
|
||||
String errorUrl = null;
|
||||
|
||||
if (sessionMgmtElt != null) {
|
||||
if (sessionPolicy == SessionCreationPolicy.stateless) {
|
||||
pc.getReaderContext().error(Elements.SESSION_MANAGEMENT + " cannot be used" +
|
||||
" in combination with " + ATT_CREATE_SESSION + "='"+ SessionCreationPolicy.stateless +"'",
|
||||
pc.extractSource(sessionMgmtElt));
|
||||
}
|
||||
sessionFixationAttribute = sessionMgmtElt.getAttribute(ATT_SESSION_FIXATION_PROTECTION);
|
||||
invalidSessionUrl = sessionMgmtElt.getAttribute(ATT_INVALID_SESSION_URL);
|
||||
sessionAuthStratRef = sessionMgmtElt.getAttribute(ATT_SESSION_AUTH_STRATEGY_REF);
|
||||
@@ -214,12 +217,7 @@ class HttpConfigurationBuilder {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
} else if (StringUtils.hasText(sessionAuthStratRef)) {
|
||||
pc.getReaderContext().error(ATT_SESSION_FIXATION_PROTECTION + " attribute cannot be used" +
|
||||
" in combination with " + ATT_SESSION_AUTH_STRATEGY_REF, pc.extractSource(sessionMgmtElt));
|
||||
}
|
||||
|
||||
if (sessionPolicy == SessionCreationPolicy.stateless) {
|
||||
// SEC-1424: do nothing
|
||||
return;
|
||||
" in combination with " + ATT_SESSION_AUTH_STRATEGY_REF, pc.extractSource(sessionCtrlElt));
|
||||
}
|
||||
|
||||
boolean sessionFixationProtectionRequired = !sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION);
|
||||
@@ -326,7 +324,7 @@ class HttpConfigurationBuilder {
|
||||
}
|
||||
|
||||
// Adds the servlet-api integration filter if required
|
||||
private void createServletApiFilter() {
|
||||
void createServletApiFilter() {
|
||||
final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
|
||||
final String DEF_SERVLET_API_PROVISION = "true";
|
||||
|
||||
@@ -339,23 +337,8 @@ class HttpConfigurationBuilder {
|
||||
servApiFilter = new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the jaas-api integration filter if required
|
||||
private void createJaasApiFilter() {
|
||||
final String ATT_JAAS_API_PROVISION = "jaas-api-provision";
|
||||
final String DEF_JAAS_API_PROVISION = "false";
|
||||
|
||||
String provideJaasApi = httpElt.getAttribute(ATT_JAAS_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideJaasApi)) {
|
||||
provideJaasApi = DEF_JAAS_API_PROVISION;
|
||||
}
|
||||
|
||||
if ("true".equals(provideJaasApi)) {
|
||||
jaasApiFilter = new RootBeanDefinition(JaasApiIntegrationFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void createChannelProcessingFilter() {
|
||||
void createChannelProcessingFilter() {
|
||||
ManagedMap<BeanDefinition,BeanDefinition> channelRequestMap = parseInterceptUrlsForChannelSecurity();
|
||||
|
||||
if (channelRequestMap.isEmpty()) {
|
||||
@@ -364,8 +347,9 @@ class HttpConfigurationBuilder {
|
||||
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
BeanDefinitionBuilder metadataSourceBldr = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
|
||||
metadataSourceBldr.addConstructorArgValue(matcher);
|
||||
metadataSourceBldr.addConstructorArgValue(channelRequestMap);
|
||||
// metadataSourceBldr.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
|
||||
metadataSourceBldr.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("securityMetadataSource", metadataSourceBldr.getBeanDefinition());
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
@@ -398,58 +382,45 @@ class HttpConfigurationBuilder {
|
||||
|
||||
for (Element urlElt : interceptUrls) {
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
||||
|
||||
if(!StringUtils.hasText(path)) {
|
||||
pc.getReaderContext().error("pattern attribute cannot be empty or null", urlElt);
|
||||
pc.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
||||
}
|
||||
|
||||
if (convertPathsToLowerCase) {
|
||||
path = path.toLowerCase();
|
||||
}
|
||||
|
||||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||
|
||||
if (StringUtils.hasText(requiredChannel)) {
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, method);
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
if(OPT_FILTERS_NONE.equals(filters)) {
|
||||
pc.getReaderContext().error(
|
||||
"Ambiguous configuration. Cannot contain " + INTERCEPT_URL+"@" + ATT_FILTERS +
|
||||
"=\"" + OPT_FILTERS_NONE + "\" and " + INTERCEPT_URL + "@" + ATT_REQUIRES_CHANNEL,
|
||||
pc.extractSource(urlElt));
|
||||
}
|
||||
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
|
||||
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
|
||||
|
||||
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
||||
if(StringUtils.hasText(method)) {
|
||||
requestKey.getConstructorArgumentValues().addGenericArgumentValue(method);
|
||||
}
|
||||
|
||||
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
|
||||
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
||||
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
||||
|
||||
channelRequestMap.put(matcher, channelAttributes);
|
||||
channelRequestMap.put(requestKey, channelAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
return channelRequestMap;
|
||||
}
|
||||
|
||||
private void createRequestCacheFilter() {
|
||||
Element requestCacheElt = DomUtils.getChildElementByTagName(httpElt, Elements.REQUEST_CACHE);
|
||||
|
||||
if (requestCacheElt != null) {
|
||||
requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
|
||||
} else {
|
||||
BeanDefinitionBuilder requestCacheBldr;
|
||||
|
||||
if (sessionPolicy == SessionCreationPolicy.stateless) {
|
||||
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(NullRequestCache.class);
|
||||
} else {
|
||||
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
|
||||
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
|
||||
portResolver.addPropertyReference("portMapper", portMapperName);
|
||||
requestCacheBldr.addPropertyValue("createSessionAllowed", sessionPolicy == SessionCreationPolicy.ifRequired);
|
||||
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
|
||||
}
|
||||
|
||||
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
|
||||
String id = pc.getReaderContext().generateBeanName(bean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
|
||||
|
||||
this.requestCache = new RuntimeBeanReference(id);
|
||||
}
|
||||
|
||||
requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
|
||||
requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", requestCache);
|
||||
}
|
||||
|
||||
private void createFilterSecurityInterceptor(BeanReference authManager) {
|
||||
void createFilterSecurityInterceptor(BeanReference authManager) {
|
||||
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
|
||||
BeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
|
||||
|
||||
@@ -457,12 +428,7 @@ class HttpConfigurationBuilder {
|
||||
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
|
||||
|
||||
if (useExpressions) {
|
||||
BeanDefinitionBuilder expressionVoter = BeanDefinitionBuilder.rootBeanDefinition(WebExpressionVoter.class);
|
||||
RuntimeBeanReference expressionHandler = new RuntimeBeanReference(
|
||||
FilterInvocationSecurityMetadataSourceParser.registerDefaultExpressionHandler(pc));
|
||||
expressionVoter.addPropertyValue("expressionHandler", expressionHandler);
|
||||
|
||||
voters.add(expressionVoter.getBeanDefinition());
|
||||
voters.add(new RootBeanDefinition(WebExpressionVoter.class));
|
||||
} else {
|
||||
voters.add(new RootBeanDefinition(RoleVoter.class));
|
||||
voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
|
||||
@@ -506,12 +472,13 @@ class HttpConfigurationBuilder {
|
||||
return sessionStrategyRef;
|
||||
}
|
||||
|
||||
SessionCreationPolicy getSessionCreationPolicy() {
|
||||
return sessionPolicy;
|
||||
|
||||
boolean isAllowSessionCreation() {
|
||||
return allowSessionCreation;
|
||||
}
|
||||
|
||||
BeanReference getRequestCache() {
|
||||
return requestCache;
|
||||
public ManagedMap<Object, List<BeanMetadataElement>> getFilterChainMap() {
|
||||
return filterChainMap;
|
||||
}
|
||||
|
||||
List<OrderDecorator> getFilters() {
|
||||
@@ -531,20 +498,12 @@ class HttpConfigurationBuilder {
|
||||
filters.add(new OrderDecorator(servApiFilter, SERVLET_API_SUPPORT_FILTER));
|
||||
}
|
||||
|
||||
if (jaasApiFilter != null) {
|
||||
filters.add(new OrderDecorator(jaasApiFilter, JAAS_API_SUPPORT_FILTER));
|
||||
}
|
||||
|
||||
if (sfpf != null) {
|
||||
filters.add(new OrderDecorator(sfpf, SESSION_MANAGEMENT_FILTER));
|
||||
}
|
||||
|
||||
filters.add(new OrderDecorator(fsi, FILTER_SECURITY_INTERCEPTOR));
|
||||
|
||||
if (sessionPolicy != SessionCreationPolicy.stateless) {
|
||||
filters.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -3,7 +3,9 @@ package org.springframework.security.config.http;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
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.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
@@ -26,11 +28,10 @@ public class HttpFirewallBeanDefinitionParser implements BeanDefinitionParser {
|
||||
pc.getReaderContext().error("ref attribute is required", pc.extractSource(element));
|
||||
}
|
||||
|
||||
HttpSecurityBeanDefinitionParser.registerFilterChainProxy(pc,
|
||||
new ManagedMap<BeanDefinition, List<BeanMetadataElement>>(),
|
||||
pc.extractSource(element));
|
||||
BeanDefinition filterChainProxy = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("firewall", new RuntimeBeanReference(ref));
|
||||
BeanDefinitionBuilder injector = BeanDefinitionBuilder.rootBeanDefinition(HttpFirewallInjectionBeanPostProcessor.class);
|
||||
injector.addConstructorArgValue(ref);
|
||||
|
||||
pc.getReaderContext().registerWithGeneratedName(injector.getBeanDefinition());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
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.config.BeanIds;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class HttpFirewallInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
private String ref;
|
||||
|
||||
public HttpFirewallInjectionBeanPostProcessor(String ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
|
||||
HttpFirewall fw = (HttpFirewall) beanFactory.getBean(ref);
|
||||
((FilterChainProxy)bean).setFirewall(fw);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
+111
-83
@@ -1,5 +1,7 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.SecurityFilters.REQUEST_CACHE_FILTER;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -12,7 +14,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
@@ -28,7 +29,10 @@ import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.util.AnyRequestMatcher;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.util.AntUrlPathMatcher;
|
||||
import org.springframework.security.web.util.RegexUrlPathMatcher;
|
||||
import org.springframework.security.web.util.UrlMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -44,16 +48,24 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class);
|
||||
|
||||
static final String ATT_PATH_PATTERN = "pattern";
|
||||
static final String ATT_HTTP_METHOD = "method";
|
||||
static final String ATT_PATH_TYPE = "path-type";
|
||||
static final String OPT_PATH_TYPE_REGEX = "regex";
|
||||
private static final String DEF_PATH_TYPE_ANT = "ant";
|
||||
|
||||
static final String ATT_FILTERS = "filters";
|
||||
static final String OPT_FILTERS_NONE = "none";
|
||||
|
||||
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
|
||||
static final String ATT_HTTP_METHOD = "method";
|
||||
|
||||
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
|
||||
|
||||
private static final String ATT_REF = "ref";
|
||||
private static final String ATT_SECURED = "security";
|
||||
private static final String OPT_SECURITY_NONE = "none";
|
||||
|
||||
static final String EXPRESSION_FIMDS_CLASS = "org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource";
|
||||
static final String EXPRESSION_HANDLER_CLASS = "org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler";
|
||||
|
||||
static final List<BeanMetadataElement> NO_FILTERS = Collections.emptyList();
|
||||
|
||||
public HttpSecurityBeanDefinitionParser() {
|
||||
}
|
||||
@@ -70,69 +82,54 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
CompositeComponentDefinition compositeDef =
|
||||
new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
|
||||
pc.pushContainingComponent(compositeDef);
|
||||
|
||||
MatcherType matcherType = MatcherType.fromElement(element);
|
||||
ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = new ManagedMap<BeanDefinition, List<BeanMetadataElement>>();
|
||||
|
||||
String filterChainPattern = element.getAttribute(ATT_PATH_PATTERN);
|
||||
|
||||
BeanDefinition filterChainMatcher;
|
||||
|
||||
if (StringUtils.hasText(filterChainPattern)) {
|
||||
filterChainMatcher = matcherType.createMatcher(filterChainPattern, null);
|
||||
} else {
|
||||
filterChainMatcher = new RootBeanDefinition(AnyRequestMatcher.class);
|
||||
}
|
||||
|
||||
filterChainMap.put(filterChainMatcher, createFilterChain(element, pc, matcherType));
|
||||
|
||||
registerFilterChainProxy(pc, filterChainMap, pc.extractSource(element));
|
||||
|
||||
pc.popAndRegisterContainingComponent();
|
||||
return null;
|
||||
}
|
||||
|
||||
List<BeanMetadataElement> createFilterChain(Element element, ParserContext pc, MatcherType matcherType) {
|
||||
boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED));
|
||||
|
||||
if (!secured) {
|
||||
if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN))) {
|
||||
pc.getReaderContext().error("The '" + ATT_SECURED + "' attribute must be used in combination with" +
|
||||
" the '" + ATT_PATH_PATTERN +"' attribute.", pc.extractSource(element));
|
||||
}
|
||||
|
||||
for (int n=0; n < element.getChildNodes().getLength(); n ++) {
|
||||
if (element.getChildNodes().item(n) instanceof Element) {
|
||||
pc.getReaderContext().error("If you are using <http> to define an unsecured pattern, " +
|
||||
"it cannot contain child elements.", pc.extractSource(element));
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final Object source = pc.extractSource(element);
|
||||
|
||||
final String portMapperName = createPortMapper(element, pc);
|
||||
final UrlMatcher matcher = createUrlMatcher(element);
|
||||
|
||||
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName);
|
||||
|
||||
httpBldr.parseInterceptUrlsForEmptyFilterChains();
|
||||
httpBldr.createSecurityContextPersistenceFilter();
|
||||
httpBldr.createSessionManagementFilters();
|
||||
|
||||
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
|
||||
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders);
|
||||
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null);
|
||||
|
||||
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcherType,
|
||||
portMapperName, authenticationManager);
|
||||
httpBldr.createServletApiFilter();
|
||||
httpBldr.createChannelProcessingFilter();
|
||||
httpBldr.createFilterSecurityInterceptor(authenticationManager);
|
||||
|
||||
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
|
||||
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
|
||||
httpBldr.getSessionStrategy());
|
||||
httpBldr.isAllowSessionCreation(), portMapperName);
|
||||
|
||||
authenticationProviders.addAll(authBldr.getProviders());
|
||||
authBldr.createAnonymousFilter();
|
||||
authBldr.createRememberMeFilter(authenticationManager);
|
||||
authBldr.createRequestCache();
|
||||
authBldr.createBasicFilter(authenticationManager);
|
||||
authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
|
||||
authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
|
||||
authBldr.createX509Filter(authenticationManager);
|
||||
authBldr.createLogoutFilter();
|
||||
authBldr.createLoginPageFilterIfNeeded();
|
||||
authBldr.createUserServiceInjector();
|
||||
authBldr.createExceptionTranslationFilter();
|
||||
|
||||
List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();
|
||||
|
||||
unorderedFilterChain.addAll(httpBldr.getFilters());
|
||||
unorderedFilterChain.addAll(authBldr.getFilters());
|
||||
|
||||
authenticationProviders.addAll(authBldr.getProviders());
|
||||
|
||||
BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
|
||||
requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());
|
||||
unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
|
||||
|
||||
unorderedFilterChain.addAll(buildCustomFilterList(element, pc));
|
||||
|
||||
Collections.sort(unorderedFilterChain, new OrderComparator());
|
||||
checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));
|
||||
checkFilterChainOrder(unorderedFilterChain, pc, source);
|
||||
|
||||
List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();
|
||||
|
||||
@@ -140,9 +137,14 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
filterChain.add(od.bean);
|
||||
}
|
||||
|
||||
return filterChain;
|
||||
}
|
||||
ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
|
||||
filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
|
||||
|
||||
registerFilterChainProxy(pc, filterChainMap, matcher, source);
|
||||
|
||||
pc.popAndRegisterContainingComponent();
|
||||
return null;
|
||||
}
|
||||
|
||||
private String createPortMapper(Element elt, ParserContext pc) {
|
||||
// Register the portMapper. A default will always be created, even if no element exists.
|
||||
@@ -162,7 +164,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
* authentication manager.
|
||||
*/
|
||||
private BeanReference createAuthenticationManager(Element element, ParserContext pc,
|
||||
ManagedList<BeanReference> authenticationProviders) {
|
||||
ManagedList<BeanReference> authenticationProviders, BeanReference concurrencyController) {
|
||||
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
||||
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||
authManager.addPropertyValue("providers", authenticationProviders);
|
||||
@@ -171,6 +173,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
|
||||
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
|
||||
|
||||
if (concurrencyController != null) {
|
||||
authManager.addPropertyValue("sessionController", concurrencyController);
|
||||
}
|
||||
authManager.getRawBeanDefinition().setSource(pc.extractSource(element));
|
||||
BeanDefinition authMgrBean = authManager.getBeanDefinition();
|
||||
String id = pc.getReaderContext().generateBeanName(authMgrBean);
|
||||
@@ -183,10 +188,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
logger.info("Checking sorted filter chain: " + filters);
|
||||
|
||||
for(int i=0; i < filters.size(); i++) {
|
||||
OrderDecorator filter = filters.get(i);
|
||||
OrderDecorator filter = (OrderDecorator)filters.get(i);
|
||||
|
||||
if (i > 0) {
|
||||
OrderDecorator previous = filters.get(i-1);
|
||||
OrderDecorator previous = (OrderDecorator)filters.get(i-1);
|
||||
if (filter.getOrder() == previous.getOrder()) {
|
||||
pc.getReaderContext().error("Filter beans '" + filter.bean + "' and '" +
|
||||
previous.bean + "' have the same 'order' value. When using custom filters, " +
|
||||
@@ -246,39 +251,62 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return customFilters;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, Object source) {
|
||||
private void registerFilterChainProxy(ParserContext pc, Map<Object, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||
// Already registered. Obtain the filter chain map and add the new entries to it
|
||||
|
||||
BeanDefinition fcp = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY);
|
||||
Map existingFilterChainMap = (Map) fcp.getPropertyValues().getPropertyValue("filterChainMap").getValue();
|
||||
|
||||
for (BeanDefinition matcherBean : filterChainMap.keySet()) {
|
||||
if (existingFilterChainMap.containsKey(matcherBean)) {
|
||||
Map<Integer,ValueHolder> args = matcherBean.getConstructorArgumentValues().getIndexedArgumentValues();
|
||||
pc.getReaderContext().error("The filter chain map already contains this request matcher ["
|
||||
+ args.get(0).getValue() + ", " +args.get(1).getValue() + "]", source);
|
||||
}
|
||||
}
|
||||
existingFilterChainMap.putAll(filterChainMap);
|
||||
} else {
|
||||
// Not already registered, so register it
|
||||
BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
|
||||
fcpBldr.getRawBeanDefinition().setSource(source);
|
||||
fcpBldr.addPropertyValue("filterChainMap", filterChainMap);
|
||||
fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(DefaultFilterChainValidator.class));
|
||||
BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
|
||||
fcpBldr.getRawBeanDefinition().setSource(source);
|
||||
fcpBldr.addPropertyValue("matcher", matcher);
|
||||
fcpBldr.addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
|
||||
fcpBldr.addPropertyValue("filterChainMap", filterChainMap);
|
||||
BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
}
|
||||
|
||||
static UrlMatcher createUrlMatcher(Element element) {
|
||||
String patternType = element.getAttribute(ATT_PATH_TYPE);
|
||||
if (!StringUtils.hasText(patternType)) {
|
||||
patternType = DEF_PATH_TYPE_ANT;
|
||||
}
|
||||
|
||||
boolean useRegex = patternType.equals(OPT_PATH_TYPE_REGEX);
|
||||
|
||||
UrlMatcher matcher = new AntUrlPathMatcher();
|
||||
|
||||
if (useRegex) {
|
||||
matcher = new RegexUrlPathMatcher();
|
||||
}
|
||||
|
||||
// Deal with lowercase conversion requests
|
||||
String lowercaseComparisons = element.getAttribute(ATT_LOWERCASE_COMPARISONS);
|
||||
if (!StringUtils.hasText(lowercaseComparisons)) {
|
||||
lowercaseComparisons = null;
|
||||
}
|
||||
|
||||
// Only change from the defaults if the attribute has been set
|
||||
if ("true".equals(lowercaseComparisons)) {
|
||||
if (useRegex) {
|
||||
((RegexUrlPathMatcher)matcher).setRequiresLowerCaseUrl(true);
|
||||
}
|
||||
// Default for ant is already to force lower case
|
||||
} else if ("false".equals(lowercaseComparisons)) {
|
||||
if (!useRegex) {
|
||||
((AntUrlPathMatcher)matcher).setRequiresLowerCaseUrl(false);
|
||||
}
|
||||
// Default for regex is no change
|
||||
}
|
||||
|
||||
return matcher;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class OrderDecorator implements Ordered {
|
||||
final BeanMetadataElement bean;
|
||||
final int order;
|
||||
BeanMetadataElement bean;
|
||||
int order;
|
||||
|
||||
public OrderDecorator(BeanMetadataElement bean, SecurityFilters filterOrder) {
|
||||
this.bean = bean;
|
||||
|
||||
+13
-16
@@ -4,10 +4,8 @@ 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.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -22,13 +20,13 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String DEF_LOGOUT_SUCCESS_URL = "/";
|
||||
|
||||
static final String ATT_INVALIDATE_SESSION = "invalidate-session";
|
||||
static final String DEF_INVALIDATE_SESSION = "true";
|
||||
|
||||
static final String ATT_LOGOUT_URL = "logout-url";
|
||||
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
|
||||
static final String ATT_LOGOUT_HANDLER = "success-handler-ref";
|
||||
static final String ATT_DELETE_COOKIES = "delete-cookies";
|
||||
|
||||
final String rememberMeServices;
|
||||
String rememberMeServices;
|
||||
|
||||
public LogoutBeanDefinitionParser(String rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
@@ -40,7 +38,6 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
String successHandlerRef = null;
|
||||
String logoutSuccessUrl = null;
|
||||
String invalidateSession = null;
|
||||
String deleteCookies = null;
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
|
||||
|
||||
@@ -53,7 +50,6 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL);
|
||||
WebConfigUtils.validateHttpRedirect(logoutSuccessUrl, pc, source);
|
||||
invalidateSession = element.getAttribute(ATT_INVALIDATE_SESSION);
|
||||
deleteCookies = element.getAttribute(ATT_DELETE_COOKIES);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(logoutUrl)) {
|
||||
@@ -63,7 +59,7 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
if (StringUtils.hasText(successHandlerRef)) {
|
||||
if (StringUtils.hasText(logoutSuccessUrl)) {
|
||||
pc.getReaderContext().error("Use " + ATT_LOGOUT_URL + " or " + ATT_LOGOUT_HANDLER + ", but not both",
|
||||
pc.getReaderContext().error("Use " + ATT_LOGOUT_SUCCESS_URL + " or " + ATT_LOGOUT_HANDLER + ", but not both",
|
||||
pc.extractSource(element));
|
||||
}
|
||||
builder.addConstructorArgReference(successHandlerRef);
|
||||
@@ -75,22 +71,23 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
builder.addConstructorArgValue(logoutSuccessUrl);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(invalidateSession)) {
|
||||
invalidateSession = DEF_INVALIDATE_SESSION;
|
||||
}
|
||||
|
||||
ManagedList handlers = new ManagedList();
|
||||
BeanDefinition sclh = new RootBeanDefinition(SecurityContextLogoutHandler.class);
|
||||
sclh.getPropertyValues().addPropertyValue("invalidateHttpSession", !"false".equals(invalidateSession));
|
||||
SecurityContextLogoutHandler sclh = new SecurityContextLogoutHandler();
|
||||
if ("true".equals(invalidateSession)) {
|
||||
sclh.setInvalidateHttpSession(true);
|
||||
} else {
|
||||
sclh.setInvalidateHttpSession(false);
|
||||
}
|
||||
handlers.add(sclh);
|
||||
|
||||
if (rememberMeServices != null) {
|
||||
handlers.add(new RuntimeBeanReference(rememberMeServices));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(deleteCookies)) {
|
||||
BeanDefinition cookieDeleter = new RootBeanDefinition(CookieClearingLogoutHandler.class);
|
||||
String[] names = StringUtils.commaDelimitedListToStringArray(deleteCookies);
|
||||
cookieDeleter.getConstructorArgumentValues().addGenericArgumentValue(names);
|
||||
handlers.add(cookieDeleter);
|
||||
}
|
||||
|
||||
builder.addConstructorArgValue(handlers);
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.security.web.util.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Defines the {@link RequestMatcher} types supported by the namespace.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.1
|
||||
*/
|
||||
public enum MatcherType {
|
||||
ant (AntPathRequestMatcher.class),
|
||||
regex (RegexRequestMatcher.class),
|
||||
ciRegex (RegexRequestMatcher.class);
|
||||
|
||||
private static final Log logger = LogFactory.getLog(MatcherType.class);
|
||||
|
||||
private static final String ATT_MATCHER_TYPE = "request-matcher";
|
||||
private static final String ATT_PATH_TYPE = "path-type";
|
||||
|
||||
private final Class<? extends RequestMatcher> type;
|
||||
|
||||
MatcherType(Class<? extends RequestMatcher> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public BeanDefinition createMatcher(String path, String method) {
|
||||
if (("/**".equals(path) || "**".equals(path)) && method == null) {
|
||||
return new RootBeanDefinition(AnyRequestMatcher.class);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(type);
|
||||
|
||||
matcherBldr.addConstructorArgValue(path);
|
||||
matcherBldr.addConstructorArgValue(method);
|
||||
|
||||
if (this == ciRegex) {
|
||||
matcherBldr.addConstructorArgValue(true);
|
||||
}
|
||||
|
||||
return matcherBldr.getBeanDefinition();
|
||||
}
|
||||
|
||||
static MatcherType fromElement(Element elt) {
|
||||
if (StringUtils.hasText(elt.getAttribute(ATT_MATCHER_TYPE))) {
|
||||
return valueOf(elt.getAttribute(ATT_MATCHER_TYPE));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(elt.getAttribute(ATT_PATH_TYPE))) {
|
||||
logger.warn("'" + ATT_PATH_TYPE + "' is deprecated. Please use '" + ATT_MATCHER_TYPE +"' instead.");
|
||||
return valueOf(elt.getAttribute(ATT_PATH_TYPE));
|
||||
}
|
||||
|
||||
return ant;
|
||||
}
|
||||
}
|
||||
+4
-8
@@ -10,7 +10,6 @@ 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;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
||||
@@ -88,19 +87,16 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
if (services != null) {
|
||||
RootBeanDefinition uds = new RootBeanDefinition();
|
||||
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
|
||||
uds.setFactoryMethodName("cachingUserDetailsService");
|
||||
uds.getConstructorArgumentValues().addGenericArgumentValue(userServiceRef);
|
||||
|
||||
services.getPropertyValues().addPropertyValue("userDetailsService", uds);
|
||||
if (userServiceSet) {
|
||||
services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
}
|
||||
|
||||
if ("true".equals(element.getAttribute(ATT_SECURE_COOKIE))) {
|
||||
services.getPropertyValues().addPropertyValue("useSecureCookie", true);
|
||||
}
|
||||
|
||||
if (tokenValiditySet) {
|
||||
Integer tokenValidity = Integer.valueOf(tokenValiditySeconds);
|
||||
Integer tokenValidity = new Integer(tokenValiditySeconds);
|
||||
if (tokenValidity.intValue() < 0 && isPersistent) {
|
||||
pc.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" +
|
||||
" a persistent remember-me token repository", source);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user