Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a25b8bc83 | |||
| a36c4bcb04 | |||
| 8b1f5f7cd7 | |||
| 1677836d53 | |||
| 62e127e978 | |||
| 3171cc4364 | |||
| 11116c2b80 | |||
| f5e8222115 | |||
| c67ff42b8a | |||
| b56e5edbbd | |||
| 5f5e7e7265 | |||
| 87a52ffbfd | |||
| 6e204fff72 | |||
| 5bb0ce9a8f | |||
| 0f7c2e4128 | |||
| 2cb2657f5b | |||
| 8ad16b01f5 | |||
| 09f6210c73 | |||
| 3c487c0348 | |||
| 4392205f63 | |||
| eedbf44235 | |||
| 2e1e9885ec | |||
| e2f7b38b87 | |||
| dfa17bdb98 | |||
| 30c5788b8b | |||
| 1cca72e6d8 | |||
| 4d738d8576 | |||
| 0704f88e99 | |||
| 3089f1603e | |||
| 05882b5f24 | |||
| 5810681b06 | |||
| 4dcc89fab0 | |||
| 002a78d87d | |||
| 95c70f29bd | |||
| ff95a34b1f | |||
| 3b8f7fdd67 | |||
| 55d6d5a86a | |||
| f20219d541 | |||
| fa9e7999da | |||
| 97df23e3b5 | |||
| 24dec7ec3e | |||
| 4e7398eec0 | |||
| d429c96253 | |||
| a28650c715 | |||
| 5ba8f000a7 | |||
| d2fa019fe5 | |||
| 28446284a6 | |||
| b717333707 | |||
| b6fcde880a | |||
| e7edb77cae | |||
| d316f661e8 | |||
| 02c3565e22 | |||
| 39d544b901 | |||
| 96ea4ddc7b | |||
| a932d6ecf3 | |||
| bd322542ca | |||
| 57ea75a7ce | |||
| b9df7ba01f | |||
| 613820a218 | |||
| 533b71b9b8 | |||
| 6321665353 | |||
| 3f30529039 | |||
| 934937d9c1 | |||
| f50e058d07 | |||
| 939df5f0f9 | |||
| 3187ee8bf3 | |||
| 1eaa621619 | |||
| 94a0816153 | |||
| 4f936c4c51 | |||
| 3e8c879cea | |||
| 1f861f512a | |||
| 4a633a938a | |||
| 0f6235bbe0 | |||
| aac4ede3a4 | |||
| 1761b29e58 | |||
| 15c837d5de | |||
| 6b43b261bc | |||
| 93b863d2e5 | |||
| 8a2a1b7a5b | |||
| b2d66e2a78 | |||
| 44f688c9d2 | |||
| 08d703545c | |||
| b72c1ad314 | |||
| e14e5b42fc | |||
| 9654817fd8 | |||
| c8348d60e1 | |||
| ecb4296540 | |||
| b97b84063a | |||
| 3289c1c92a | |||
| 906a0cb0e2 | |||
| 75df42cb7c | |||
| 66c926f2c7 | |||
| c3d05bea62 | |||
| a3fd706335 | |||
| 6dc0733d9e | |||
| b255478b14 | |||
| a2b53fabce | |||
| 63d1b531a1 | |||
| 47e02c41b6 | |||
| e4fa42c399 | |||
| 7e3e821db1 | |||
| 626b521c0e | |||
| 6b121c7543 | |||
| 19ce54e4ff | |||
| f7d09c6b62 | |||
| 025c0857f4 | |||
| 0e9999e429 | |||
| ec1c5b0e78 | |||
| 6964c2e3de | |||
| 8f84921713 | |||
| 41c19e88b2 | |||
| 11d83cdce1 | |||
| 80c0f5fa17 | |||
| 2aea199001 | |||
| 10c4d8f1af | |||
| cb94fb2c99 | |||
| ac712f9f17 | |||
| 5953a35c95 | |||
| 91b2b7f875 | |||
| 1bff58577c | |||
| 15ab3316b3 | |||
| 82e89db1c8 | |||
| fb25273672 | |||
| dd0253048e | |||
| b13603f480 | |||
| 2e88c1dfc7 | |||
| 26ffbeadf0 | |||
| e86cbc8731 | |||
| e9d9a83df4 | |||
| 26db320d3c | |||
| 3ba1f66f9d | |||
| e6e35932ed | |||
| cbd06a4994 | |||
| b8f0db41f4 | |||
| d95640d3e5 | |||
| 6d45957eec | |||
| dabe3a03e7 | |||
| 2082d3747a | |||
| f73b579ad9 | |||
| 809f98843b | |||
| 76bf378077 | |||
| 04226caf63 | |||
| d9efd08bfd | |||
| 1d7402e0cd | |||
| 9a4c50035c | |||
| 475f25c787 | |||
| 37bb350883 | |||
| 00e1094178 | |||
| 2b3becf666 | |||
| 8baf82532c | |||
| 1c75d33adb | |||
| fa6218cf73 | |||
| 5b216bd0b2 | |||
| f6cc9d87d5 | |||
| 8e31b66f06 | |||
| ccf96a4d69 | |||
| 3118e39de8 | |||
| 71ba977dad | |||
| c411014c24 | |||
| cb0549a609 | |||
| d079044592 | |||
| c0590e614a | |||
| 7cf37856c0 | |||
| 5be4bfd55e | |||
| 2628be60d1 | |||
| 1c50a86661 | |||
| 7325b97c76 | |||
| 91a074c744 | |||
| 50637d4451 | |||
| a7005bd742 | |||
| ea902e5829 | |||
| e4a58375cc | |||
| 32d3e29c65 | |||
| a3e0475998 | |||
| 26cee61b98 | |||
| 56bb331760 | |||
| 1e3cdaf8a9 | |||
| 1d6536fa71 | |||
| e15cee62f4 | |||
| 6de138c2f2 | |||
| 4cdeacc277 | |||
| 9988fa141c | |||
| 8afa8d8588 | |||
| 6dfdb10e31 | |||
| 6be4e3a9fc | |||
| 04a527d4ec | |||
| de4ed136ea | |||
| 4a1a2dfed4 | |||
| 3fc9dd82f3 | |||
| 551f600073 | |||
| f9998d582a |
+1
-2
@@ -18,5 +18,4 @@ build/
|
||||
*.ipr
|
||||
*.iws
|
||||
.gradle/
|
||||
atlassian-ide-plugin.xml
|
||||
/samples
|
||||
atlassian-ide-plugin.xml
|
||||
+13
-1
@@ -6,6 +6,18 @@ _Please refer back to this document as a checklist before issuing any pull reque
|
||||
|
||||
Each Spring module is slightly different than another in terms of team size, number of issues, etc. Therefore each project is managed slightly different. You will notice that this document is very similar to the [Spring Framework Contributor guidelines](https://github.com/SpringSource/spring-framework/wiki/Contributor-guidelines). However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
|
||||
|
||||
# Importing into IDE
|
||||
|
||||
The following provides information on setting up a development environment that can run the sample in [Spring Tool Suite 3.6.0+](http://www.springsource.org/sts). Other IDE's should work using Gradle's IDE support, but have not been tested.
|
||||
|
||||
* IDE Setup
|
||||
* Install Spring Tool Suite 3.6.0+
|
||||
* You will need the following plugins installed (can be found on the Extensions Page)
|
||||
* Gradle Eclipse
|
||||
* Groovy Eclipse
|
||||
* Importing the project into Spring Tool Suite
|
||||
* File->Import...->Gradle Project
|
||||
|
||||
# Understand the basics
|
||||
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent [help documentation first](https://help.github.com/articles/using-pull-requests).
|
||||
|
||||
@@ -16,7 +28,7 @@ Is there already an issue that addresses your concern? Do a bit of searching in
|
||||
If you're considering anything more than correcting a typo or fixing a minor bug , please discuss it on the [Spring Security forums](http://forum.springsource.org/forumdisplay.php?33-Security) before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
|
||||
|
||||
# Sign the Contributor License Agreement
|
||||
If you have not previously done so, please fill out and submit the SpringSource CLA form. You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
|
||||
If you have not previously done so, please fill out and submit the [SpringSource CLA form](https://support.springsource.com/spring_committer_signup). You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
|
||||
|
||||
* For **Project** select _Spring Security_
|
||||
* For **Project Lead** enter _Rob Winch_
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
|
||||
+30
-31
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<name>spring-security-acl</name>
|
||||
<description>spring-security-acl</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -31,21 +30,10 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
@@ -58,25 +46,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -88,39 +76,39 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<version>2.9.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.29</version>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -132,7 +120,7 @@
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<version>2.3.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -144,26 +132,37 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.5</version>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
+12
-1
@@ -87,7 +87,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
// Check if authorized by virtue of ACL ownership
|
||||
Sid currentUser = new PrincipalSid(authentication);
|
||||
Sid currentUser = createCurrentUser(authentication);
|
||||
|
||||
if (currentUser.equals(acl.getOwner())
|
||||
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
|
||||
@@ -123,6 +123,17 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
"Principal does not have required ACL permissions to perform requested operation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a principal-like sid from the authentication information.
|
||||
*
|
||||
* @param authentication the authentication information that can provide principal and thus the sid's id will be
|
||||
* dependant on the value inside
|
||||
* @return a sid with the ID taken from the authentication information
|
||||
*/
|
||||
protected Sid createCurrentUser(Authentication authentication) {
|
||||
return new PrincipalSid(authentication);
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
|
||||
@@ -73,16 +73,6 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor, which should be used by persistence tools that do not
|
||||
* provide field-level access features.
|
||||
|
||||
@@ -46,15 +46,6 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
|
||||
//~ 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");
|
||||
|
||||
@@ -74,7 +74,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public final class BasicLookupStrategy implements LookupStrategy {
|
||||
public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
public final static String DEFAULT_SELECT_CLAUSE = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, "
|
||||
@@ -131,15 +131,20 @@ 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param dataSource to access the database
|
||||
* @param aclCache the cache where fully-loaded elements can be stored
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
* @param grantingStrategy the PermissionGrantingStrategy
|
||||
*/
|
||||
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
@@ -256,7 +261,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
*/
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
||||
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
|
||||
@@ -428,17 +433,33 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a particular implementation of {@link Sid} depending on the arguments.
|
||||
*
|
||||
* @param sid the name of the sid representing its unique identifier. In typical ACL database schema it's
|
||||
* located in table {@code acl_sid} table, {@code sid} column.
|
||||
* @param isPrincipal whether it's a user or granted authority like role
|
||||
* @return the instance of Sid with the {@code sidName} as an identifier
|
||||
*/
|
||||
protected Sid createSid(boolean isPrincipal, String sid) {
|
||||
if (isPrincipal) {
|
||||
return new PrincipalSid(sid);
|
||||
} else {
|
||||
return new GrantedAuthoritySid(sid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
|
||||
* data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
|
||||
*
|
||||
* @param permissionFactory
|
||||
*/
|
||||
public void setPermissionFactory(PermissionFactory permissionFactory) {
|
||||
public final void setPermissionFactory(PermissionFactory permissionFactory) {
|
||||
this.permissionFactory = permissionFactory;
|
||||
}
|
||||
|
||||
public void setBatchSize(int batchSize) {
|
||||
public final void setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
@@ -448,28 +469,28 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
*
|
||||
* @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
|
||||
*/
|
||||
public void setSelectClause(String selectClause) {
|
||||
public final void setSelectClause(String selectClause) {
|
||||
this.selectClause = selectClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
|
||||
*/
|
||||
public void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
|
||||
public final void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
|
||||
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
|
||||
*/
|
||||
public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
|
||||
public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
|
||||
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL for the "order by" clause used in both queries.
|
||||
*/
|
||||
public void setOrderByClause(String orderByClause) {
|
||||
public final void setOrderByClause(String orderByClause) {
|
||||
this.orderByClause = orderByClause;
|
||||
}
|
||||
|
||||
@@ -556,13 +577,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
Sid owner;
|
||||
|
||||
if (rs.getBoolean("acl_principal")) {
|
||||
owner = new PrincipalSid(rs.getString("acl_sid"));
|
||||
} else {
|
||||
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
|
||||
}
|
||||
Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));
|
||||
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
|
||||
entriesInheriting, owner);
|
||||
@@ -574,13 +589,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
// It is permissible to have no ACEs in an ACL (which is detected by a null ACE_SID)
|
||||
if (rs.getString("ace_sid") != null) {
|
||||
Long aceId = new Long(rs.getLong("ace_id"));
|
||||
Sid recipient;
|
||||
|
||||
if (rs.getBoolean("ace_principal")) {
|
||||
recipient = new PrincipalSid(rs.getString("ace_sid"));
|
||||
} else {
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
|
||||
}
|
||||
Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));
|
||||
|
||||
int mask = rs.getInt("mask");
|
||||
Permission permission = permissionFactory.buildFromMask(mask);
|
||||
|
||||
@@ -209,6 +209,19 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
throw new IllegalArgumentException("Unsupported implementation of Sid");
|
||||
}
|
||||
|
||||
return createOrRetrieveSidPrimaryKey(sidName, sidIsPrincipal, allowCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
|
||||
* true.
|
||||
* @param sidName name of Sid to find or to create
|
||||
* @param sidIsPrincipal whether it's a user or granted authority like role
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
* @return the primary key or null if not found
|
||||
*/
|
||||
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
|
||||
|
||||
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
|
||||
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
-- drop table acl_class;
|
||||
-- drop table acl_sid;
|
||||
|
||||
|
||||
create table acl_sid(
|
||||
id bigint generated by default as identity(start with 100) not null primary key,
|
||||
principal boolean not null,
|
||||
sid varchar_ignorecase(100) not null,
|
||||
constraint unique_uk_1 unique(sid,principal));
|
||||
constraint unique_uk_1 unique(sid,principal)
|
||||
);
|
||||
|
||||
create table acl_class(
|
||||
id bigint generated by default as identity(start with 100) not null primary key,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
-- ACL Schema SQL for MySQL 5.5+ / MariaDB equivalent
|
||||
|
||||
-- drop table acl_entry;
|
||||
-- drop table acl_object_identity;
|
||||
-- drop table acl_class;
|
||||
-- drop table acl_sid;
|
||||
|
||||
CREATE TABLE acl_sid (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
principal BOOLEAN NOT NULL,
|
||||
sid VARCHAR(100) NOT NULL,
|
||||
UNIQUE KEY unique_acl_sid (sid, principal)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE acl_class (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
class VARCHAR(100) NOT NULL,
|
||||
UNIQUE KEY uk_acl_class (class)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE acl_object_identity (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
object_id_class BIGINT UNSIGNED NOT NULL,
|
||||
object_id_identity BIGINT NOT NULL,
|
||||
parent_object BIGINT UNSIGNED,
|
||||
owner_sid BIGINT UNSIGNED,
|
||||
entries_inheriting BOOLEAN NOT NULL,
|
||||
UNIQUE KEY uk_acl_object_identity (object_id_class, object_id_identity),
|
||||
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
|
||||
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
|
||||
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE acl_entry (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
acl_object_identity BIGINT UNSIGNED NOT NULL,
|
||||
ace_order INTEGER NOT NULL,
|
||||
sid BIGINT UNSIGNED NOT NULL,
|
||||
mask INTEGER UNSIGNED NOT NULL,
|
||||
granting BOOLEAN NOT NULL,
|
||||
audit_success BOOLEAN NOT NULL,
|
||||
audit_failure BOOLEAN NOT NULL,
|
||||
UNIQUE KEY unique_acl_entry (acl_object_identity, ace_order),
|
||||
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
|
||||
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
|
||||
) ENGINE=InnoDB;
|
||||
@@ -0,0 +1,82 @@
|
||||
-- ACL Schema SQL for Oracle Database 10g+
|
||||
|
||||
-- drop trigger acl_sid_id_trigger;
|
||||
-- drop trigger acl_class_id_trigger;
|
||||
-- drop trigger acl_object_identity_id_trigger;
|
||||
-- drop trigger acl_entry_id_trigger;
|
||||
-- drop sequence acl_sid_sequence;
|
||||
-- drop sequence acl_class_sequence;
|
||||
-- drop sequence acl_object_identity_sequence;
|
||||
-- drop sequence acl_entry_sequence;
|
||||
-- drop table acl_entry;
|
||||
-- drop table acl_object_identity;
|
||||
-- drop table acl_class;
|
||||
-- drop table acl_sid;
|
||||
|
||||
CREATE TABLE acl_sid (
|
||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
||||
principal NUMBER(1) NOT NULL CHECK (principal in (0, 1)),
|
||||
sid NVARCHAR2(100) NOT NULL,
|
||||
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
|
||||
);
|
||||
CREATE SEQUENCE acl_sid_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
||||
CREATE OR REPLACE TRIGGER acl_sid_id_trigger
|
||||
BEFORE INSERT ON acl_sid
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SELECT acl_sid_sequence.nextval INTO :new.id FROM dual;
|
||||
END;
|
||||
|
||||
CREATE TABLE acl_class (
|
||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
||||
class NVARCHAR2(100) NOT NULL,
|
||||
CONSTRAINT uk_acl_class UNIQUE (class)
|
||||
);
|
||||
CREATE SEQUENCE acl_class_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
||||
CREATE OR REPLACE TRIGGER acl_class_id_trigger
|
||||
BEFORE INSERT ON acl_class
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SELECT acl_class_sequence.nextval INTO :new.id FROM dual;
|
||||
END;
|
||||
|
||||
CREATE TABLE acl_object_identity (
|
||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
||||
object_id_class NUMBER(38) NOT NULL,
|
||||
object_id_identity NUMBER(38) NOT NULL,
|
||||
parent_object NUMBER(38),
|
||||
owner_sid NUMBER(38),
|
||||
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
|
||||
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
|
||||
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
|
||||
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
|
||||
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
|
||||
);
|
||||
CREATE SEQUENCE acl_object_identity_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
||||
CREATE OR REPLACE TRIGGER acl_object_identity_id_trigger
|
||||
BEFORE INSERT ON acl_object_identity
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SELECT acl_object_identity_sequence.nextval INTO :new.id FROM dual;
|
||||
END;
|
||||
|
||||
CREATE TABLE acl_entry (
|
||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
||||
acl_object_identity NUMBER(38) NOT NULL,
|
||||
ace_order INTEGER NOT NULL,
|
||||
sid NUMBER(38) NOT NULL,
|
||||
mask INTEGER NOT NULL,
|
||||
granting NUMBER(1) NOT NULL CHECK (granting in (0, 1)),
|
||||
audit_success NUMBER(1) NOT NULL CHECK (audit_success in (0, 1)),
|
||||
audit_failure NUMBER(1) NOT NULL CHECK (audit_failure in (0, 1)),
|
||||
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
|
||||
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
|
||||
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
|
||||
);
|
||||
CREATE SEQUENCE acl_entry_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
||||
CREATE OR REPLACE TRIGGER acl_entry_id_trigger
|
||||
BEFORE INSERT ON acl_entry
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SELECT acl_entry_sequence.nextval INTO :new.id FROM dual;
|
||||
END;
|
||||
@@ -0,0 +1,46 @@
|
||||
-- ACL Schema SQL for Microsoft SQL Server 2008+
|
||||
|
||||
-- drop table acl_entry;
|
||||
-- drop table acl_object_identity;
|
||||
-- drop table acl_class;
|
||||
-- drop table acl_sid;
|
||||
|
||||
CREATE TABLE acl_sid (
|
||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
||||
principal BIT NOT NULL,
|
||||
sid VARCHAR(100) NOT NULL,
|
||||
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
|
||||
);
|
||||
|
||||
CREATE TABLE acl_class (
|
||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
||||
class VARCHAR(100) NOT NULL,
|
||||
CONSTRAINT uk_acl_class UNIQUE (class)
|
||||
);
|
||||
|
||||
CREATE TABLE acl_object_identity (
|
||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
||||
object_id_class BIGINT NOT NULL,
|
||||
object_id_identity BIGINT NOT NULL,
|
||||
parent_object BIGINT,
|
||||
owner_sid BIGINT,
|
||||
entries_inheriting BIT NOT NULL,
|
||||
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
|
||||
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
|
||||
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
|
||||
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
|
||||
);
|
||||
|
||||
CREATE TABLE acl_entry (
|
||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
||||
acl_object_identity BIGINT NOT NULL,
|
||||
ace_order INTEGER NOT NULL,
|
||||
sid BIGINT NOT NULL,
|
||||
mask INTEGER NOT NULL,
|
||||
granting BIT NOT NULL,
|
||||
audit_success BIT NOT NULL,
|
||||
audit_failure BIT NOT NULL,
|
||||
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
|
||||
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
|
||||
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
|
||||
);
|
||||
@@ -77,7 +77,7 @@ public class AclImplTests {
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullAclAuthzStrategy() throws Exception {
|
||||
try {
|
||||
new AclImpl(objectIdentity, 1, null, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
new AclImpl(objectIdentity, 1, null, new DefaultPermissionGrantingStrategy(mockAuditLogger), null, null, true, new PrincipalSid("joe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
+1
-2
@@ -223,7 +223,6 @@ public class AclImplementationSecurityCheckTests {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testSecurityCheckPrincipalOwner() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_ONE");
|
||||
@@ -235,7 +234,7 @@ public class AclImplementationSecurityCheckTests {
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
new SimpleGrantedAuthority("ROLE_GENERAL"));
|
||||
|
||||
Acl acl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
|
||||
Acl acl = new AclImpl(identity, 1, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), null, null,
|
||||
false, new PrincipalSid(auth));
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
|
||||
+18
-10
@@ -9,15 +9,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
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;
|
||||
import org.springframework.security.acls.domain.*;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
@@ -92,7 +84,7 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
@Before
|
||||
public void initializeBeans() {
|
||||
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache());
|
||||
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache(), new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
|
||||
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy,
|
||||
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
|
||||
@@ -301,4 +293,20 @@ public class BasicLookupStrategyTests {
|
||||
strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePrincipalSid() {
|
||||
Sid result = strategy.createSid(true, "sid");
|
||||
|
||||
Assert.assertEquals(PrincipalSid.class, result.getClass());
|
||||
Assert.assertEquals("sid", ((PrincipalSid)result).getPrincipal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateGrantedAuthority() {
|
||||
Sid result = strategy.createSid(false, "sid");
|
||||
|
||||
Assert.assertEquals(GrantedAuthoritySid.class, result.getClass());
|
||||
Assert.assertEquals("sid", ((GrantedAuthoritySid)result).getGrantedAuthority());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+142
-132
@@ -1,24 +1,9 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import org.junit.*;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
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.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import static org.fest.assertions.Assertions.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -26,53 +11,78 @@ import java.io.FileOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.security.acls.domain.*;
|
||||
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.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link EhCacheBasedAclCache}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EhCacheBasedAclCacheTests {
|
||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
||||
|
||||
private static CacheManager cacheManager;
|
||||
@Mock
|
||||
private Ehcache cache;
|
||||
@Captor
|
||||
private ArgumentCaptor<Element> element;
|
||||
|
||||
@BeforeClass
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = CacheManager.create();
|
||||
// Use disk caching immediately (to test for serialization issue reported in SEC-527)
|
||||
cacheManager.addCache(new Cache("ehcachebasedacltests", 0, true, false, 600, 300));
|
||||
}
|
||||
private EhCacheBasedAclCache myCache;
|
||||
|
||||
@AfterClass
|
||||
public static void shutdownCacheManager() {
|
||||
cacheManager.removalAll();
|
||||
cacheManager.shutdown();
|
||||
private MutableAcl acl;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
myCache = new EhCacheBasedAclCache(cache, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
|
||||
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"));
|
||||
|
||||
acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearContext() {
|
||||
public void cleanup() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
private Ehcache getCache() {
|
||||
Ehcache cache = cacheManager.getCache("ehcachebasedacltests");
|
||||
cache.removeAll();
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorRejectsNullParameters() throws Exception {
|
||||
new EhCacheBasedAclCache(null);
|
||||
new EhCacheBasedAclCache(null, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodsRejectNullParameters() throws Exception {
|
||||
Ehcache cache = new MockEhcache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
try {
|
||||
Serializable id = null;
|
||||
myCache.evictFromCache(id);
|
||||
@@ -122,12 +132,6 @@ 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());
|
||||
|
||||
// Serialization test
|
||||
File file = File.createTempFile("SEC_TEST", ".object");
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
@@ -150,111 +154,117 @@ public class EhCacheBasedAclCacheTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheOperationsAclWithoutParent() throws Exception {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
public void clearCache() throws Exception {
|
||||
myCache.clearCache();
|
||||
|
||||
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());
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
myCache.putInCache(acl);
|
||||
assertEquals(cache.getSize(), 2);
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
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(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());
|
||||
|
||||
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)));
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
myCache.evictFromCache(Long.valueOf(1));
|
||||
assertEquals(cache.getSize(), 2);
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
|
||||
// Check the second object inserted
|
||||
assertEquals(myCache.getFromCache(Long.valueOf(2)), acl2);
|
||||
assertEquals(myCache.getFromCache(identity2), acl2);
|
||||
|
||||
myCache.evictFromCache(identity2);
|
||||
assertEquals(cache.getSize(), 0);
|
||||
verify(cache).removeAll();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void cacheOperationsAclWithParent() throws Exception {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
public void putInCache() throws Exception {
|
||||
myCache.putInCache(acl);
|
||||
|
||||
verify(cache, times(2)).put(element.capture());
|
||||
assertThat(element.getValue().getKey()).isEqualTo(acl.getId());
|
||||
assertThat(element.getValue().getObjectValue()).isEqualTo(acl);
|
||||
assertThat(element.getAllValues().get(0).getKey()).isEqualTo(acl.getObjectIdentity());
|
||||
assertThat(element.getAllValues().get(0).getObjectValue()).isEqualTo(acl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putInCacheAclWithParent() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "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());
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
myCache.putInCache(acl);
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
assertTrue(cache.isElementOnDisk(Long.valueOf(1)));
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
assertFalse(cache.isElementInMemory(Long.valueOf(1)));
|
||||
cache.flush();
|
||||
// Wait for the spool to be written to disk (it's asynchronous)
|
||||
Map spool = (Map) FieldUtils.getFieldValue(cache, "diskStore.spool");
|
||||
|
||||
while(spool.size() > 0) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
verify(cache, times(4)).put(element.capture());
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(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"));
|
||||
assertEquals(acl, myCache.getFromCache(identity));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache, "aclAuthorizationStrategy"));
|
||||
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(2));
|
||||
assertEquals(parentAcl, parentAclFromCache);
|
||||
assertNotNull(FieldUtils.getFieldValue(parentAclFromCache, "aclAuthorizationStrategy"));
|
||||
assertEquals(parentAcl, myCache.getFromCache(identityParent));
|
||||
List<Element> allValues = element.getAllValues();
|
||||
|
||||
assertThat(allValues.get(0).getKey()).isEqualTo(parentAcl.getObjectIdentity());
|
||||
assertThat(allValues.get(0).getObjectValue()).isEqualTo(parentAcl);
|
||||
|
||||
assertThat(allValues.get(1).getKey()).isEqualTo(parentAcl.getId());
|
||||
assertThat(allValues.get(1).getObjectValue()).isEqualTo(parentAcl);
|
||||
|
||||
|
||||
assertThat(allValues.get(2).getKey()).isEqualTo(acl.getObjectIdentity());
|
||||
assertThat(allValues.get(2).getObjectValue()).isEqualTo(acl);
|
||||
|
||||
assertThat(allValues.get(3).getKey()).isEqualTo(acl.getId());
|
||||
assertThat(allValues.get(3).getObjectValue()).isEqualTo(acl);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
@Test
|
||||
public void getFromCacheSerializable() throws Exception {
|
||||
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
|
||||
|
||||
private class MockEhcache extends Cache {
|
||||
public MockEhcache() {
|
||||
super("cache", 0, true, true, 0, 0);
|
||||
}
|
||||
assertThat(myCache.getFromCache(acl.getId())).isEqualTo(acl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromCacheSerializablePopulatesTransient() throws Exception {
|
||||
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
|
||||
|
||||
myCache.putInCache(acl);
|
||||
|
||||
ReflectionTestUtils.setField(acl, "permissionGrantingStrategy", null);
|
||||
ReflectionTestUtils.setField(acl, "aclAuthorizationStrategy", null);
|
||||
|
||||
MutableAcl fromCache = myCache.getFromCache(acl.getId());
|
||||
|
||||
assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromCacheObjectIdentity() throws Exception {
|
||||
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
|
||||
|
||||
assertThat(myCache.getFromCache(acl.getId())).isEqualTo(acl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromCacheObjectIdentityPopulatesTransient() throws Exception {
|
||||
when(cache.get(acl.getObjectIdentity())).thenReturn(new Element(acl.getId(),acl));
|
||||
|
||||
myCache.putInCache(acl);
|
||||
|
||||
ReflectionTestUtils.setField(acl, "permissionGrantingStrategy", null);
|
||||
ReflectionTestUtils.setField(acl, "aclAuthorizationStrategy", null);
|
||||
|
||||
MutableAcl fromCache = myCache.getFromCache(acl.getObjectIdentity());
|
||||
|
||||
assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evictCacheSerializable() throws Exception {
|
||||
when(cache.get(acl.getObjectIdentity())).thenReturn(new Element(acl.getId(),acl));
|
||||
|
||||
myCache.evictFromCache(acl.getObjectIdentity());
|
||||
|
||||
verify(cache).remove(acl.getId());
|
||||
verify(cache).remove(acl.getObjectIdentity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evictCacheObjectIdentity() throws Exception {
|
||||
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
|
||||
|
||||
myCache.evictFromCache(acl.getId());
|
||||
|
||||
verify(cache).remove(acl.getId());
|
||||
verify(cache).remove(acl.getObjectIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
+40
-1
@@ -15,6 +15,7 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -43,6 +44,7 @@ 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.acls.sid.CustomSid;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -489,6 +491,43 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
|
||||
assertTrue(topParent.isGranted(Arrays.asList(cm), Arrays.asList(benSid), true));
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testProcessingCustomSid() {
|
||||
CustomJdbcMutableAclService customJdbcMutableAclService = spy(new CustomJdbcMutableAclService(dataSource,
|
||||
lookupStrategy, aclCache));
|
||||
CustomSid customSid = new CustomSid("Custom sid");
|
||||
when(customJdbcMutableAclService.createOrRetrieveSidPrimaryKey("Custom sid", false, false)).thenReturn(1L);
|
||||
|
||||
Long result = customJdbcMutableAclService.createOrRetrieveSidPrimaryKey(customSid, false);
|
||||
|
||||
assertEquals(result, new Long(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* This class needed to show how to extend {@link JdbcMutableAclService} for processing
|
||||
* custom {@link Sid} implementations
|
||||
*/
|
||||
private class CustomJdbcMutableAclService extends JdbcMutableAclService {
|
||||
|
||||
private CustomJdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
|
||||
super(dataSource, lookupStrategy, aclCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
String sidName;
|
||||
boolean isPrincipal = false;
|
||||
if (sid instanceof CustomSid) {
|
||||
sidName = ((CustomSid)sid).getSid();
|
||||
} else if (sid instanceof GrantedAuthoritySid) {
|
||||
sidName = ((GrantedAuthoritySid)sid).getGrantedAuthority();
|
||||
} else {
|
||||
sidName = ((PrincipalSid)sid).getPrincipal();
|
||||
isPrincipal = true;
|
||||
}
|
||||
return createOrRetrieveSidPrimaryKey(sidName, isPrincipal, allowCreate);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
|
||||
/**
|
||||
* This class is example of custom {@link Sid} implementation
|
||||
* @author Mikhail Stryzhonok
|
||||
*/
|
||||
public class CustomSid implements Sid {
|
||||
|
||||
private String sid;
|
||||
|
||||
public CustomSid(String sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
public String getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public void setSid(String sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,25 @@
|
||||
<property name="cacheName" value="aclCache"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_USER"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
Implementation-Title: org.springframework.security.acls
|
||||
Implementation-Version: ${version}
|
||||
Bundle-SymbolicName: org.springframework.security.acls
|
||||
Bundle-Name: Spring Security Acls
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-Version: ${version}
|
||||
Bundle-ManifestVersion: 2
|
||||
Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
org.aopalliance.*;version="${aopAllianceRange}",
|
||||
org.apache.commons.logging.*;version="${cloggingRange}",
|
||||
org.springframework.cache.*;version="${springRange}";resolution:=optional,
|
||||
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
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion"
|
||||
|
||||
|
||||
+26
-27
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<name>spring-security-aspects</name>
|
||||
<description>spring-security-aspects</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -31,46 +30,35 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -82,14 +70,14 @@
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.10</version>
|
||||
<version>1.8.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -102,13 +90,13 @@
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.29</version>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -126,20 +114,31 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.5</version>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
+1
-2
@@ -53,10 +53,9 @@ public class AnnotationSecurityAspectTests {
|
||||
public final void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
interceptor = new AspectJMethodSecurityInterceptor();
|
||||
adm = new AffirmativeBased();
|
||||
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
|
||||
{new RoleVoter(), new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
|
||||
adm.setDecisionVoters(Arrays.asList(voters));
|
||||
adm = new AffirmativeBased(Arrays.<AccessDecisionVoter<? extends Object>>asList(voters));
|
||||
interceptor.setAccessDecisionManager(adm);
|
||||
interceptor.setAuthenticationManager(authman);
|
||||
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
Implementation-Title: org.springframework.security.aspects
|
||||
Implementation-Version: ${version}
|
||||
Bundle-SymbolicName: org.springframework.security.aspects
|
||||
Bundle-Name: Spring Security Aspects
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Version: ${version}
|
||||
Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
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}"
|
||||
+15
-43
@@ -2,15 +2,15 @@ import groovy.text.SimpleTemplateEngine
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "http://repo.springsource.org/plugins-release" }
|
||||
maven { url "https://repo.spring.io/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.5")
|
||||
classpath("org.springframework.build.gradle:bundlor-plugin:0.1.2")
|
||||
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:0.9.8")
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath("org.springframework.build.gradle:spring-io-plugin:0.0.3.RELEASE")
|
||||
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:1.2.5")
|
||||
classpath('me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1')
|
||||
classpath('org.asciidoctor:asciidoctor-gradle-plugin:0.7.0')
|
||||
classpath('org.asciidoctor:asciidoctor-java-integration:0.1.4.preview.1')
|
||||
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.1')
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,8 @@ allprojects {
|
||||
|
||||
ext.releaseBuild = version.endsWith('RELEASE')
|
||||
ext.snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
ext.springVersion = '3.2.8.RELEASE'
|
||||
ext.spring4Version = '4.0.2.RELEASE'
|
||||
ext.springLdapVersion = '1.3.2.RELEASE'
|
||||
ext.springLdap2Version = '2.0.1.RELEASE'
|
||||
ext.springVersion = '4.1.3.RELEASE'
|
||||
ext.springLdapVersion = '2.0.2.RELEASE'
|
||||
|
||||
group = 'org.springframework.security'
|
||||
|
||||
@@ -39,7 +37,7 @@ allprojects {
|
||||
maven { url "http://repo.terracotta.org/maven2/" }
|
||||
}
|
||||
|
||||
eclipse.project.name = "${project.name}-3.2.x"
|
||||
eclipse.project.name = "${project.name}-4.0.x"
|
||||
}
|
||||
|
||||
sonarRunner {
|
||||
@@ -61,7 +59,7 @@ ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && pr
|
||||
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-xml')]
|
||||
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj-xml'), project(':spring-security-samples-aspectj-jc')]
|
||||
|
||||
configure(allprojects - javaProjects) {
|
||||
task afterEclipseImport {
|
||||
@@ -98,35 +96,17 @@ configure(javaProjects) {
|
||||
}
|
||||
|
||||
configure(coreModuleProjects) {
|
||||
apply plugin: 'bundlor'
|
||||
apply plugin: 'emma'
|
||||
apply plugin: 'spring-io'
|
||||
|
||||
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : '1.1.0.BUILD-SNAPSHOT'
|
||||
|
||||
bundlor.doFirst {
|
||||
def templateText = file("template.mf").text
|
||||
bundlor.manifestTemplate = new SimpleTemplateEngine().createTemplate(templateText).make(bundlorProperties).toString()
|
||||
}
|
||||
configurations {
|
||||
jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo
|
||||
spring4TestRuntime.extendsFrom testRuntime
|
||||
}
|
||||
configurations.spring4TestRuntime {
|
||||
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
|
||||
if (details.requested.group == 'org.springframework') {
|
||||
details.useVersion spring4Version
|
||||
}
|
||||
if (details.requested.name == 'ehcache') {
|
||||
details.useVersion '2.6.5'
|
||||
}
|
||||
if (details.requested.name == 'ehcache-terracotta') {
|
||||
details.useVersion '2.1.1'
|
||||
}
|
||||
if (details.requested.group == 'org.springframework.ldap') {
|
||||
details.useVersion springLdap2Version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
springIoVersions "io.spring.platform:platform-versions:${springIoVersion}@properties"
|
||||
jacoco "org.jacoco:org.jacoco.agent:0.6.2.201302030002:runtime"
|
||||
}
|
||||
test {
|
||||
@@ -135,14 +115,6 @@ configure(coreModuleProjects) {
|
||||
integrationTest {
|
||||
jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=${project.group}.*"
|
||||
}
|
||||
task spring4Test(type: Test) {
|
||||
jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=128M']
|
||||
exclude "**/EhCacheBasedAclCacheTests.class", "**/Issue55Tests.class"
|
||||
classpath = sourceSets.test.output + sourceSets.main.output + configurations.spring4TestRuntime
|
||||
testResultsDir = file("$buildDir/spring4-test-results/")
|
||||
testReportDir = file("$buildDir/reports/spring4-tests/")
|
||||
}
|
||||
check.dependsOn spring4Test
|
||||
}
|
||||
|
||||
configure (aspectjProjects) {
|
||||
@@ -194,5 +166,5 @@ artifacts {
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '1.10-rc-2'
|
||||
gradleVersion = '1.12'
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class AspectJPlugin implements Plugin<Project> {
|
||||
}
|
||||
|
||||
if (project.configurations.findByName('ajtools') == null) {
|
||||
project.configurations.add('ajtools')
|
||||
project.configurations.create('ajtools')
|
||||
project.dependencies {
|
||||
ajtools "org.aspectj:aspectjtools:${project.aspectjVersion}"
|
||||
optional "org.aspectj:aspectjrt:${project.aspectjVersion}"
|
||||
@@ -38,10 +38,10 @@ class AspectJPlugin implements Plugin<Project> {
|
||||
}
|
||||
|
||||
if (project.configurations.findByName('aspectpath') == null) {
|
||||
project.configurations.add('aspectpath')
|
||||
project.configurations.create('aspectpath')
|
||||
}
|
||||
|
||||
project.tasks.add(name: 'compileAspect', overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
|
||||
project.tasks.create(name: 'compileAspect', overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
|
||||
dependsOn project.configurations*.getTaskDependencyFromProjectDependency(true, "compileJava")
|
||||
|
||||
dependsOn project.processResources
|
||||
@@ -54,7 +54,7 @@ class AspectJPlugin implements Plugin<Project> {
|
||||
project.tasks.compileJava.dependsOn project.tasks.compileAspect
|
||||
|
||||
|
||||
project.tasks.add(name: 'compileTestAspect', overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
|
||||
project.tasks.create(name: 'compileTestAspect', overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
|
||||
dependsOn project.processTestResources, project.compileJava, project.jar
|
||||
sourceSet = project.sourceSets.test
|
||||
inputs.files(sourceSet.allSource)
|
||||
|
||||
@@ -21,7 +21,7 @@ class EmmaPlugin implements Plugin<Project> {
|
||||
def emmaCoverageFile = "${rootProject.buildDir}/emma/emma.ec"
|
||||
|
||||
if (project.configurations.findByName('emma_rt') == null) {
|
||||
project.configurations.add('emma_rt')
|
||||
project.configurations.create('emma_rt')
|
||||
project.dependencies {
|
||||
emma_rt 'emma:emma:2.0.5312'
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class EmmaPlugin implements Plugin<Project> {
|
||||
CoverageReport task;
|
||||
|
||||
if (reportTasks.isEmpty()) {
|
||||
task = rootProject.tasks.add('coverageReport', CoverageReport.class);
|
||||
task = rootProject.tasks.create('coverageReport', CoverageReport.class);
|
||||
task.dataPath = [emmaMetaDataFile, emmaCoverageFile];
|
||||
} else {
|
||||
task = reportTasks[0];
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.gradle.api.file.FileCollection
|
||||
*/
|
||||
class TrangPlugin implements Plugin<Project> {
|
||||
public void apply(Project project) {
|
||||
Task rncToXsd = project.tasks.add('rncToXsd', RncToXsd.class)
|
||||
Task rncToXsd = project.tasks.create('rncToXsd', RncToXsd.class)
|
||||
rncToXsd.description = 'Converts .rnc to .xsd'
|
||||
rncToXsd.group = 'Build'
|
||||
}
|
||||
|
||||
+3
-2
@@ -2,12 +2,13 @@
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
project(':spring-security-web'),
|
||||
springCoreDependency,
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.jasig.cas.client:cas-client-core:3.2.1"
|
||||
"org.jasig.cas.client:cas-client-core:$casClientVersion"
|
||||
|
||||
optional "net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||
|
||||
provided "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion"
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
}
|
||||
|
||||
+31
-32
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<name>spring-security-cas</name>
|
||||
<description>spring-security-cas</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -31,58 +30,47 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<version>3.3.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -94,39 +82,39 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<version>2.9.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
<version>7.0.33</version>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.29</version>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -144,14 +132,25 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.5</version>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -49,9 +49,7 @@ public class ServiceProperties implements InitializingBean {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if(!authenticateAllArtifacts) {
|
||||
Assert.hasLength(this.service, "service must be specified unless authenticateAllArtifacts is true.");
|
||||
}
|
||||
Assert.hasLength(this.service, "service cannot be empty.");
|
||||
Assert.hasLength(this.artifactParameter, "artifactParameter cannot be empty.");
|
||||
Assert.hasLength(this.serviceParameter, "serviceParameter cannot be empty.");
|
||||
}
|
||||
@@ -62,7 +60,7 @@ public class ServiceProperties implements InitializingBean {
|
||||
* This service is the callback URL belonging to the local Spring Security System for Spring secured application.
|
||||
* For example,
|
||||
* <pre>
|
||||
* https://www.mycompany.com/application/j_spring_cas_security_check
|
||||
* https://www.mycompany.com/application/login/cas
|
||||
* </pre>
|
||||
*
|
||||
* @return the URL of the service the user is authenticating to
|
||||
|
||||
+2
-2
@@ -185,15 +185,15 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
return this.authenticationUserDetailsService.loadUserDetails(token);
|
||||
}
|
||||
|
||||
@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.
|
||||
* Sets the UserDetailsService to use. This is a convenience method to invoke
|
||||
*/
|
||||
public void setUserDetailsService(final UserDetailsService userDetailsService) {
|
||||
this.authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService);
|
||||
}
|
||||
|
||||
|
||||
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService) {
|
||||
this.authenticationUserDetailsService = authenticationUserDetailsService;
|
||||
}
|
||||
|
||||
-6
@@ -55,9 +55,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
|
||||
* disable the session encoding is provided for backwards compatibility.
|
||||
*
|
||||
* By default, encoding is enabled.
|
||||
* @deprecated since 3.0.0 because CAS is currently on 3.3.5.
|
||||
*/
|
||||
@Deprecated
|
||||
private boolean encodeServiceUrlWithSessionId = true;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -135,9 +133,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
|
||||
* Sets whether to encode the service url with the session id or not.
|
||||
*
|
||||
* @param encodeServiceUrlWithSessionId whether to encode the service url with the session id or not.
|
||||
* @deprecated since 3.0.0 because CAS is currently on 3.3.5.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void setEncodeServiceUrlWithSessionId(final boolean encodeServiceUrlWithSessionId) {
|
||||
this.encodeServiceUrlWithSessionId = encodeServiceUrlWithSessionId;
|
||||
}
|
||||
@@ -146,9 +142,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
|
||||
* Sets whether to encode the service url with the session id or not.
|
||||
* @return whether to encode the service url with the session id or not.
|
||||
*
|
||||
* @deprecated since 3.0.0 because CAS is currently on 3.3.5.
|
||||
*/
|
||||
@Deprecated
|
||||
protected boolean getEncodeServiceUrlWithSessionId() {
|
||||
return this.encodeServiceUrlWithSessionId;
|
||||
}
|
||||
|
||||
+11
-11
@@ -38,6 +38,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -49,7 +51,7 @@ import org.springframework.util.Assert;
|
||||
* presented in the <code>ticket</code> request parameter.
|
||||
* <p>
|
||||
* This filter monitors the <code>service</code> URL so it can
|
||||
* receive the service ticket and process it. By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
|
||||
* receive the service ticket and process it. By default this filter processes the URL <tt>/login/cas</tt>.
|
||||
* When processing this URL, the value of {@link ServiceProperties#getService()} is used as the <tt>service</tt> when validating
|
||||
* the <code>ticket</code>. This means that it is important that {@link ServiceProperties#getService()} specifies the same value
|
||||
* as the <tt>filterProcessesUrl</tt>.
|
||||
@@ -90,7 +92,7 @@ import org.springframework.util.Assert;
|
||||
* <pre>
|
||||
* <b:bean id="serviceProperties"
|
||||
* class="org.springframework.security.cas.ServiceProperties"
|
||||
* p:service="https://service.example.com/cas-sample/j_spring_cas_security_check"
|
||||
* p:service="https://service.example.com/cas-sample/login/cas"
|
||||
* p:authenticateAllArtifacts="true"/>
|
||||
* <b:bean id="casEntryPoint"
|
||||
* class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"
|
||||
@@ -100,7 +102,7 @@ import org.springframework.util.Assert;
|
||||
* p:authenticationManager-ref="authManager"
|
||||
* p:serviceProperties-ref="serviceProperties"
|
||||
* p:proxyGrantingTicketStorage-ref="pgtStorage"
|
||||
* p:proxyReceptorUrl="/j_spring_cas_security_proxyreceptor">
|
||||
* p:proxyReceptorUrl="/login/cas/proxyreceptor">
|
||||
* <b:property name="authenticationDetailsSource">
|
||||
* <b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
|
||||
* </b:property>
|
||||
@@ -127,7 +129,7 @@ import org.springframework.util.Assert;
|
||||
* <b:bean
|
||||
* class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"
|
||||
* p:acceptAnyProxy="true"
|
||||
* p:proxyCallbackUrl="https://service.example.com/cas-sample/j_spring_cas_security_proxyreceptor"
|
||||
* p:proxyCallbackUrl="https://service.example.com/cas-sample/login/cas/proxyreceptor"
|
||||
* p:proxyGrantingTicketStorage-ref="pgtStorage">
|
||||
* <b:constructor-arg value="https://login.example.org/cas" />
|
||||
* </b:bean>
|
||||
@@ -170,7 +172,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
/**
|
||||
* The last portion of the receptor url, i.e. /proxy/receptor
|
||||
*/
|
||||
private String proxyReceptorUrl;
|
||||
private RequestMatcher proxyReceptorMatcher;
|
||||
|
||||
/**
|
||||
* The backing storage to store ProxyGrantingTicket requests.
|
||||
@@ -186,7 +188,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public CasAuthenticationFilter() {
|
||||
super("/j_spring_cas_security_check");
|
||||
super("/login/cas");
|
||||
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
|
||||
}
|
||||
|
||||
@@ -254,7 +256,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
/**
|
||||
* Overridden to provide proxying capabilities.
|
||||
*/
|
||||
@Override
|
||||
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
final boolean serviceTicketRequest = serviceTicketRequest(request, response);
|
||||
final boolean result = serviceTicketRequest || proxyReceptorRequest(request) || (proxyTicketRequest(serviceTicketRequest, request));
|
||||
@@ -286,7 +287,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
}
|
||||
|
||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||
this.proxyReceptorUrl = proxyReceptorUrl;
|
||||
this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl);
|
||||
}
|
||||
|
||||
public final void setProxyGrantingTicketStorage(
|
||||
@@ -343,8 +344,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
* @return
|
||||
*/
|
||||
private boolean proxyReceptorRequest(final HttpServletRequest request) {
|
||||
final String requestUri = request.getRequestURI();
|
||||
final boolean result = proxyReceptorConfigured() && requestUri.endsWith(this.proxyReceptorUrl);
|
||||
final boolean result = proxyReceptorConfigured() && proxyReceptorMatcher.matches(request);
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("proxyReceptorRequest = "+result);
|
||||
}
|
||||
@@ -357,7 +357,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
* @return
|
||||
*/
|
||||
private boolean proxyReceptorConfigured() {
|
||||
final boolean result = this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl);
|
||||
final boolean result = this.proxyGrantingTicketStorage != null && proxyReceptorMatcher != null;
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("proxyReceptorConfigured = "+result);
|
||||
}
|
||||
|
||||
+23
-6
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -50,11 +52,13 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
* string from containing the artifact name and value. This can
|
||||
* be created using {@link #createArtifactPattern(String)}.
|
||||
*/
|
||||
DefaultServiceAuthenticationDetails(HttpServletRequest request, Pattern artifactPattern) {
|
||||
DefaultServiceAuthenticationDetails(String casService, HttpServletRequest request, Pattern artifactPattern) throws MalformedURLException {
|
||||
super(request);
|
||||
URL casServiceUrl = new URL(casService);
|
||||
int port = getServicePort(casServiceUrl);
|
||||
final String query = getQueryString(request,artifactPattern);
|
||||
this.serviceUrl = UrlUtils.buildFullRequestUrl(request.getScheme(),
|
||||
request.getServerName(), request.getServerPort(),
|
||||
this.serviceUrl = UrlUtils.buildFullRequestUrl(casServiceUrl.getProtocol(),
|
||||
casServiceUrl.getHost(), port,
|
||||
request.getRequestURI(), query);
|
||||
}
|
||||
|
||||
@@ -128,4 +132,17 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
Assert.hasLength(artifactParameterName);
|
||||
return Pattern.compile("&?"+Pattern.quote(artifactParameterName)+"=[^&]*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the port from the casServiceURL ensuring to return the proper value if the default port is being used.
|
||||
* @param casServiceUrl the casServerUrl to be used (i.e. "https://example.com/context/login/cas")
|
||||
* @return the port that is configured for the casServerUrl
|
||||
*/
|
||||
private static int getServicePort(URL casServiceUrl) {
|
||||
int port = casServiceUrl.getPort();
|
||||
if(port == -1) {
|
||||
port = casServiceUrl.getDefaultPort();
|
||||
}
|
||||
return port;
|
||||
}
|
||||
}
|
||||
+21
-8
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
@@ -15,12 +15,14 @@
|
||||
*/
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The {@code AuthenticationDetailsSource} that is set on the
|
||||
@@ -38,24 +40,31 @@ public class ServiceAuthenticationDetailsSource implements AuthenticationDetails
|
||||
|
||||
private final Pattern artifactPattern;
|
||||
|
||||
private ServiceProperties serviceProperties;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Creates an implementation that uses the default CAS artifactParameterName.
|
||||
* Creates an implementation that uses the specified ServiceProperites and the default CAS artifactParameterName.
|
||||
*
|
||||
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
|
||||
*/
|
||||
public ServiceAuthenticationDetailsSource() {
|
||||
this(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
|
||||
public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties) {
|
||||
this(serviceProperties,ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an implementation that uses the specified artifactParameterName
|
||||
*
|
||||
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
|
||||
* @param artifactParameterName
|
||||
* the artifactParameterName that is removed from the current
|
||||
* URL. The result becomes the service url. Cannot be null and
|
||||
* cannot be an empty String.
|
||||
*/
|
||||
public ServiceAuthenticationDetailsSource(final String artifactParameterName) {
|
||||
public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties, String artifactParameterName) {
|
||||
Assert.notNull(serviceProperties, "serviceProperties cannot be null");
|
||||
this.serviceProperties = serviceProperties;
|
||||
this.artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(artifactParameterName);
|
||||
}
|
||||
|
||||
@@ -66,6 +75,10 @@ public class ServiceAuthenticationDetailsSource implements AuthenticationDetails
|
||||
* @return the {@code ServiceAuthenticationDetails} containing information about the current request
|
||||
*/
|
||||
public ServiceAuthenticationDetails buildDetails(HttpServletRequest context) {
|
||||
return new DefaultServiceAuthenticationDetails(context,artifactPattern);
|
||||
try {
|
||||
return new DefaultServiceAuthenticationDetails(serviceProperties.getService(),context,artifactPattern);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ public abstract class AbstractStatelessTicketCacheTests {
|
||||
|
||||
protected CasAuthenticationToken getToken() {
|
||||
List<String> proxyList = new ArrayList<String>();
|
||||
proxyList.add("https://localhost/newPortal/j_spring_cas_security_check");
|
||||
proxyList.add("https://localhost/newPortal/login/cas");
|
||||
|
||||
User user = new User("rod", "password", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
|
||||
final Assertion assertion = new AssertionImpl("rod");
|
||||
|
||||
+4
-4
@@ -69,7 +69,7 @@ public class CasAuthenticationEntryPointTests extends TestCase {
|
||||
public void testNormalOperationWithRenewFalse() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.setSendRenew(false);
|
||||
sp.setService("https://mycompany.com/bigWebApp/j_spring_cas_security_check");
|
||||
sp.setService("https://mycompany.com/bigWebApp/login/cas");
|
||||
|
||||
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
|
||||
ep.setLoginUrl("https://cas/login");
|
||||
@@ -84,14 +84,14 @@ public class CasAuthenticationEntryPointTests extends TestCase {
|
||||
ep.commence(request, response, null);
|
||||
|
||||
assertEquals("https://cas/login?service="
|
||||
+ URLEncoder.encode("https://mycompany.com/bigWebApp/j_spring_cas_security_check", "UTF-8"),
|
||||
+ URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8"),
|
||||
response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
public void testNormalOperationWithRenewTrue() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.setSendRenew(true);
|
||||
sp.setService("https://mycompany.com/bigWebApp/j_spring_cas_security_check");
|
||||
sp.setService("https://mycompany.com/bigWebApp/login/cas");
|
||||
|
||||
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
|
||||
ep.setLoginUrl("https://cas/login");
|
||||
@@ -105,7 +105,7 @@ public class CasAuthenticationEntryPointTests extends TestCase {
|
||||
ep.afterPropertiesSet();
|
||||
ep.commence(request, response, null);
|
||||
assertEquals("https://cas/login?service="
|
||||
+ URLEncoder.encode("https://mycompany.com/bigWebApp/j_spring_cas_security_check", "UTF-8") + "&renew=true",
|
||||
+ URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8") + "&renew=true",
|
||||
response.getRedirectedUrl());
|
||||
}
|
||||
}
|
||||
|
||||
+18
-14
@@ -63,7 +63,6 @@ public class CasAuthenticationFilterTests {
|
||||
@Test
|
||||
public void testGettersSetters() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
assertEquals("/j_spring_cas_security_check", filter.getFilterProcessesUrl());
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl("/someurl");
|
||||
filter.setServiceProperties(new ServiceProperties());
|
||||
@@ -71,7 +70,8 @@ public class CasAuthenticationFilterTests {
|
||||
|
||||
@Test
|
||||
public void testNormalOperation() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/j_spring_cas_security_check");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/login/cas");
|
||||
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
|
||||
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
@@ -101,11 +101,13 @@ public class CasAuthenticationFilterTests {
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationFilterProcessUrl() {
|
||||
String url = "/login/cas";
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setFilterProcessesUrl(url);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI(filter.getFilterProcessesUrl());
|
||||
request.setServletPath(url);
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
}
|
||||
|
||||
@@ -115,13 +117,13 @@ public class CasAuthenticationFilterTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
request.setServletPath("/pgtCallback");
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
request.setRequestURI("/other");
|
||||
request.setServletPath("/other");
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
}
|
||||
|
||||
@@ -130,15 +132,17 @@ public class CasAuthenticationFilterTests {
|
||||
ServiceProperties properties = new ServiceProperties();
|
||||
properties.setAuthenticateAllArtifacts(true);
|
||||
|
||||
String url = "/login/cas";
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
filter.setFilterProcessesUrl(url);
|
||||
filter.setServiceProperties(properties);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI(filter.getFilterProcessesUrl());
|
||||
request.setServletPath(url);
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
|
||||
request.setRequestURI("/other");
|
||||
request.setServletPath("/other");
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
request.setParameter(properties.getArtifactParameter(), "value");
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
@@ -156,9 +160,9 @@ public class CasAuthenticationFilterTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
request.setServletPath("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
assertNull(filter.attemptAuthentication(request, response));
|
||||
}
|
||||
|
||||
@@ -172,7 +176,7 @@ public class CasAuthenticationFilterTests {
|
||||
serviceProperties.setAuthenticateAllArtifacts(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setParameter("ticket", "ST-1-123");
|
||||
request.setRequestURI("/authenticate");
|
||||
request.setServletPath("/authenticate");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
|
||||
@@ -189,7 +193,7 @@ public class CasAuthenticationFilterTests {
|
||||
verifyZeroInteractions(successHandler);
|
||||
|
||||
// validate for when the filterProcessUrl matches
|
||||
filter.setFilterProcessesUrl(request.getRequestURI());
|
||||
filter.setFilterProcessesUrl(request.getServletPath());
|
||||
SecurityContextHolder.clearContext();
|
||||
filter.doFilter(request,response,chain);
|
||||
verifyNoMoreInteractions(chain);
|
||||
@@ -204,9 +208,9 @@ public class CasAuthenticationFilterTests {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
request.setServletPath("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
filter.setProxyReceptorUrl(request.getServletPath());
|
||||
|
||||
filter.doFilter(request,response,chain);
|
||||
verifyZeroInteractions(chain);
|
||||
|
||||
@@ -36,10 +36,13 @@ public class ServicePropertiesTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowNullServiceWhenAuthenticateAllTokens() throws Exception {
|
||||
public void nullServiceWhenAuthenticateAllTokens() throws Exception {
|
||||
ServiceProperties sp = new ServiceProperties();
|
||||
sp.setAuthenticateAllArtifacts(true);
|
||||
sp.afterPropertiesSet();
|
||||
try {
|
||||
sp.afterPropertiesSet();
|
||||
fail("Expected Exception");
|
||||
}catch(IllegalArgumentException success) {}
|
||||
sp.setAuthenticateAllArtifacts(false);
|
||||
try {
|
||||
sp.afterPropertiesSet();
|
||||
|
||||
+55
-12
@@ -18,11 +18,21 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,9 +42,13 @@ public class DefaultServiceAuthenticationDetailsTests {
|
||||
private DefaultServiceAuthenticationDetails details;
|
||||
private MockHttpServletRequest request;
|
||||
private Pattern artifactPattern;
|
||||
private String casServiceUrl;
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
casServiceUrl = "https://localhost:8443/j_spring_security_cas";
|
||||
request = new MockHttpServletRequest();
|
||||
request.setScheme("https");
|
||||
request.setServerName("localhost");
|
||||
@@ -44,45 +58,74 @@ public class DefaultServiceAuthenticationDetailsTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlNullQuery() throws Exception {
|
||||
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
|
||||
assertEquals(UrlUtils.buildFullRequestUrl(request),details.getServiceUrl());
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketOnlyParam() {
|
||||
public void getServiceUrlNullQuery() throws Exception {
|
||||
details = new DefaultServiceAuthenticationDetails(casServiceUrl, request,artifactPattern);
|
||||
assertEquals(UrlUtils.buildFullRequestUrl(request), details.getServiceUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketOnlyParam() throws Exception {
|
||||
request.setQueryString("ticket=123");
|
||||
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
|
||||
details = new DefaultServiceAuthenticationDetails(casServiceUrl,request,artifactPattern);
|
||||
String serviceUrl = details.getServiceUrl();
|
||||
request.setQueryString(null);
|
||||
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketFirstMultiParam() {
|
||||
public void getServiceUrlTicketFirstMultiParam() throws Exception {
|
||||
request.setQueryString("ticket=123&other=value");
|
||||
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
|
||||
details = new DefaultServiceAuthenticationDetails(casServiceUrl, request,artifactPattern);
|
||||
String serviceUrl = details.getServiceUrl();
|
||||
request.setQueryString("other=value");
|
||||
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketLastMultiParam() {
|
||||
public void getServiceUrlTicketLastMultiParam() throws Exception {
|
||||
request.setQueryString("other=value&ticket=123");
|
||||
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
|
||||
details = new DefaultServiceAuthenticationDetails(casServiceUrl,request,artifactPattern);
|
||||
String serviceUrl = details.getServiceUrl();
|
||||
request.setQueryString("other=value");
|
||||
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlTicketMiddleMultiParam() {
|
||||
public void getServiceUrlTicketMiddleMultiParam() throws Exception {
|
||||
request.setQueryString("other=value&ticket=123&last=this");
|
||||
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
|
||||
details = new DefaultServiceAuthenticationDetails(casServiceUrl,request,artifactPattern);
|
||||
String serviceUrl = details.getServiceUrl();
|
||||
request.setQueryString("other=value&last=this");
|
||||
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlDoesNotUseHostHeader() throws Exception {
|
||||
casServiceUrl = "https://example.com/j_spring_security_cas";
|
||||
request.setServerName("evil.com");
|
||||
details = new DefaultServiceAuthenticationDetails(casServiceUrl, request,artifactPattern);
|
||||
assertEquals("https://example.com/cas-sample/secure/",details.getServiceUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServiceUrlDoesNotUseHostHeaderExplicit() {
|
||||
casServiceUrl = "https://example.com/j_spring_security_cas";
|
||||
request.setServerName("evil.com");
|
||||
ServiceAuthenticationDetails details = loadServiceAuthenticationDetails("defaultserviceauthenticationdetails-explicit.xml");
|
||||
assertEquals("https://example.com/cas-sample/secure/", details.getServiceUrl());
|
||||
}
|
||||
|
||||
private ServiceAuthenticationDetails loadServiceAuthenticationDetails(String resourceName) {
|
||||
context = new GenericXmlApplicationContext(getClass(), resourceName);
|
||||
ServiceAuthenticationDetailsSource source = context.getBean(ServiceAuthenticationDetailsSource.class);
|
||||
return source.buildDetails(request);
|
||||
}
|
||||
}
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
<bean id="serviceProperties2"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example2.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
|
||||
<constructor-arg ref="serviceProperties"/>
|
||||
</bean>
|
||||
</beans>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
|
||||
</beans>
|
||||
@@ -1,23 +0,0 @@
|
||||
Implementation-Title: org.springframework.security.cas
|
||||
Implementation-Version: ${version}
|
||||
Bundle-SymbolicName: org.springframework.security.cas
|
||||
Bundle-Name: Spring Security CAS
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-Version: ${version}
|
||||
Bundle-ManifestVersion: 2
|
||||
Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
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.cache.*;version="${springRange}";resolution:=optional,
|
||||
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"
|
||||
+15
-10
@@ -10,6 +10,7 @@ compileTestJava.dependsOn(':spring-security-core:compileTestJava')
|
||||
dependencies {
|
||||
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
@@ -18,26 +19,27 @@ dependencies {
|
||||
optional project(':spring-security-web'),
|
||||
project(':spring-security-ldap'),
|
||||
project(':spring-security-openid'),
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
project(':spring-security-messaging'),
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-websocket:$springVersion",
|
||||
"org.springframework:spring-webmvc:$springVersion",
|
||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion"
|
||||
|
||||
provided "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion"
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
|
||||
testCompile project(':spring-security-cas'),
|
||||
project(':spring-security-core').sourceSets.test.output,
|
||||
project(':spring-security-aspects'),
|
||||
'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-orm:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.spockframework:spock-core:$spockVersion",
|
||||
"org.spockframework:spock-spring:$spockVersion",
|
||||
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
|
||||
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final",
|
||||
"org.eclipse.persistence:javax.persistence:2.0.5",
|
||||
"org.hibernate:hibernate-entitymanager:4.1.0.Final",
|
||||
"org.codehaus.groovy:groovy-all:$groovyVersion",
|
||||
"org.apache.directory.server:apacheds-core:$apacheDsVersion",
|
||||
@@ -48,16 +50,19 @@ dependencies {
|
||||
'org.apache.directory.shared:shared-ldap:0.9.15',
|
||||
'ldapsdk:ldapsdk:4.1',
|
||||
powerMockDependencies,
|
||||
"org.springframework.data:spring-data-jpa:1.2.0.RELEASE",
|
||||
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.0.Final",
|
||||
"org.hibernate:hibernate-entitymanager:3.6.10.Final",
|
||||
"org.hsqldb:hsqldb:2.2.8"
|
||||
"org.hsqldb:hsqldb:$hsqlVersion",
|
||||
spockDependencies
|
||||
|
||||
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
}
|
||||
testCompile("org.springframework.data:spring-data-jpa:$springDataJpaVersion") {
|
||||
exclude group: 'org.aspectj', module: 'aspectjrt'
|
||||
}
|
||||
|
||||
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
|
||||
"cglib:cglib-nodep:2.2"
|
||||
"cglib:cglib-nodep:$cglibVersion"
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
+97
-66
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<name>spring-security-config</name>
|
||||
<description>spring-security-config</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -31,21 +30,10 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<id>spring-milestone</id>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
@@ -58,31 +46,31 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -94,82 +82,96 @@
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.6.10</version>
|
||||
<version>1.8.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-messaging</artifactId>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-openid</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
<version>7.0.33</version>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>2.2</version>
|
||||
<version>3.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.29</version>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -181,7 +183,7 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -229,7 +231,7 @@
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<version>2.0.5</version>
|
||||
<version>2.3.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -239,15 +241,9 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<version>1.0.0.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<version>1.0.1.Final</version>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>javax.persistence</artifactId>
|
||||
<version>2.0.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -265,13 +261,7 @@
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.2.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<version>2.3.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -295,43 +285,49 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-support</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-core</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4-common</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-reflect</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.5</version>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -339,48 +335,83 @@
|
||||
<artifactId>spock-core</artifactId>
|
||||
<version>0.7-groovy-2.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<version>0.7-groovy-2.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-jpa</artifactId>
|
||||
<version>1.2.0.RELEASE</version>
|
||||
<version>1.7.1.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<groupId>org.aspectj</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
<version>1.3.2.RELEASE</version>
|
||||
<version>2.0.2.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>3.2.1.CI-SNAPSHOT</version>
|
||||
<version>4.0.0.RC1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
+62
-6
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.authentication.ldap
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory
|
||||
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
@@ -27,7 +29,13 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication
|
||||
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor
|
||||
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessorTests
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
@@ -57,6 +65,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +83,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupRoleAttribute("group")
|
||||
}
|
||||
}
|
||||
@@ -92,6 +102,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupSearchFilter("ou=groupName");
|
||||
}
|
||||
}
|
||||
@@ -110,6 +121,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.rolePrefix("role_")
|
||||
}
|
||||
}
|
||||
@@ -120,7 +132,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("admin","password")).authorities.collect { it.authority }.sort() == ["ROLE_ADMIN","ROLE_USER"]
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -130,6 +142,29 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2472: Can use crypto PasswordEncoder"() {
|
||||
setup:
|
||||
loadConfig(PasswordEncoderConfig)
|
||||
when:
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class PasswordEncoderConfig extends BaseLdapServerConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.passwordEncoder(new BCryptPasswordEncoder())
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
@@ -142,23 +177,44 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
||||
@Bean
|
||||
public ApacheDSContainer ldapServer() throws Exception {
|
||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/users.ldif");
|
||||
apacheDSContainer.setPort(33389);
|
||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
apacheDSContainer.setPort(getPort());
|
||||
return apacheDSContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalAuthentication
|
||||
@Import(ObjectPostProcessorConfiguration)
|
||||
static abstract class BaseLdapProviderConfig {
|
||||
|
||||
@Bean
|
||||
public BaseLdapPathContextSource contextSource() throws Exception {
|
||||
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:33389/dc=springframework,dc=org")
|
||||
"ldap://127.0.0.1:"+ getPort() + "/dc=springframework,dc=org")
|
||||
contextSource.userDn = "uid=admin,ou=system"
|
||||
contextSource.password = "secret"
|
||||
contextSource.afterPropertiesSet();
|
||||
contextSource.afterPropertiesSet()
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) {
|
||||
configure(auth)
|
||||
auth.build()
|
||||
}
|
||||
|
||||
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception
|
||||
}
|
||||
|
||||
static Integer port;
|
||||
|
||||
static int getPort() {
|
||||
if(port == null) {
|
||||
ServerSocket socket = new ServerSocket(0)
|
||||
port = socket.localPort
|
||||
socket.close()
|
||||
}
|
||||
port
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.annotation.authentication.ldap
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.LdapAuthenticationProviderConfig
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider
|
||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator
|
||||
import org.springframework.security.ldap.userdetails.PersonContextMapper
|
||||
import org.springframework.test.util.ReflectionTestUtils
|
||||
|
||||
import static org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.*
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
class LdapAuthenticationProviderConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "authentication-manager support multiple default ldap contexts (ports dynamically allocated)"() {
|
||||
when:
|
||||
loadConfig(MultiLdapAuthenticationProvidersConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.and()
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -40,7 +40,7 @@ class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
|
||||
when:
|
||||
loadConfig(LdapAuthenticationProviderConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER']
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
|
||||
def "ldap-authentication-provider custom"() {
|
||||
@@ -75,6 +75,6 @@ class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authenticator instanceof PasswordComparisonAuthenticator
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER']
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
}
|
||||
+32
-4
@@ -1,7 +1,13 @@
|
||||
package org.springframework.security.config.ldap
|
||||
|
||||
|
||||
import static org.mockito.Mockito.*
|
||||
|
||||
import java.text.MessageFormat
|
||||
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.security.config.AbstractXmlConfigTests
|
||||
import org.springframework.security.config.BeanIds
|
||||
import org.springframework.security.util.FieldUtils
|
||||
@@ -36,7 +42,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
|
||||
|
||||
|
||||
def simpleProviderAuthenticatesCorrectly() {
|
||||
xml.'ldap-server'()
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('group-search-filter':'member={0}')
|
||||
}
|
||||
@@ -66,7 +72,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
|
||||
}
|
||||
|
||||
def supportsPasswordComparisonAuthentication() {
|
||||
xml.'ldap-server'()
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people')
|
||||
'password-compare'
|
||||
@@ -83,7 +89,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
|
||||
}
|
||||
|
||||
def supportsPasswordComparisonAuthenticationWithHashAttribute() {
|
||||
xml.'ldap-server'()
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'('password-attribute': 'uid', hash: 'plaintext')
|
||||
@@ -102,7 +108,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
|
||||
}
|
||||
|
||||
def supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
|
||||
xml.'ldap-server'()
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'('password-attribute': 'uid') {
|
||||
@@ -122,6 +128,28 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
|
||||
notThrown(AuthenticationException)
|
||||
}
|
||||
|
||||
def 'SEC-2472: Supports Crypto PasswordEncoder'() {
|
||||
setup:
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'() {
|
||||
'password-encoder'(ref: 'pe')
|
||||
}
|
||||
}
|
||||
}
|
||||
xml.'b:bean'(id:'pe','class':BCryptPasswordEncoder.class.name)
|
||||
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", 'password'))
|
||||
|
||||
then:
|
||||
auth != null
|
||||
}
|
||||
|
||||
def inetOrgContextMapperIsSupported() {
|
||||
xml.'ldap-server'(url: 'ldap://127.0.0.1:343/dc=springframework,dc=org')
|
||||
xml.'authentication-manager'{
|
||||
|
||||
+1
-6
@@ -28,8 +28,6 @@ import org.springframework.security.ldap.userdetails.PersonContextMapper;
|
||||
*
|
||||
*/
|
||||
public class NamespaceLdapAuthenticationProviderTestsConfigs {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class LdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
@@ -40,7 +38,6 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class CustomLdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
@@ -56,7 +53,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
|
||||
.userSearchFilter("(uid={0})") // ldap-authentication-provider@user-search-filter
|
||||
// .contextSource(contextSource) // ldap-authentication-provider@server-ref
|
||||
.contextSource()
|
||||
.ldif("classpath:user.ldif") // ldap-server@ldif
|
||||
.ldif("classpath:users.xldif") // ldap-server@ldif
|
||||
.managerDn("uid=admin,ou=system") // ldap-server@manager-dn
|
||||
.managerPassword("secret") // ldap-server@manager-password
|
||||
.port(33399) // ldap-server@port
|
||||
@@ -66,7 +63,6 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class CustomAuthoritiesPopulatorConfig extends WebSecurityConfigurerAdapter {
|
||||
static LdapAuthoritiesPopulator LAP;
|
||||
@@ -78,7 +74,6 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class PasswordCompareLdapConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
|
||||
@@ -28,6 +28,16 @@ sn: Alex
|
||||
uid: ben
|
||||
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
|
||||
|
||||
dn: uid=bcrypt,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: BCrypt user
|
||||
sn: BCrypt
|
||||
uid: bcrypt
|
||||
userPassword: $2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u
|
||||
|
||||
dn: uid=bob,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
@@ -58,11 +68,22 @@ sn: Mouse
|
||||
uid: jerry
|
||||
userPassword: jerryspassword
|
||||
|
||||
dn: uid=bcrypt,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: BCrypt user
|
||||
sn: BCrypt
|
||||
uid: bcrypt
|
||||
userPassword: $2a$10$lDa0YFNHAt63MjIzK/wUqeM0qjIhzPhp3RNI/MLUQEAUbzhB/SnnS
|
||||
|
||||
dn: cn=developers,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: developers
|
||||
ou: developer
|
||||
member: uid=bcrypt,ou=people,dc=springframework,dc=org
|
||||
member: uid=ben,ou=people,dc=springframework,dc=org
|
||||
member: uid=bob,ou=people,dc=springframework,dc=org
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
dn: ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: people
|
||||
|
||||
dn: uid=admin,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Rod Johnson
|
||||
sn: Johnson
|
||||
uid: admin
|
||||
userPassword: password
|
||||
|
||||
dn: uid=user,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Dianne Emu
|
||||
sn: Emu
|
||||
uid: user
|
||||
userPassword: password
|
||||
|
||||
dn: cn=user,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: user
|
||||
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
|
||||
uniqueMember: uid=user,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=admin,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: admin
|
||||
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
|
||||
@@ -0,0 +1,92 @@
|
||||
dn: ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: ou=subgroups,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: subgroups
|
||||
|
||||
dn: ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: people
|
||||
|
||||
dn: ou=otherpeople,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: otherpeople
|
||||
|
||||
dn: uid=ben,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Ben Alex
|
||||
sn: Alex
|
||||
uid: ben
|
||||
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
|
||||
|
||||
dn: uid=bcrypt,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: BCrypt user
|
||||
sn: BCrypt
|
||||
uid: bcrypt
|
||||
userPassword: $2a$10$lDa0YFNHAt63MjIzK/wUqeM0qjIhzPhp3RNI/MLUQEAUbzhB/SnnS
|
||||
|
||||
dn: uid=bob,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Bob Hamilton
|
||||
sn: Hamilton
|
||||
uid: bob
|
||||
userPassword: bobspassword
|
||||
|
||||
dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Joe Smeth
|
||||
sn: Smeth
|
||||
uid: joe
|
||||
userPassword: joespassword
|
||||
|
||||
dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Mouse, Jerry
|
||||
sn: Mouse
|
||||
uid: jerry
|
||||
userPassword: jerryspassword
|
||||
|
||||
dn: cn=developers,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: developers
|
||||
ou: developer
|
||||
member: uid=ben,ou=people,dc=springframework,dc=org
|
||||
member: uid=bob,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=managers,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: managers
|
||||
ou: manager
|
||||
member: uid=ben,ou=people,dc=springframework,dc=org
|
||||
member: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: submanagers
|
||||
ou: submanager
|
||||
member: uid=ben,ou=people,dc=springframework,dc=org
|
||||
@@ -49,11 +49,12 @@ public abstract class Elements {
|
||||
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";
|
||||
public static final String HEADERS = "headers";
|
||||
public static final String CSRF = "csrf";
|
||||
|
||||
public static final String MESSAGES = "messages";
|
||||
public static final String INTERCEPT_MESSAGE = "message-interceptor";
|
||||
}
|
||||
|
||||
+7
-2
@@ -38,6 +38,7 @@ import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser
|
||||
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
|
||||
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
||||
import org.springframework.security.config.message.MessageSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
||||
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
|
||||
@@ -56,6 +57,7 @@ import org.w3c.dom.Node;
|
||||
*/
|
||||
public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
private static final String FILTER_CHAIN_PROXY_CLASSNAME = "org.springframework.security.web.FilterChainProxy";
|
||||
private static final String MESSAGE_CLASSNAME = "org.springframework.messaging.Message";
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
|
||||
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
|
||||
@@ -171,11 +173,14 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
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());
|
||||
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||
parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
|
||||
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
|
||||
}
|
||||
|
||||
if(ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
|
||||
parsers.put(Elements.MESSAGES, new MessageSecurityBeanDefinitionParser());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +201,7 @@ 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\\.2.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-4\\.0.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
-2
@@ -29,8 +29,6 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
|
||||
import com.google.inject.internal.ImmutableList.Builder;
|
||||
|
||||
/**
|
||||
* <p>A base {@link SecurityBuilder} that allows {@link SecurityConfigurer} to be
|
||||
* applied to it. This makes modifying the {@link SecurityBuilder} a strategy
|
||||
|
||||
+21
-6
@@ -78,6 +78,9 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
|
||||
*/
|
||||
public AuthenticationManagerBuilder parentAuthenticationManager(
|
||||
AuthenticationManager authenticationManager) {
|
||||
if(authenticationManager instanceof ProviderManager) {
|
||||
eraseCredentials(((ProviderManager) authenticationManager).isEraseCredentialsAfterAuthentication());
|
||||
}
|
||||
this.parentAuthenticationManager = authenticationManager;
|
||||
return this;
|
||||
}
|
||||
@@ -135,19 +138,31 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
|
||||
|
||||
/**
|
||||
* Add JDBC authentication to the {@link AuthenticationManagerBuilder} and
|
||||
* return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
|
||||
* JDBC authentication.
|
||||
* return a {@link JdbcUserDetailsManagerConfigurer} to allow customization
|
||||
* of the JDBC authentication.
|
||||
*
|
||||
* <p>
|
||||
* When using with a persistent data store, it is best to add users external
|
||||
* of configuration using something like <a
|
||||
* href="http://flywaydb.org/">Flyway</a> or <a
|
||||
* href="http://www.liquibase.org/">Liquibase</a> to create the schema and
|
||||
* adding users to ensure these steps are only done once and that the
|
||||
* optimal SQL is used.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method also ensure that a {@link UserDetailsService} is available
|
||||
* for the {@link #getDefaultUserDetailsService()} method. Note that
|
||||
* additional {@link UserDetailsService}'s may override this
|
||||
* {@link UserDetailsService} as the default.
|
||||
* {@link UserDetailsService} as the default. See the <a href=
|
||||
* "http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#user-schema"
|
||||
* >User Schema</a> section of the reference for the default schema.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
|
||||
* JDBC authentication
|
||||
* @throws Exception if an error occurs when adding the JDBC authentication
|
||||
* @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization
|
||||
* of the JDBC authentication
|
||||
* @throws Exception
|
||||
* if an error occurs when adding the JDBC authentication
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()
|
||||
throws Exception {
|
||||
|
||||
+1
-2
@@ -113,8 +113,8 @@ public class AuthenticationConfiguration {
|
||||
lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
|
||||
lazyTargetSource.setBeanFactory(applicationContext);
|
||||
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
|
||||
proxyFactory = objectPostProcessor.postProcess(proxyFactory);
|
||||
proxyFactory.setTargetSource(lazyTargetSource);
|
||||
proxyFactory.setInterfaces(new Class[] { interfaceName });
|
||||
return (T) proxyFactory.getObject();
|
||||
}
|
||||
|
||||
@@ -122,7 +122,6 @@ public class AuthenticationConfiguration {
|
||||
return lazyBean(AuthenticationManager.class);
|
||||
}
|
||||
|
||||
|
||||
private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter {
|
||||
private final ApplicationContext context;
|
||||
private static final Log logger = LogFactory.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
@@ -88,4 +89,5 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
|
||||
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||
@Documented
|
||||
@Import(AuthenticationConfiguration.class)
|
||||
@Configuration
|
||||
public @interface EnableGlobalAuthentication {}
|
||||
|
||||
+56
-6
@@ -40,6 +40,10 @@ import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
|
||||
import org.springframework.security.ldap.userdetails.PersonContextMapper;
|
||||
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
/**
|
||||
* Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}.
|
||||
@@ -60,7 +64,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
private BaseLdapPathContextSource contextSource;
|
||||
private ContextSourceBuilder contextSourceBuilder = new ContextSourceBuilder();
|
||||
private UserDetailsContextMapper userDetailsContextMapper;
|
||||
private PasswordEncoder passwordEncoder;
|
||||
private Object passwordEncoder;
|
||||
private String passwordAttribute;
|
||||
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
|
||||
|
||||
@@ -149,7 +153,9 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
*/
|
||||
private PasswordComparisonAuthenticator createPasswordCompareAuthenticator(BaseLdapPathContextSource contextSource) {
|
||||
PasswordComparisonAuthenticator ldapAuthenticator = new PasswordComparisonAuthenticator(contextSource);
|
||||
ldapAuthenticator.setPasswordAttributeName(passwordAttribute);
|
||||
if(passwordAttribute != null) {
|
||||
ldapAuthenticator.setPasswordAttributeName(passwordAttribute);
|
||||
}
|
||||
ldapAuthenticator.setPasswordEncoder(passwordEncoder);
|
||||
return ldapAuthenticator;
|
||||
}
|
||||
@@ -204,12 +210,26 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
*
|
||||
* @param passwordEncoder the {@link PasswordEncoder} to use
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customization
|
||||
* @deprecated Use {@link #passwordEncoder(org.springframework.security.crypto.password.PasswordEncoder)} instead
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> passwordEncoder(PasswordEncoder passwordEncoder) {
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link org.springframework.security.crypto.password.PasswordEncoder} to be used when authenticating with
|
||||
* password comparison.
|
||||
*
|
||||
* @param passwordEncoder the {@link org.springframework.security.crypto.password.PasswordEncoder} to use
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customization
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> passwordEncoder(final org.springframework.security.crypto.password.PasswordEncoder passwordEncoder) {
|
||||
Assert.notNull(passwordEncoder, "passwordEncoder must not be null.");
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If your users are at a fixed location in the directory (i.e. you can work
|
||||
* out the DN directly from the username without doing a directory search),
|
||||
@@ -373,7 +393,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
private String ldif = "classpath*:*.ldif";
|
||||
private String managerPassword;
|
||||
private String managerDn;
|
||||
private int port = 33389;
|
||||
private Integer port;
|
||||
private static final int DEFAULT_PORT = 33389;
|
||||
private String root = "dc=springframework,dc=org";
|
||||
private String url;
|
||||
|
||||
@@ -418,7 +439,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
}
|
||||
|
||||
/**
|
||||
* The port to connect to LDAP to (the default is 33389).
|
||||
* The port to connect to LDAP to (the default is 33389 or random available port if unavailable).
|
||||
* @param port the port to connect to
|
||||
* @return the {@link ContextSourceBuilder} for further customization
|
||||
*/
|
||||
@@ -478,14 +499,43 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
return contextSource;
|
||||
}
|
||||
ApacheDSContainer apacheDsContainer = new ApacheDSContainer(root, ldif);
|
||||
apacheDsContainer.setPort(port);
|
||||
apacheDsContainer.setPort(getPort());
|
||||
postProcess(apacheDsContainer);
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
private int getPort() {
|
||||
if(port == null) {
|
||||
port = getDefaultPort();
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
private int getDefaultPort() {
|
||||
ServerSocket serverSocket = null;
|
||||
try {
|
||||
try {
|
||||
serverSocket = new ServerSocket(DEFAULT_PORT);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
serverSocket = new ServerSocket(0);
|
||||
} catch(IOException e2) {
|
||||
return DEFAULT_PORT;
|
||||
}
|
||||
}
|
||||
return serverSocket.getLocalPort();
|
||||
} finally {
|
||||
if(serverSocket != null) {
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getProviderUrl() {
|
||||
if(url == null) {
|
||||
return "ldap://127.0.0.1:" + port + "/" + root;
|
||||
return "ldap://127.0.0.1:" + getPort() + "/" + root;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
+1
@@ -62,6 +62,7 @@ final class AutowireBeanFactoryObjectPostProcessor implements ObjectPostProcesso
|
||||
Class<?> type = object.getClass();
|
||||
throw new RuntimeException("Could not postProcess " + object + " of type " + type, e);
|
||||
}
|
||||
autowireBeanFactory.autowireBean(object);
|
||||
if(result instanceof DisposableBean) {
|
||||
disposableBeans.add((DisposableBean) result);
|
||||
}
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
@@ -46,6 +47,7 @@ import org.springframework.security.config.annotation.configuration.ObjectPostPr
|
||||
@Documented
|
||||
@Import({GlobalMethodSecuritySelector.class,ObjectPostProcessorConfiguration.class})
|
||||
@EnableGlobalAuthentication
|
||||
@Configuration
|
||||
public @interface EnableGlobalMethodSecurity {
|
||||
|
||||
/**
|
||||
|
||||
+9
-10
@@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.method.configuration;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
@@ -50,18 +52,15 @@ class GlobalMethodSecurityAspectJAutoProxyRegistrar implements
|
||||
AnnotationMetadata importingClassMetadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
|
||||
AopConfigUtils
|
||||
.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
|
||||
BeanDefinition interceptor = registry.getBeanDefinition("methodSecurityInterceptor");
|
||||
|
||||
Map<String, Object> annotationAttributes = importingClassMetadata
|
||||
.getAnnotationAttributes(EnableGlobalMethodSecurity.class
|
||||
.getName());
|
||||
AnnotationAttributes enableAJAutoProxy = AnnotationAttributes
|
||||
.fromMap(annotationAttributes);
|
||||
BeanDefinitionBuilder aspect =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
|
||||
aspect.setFactoryMethod("aspectOf");
|
||||
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
aspect.addPropertyValue("securityInterceptor", interceptor);
|
||||
|
||||
if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
}
|
||||
registry.registerBeanDefinition("annotationSecurityAspect$0", aspect.getBeanDefinition());
|
||||
}
|
||||
|
||||
}
|
||||
+8
-6
@@ -24,10 +24,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -48,6 +45,7 @@ import org.springframework.security.access.intercept.AfterInvocationProviderMana
|
||||
import org.springframework.security.access.intercept.RunAsManager;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.method.MethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
||||
@@ -111,7 +109,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
*/
|
||||
@Bean
|
||||
public MethodInterceptor methodSecurityInterceptor() throws Exception {
|
||||
MethodSecurityInterceptor methodSecurityInterceptor = new MethodSecurityInterceptor();
|
||||
MethodSecurityInterceptor methodSecurityInterceptor = isAspectJ() ? new AspectJMethodSecurityInterceptor() : new MethodSecurityInterceptor();
|
||||
methodSecurityInterceptor
|
||||
.setAccessDecisionManager(accessDecisionManager());
|
||||
methodSecurityInterceptor
|
||||
@@ -175,7 +173,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected AccessDecisionManager accessDecisionManager() {
|
||||
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
|
||||
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends Object>>();
|
||||
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
|
||||
expressionAdvice.setExpressionHandler(getExpressionHandler());
|
||||
if(prePostEnabled()) {
|
||||
@@ -379,6 +377,10 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
return (Integer) enableMethodSecurity().get("order");
|
||||
}
|
||||
|
||||
private boolean isAspectJ() {
|
||||
return enableMethodSecurity().getEnum("mode") == AdviceMode.ASPECTJ;
|
||||
}
|
||||
|
||||
private AnnotationAttributes enableMethodSecurity() {
|
||||
if (enableMethodSecurity == null) {
|
||||
// if it is null look at this instance (i.e. a subclass was used)
|
||||
|
||||
+1
-5
@@ -41,10 +41,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
/**
|
||||
* Maps any request.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
|
||||
* from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C anyRequest() {
|
||||
@@ -181,7 +177,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
/**
|
||||
* Create a {@link List} of {@link RegexRequestMatcher} instances that do not specify an {@link HttpMethod}.
|
||||
*
|
||||
* @param regexPatterns the regular expressions to create {@link RegexRequestMatcher} from
|
||||
* @param regexPatterns the regular expressions to create {@link RegexRequestMatcher} from
|
||||
*
|
||||
* @return a {@link List} of {@link RegexRequestMatcher} instances
|
||||
*/
|
||||
|
||||
+3
-3
@@ -948,8 +948,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* .antMatchers("/**").hasRole("USER")
|
||||
* .and()
|
||||
* .formLogin()
|
||||
* .usernameParameter("j_username") // default is username
|
||||
* .passwordParameter("j_password") // default is password
|
||||
* .usernameParameter("username") // default is username
|
||||
* .passwordParameter("password") // default is password
|
||||
* .loginPage("/authentication/login") // default is /login with an HTTP get
|
||||
* .failureUrl("/authentication/login?failed") // default is /login?error
|
||||
* .loginProcessingUrl("/authentication/login/process"); // default is /login with an HTTP post
|
||||
@@ -1000,7 +1000,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* .and()
|
||||
* .formLogin()
|
||||
* .and()
|
||||
* .channelSecurity()
|
||||
* .requiresChannel()
|
||||
* .anyRequest().requiresSecure();
|
||||
* }
|
||||
*
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 4.0
|
||||
*/
|
||||
@Conditional(OnMissingBeanCondition.class)
|
||||
@interface ConditionalOnMissingBean {
|
||||
|
||||
Class<?> value();
|
||||
}
|
||||
+3
-1
@@ -19,6 +19,7 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
@@ -77,8 +78,9 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||
@Documented
|
||||
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class})
|
||||
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class, SpringWebMvcImportSelector.class})
|
||||
@EnableGlobalAuthentication
|
||||
@Configuration
|
||||
public @interface EnableWebSecurity {
|
||||
|
||||
/**
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.annotation.web.configuration;
|
||||
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.ConfigurationCondition;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class OnMissingBeanCondition implements ConfigurationCondition {
|
||||
@Override
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.REGISTER_BEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
Map<String,Object> attrs = metadata.getAnnotationAttributes(ConditionalOnMissingBean.class.getName());
|
||||
|
||||
Class<?> type = (Class) attrs.get("value");
|
||||
final Map<String, ?> beans = context.getBeanFactory().getBeansOfType(type);
|
||||
return beans.isEmpty();
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.annotation.web.configuration;
|
||||
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Used by {@link EnableWebSecurity} to conditionaly import
|
||||
* {@link WebMvcSecurityConfiguration} when the DispatcherServlet is present on the
|
||||
* classpath.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
class SpringWebMvcImportSelector implements ImportSelector {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.annotation.ImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
|
||||
*/
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
boolean webmvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", getClass().getClassLoader());
|
||||
return webmvcPresent ? new String[] {"org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration"} : new String[] {};
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.annotation.web.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
|
||||
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used to add a {@link RequestDataValueProcessor} for Spring MVC and Spring
|
||||
* Security CSRF integration. This configuration is added whenever
|
||||
* {@link EnableWebMvc} is added by {@link SpringWebMvcImportSelector} and the
|
||||
* DispatcherServlet is present on the classpath. It also adds the
|
||||
* {@link AuthenticationPrincipalArgumentResolver} as a
|
||||
* {@link HandlerMethodArgumentResolver}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void addArgumentResolvers(
|
||||
List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
|
||||
argumentResolvers.add(new org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver());
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(RequestDataValueProcessor.class)
|
||||
@Bean
|
||||
public RequestDataValueProcessor requestDataValueProcessor() {
|
||||
return new CsrfRequestDataValueProcessor();
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -38,8 +38,10 @@ import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.context.DelegatingApplicationListener;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
@@ -72,6 +74,14 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ObjectPostProcessor<Object> objectObjectPostProcessor;
|
||||
|
||||
@Bean
|
||||
public static DelegatingApplicationListener delegatingApplicationListener() {
|
||||
return new DelegatingApplicationListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
|
||||
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
|
||||
@@ -87,7 +97,8 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
public Filter springSecurityFilterChain() throws Exception {
|
||||
boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty();
|
||||
if(!hasConfigurers) {
|
||||
throw new IllegalStateException("At least one non-null instance of "+ WebSecurityConfigurer.class.getSimpleName()+" must be exposed as a @Bean when using @EnableWebSecurity. Hint try extending "+ WebSecurityConfigurerAdapter.class.getSimpleName());
|
||||
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});
|
||||
webSecurity.apply(adapter);
|
||||
}
|
||||
return webSecurity.build();
|
||||
}
|
||||
|
||||
+49
-13
@@ -16,11 +16,20 @@
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.target.LazyInitTargetSource;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -44,6 +53,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
|
||||
@@ -71,8 +81,8 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
|
||||
private AuthenticationConfiguration authenticationConfiguration;
|
||||
private AuthenticationManagerBuilder authenticationBuilder;
|
||||
private AuthenticationManagerBuilder parentAuthenticationBuilder;
|
||||
private boolean disableAuthenticationRegistration;
|
||||
private AuthenticationManagerBuilder localConfigureAuthenticationBldr;
|
||||
private boolean disableLocalConfigureAuthenticationBldr;
|
||||
private boolean authenticationManagerInitialized;
|
||||
private AuthenticationManager authenticationManager;
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
@@ -148,7 +158,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
this.disableAuthenticationRegistration = true;
|
||||
this.disableLocalConfigureAuthenticationBldr = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,11 +173,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
}
|
||||
|
||||
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
|
||||
parentAuthenticationBuilder.authenticationEventPublisher(eventPublisher);
|
||||
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
|
||||
|
||||
AuthenticationManager authenticationManager = authenticationManager();
|
||||
authenticationBuilder.parentAuthenticationManager(authenticationManager);
|
||||
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, parentAuthenticationBuilder.getSharedObjects());
|
||||
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, localConfigureAuthenticationBldr.getSharedObjects());
|
||||
http.setSharedObject(UserDetailsService.class, userDetailsService());
|
||||
http.setSharedObject(ApplicationContext.class, context);
|
||||
http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy);
|
||||
@@ -207,7 +217,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
* @throws Exception
|
||||
*/
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return new AuthenticationManagerDelegator(authenticationBuilder);
|
||||
return new AuthenticationManagerDelegator(authenticationBuilder, context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,11 +231,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
*/
|
||||
protected AuthenticationManager authenticationManager() throws Exception {
|
||||
if(!authenticationManagerInitialized) {
|
||||
configure(parentAuthenticationBuilder);
|
||||
if(disableAuthenticationRegistration) {
|
||||
configure(localConfigureAuthenticationBldr);
|
||||
if(disableLocalConfigureAuthenticationBldr) {
|
||||
authenticationManager = authenticationConfiguration.getAuthenticationManager();
|
||||
} else {
|
||||
authenticationManager = parentAuthenticationBuilder.build();
|
||||
authenticationManager = localConfigureAuthenticationBldr.build();
|
||||
}
|
||||
authenticationManagerInitialized = true;
|
||||
}
|
||||
@@ -253,7 +263,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
*/
|
||||
public UserDetailsService userDetailsServiceBean() throws Exception {
|
||||
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
|
||||
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
|
||||
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,7 +276,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
*/
|
||||
protected UserDetailsService userDetailsService() {
|
||||
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
|
||||
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
|
||||
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
|
||||
}
|
||||
|
||||
public void init(final WebSecurity web) throws Exception {
|
||||
@@ -337,7 +347,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
|
||||
authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);
|
||||
parentAuthenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor) {
|
||||
localConfigureAuthenticationBldr = new AuthenticationManagerBuilder(objectPostProcessor) {
|
||||
@Override
|
||||
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
|
||||
authenticationBuilder.eraseCredentials(eraseCredentials);
|
||||
@@ -410,9 +420,14 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
private AuthenticationManagerBuilder delegateBuilder;
|
||||
private AuthenticationManager delegate;
|
||||
private final Object delegateMonitor = new Object();
|
||||
private Set<String> beanNames;
|
||||
|
||||
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {
|
||||
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder, ApplicationContext context) {
|
||||
Assert.notNull(delegateBuilder,"delegateBuilder cannot be null");
|
||||
Field parentAuthMgrField = ReflectionUtils.findField(AuthenticationManagerBuilder.class, "parentAuthenticationManager");
|
||||
ReflectionUtils.makeAccessible(parentAuthMgrField);
|
||||
beanNames = getAuthenticationManagerBeanNames(context);
|
||||
validateBeanCycle(ReflectionUtils.getField(parentAuthMgrField, delegateBuilder), beanNames);
|
||||
this.delegateBuilder = delegateBuilder;
|
||||
}
|
||||
|
||||
@@ -430,5 +445,26 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||
|
||||
return delegate.authenticate(authentication);
|
||||
}
|
||||
|
||||
private static Set<String> getAuthenticationManagerBeanNames(ApplicationContext applicationContext) {
|
||||
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, AuthenticationManager.class);
|
||||
return new HashSet<String>(Arrays.asList(beanNamesForType));
|
||||
}
|
||||
|
||||
private static void validateBeanCycle(Object auth, Set<String> beanNames) {
|
||||
if(auth != null && !beanNames.isEmpty()) {
|
||||
if(auth instanceof Advised){
|
||||
Advised advised = (Advised) auth;
|
||||
TargetSource targetSource = advised.getTargetSource();
|
||||
if(targetSource instanceof LazyInitTargetSource) {
|
||||
LazyInitTargetSource lits = (LazyInitTargetSource) targetSource;
|
||||
if(beanNames.contains(lits.getTargetBeanName())) {
|
||||
throw new FatalBeanException("A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.");
|
||||
}
|
||||
}
|
||||
}
|
||||
beanNames = Collections.emptySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -103,7 +103,7 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
|
||||
* default {@link AccessDecisionManager}
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
abstract List<AccessDecisionVoter> getDecisionVoters(H http);
|
||||
abstract List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http);
|
||||
|
||||
abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R,T>,T> extends AbstractConfigAttributeRequestMatcherRegistry<T> {
|
||||
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>> extends Abst
|
||||
* @return the {@link CsrfConfigurer} for further customizations
|
||||
*/
|
||||
public CsrfConfigurer<H> requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {
|
||||
Assert.notNull(csrfTokenRepository, "requireCsrfProtectionMatcher cannot be null");
|
||||
Assert.notNull(requireCsrfProtectionMatcher, "requireCsrfProtectionMatcher cannot be null");
|
||||
this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
+2
-4
@@ -141,8 +141,8 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
final List<AccessDecisionVoter> getDecisionVoters(H http) {
|
||||
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
|
||||
final List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http) {
|
||||
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends Object>>();
|
||||
WebExpressionVoter expressionVoter = new WebExpressionVoter();
|
||||
expressionVoter.setExpressionHandler(getExpressionHandler(http));
|
||||
decisionVoters.add(expressionVoter);
|
||||
@@ -213,8 +213,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
/**
|
||||
* Negates the following expression.
|
||||
*
|
||||
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as
|
||||
* this is automatically inserted.
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
|
||||
*/
|
||||
public AuthorizedUrl not() {
|
||||
|
||||
+3
-1
@@ -294,7 +294,9 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
|
||||
}
|
||||
if(http.getConfigurer(CsrfConfigurer.class) != null) {
|
||||
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
|
||||
} else {
|
||||
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl);
|
||||
}
|
||||
return new AntPathRequestMatcher(this.logoutUrl);
|
||||
return this.logoutRequestMatcher;
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
@@ -114,12 +116,13 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
|
||||
return defaultCache;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private RequestMatcher createDefaultSavedRequestMatcher(H http) {
|
||||
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
|
||||
if(contentNegotiationStrategy == null) {
|
||||
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
|
||||
}
|
||||
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
|
||||
|
||||
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher("/**/favicon.ico"));
|
||||
|
||||
MediaTypeRequestMatcher jsonRequest = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_JSON);
|
||||
@@ -127,6 +130,18 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
|
||||
RequestMatcher notJson = new NegatedRequestMatcher(jsonRequest);
|
||||
|
||||
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(new RequestHeaderRequestMatcher("X-Requested-With","XMLHttpRequest"));
|
||||
return new AndRequestMatcher(getRequests, notFavIcon, notJson, notXRequestedWith);
|
||||
|
||||
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
|
||||
|
||||
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
if(isCsrfEnabled) {
|
||||
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
|
||||
matchers.add(0, getRequests);
|
||||
}
|
||||
matchers.add(notFavIcon);
|
||||
matchers.add(notJson);
|
||||
matchers.add(notXRequestedWith);
|
||||
|
||||
return new AndRequestMatcher(matchers);
|
||||
}
|
||||
}
|
||||
|
||||
+33
-5
@@ -22,10 +22,15 @@ import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.GenericApplicationListenerAdapter;
|
||||
import org.springframework.context.event.SmartApplicationListener;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.context.DelegatingApplicationListener;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
@@ -87,7 +92,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
|
||||
private InvalidSessionStrategy invalidSessionStrategy;
|
||||
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<SessionAuthenticationStrategy>();
|
||||
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
|
||||
private SessionRegistry sessionRegistry;
|
||||
private Integer maximumSessions;
|
||||
private String expiredUrl;
|
||||
private boolean maxSessionsPreventsLogin;
|
||||
@@ -367,14 +372,14 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
http.setSharedObject(RequestCache.class, new NullRequestCache());
|
||||
}
|
||||
}
|
||||
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
|
||||
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy(http));
|
||||
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
|
||||
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy());
|
||||
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy(http));
|
||||
if(sessionAuthenticationErrorUrl != null) {
|
||||
sessionManagementFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(sessionAuthenticationErrorUrl));
|
||||
}
|
||||
@@ -389,7 +394,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
http.addFilter(sessionManagementFilter);
|
||||
if(isConcurrentSessionControlEnabled()) {
|
||||
ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry, expiredUrl);
|
||||
ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(getSessionRegistry(http), expiredUrl);
|
||||
concurrentSessionFilter = postProcess(concurrentSessionFilter);
|
||||
http.addFilter(concurrentSessionFilter);
|
||||
}
|
||||
@@ -444,12 +449,13 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
*
|
||||
* @return the {@link SessionAuthenticationStrategy} to use
|
||||
*/
|
||||
private SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
|
||||
private SessionAuthenticationStrategy getSessionAuthenticationStrategy(H http) {
|
||||
if(sessionAuthenticationStrategy != null) {
|
||||
return sessionAuthenticationStrategy;
|
||||
}
|
||||
List<SessionAuthenticationStrategy> delegateStrategies = sessionAuthenticationStrategies;
|
||||
if(isConcurrentSessionControlEnabled()) {
|
||||
SessionRegistry sessionRegistry = getSessionRegistry(http);
|
||||
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
|
||||
concurrentSessionControlStrategy.setMaximumSessions(maximumSessions);
|
||||
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(maxSessionsPreventsLogin);
|
||||
@@ -466,6 +472,28 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return sessionAuthenticationStrategy;
|
||||
}
|
||||
|
||||
private SessionRegistry getSessionRegistry(H http) {
|
||||
if(sessionRegistry == null) {
|
||||
SessionRegistryImpl sessionRegistry = new SessionRegistryImpl();
|
||||
registerDelegateApplicationListener(http, sessionRegistry);
|
||||
this.sessionRegistry = sessionRegistry;
|
||||
}
|
||||
return sessionRegistry;
|
||||
}
|
||||
|
||||
private void registerDelegateApplicationListener(H http, ApplicationListener<?> delegate) {
|
||||
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
|
||||
if(context == null) {
|
||||
return;
|
||||
}
|
||||
if(context.getBeansOfType(DelegatingApplicationListener.class).isEmpty()) {
|
||||
return;
|
||||
}
|
||||
DelegatingApplicationListener delegating = context.getBean(DelegatingApplicationListener.class);
|
||||
SmartApplicationListener smartListener = new GenericApplicationListenerAdapter(delegate);
|
||||
delegating.addListener(smartListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the number of concurrent sessions per user should be restricted.
|
||||
* @return
|
||||
|
||||
+4
-8
@@ -81,14 +81,12 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}
|
||||
* AuthenticationManager
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H>
|
||||
* the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @param <C>
|
||||
* the type of object that is being chained
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
@@ -144,15 +142,14 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Creates the default {@link AccessDecisionVoter} instances used if an
|
||||
* {@link AccessDecisionManager} was not specified using
|
||||
* {@link #accessDecisionManager(AccessDecisionManager)}.
|
||||
* {@link AccessDecisionManager} was not specified.
|
||||
*
|
||||
* @param http the builder to use
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
final List<AccessDecisionVoter> getDecisionVoters(H http) {
|
||||
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
|
||||
final List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http) {
|
||||
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends Object>>();
|
||||
decisionVoters.add(new RoleVoter());
|
||||
decisionVoters.add(new AuthenticatedVoter());
|
||||
return decisionVoters;
|
||||
@@ -236,7 +233,6 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map to some {@link ConfigAttribute} instances.
|
||||
* @see UrlAuthorizationConfigurer#chainRequestMatchers(List)
|
||||
*/
|
||||
private AuthorizedUrl(List<RequestMatcher> requestMatchers) {
|
||||
Assert.notEmpty(requestMatchers, "requestMatchers must contain at least one value");
|
||||
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.annotation.web.messaging;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
|
||||
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
|
||||
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Allows mapping security constraints using {@link MessageMatcher} to the security expressions.
|
||||
*
|
||||
* @since 4.0
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class MessageSecurityMetadataSourceRegistry {
|
||||
private static final String permitAll = "permitAll";
|
||||
private static final String denyAll = "denyAll";
|
||||
private static final String anonymous = "anonymous";
|
||||
private static final String authenticated = "authenticated";
|
||||
private static final String fullyAuthenticated = "fullyAuthenticated";
|
||||
private static final String rememberMe = "rememberMe";
|
||||
|
||||
private final LinkedHashMap<MatcherBuilder,String> matcherToExpression = new LinkedHashMap<MatcherBuilder,String>();
|
||||
|
||||
private PathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
/**
|
||||
* Maps any {@link Message} to a security expression.
|
||||
*
|
||||
* @return the Expression to associate
|
||||
*/
|
||||
public Constraint anyMessage() {
|
||||
return matchers(MessageMatcher.ANY_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances.
|
||||
*
|
||||
* @param typesToMatch the {@link SimpMessageType} instance to match on
|
||||
* @return the {@link Constraint} associated to the matchers.
|
||||
*/
|
||||
public Constraint typeMatchers(SimpMessageType... typesToMatch) {
|
||||
MessageMatcher<?>[] typeMatchers = new MessageMatcher<?>[typesToMatch.length];
|
||||
for (int i = 0; i < typesToMatch.length; i++) {
|
||||
SimpMessageType typeToMatch = typesToMatch[i];
|
||||
typeMatchers[i] = new SimpMessageTypeMatcher(typeToMatch);
|
||||
}
|
||||
return matchers(typeMatchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances
|
||||
* without regard to the {@link SimpMessageType}. If no destination is found
|
||||
* on the Message, then the Matcher returns false.
|
||||
*
|
||||
* @param patterns
|
||||
* the patterns to create
|
||||
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
|
||||
* from. Uses
|
||||
* {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}
|
||||
* .
|
||||
*
|
||||
* @return the {@link Constraint} that is associated to the
|
||||
* {@link MessageMatcher}
|
||||
* @see {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}
|
||||
*/
|
||||
public Constraint antMatchers(String... patterns) {
|
||||
return antMatchers(null, patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances.
|
||||
* If no destination is found on the Message, then the Matcher returns
|
||||
* false.
|
||||
*
|
||||
* @param type the {@link SimpMessageType} to match on. If null, the {@link SimpMessageType} is not considered for matching.
|
||||
* @param patterns the patterns to create {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
|
||||
* from. Uses {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}.
|
||||
*
|
||||
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
|
||||
* @see {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}
|
||||
*/
|
||||
public Constraint antMatchers(SimpMessageType type, String... patterns) {
|
||||
List<MatcherBuilder> matchers = new ArrayList<MatcherBuilder>(patterns.length);
|
||||
for(String pattern : patterns) {
|
||||
matchers.add(new PathMatcherMessageMatcherBuilder(pattern, type));
|
||||
}
|
||||
return new Constraint(matchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link PathMatcher} to be used with the {@link MessageSecurityMetadataSourceRegistry#antMatchers(String...)}.
|
||||
* The default is to use the default constructor of {@link AntPathMatcher}.
|
||||
*
|
||||
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization.
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry pathMatcher(PathMatcher pathMatcher) {
|
||||
Assert.notNull(pathMatcher, "pathMatcher cannot be null");
|
||||
this.pathMatcher = pathMatcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link MessageMatcher} instances to a security expression.
|
||||
*
|
||||
* @param matchers the {@link MessageMatcher} instances to map.
|
||||
* @return The {@link Constraint} that is associated to the {@link MessageMatcher} instances
|
||||
*/
|
||||
public Constraint matchers(MessageMatcher<?>... matchers) {
|
||||
List<MatcherBuilder> builders = new ArrayList<MatcherBuilder>(matchers.length);
|
||||
for(MessageMatcher<?> matcher : matchers) {
|
||||
builders.add(new PreBuiltMatcherBuilder(matcher));
|
||||
}
|
||||
return new Constraint(builders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to create creating a {@link MessageSecurityMetadataSource}.
|
||||
*
|
||||
* <p>This is not exposed so as not to confuse users of the API, which should never invoke this method.</p>
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSource} to use
|
||||
*/
|
||||
protected MessageSecurityMetadataSource createMetadataSource() {
|
||||
LinkedHashMap<MessageMatcher<?>,String> matcherToExpression = new LinkedHashMap<MessageMatcher<?>,String>();
|
||||
for(Map.Entry<MatcherBuilder,String> entry : this.matcherToExpression.entrySet()) {
|
||||
matcherToExpression.put(entry.getKey().build(), entry.getValue());
|
||||
}
|
||||
return ExpressionBasedMessageSecurityMetadataSourceFactory.createExpressionMessageMetadataSource(matcherToExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows determining if a mapping was added.
|
||||
*
|
||||
* <p>This is not exposed so as not to confuse users of the API, which should never need to invoke this method.</p>
|
||||
*
|
||||
* @return true if a mapping was added, else false
|
||||
*/
|
||||
protected boolean containsMapping() {
|
||||
return !this.matcherToExpression.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the security constraint to be applied to the {@link MessageMatcher} instances.
|
||||
*/
|
||||
public class Constraint {
|
||||
private final List<? extends MatcherBuilder> messageMatchers;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param messageMatchers the {@link MessageMatcher} instances to map to this constraint
|
||||
*/
|
||||
private Constraint(List<? extends MatcherBuilder> messageMatchers) {
|
||||
Assert.notEmpty(messageMatchers, "messageMatchers cannot be null or empty");
|
||||
this.messageMatchers = messageMatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for specifying {@link Message} instances require a particular role. If you do not want to have "ROLE_" automatically
|
||||
* inserted see {@link #hasAuthority(String)}.
|
||||
*
|
||||
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as
|
||||
* this is automatically inserted.
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry hasRole(String role) {
|
||||
return access(MessageSecurityMetadataSourceRegistry.hasRole(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for specifying {@link Message} instances require any of a number of roles. If you
|
||||
* do not want to have "ROLE_" automatically inserted see
|
||||
* {@link #hasAnyAuthority(String...)}
|
||||
*
|
||||
* @param roles
|
||||
* the roles to require (i.e. USER, ADMIN, etc). Note, it
|
||||
* should not start with "ROLE_" as this is automatically
|
||||
* inserted.
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
|
||||
* customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry hasAnyRole(String... roles) {
|
||||
return access(MessageSecurityMetadataSourceRegistry.hasAnyRole(roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that {@link Message} instances require a particular authority.
|
||||
*
|
||||
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry hasAuthority(String authority) {
|
||||
return access(MessageSecurityMetadataSourceRegistry.hasAuthority(authority));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that {@link Message} instances requires any of a number authorities.
|
||||
*
|
||||
* @param authorities the requests require at least one of the authorities (i.e. "ROLE_USER","ROLE_ADMIN" would
|
||||
* mean either "ROLE_USER" or "ROLE_ADMIN" is required).
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry hasAnyAuthority(String... authorities) {
|
||||
return access(MessageSecurityMetadataSourceRegistry.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that Messages are allowed by anyone.
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry permitAll() {
|
||||
return access(permitAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that Messages are allowed by anonymous users.
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry anonymous() {
|
||||
return access(anonymous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that Messages are allowed by users that have been remembered.
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry rememberMe() {
|
||||
return access(rememberMe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that Messages are not allowed by anyone.
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry denyAll() {
|
||||
return access(denyAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that Messages are allowed by any authenticated user.
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry authenticated() {
|
||||
return access(authenticated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that Messages are allowed by users who have authenticated and were not "remembered".
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry fullyAuthenticated() {
|
||||
return access(fullyAuthenticated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows specifying that Messages are secured by an arbitrary expression
|
||||
*
|
||||
* @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER') and hasRole('ROLE_SUPER')")
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry access(String attribute) {
|
||||
for(MatcherBuilder messageMatcher : messageMatchers) {
|
||||
matcherToExpression.put(messageMatcher, attribute);
|
||||
}
|
||||
return MessageSecurityMetadataSourceRegistry.this;
|
||||
}
|
||||
}
|
||||
|
||||
private static String hasAnyRole(String... authorities) {
|
||||
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_");
|
||||
return "hasAnyRole('ROLE_" + anyAuthorities + "')";
|
||||
}
|
||||
|
||||
private static String hasRole(String role) {
|
||||
Assert.notNull(role, "role cannot be null");
|
||||
if (role.startsWith("ROLE_")) {
|
||||
throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
|
||||
}
|
||||
return "hasRole('ROLE_" + role + "')";
|
||||
}
|
||||
|
||||
private static String hasAuthority(String authority) {
|
||||
return "hasAuthority('" + authority + "')";
|
||||
}
|
||||
|
||||
private static String hasAnyAuthority(String... authorities) {
|
||||
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','");
|
||||
return "hasAnyAuthority('" + anyAuthorities + "')";
|
||||
}
|
||||
|
||||
private class PreBuiltMatcherBuilder implements MatcherBuilder {
|
||||
private MessageMatcher<?> matcher;
|
||||
|
||||
private PreBuiltMatcherBuilder(MessageMatcher<?> matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
|
||||
public MessageMatcher<?> build() {
|
||||
return matcher;
|
||||
}
|
||||
}
|
||||
|
||||
private class PathMatcherMessageMatcherBuilder implements MatcherBuilder {
|
||||
private final String pattern;
|
||||
private final SimpMessageType type;
|
||||
|
||||
private PathMatcherMessageMatcherBuilder(String pattern, SimpMessageType type) {
|
||||
this.pattern = pattern;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public MessageMatcher<?> build() {
|
||||
return new SimpDestinationMessageMatcher(pattern, type, pathMatcher);
|
||||
}
|
||||
}
|
||||
|
||||
private interface MatcherBuilder {
|
||||
MessageMatcher<?> build();
|
||||
}
|
||||
}
|
||||
+4
@@ -19,6 +19,7 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||
|
||||
@@ -27,6 +28,7 @@ import org.springframework.security.config.annotation.authentication.configurati
|
||||
* Add this annotation to an {@code @Configuration} class to have the Spring Security
|
||||
* configuration integrate with Spring MVC.
|
||||
*
|
||||
* @deprecated Use EnableWebSecurity instead which will automatically add the Spring MVC related Security items.
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
@@ -35,5 +37,7 @@ import org.springframework.security.config.annotation.authentication.configurati
|
||||
@Documented
|
||||
@Import(WebMvcSecurityConfiguration.class)
|
||||
@EnableGlobalAuthentication
|
||||
@Configuration
|
||||
@Deprecated
|
||||
public @interface EnableWebMvcSecurity {
|
||||
}
|
||||
|
||||
+4
-2
@@ -20,7 +20,7 @@ import java.util.List;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver;
|
||||
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
|
||||
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
@@ -35,17 +35,19 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
* {@link AuthenticationPrincipalArgumentResolver} as a
|
||||
* {@link HandlerMethodArgumentResolver}.
|
||||
*
|
||||
* @deprecated This is applied internally using SpringWebMvcImportSelector
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void addArgumentResolvers(
|
||||
List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
|
||||
argumentResolvers.add(new org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.annotation.web.socket;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||
import org.springframework.messaging.simp.config.ChannelRegistration;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
|
||||
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
|
||||
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
|
||||
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
|
||||
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
|
||||
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
|
||||
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Allows configuring WebSocket Authorization.
|
||||
*
|
||||
* <p>For example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* @Configuration
|
||||
* public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
*
|
||||
* @Override
|
||||
* protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
* messages
|
||||
* .antMatchers("/user/queue/errors").permitAll()
|
||||
* .antMatchers("/admin/**").hasRole("ADMIN")
|
||||
* .anyMessage().authenticated();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @since 4.0
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 100)
|
||||
public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry();
|
||||
|
||||
public final void registerStompEndpoints(StompEndpointRegistry registry) {}
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(
|
||||
List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void configureClientInboundChannel(ChannelRegistration registration) {
|
||||
ChannelSecurityInterceptor inboundChannelSecurity = inboundChannelSecurity();
|
||||
if(inboundRegistry.containsMapping()) {
|
||||
registration.setInterceptors(securityContextChannelInterceptor(),inboundChannelSecurity);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ChannelSecurityInterceptor inboundChannelSecurity() {
|
||||
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(inboundMessageSecurityMetadataSource());
|
||||
List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>();
|
||||
voters.add(new MessageExpressionVoter());
|
||||
AffirmativeBased manager = new AffirmativeBased(voters);
|
||||
channelSecurityInterceptor.setAccessDecisionManager(manager);
|
||||
return channelSecurityInterceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityContextChannelInterceptor securityContextChannelInterceptor() {
|
||||
return new SecurityContextChannelInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() {
|
||||
configureInbound(inboundRegistry);
|
||||
return inboundRegistry.createMetadataSource();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param messages
|
||||
*/
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {}
|
||||
|
||||
private class WebSocketMessageSecurityMetadataSourceRegistry extends MessageSecurityMetadataSourceRegistry {
|
||||
@Override
|
||||
public MessageSecurityMetadataSource createMetadataSource() {
|
||||
return super.createMetadataSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean containsMapping() {
|
||||
return super.containsMapping();
|
||||
}
|
||||
}
|
||||
}
|
||||
-11
@@ -52,7 +52,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
|
||||
String alias = element.getAttribute(ATT_ALIAS);
|
||||
|
||||
checkForDeprecatedSessionControllerRef(element, pc);
|
||||
List<BeanMetadataElement> providers = new ManagedList<BeanMetadataElement>();
|
||||
NamespaceHandlerResolver resolver = pc.getReaderContext().getNamespaceHandlerResolver();
|
||||
|
||||
@@ -113,16 +112,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkForDeprecatedSessionControllerRef(Element element, ParserContext pc) {
|
||||
final String ATT_SESSION_CONTROLLER_REF = "session-controller-ref";
|
||||
|
||||
if (StringUtils.hasText(element.getAttribute(ATT_SESSION_CONTROLLER_REF))) {
|
||||
pc.getReaderContext().warning(ATT_SESSION_CONTROLLER_REF + " is not supported in Spring Security " +
|
||||
" 3.0 and will be ignored. Use the attribute on the <concurrent-session-control> element instead.",
|
||||
pc.extractSource(element));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider which doesn't provide any service. Only used to prevent a configuration exception if the provider list
|
||||
* is empty (usually because a child ProviderManager from the <http> namespace, such as OpenID, is expected
|
||||
|
||||
+12
@@ -6,8 +6,13 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Factory bean for the namespace AuthenticationManager, which allows a more meaningful error message
|
||||
@@ -28,6 +33,13 @@ public class AuthenticationManagerFactoryBean implements FactoryBean<Authenticat
|
||||
return (AuthenticationManager) bf.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
|
||||
try {
|
||||
UserDetailsService uds = bf.getBean(UserDetailsService.class);
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setUserDetailsService(uds);
|
||||
provider.afterPropertiesSet();
|
||||
return new ProviderManager(Arrays.<AuthenticationProvider>asList(provider));
|
||||
} catch(NoSuchBeanDefinitionException noUds) {}
|
||||
throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER, MISSING_BEAN_ERROR_MESSAGE);
|
||||
}
|
||||
throw e;
|
||||
|
||||
+9
-17
@@ -84,7 +84,6 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
private static final String ATT_AUTO_CONFIG = "auto-config";
|
||||
|
||||
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
private static final String ATT_ACCESS_DENIED_ERROR_PAGE = "error-page";
|
||||
private static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
|
||||
|
||||
@@ -131,12 +130,12 @@ final class AuthenticationConfigBuilder {
|
||||
private String loginProcessingUrl;
|
||||
private String openidLoginProcessingUrl;
|
||||
|
||||
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
|
||||
public AuthenticationConfigBuilder(Element element, boolean forceAutoConfig, ParserContext pc, SessionCreationPolicy sessionPolicy,
|
||||
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy, BeanReference portMapper, BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
|
||||
this.httpElt = element;
|
||||
this.pc = pc;
|
||||
this.requestCache = requestCache;
|
||||
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||
autoConfig = forceAutoConfig | "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.NEVER
|
||||
&& sessionPolicy != SessionCreationPolicy.STATELESS;
|
||||
this.portMapper = portMapper;
|
||||
@@ -194,7 +193,7 @@ final class AuthenticationConfigBuilder {
|
||||
RootBeanDefinition formFilter = null;
|
||||
|
||||
if (formLoginElt != null || autoConfig) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/login", "POST",
|
||||
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
|
||||
|
||||
parser.parse(formLoginElt, pc);
|
||||
@@ -219,7 +218,7 @@ final class AuthenticationConfigBuilder {
|
||||
RootBeanDefinition openIDFilter = null;
|
||||
|
||||
if (openIDLoginElt != null) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/login/openid", null,
|
||||
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
|
||||
|
||||
parser.parse(openIDLoginElt, pc);
|
||||
@@ -493,7 +492,11 @@ final class AuthenticationConfigBuilder {
|
||||
void createLogoutFilter() {
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
LogoutBeanDefinitionParser logoutParser = new LogoutBeanDefinitionParser(rememberMeServicesId, csrfLogoutHandler);
|
||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||
if(formLoginPage == null) {
|
||||
formLoginPage = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
|
||||
}
|
||||
LogoutBeanDefinitionParser logoutParser = new LogoutBeanDefinitionParser(formLoginPage,rememberMeServicesId, csrfLogoutHandler);
|
||||
logoutFilter = logoutParser.parse(logoutElt, pc);
|
||||
logoutHandlers = logoutParser.getLogoutHandlers();
|
||||
}
|
||||
@@ -587,20 +590,9 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
|
||||
private BeanMetadataElement createAccessDeniedHandler(Element element, ParserContext pc) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
WebConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
Element accessDeniedElt = DomUtils.getChildElementByTagName(element, Elements.ACCESS_DENIED_HANDLER);
|
||||
BeanDefinitionBuilder accessDeniedHandler = BeanDefinitionBuilder.rootBeanDefinition(AccessDeniedHandlerImpl.class);
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
if (accessDeniedElt != null) {
|
||||
pc.getReaderContext().error("The attribute " + ATT_ACCESS_DENIED_PAGE +
|
||||
" cannot be used with <" + Elements.ACCESS_DENIED_HANDLER + ">", pc.extractSource(accessDeniedElt));
|
||||
}
|
||||
|
||||
accessDeniedHandler.addPropertyValue("errorPage", accessDeniedPage);
|
||||
}
|
||||
|
||||
if (accessDeniedElt != null) {
|
||||
String errorPage = accessDeniedElt.getAttribute("error-page");
|
||||
String ref = accessDeniedElt.getAttribute("ref");
|
||||
|
||||
+9
-2
@@ -56,6 +56,10 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private BeanDefinition csrfFilter;
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
boolean disabled = element != null && "true".equals(element.getAttribute("disabled"));
|
||||
if(disabled) {
|
||||
return null;
|
||||
}
|
||||
boolean webmvcPresent = ClassUtils.isPresent(DISPATCHER_SERVLET_CLASS_NAME, getClass().getClassLoader());
|
||||
if(webmvcPresent) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(CsrfRequestDataValueProcessor.class);
|
||||
@@ -64,8 +68,11 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
|
||||
pc.registerBeanComponent(componentDefinition);
|
||||
}
|
||||
|
||||
csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
|
||||
String matcherRef = element.getAttribute(ATT_MATCHER);
|
||||
String matcherRef = null;
|
||||
if(element != null) {
|
||||
csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
|
||||
matcherRef = element.getAttribute(ATT_MATCHER);
|
||||
}
|
||||
|
||||
if(!StringUtils.hasText(csrfRepositoryRef)) {
|
||||
RootBeanDefinition csrfTokenRepository = new RootBeanDefinition(HttpSessionCsrfTokenRepository.class);
|
||||
|
||||
+14
-7
@@ -5,14 +5,17 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
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.DefaultSecurityFilterChain;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -29,7 +32,7 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
BeanDefinition filterChainProxy = holder.getBeanDefinition();
|
||||
|
||||
Map filterChainMap = new LinkedHashMap();
|
||||
ManagedList<BeanMetadataElement> securityFilterChains = new ManagedList<BeanMetadataElement>();
|
||||
Element elt = (Element)node;
|
||||
|
||||
MatcherType matcherType = MatcherType.fromElement(elt);
|
||||
@@ -53,7 +56,7 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, null);
|
||||
|
||||
if (filters.equals(HttpSecurityBeanDefinitionParser.OPT_FILTERS_NONE)) {
|
||||
filterChainMap.put(matcher, Collections.EMPTY_LIST);
|
||||
securityFilterChains.add(createSecurityFilterChain(matcher, new ManagedList(0)));
|
||||
} else {
|
||||
String[] filterBeanNames = StringUtils.tokenizeToStringArray(filters, ",");
|
||||
ManagedList filterChain = new ManagedList(filterBeanNames.length);
|
||||
@@ -62,15 +65,19 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
|
||||
filterChain.add(new RuntimeBeanReference(name));
|
||||
}
|
||||
|
||||
filterChainMap.put(matcher, filterChain);
|
||||
securityFilterChains.add(createSecurityFilterChain(matcher, filterChain));
|
||||
}
|
||||
}
|
||||
|
||||
ManagedMap map = new ManagedMap(filterChainMap.size());
|
||||
map.putAll(filterChainMap);
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", map);
|
||||
filterChainProxy.getConstructorArgumentValues().addGenericArgumentValue(securityFilterChains);
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
private BeanDefinition createSecurityFilterChain(BeanDefinition matcher, ManagedList<?> filters) {
|
||||
BeanDefinitionBuilder sfc = BeanDefinitionBuilder.rootBeanDefinition(DefaultSecurityFilterChain.class);
|
||||
sfc.addConstructorArgValue(matcher);
|
||||
sfc.addConstructorArgValue(filters);
|
||||
return sfc.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
+22
-11
@@ -48,7 +48,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
}
|
||||
}
|
||||
|
||||
BeanDefinition mds = createSecurityMetadataSource(interceptUrls, element, parserContext);
|
||||
BeanDefinition mds = createSecurityMetadataSource(interceptUrls, false, element, parserContext);
|
||||
|
||||
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
|
||||
|
||||
@@ -60,16 +60,16 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
return mds;
|
||||
}
|
||||
|
||||
static RootBeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
|
||||
MatcherType matcherType = MatcherType.fromElement(elt);
|
||||
boolean useExpressions = isUseExpressions(elt);
|
||||
static RootBeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, boolean addAllAuth, Element httpElt, ParserContext pc) {
|
||||
MatcherType matcherType = MatcherType.fromElement(httpElt);
|
||||
boolean useExpressions = isUseExpressions(httpElt);
|
||||
|
||||
ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap(
|
||||
matcherType, interceptUrls, useExpressions, pc);
|
||||
matcherType, interceptUrls, useExpressions, addAllAuth, pc);
|
||||
BeanDefinitionBuilder fidsBuilder;
|
||||
|
||||
if (useExpressions) {
|
||||
Element expressionHandlerElt = DomUtils.getChildElementByTagName(elt, Elements.EXPRESSION_HANDLER);
|
||||
Element expressionHandlerElt = DomUtils.getChildElementByTagName(httpElt, Elements.EXPRESSION_HANDLER);
|
||||
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
|
||||
|
||||
if (StringUtils.hasText(expressionHandlerRef)) {
|
||||
@@ -86,7 +86,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
|
||||
}
|
||||
|
||||
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt));
|
||||
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(httpElt));
|
||||
|
||||
return (RootBeanDefinition) fidsBuilder.getBeanDefinition();
|
||||
}
|
||||
@@ -100,12 +100,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
}
|
||||
|
||||
static boolean isUseExpressions(Element elt) {
|
||||
return "true".equals(elt.getAttribute(ATT_USE_EXPRESSIONS));
|
||||
String useExpressions = elt.getAttribute(ATT_USE_EXPRESSIONS);
|
||||
return !StringUtils.hasText(useExpressions) || "true".equals(useExpressions);
|
||||
}
|
||||
|
||||
private static ManagedMap<BeanDefinition, BeanDefinition>
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(MatcherType matcherType,
|
||||
List<Element> urlElts, boolean useExpressions, ParserContext parserContext) {
|
||||
List<Element> urlElts, boolean useExpressions, boolean addAuthenticatedAll, ParserContext parserContext) {
|
||||
|
||||
ManagedMap<BeanDefinition, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<BeanDefinition, BeanDefinition>();
|
||||
|
||||
@@ -128,14 +129,15 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, method);
|
||||
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
|
||||
attributeBuilder.addConstructorArgValue(access);
|
||||
|
||||
if (useExpressions) {
|
||||
logger.info("Creating access control expression attribute '" + access + "' for " + path);
|
||||
// The single expression will be parsed later by the ExpressionFilterInvocationSecurityMetadataSource
|
||||
attributeBuilder.setFactoryMethod("createSingleAttributeList");
|
||||
attributeBuilder.addConstructorArgValue(new String[] { access });
|
||||
attributeBuilder.setFactoryMethod("createList");
|
||||
|
||||
} else {
|
||||
attributeBuilder.addConstructorArgValue(access);
|
||||
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
|
||||
}
|
||||
|
||||
@@ -146,6 +148,15 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
if(addAuthenticatedAll && filterInvocationDefinitionMap.isEmpty()) {
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher("/**", null);
|
||||
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
|
||||
attributeBuilder.addConstructorArgValue(new String[] { "authenticated" });
|
||||
attributeBuilder.setFactoryMethod("createList");
|
||||
filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
return filterInvocationDefinitionMap;
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -66,11 +66,13 @@ public class FormLoginBeanDefinitionParser {
|
||||
private RootBeanDefinition filterBean;
|
||||
private RootBeanDefinition entryPointBean;
|
||||
private String loginPage;
|
||||
private String loginMethod;
|
||||
private String loginProcessingUrl;
|
||||
|
||||
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
||||
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String loginMethod, String filterClassName,
|
||||
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation, BeanReference portMapper, BeanReference portResolver) {
|
||||
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
||||
this.loginMethod = loginMethod;
|
||||
this.filterClassName = filterClassName;
|
||||
this.requestCache = requestCache;
|
||||
this.sessionStrategy = sessionStrategy;
|
||||
@@ -151,8 +153,11 @@ public class FormLoginBeanDefinitionParser {
|
||||
|
||||
this.loginProcessingUrl = loginUrl;
|
||||
|
||||
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.authentication.logout.LogoutFilter$FilterProcessUrlRequestMatcher");
|
||||
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.util.matcher.AntPathRequestMatcher");
|
||||
matcherBuilder.addConstructorArgValue(loginUrl);
|
||||
if(loginMethod != null) {
|
||||
matcherBuilder.addConstructorArgValue("POST");
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("requiresAuthenticationRequestMatcher", matcherBuilder.getBeanDefinition());
|
||||
|
||||
|
||||
+17
-7
@@ -80,14 +80,24 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
headerWriters = new ManagedList<BeanMetadataElement>();
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HeaderWriterFilter.class);
|
||||
|
||||
parseCacheControlElement(element);
|
||||
parseHstsElement(element);
|
||||
parseXssElement(element, parserContext);
|
||||
parseFrameOptionsElement(element, parserContext);
|
||||
parseContentTypeOptionsElement(element);
|
||||
if(element != null) {
|
||||
|
||||
parseHeaderElements(element);
|
||||
parseCacheControlElement(element);
|
||||
parseHstsElement(element);
|
||||
parseXssElement(element, parserContext);
|
||||
parseFrameOptionsElement(element, parserContext);
|
||||
parseContentTypeOptionsElement(element);
|
||||
|
||||
parseHeaderElements(element);
|
||||
}
|
||||
|
||||
boolean disabled = element != null && "true".equals(element.getAttribute("disabled"));
|
||||
if(disabled) {
|
||||
if(!headerWriters.isEmpty()) {
|
||||
parserContext.getReaderContext().error("Cannot specify <headers disabled=\"true\"> with child elements.", element);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if(headerWriters.isEmpty()) {
|
||||
addCacheControl();
|
||||
addHsts(null);
|
||||
@@ -208,7 +218,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
String fromParameter = getAttribute(frameElt, ATT_FROM_PARAMETER, "from");
|
||||
allowFromStrategy.addPropertyValue("allowFromParameterName", fromParameter);
|
||||
builder.addConstructorArgValue(allowFromStrategy);
|
||||
builder.addConstructorArgValue(allowFromStrategy.getBeanDefinition());
|
||||
}
|
||||
} else {
|
||||
parserContext.getReaderContext().error("One of 'strategy' and 'strategy-ref' must be set.",
|
||||
|
||||
+15
-13
@@ -133,10 +133,12 @@ class HttpConfigurationBuilder {
|
||||
private CsrfBeanDefinitionParser csrfParser;
|
||||
|
||||
private BeanDefinition invalidSession;
|
||||
private boolean addAllAuth;
|
||||
|
||||
public HttpConfigurationBuilder(Element element, ParserContext pc,
|
||||
public HttpConfigurationBuilder(Element element, boolean addAllAuth, ParserContext pc,
|
||||
BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) {
|
||||
this.httpElt = element;
|
||||
this.addAllAuth = addAllAuth;
|
||||
this.pc = pc;
|
||||
this.portMapper = portMapper;
|
||||
this.portResolver = portResolver;
|
||||
@@ -583,7 +585,7 @@ class HttpConfigurationBuilder {
|
||||
|
||||
private void createFilterSecurityInterceptor(BeanReference authManager) {
|
||||
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
|
||||
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
|
||||
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, addAllAuth, httpElt, pc);
|
||||
|
||||
RootBeanDefinition accessDecisionMgr;
|
||||
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
|
||||
@@ -638,22 +640,22 @@ class HttpConfigurationBuilder {
|
||||
|
||||
private void createAddHeadersFilter() {
|
||||
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.HEADERS);
|
||||
if (elmt != null) {
|
||||
this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, pc);
|
||||
}
|
||||
this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, pc);
|
||||
|
||||
}
|
||||
|
||||
private CsrfBeanDefinitionParser createCsrfFilter() {
|
||||
private void createCsrfFilter() {
|
||||
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.CSRF);
|
||||
if (elmt != null) {
|
||||
csrfParser = new CsrfBeanDefinitionParser();
|
||||
csrfFilter = csrfParser.parse(elmt, pc);
|
||||
this.csrfAuthStrategy = csrfParser.getCsrfAuthenticationStrategy();
|
||||
this.csrfLogoutHandler = csrfParser.getCsrfLogoutHandler();
|
||||
return csrfParser;
|
||||
csrfParser = new CsrfBeanDefinitionParser();
|
||||
csrfFilter = csrfParser.parse(elmt, pc);
|
||||
|
||||
if(csrfFilter == null) {
|
||||
csrfParser = null;
|
||||
return;
|
||||
}
|
||||
return null;
|
||||
|
||||
this.csrfAuthStrategy = csrfParser.getCsrfAuthenticationStrategy();
|
||||
this.csrfLogoutHandler = csrfParser.getCsrfLogoutHandler();
|
||||
}
|
||||
|
||||
BeanMetadataElement getCsrfLogoutHandler() {
|
||||
|
||||
+7
-2
@@ -132,10 +132,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
|
||||
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders);
|
||||
|
||||
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc,
|
||||
boolean forceAutoConfig = isDefaultHttpConfig(element);
|
||||
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, forceAutoConfig, pc,
|
||||
portMapper, portResolver, authenticationManager);
|
||||
|
||||
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
|
||||
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, forceAutoConfig, pc,
|
||||
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
|
||||
httpBldr.getSessionStrategy(), portMapper, portResolver, httpBldr.getCsrfLogoutHandler());
|
||||
|
||||
@@ -164,6 +165,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return createSecurityFilterChainBean(element, pc, filterChain);
|
||||
}
|
||||
|
||||
private static boolean isDefaultHttpConfig(Element httpElt) {
|
||||
return httpElt.getChildNodes().getLength() == 0 && httpElt.getAttributes().getLength() == 0;
|
||||
}
|
||||
|
||||
private BeanReference createSecurityFilterChainBean(Element element, ParserContext pc, List<?> filterChain) {
|
||||
BeanMetadataElement filterChainMatcher;
|
||||
|
||||
|
||||
+20
-8
@@ -35,21 +35,24 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_LOGOUT_SUCCESS_URL = "logout-success-url";
|
||||
static final String DEF_LOGOUT_SUCCESS_URL = "/";
|
||||
|
||||
static final String ATT_INVALIDATE_SESSION = "invalidate-session";
|
||||
|
||||
static final String ATT_LOGOUT_URL = "logout-url";
|
||||
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
|
||||
static final String DEF_LOGOUT_URL = "/logout";
|
||||
static final String ATT_LOGOUT_HANDLER = "success-handler-ref";
|
||||
static final String ATT_DELETE_COOKIES = "delete-cookies";
|
||||
|
||||
final String rememberMeServices;
|
||||
private final String defaultLogoutUrl;
|
||||
private ManagedList<BeanMetadataElement> logoutHandlers = new ManagedList<BeanMetadataElement>();
|
||||
private boolean csrfEnabled;
|
||||
|
||||
public LogoutBeanDefinitionParser(String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
|
||||
public LogoutBeanDefinitionParser(String loginPageUrl, String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
|
||||
this.defaultLogoutUrl = loginPageUrl + "?logout";
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
if(csrfLogoutHandler != null) {
|
||||
this.csrfEnabled = csrfLogoutHandler != null;
|
||||
if (this.csrfEnabled) {
|
||||
logoutHandlers.add(csrfLogoutHandler);
|
||||
}
|
||||
}
|
||||
@@ -78,10 +81,9 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (!StringUtils.hasText(logoutUrl)) {
|
||||
logoutUrl = DEF_LOGOUT_URL;
|
||||
}
|
||||
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter$FilterProcessUrlRequestMatcher");
|
||||
matcherBuilder.addConstructorArgValue(logoutUrl);
|
||||
|
||||
builder.addPropertyValue("logoutRequestMatcher", matcherBuilder.getBeanDefinition());
|
||||
|
||||
builder.addPropertyValue("logoutRequestMatcher", getLogoutRequestMatcher(logoutUrl));
|
||||
|
||||
if (StringUtils.hasText(successHandlerRef)) {
|
||||
if (StringUtils.hasText(logoutSuccessUrl)) {
|
||||
@@ -92,7 +94,7 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
} else {
|
||||
// Use the logout URL if no handler set
|
||||
if (!StringUtils.hasText(logoutSuccessUrl)) {
|
||||
logoutSuccessUrl = DEF_LOGOUT_SUCCESS_URL;
|
||||
logoutSuccessUrl = defaultLogoutUrl;
|
||||
}
|
||||
builder.addConstructorArgValue(logoutSuccessUrl);
|
||||
}
|
||||
@@ -117,6 +119,16 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private BeanDefinition getLogoutRequestMatcher(String logoutUrl) {
|
||||
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.util.matcher.AntPathRequestMatcher");
|
||||
matcherBuilder.addConstructorArgValue(logoutUrl);
|
||||
if(this.csrfEnabled) {
|
||||
matcherBuilder.addConstructorArgValue("POST");
|
||||
}
|
||||
|
||||
return matcherBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
ManagedList<BeanMetadataElement> getLogoutHandlers() {
|
||||
return logoutHandlers;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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;
|
||||
@@ -23,10 +21,7 @@ public enum MatcherType {
|
||||
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;
|
||||
|
||||
@@ -56,11 +51,6 @@ public enum MatcherType {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.message;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.*;
|
||||
import org.springframework.beans.factory.support.*;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
||||
import org.springframework.security.access.vote.ConsensusBased;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
|
||||
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
|
||||
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
|
||||
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
|
||||
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
|
||||
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Parses Spring Security's message namespace support. A simple example is:
|
||||
*
|
||||
* <code>
|
||||
* <messages>
|
||||
* <message-interceptor pattern='/permitAll' access='permitAll' />
|
||||
* <message-interceptor pattern='/denyAll' access='denyAll' />
|
||||
* </messages>
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* The above configuration will ensure that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver
|
||||
* registered as a custom argument resolver. It also ensures that the SecurityContextChannelInterceptor is automatically
|
||||
* registered for the clientInboundChannel. Last, it ensures that a ChannelSecurityInterceptor is registered with the
|
||||
* clientInboundChannel.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If finer control is necessary, the id attribute can be used as shown below:
|
||||
* </p>
|
||||
*
|
||||
* <code>
|
||||
* <messages id="channelSecurityInterceptor">
|
||||
* <message-interceptor pattern='/permitAll' access='permitAll' />
|
||||
* <message-interceptor pattern='/denyAll' access='denyAll' />
|
||||
* </messages>
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* Now the configuration will only create a bean named ChannelSecurityInterceptor and assign it to the id of
|
||||
* channelSecurityInterceptor. Users can explicitly wire Spring Security using the standard Spring Messaging XML
|
||||
* namespace support.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 4.0
|
||||
*/
|
||||
public final class MessageSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final Log logger = LogFactory.getLog(MessageSecurityBeanDefinitionParser.class);
|
||||
|
||||
private static final String ID_ATTR = "id";
|
||||
|
||||
private static final String PATTERN_ATTR = "pattern";
|
||||
|
||||
private static final String ACCESS_ATTR = "access";
|
||||
|
||||
|
||||
/**
|
||||
* @param element
|
||||
* @param parserContext
|
||||
* @return
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
XmlReaderContext context = parserContext.getReaderContext();
|
||||
|
||||
ManagedMap<BeanDefinition,String> matcherToExpression = new ManagedMap<BeanDefinition, String>();
|
||||
|
||||
String id = element.getAttribute(ID_ATTR);
|
||||
|
||||
List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_MESSAGE);
|
||||
for(Element interceptMessage : interceptMessages) {
|
||||
String matcherPattern = interceptMessage.getAttribute(PATTERN_ATTR);
|
||||
String accessExpression = interceptMessage.getAttribute(ACCESS_ATTR);
|
||||
BeanDefinitionBuilder matcher = BeanDefinitionBuilder.rootBeanDefinition(SimpDestinationMessageMatcher.class);
|
||||
matcher.addConstructorArgValue(matcherPattern);
|
||||
matcherToExpression.put(matcher.getBeanDefinition(), accessExpression);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder mds = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedMessageSecurityMetadataSourceFactory.class);
|
||||
mds.setFactoryMethod("createExpressionMessageMetadataSource");
|
||||
mds.addConstructorArgValue(matcherToExpression);
|
||||
|
||||
String mdsId = context.registerWithGeneratedName(mds.getBeanDefinition());
|
||||
|
||||
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>();
|
||||
voters.add(new RootBeanDefinition(MessageExpressionVoter.class));
|
||||
BeanDefinitionBuilder adm = BeanDefinitionBuilder.rootBeanDefinition(ConsensusBased.class);
|
||||
adm.addConstructorArgValue(voters);
|
||||
|
||||
BeanDefinitionBuilder inboundChannelSecurityInterceptor = BeanDefinitionBuilder.rootBeanDefinition(ChannelSecurityInterceptor.class);
|
||||
inboundChannelSecurityInterceptor.addConstructorArgValue(registry.getBeanDefinition(mdsId));
|
||||
inboundChannelSecurityInterceptor.addPropertyValue("accessDecisionManager", adm.getBeanDefinition());
|
||||
String inSecurityInterceptorName = context.registerWithGeneratedName(inboundChannelSecurityInterceptor.getBeanDefinition());
|
||||
|
||||
if(StringUtils.hasText(id)) {
|
||||
registry.registerAlias(inSecurityInterceptorName, id);
|
||||
} else {
|
||||
BeanDefinitionBuilder mspp = BeanDefinitionBuilder.rootBeanDefinition(MessageSecurityPostProcessor.class);
|
||||
mspp.addConstructorArgValue(inSecurityInterceptorName);
|
||||
context.registerWithGeneratedName(mspp.getBeanDefinition());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static class MessageSecurityPostProcessor implements BeanDefinitionRegistryPostProcessor {
|
||||
private static final String CLIENT_INBOUND_CHANNEL_BEAN_ID = "clientInboundChannel";
|
||||
|
||||
private static final String INTERCEPTORS_PROP = "interceptors";
|
||||
|
||||
private static final String CUSTOM_ARG_RESOLVERS_PROP = "customArgumentResolvers";
|
||||
|
||||
private final String inboundSecurityInterceptorId;
|
||||
|
||||
public MessageSecurityPostProcessor(String inboundSecurityInterceptorId) {
|
||||
this.inboundSecurityInterceptorId = inboundSecurityInterceptorId;
|
||||
}
|
||||
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
String[] beanNames = registry.getBeanDefinitionNames();
|
||||
for(String beanName : beanNames) {
|
||||
BeanDefinition bd = registry.getBeanDefinition(beanName);
|
||||
if(bd.getBeanClassName().equals(SimpAnnotationMethodMessageHandler.class.getName())) {
|
||||
PropertyValue current = bd.getPropertyValues().getPropertyValue(CUSTOM_ARG_RESOLVERS_PROP);
|
||||
ManagedList<Object> argResolvers = new ManagedList<Object>();
|
||||
if(current != null) {
|
||||
argResolvers.addAll((ManagedList<?>)current.getValue());
|
||||
}
|
||||
argResolvers.add(new RootBeanDefinition(AuthenticationPrincipalArgumentResolver.class));
|
||||
bd.getPropertyValues().add(CUSTOM_ARG_RESOLVERS_PROP, argResolvers);
|
||||
}
|
||||
}
|
||||
|
||||
if(!registry.containsBeanDefinition(CLIENT_INBOUND_CHANNEL_BEAN_ID)) {
|
||||
return;
|
||||
}
|
||||
ManagedList<Object> interceptors = new ManagedList();
|
||||
interceptors.add(new RootBeanDefinition(SecurityContextChannelInterceptor.class));
|
||||
interceptors.add(registry.getBeanDefinition(inboundSecurityInterceptorId));
|
||||
|
||||
BeanDefinition inboundChannel = registry.getBeanDefinition(CLIENT_INBOUND_CHANNEL_BEAN_ID);
|
||||
PropertyValue currentInterceptorsPv = inboundChannel.getPropertyValues().getPropertyValue(INTERCEPTORS_PROP);
|
||||
if(currentInterceptorsPv != null) {
|
||||
ManagedList<?> currentInterceptors = (ManagedList<?>) currentInterceptorsPv.getValue();
|
||||
interceptors.addAll(currentInterceptors);
|
||||
}
|
||||
|
||||
inboundChannel.getPropertyValues().add(INTERCEPTORS_PROP, interceptors);
|
||||
}
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -452,6 +452,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
}
|
||||
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
if(!registry.containsBeanDefinition(beanName)) {
|
||||
return;
|
||||
}
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
|
||||
beanDefinition.setLazyInit(true);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user