Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3243a7cde2 | |||
| 07848a1060 | |||
| 8207a29e52 | |||
| 1c22ec19e6 | |||
| 56e41df964 | |||
| f232f5ef05 | |||
| d467146e49 | |||
| c64b80564e | |||
| 90f230cbfa | |||
| 4cc2ffaa2d | |||
| a24065c361 | |||
| 789d29b26b | |||
| 29632ee9ea | |||
| 37aacc5e02 | |||
| 0284845289 | |||
| e6231584c8 | |||
| 23de257508 | |||
| 12ed990aa2 | |||
| d7d4ac9dc1 | |||
| 7c62164392 | |||
| eceb6a3587 | |||
| c4a1f1b4a8 | |||
| 7ecee8e733 | |||
| 63a334317b | |||
| 704b114842 | |||
| fcc9a34356 | |||
| 00042ff70b | |||
| fc1450f72c | |||
| a6cd1b6066 | |||
| 567b0ed030 | |||
| 4e6b12f8b4 | |||
| ae772294cb | |||
| c01f2d8501 | |||
| 28c6e9a8af | |||
| 13cb51c15f | |||
| b0ad8173b0 | |||
| ea27cb6593 | |||
| fe82c8ab4c | |||
| cf66f2f39e | |||
| 050407564c | |||
| 1374898cd8 | |||
| d5ed97eba6 | |||
| 8f29c2cc36 | |||
| 99d503f0a9 | |||
| 6c185f649b | |||
| 58be282f70 | |||
| 2df05ee2c3 | |||
| 72bc6bf539 | |||
| 1b26d03479 | |||
| dfaebfa63b | |||
| f794272bac | |||
| aa0a5b96ab | |||
| 27c7cd150b | |||
| b3d108fa44 | |||
| 975e4ec019 | |||
| 74f8534b17 | |||
| 478a9650aa | |||
| b79ba12502 | |||
| 72de17d79a | |||
| e27200a255 | |||
| c3f72f7b79 | |||
| b42cb9e3e1 | |||
| b40088b73d | |||
| 4116596a6c | |||
| 9de369c25f | |||
| bf2d2d4597 | |||
| c05f27af6c | |||
| cdac4d990b | |||
| db66843e0b | |||
| c36cc88ac4 | |||
| 7d82349b1e | |||
| b6ab9c85e9 | |||
| 29a8da4aa6 | |||
| b71989ecde | |||
| eeef91498a | |||
| 91bf099b01 | |||
| 137589325d | |||
| 0a184a8d79 | |||
| 2cb99f0791 | |||
| d85a0a20bc | |||
| 0a45d3170c | |||
| 89c5c56849 | |||
| 47acf17323 | |||
| 52c585aef1 | |||
| 89d80ed5c9 | |||
| 85a37bdc02 | |||
| fb1f2dc888 | |||
| d5842f949b | |||
| 3e3d819526 | |||
| 143c513f5c | |||
| 8eb89e3f12 | |||
| bdde468e7d | |||
| f574f2a2ac | |||
| 439a15b108 | |||
| 44fbf678bb | |||
| 9c94ef358d | |||
| 655ad90813 | |||
| a0ee80bc61 | |||
| 6b977d9b4b | |||
| 7ea79bacbc | |||
| fa177a22b1 | |||
| b9fbc568fb | |||
| 293e3e97ae |
+58
@@ -0,0 +1,58 @@
|
||||
= Spring Security
|
||||
|
||||
Spring Security provides security services for the http://docs.spring.io[Spring IO Platform]. Spring Security 3.1 requires Spring 3.0.3 as
|
||||
a minimum and also requires Java 5.
|
||||
|
||||
For a detailed list of features and access to the latest release, please visit http://spring.io/projects[Spring projects].
|
||||
|
||||
== Downloading Artifacts
|
||||
See https://github.com/spring-projects/spring-framework/wiki/Downloading-Spring-artifacts[downloading Spring artifacts] for Maven repository information.
|
||||
|
||||
== Documentation
|
||||
Be sure to read the http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference].
|
||||
Extensive JavaDoc for the Spring Security code is also available in the http://docs.spring.io/spring-security/site/docs/current/apidocs/[Spring Security API Documentation].
|
||||
|
||||
== Quick Start
|
||||
We recommend you visit http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference] and read the "Getting Started" page.
|
||||
|
||||
== Building from Source
|
||||
Spring Security uses a http://gradle.org[Gradle]-based build system.
|
||||
In the instructions below, http://vimeo.com/34436402[`./gradlew`] is invoked from the root of the source tree and serves as
|
||||
a cross-platform, self-contained bootstrap mechanism for the build.
|
||||
|
||||
=== Prerequisites
|
||||
http://help.github.com/set-up-git-redirect[Git] and the http://www.oracle.com/technetwork/java/javase/downloads[JDK7 build].
|
||||
|
||||
Be sure that your `JAVA_HOME` environment variable points to the `jdk1.7.0` folder extracted from the JDK download.
|
||||
|
||||
=== Check out sources
|
||||
[indent=0]
|
||||
----
|
||||
git clone git@github.com:spring-projects/spring-security.git
|
||||
----
|
||||
|
||||
=== Install all spring-\* jars into your local Maven cache
|
||||
[indent=0]
|
||||
----
|
||||
./gradlew install
|
||||
----
|
||||
|
||||
=== Compile and test; build all jars, distribution zips, and docs
|
||||
[indent=0]
|
||||
----
|
||||
./gradlew build
|
||||
----
|
||||
|
||||
Discover more commands with `./gradlew tasks`.
|
||||
See also the https://github.com/spring-projects/spring-framework/wiki/Gradle-build-and-release-FAQ[Gradle build and release FAQ].
|
||||
|
||||
== Getting Support
|
||||
Check out the http://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
|
||||
http://spring.io/services[Commercial support] is available too.
|
||||
|
||||
== Contributing
|
||||
http://help.github.com/send-pull-requests[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.md[contributor guidelines] for details.
|
||||
|
||||
== License
|
||||
Spring Security is Open Source software released under the
|
||||
http://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
|
||||
@@ -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",
|
||||
|
||||
+11
-17
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>spring-security-acl</name>
|
||||
<description>spring-security-acl</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,12 +42,6 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
@@ -58,25 +52,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -88,13 +82,13 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -138,7 +132,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -150,19 +144,19 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.springframework.security.acls;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -121,8 +122,9 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
try {
|
||||
p = permissionFactory.buildFromName(permString);
|
||||
} catch(IllegalArgumentException notfound) {
|
||||
p = permissionFactory.buildFromName(permString.toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException notfound) {
|
||||
p = permissionFactory.buildFromName(permString.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
if (p != null) {
|
||||
|
||||
@@ -4,6 +4,8 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
@@ -36,4 +38,26 @@ public class AclPermissionEvaluatorTests {
|
||||
|
||||
assertTrue(pe.hasPermission(mock(Authentication.class), new Object(), "READ"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePermissionNonEnglishLocale() {
|
||||
Locale systemLocale = Locale.getDefault();
|
||||
Locale.setDefault(new Locale("tr"));
|
||||
|
||||
AclService service = mock(AclService.class);
|
||||
AclPermissionEvaluator pe = new AclPermissionEvaluator(service);
|
||||
ObjectIdentity oid = mock(ObjectIdentity.class);
|
||||
ObjectIdentityRetrievalStrategy oidStrategy = mock(ObjectIdentityRetrievalStrategy.class);
|
||||
when(oidStrategy.getObjectIdentity(anyObject())).thenReturn(oid);
|
||||
pe.setObjectIdentityRetrievalStrategy(oidStrategy);
|
||||
pe.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
|
||||
Acl acl = mock(Acl.class);
|
||||
|
||||
when(service.readAclById(any(ObjectIdentity.class), anyList())).thenReturn(acl);
|
||||
when(acl.isGranted(anyList(), anyList(), eq(false))).thenReturn(true);
|
||||
|
||||
assertTrue(pe.hasPermission(mock(Authentication.class), new Object(), "write"));
|
||||
|
||||
Locale.setDefault(systemLocale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion"
|
||||
|
||||
|
||||
+8
-14
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>spring-security-aspects</name>
|
||||
<description>spring-security-aspects</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,35 +42,29 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -120,7 +114,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -132,13 +126,13 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+7
-6
@@ -8,7 +8,7 @@ buildscript {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.6")
|
||||
classpath("org.springframework.build.gradle:bundlor-plugin:0.1.2")
|
||||
classpath("org.springframework.build.gradle:spring-io-plugin:0.0.3.RELEASE")
|
||||
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:0.9.8")
|
||||
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:1.2.3")
|
||||
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')
|
||||
@@ -26,8 +26,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.springVersion = '3.2.13.RELEASE'
|
||||
ext.spring4Version = '4.1.6.RELEASE'
|
||||
ext.springLdapVersion = '1.3.2.RELEASE'
|
||||
ext.springLdap2Version = '2.0.1.RELEASE'
|
||||
|
||||
@@ -62,7 +62,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 {
|
||||
@@ -103,7 +103,7 @@ configure(coreModuleProjects) {
|
||||
apply plugin: 'emma'
|
||||
apply plugin: 'spring-io'
|
||||
|
||||
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : '1.0.0.BUILD-SNAPSHOT'
|
||||
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : 'latest.integration'
|
||||
|
||||
bundlor.doFirst {
|
||||
def templateText = file("template.mf").text
|
||||
@@ -145,6 +145,7 @@ task dist(type: Zip) {
|
||||
def zipRootDir = "${project.name}-$version"
|
||||
into(zipRootDir) {
|
||||
from(rootDir) {
|
||||
include '*.adoc'
|
||||
include '*.txt'
|
||||
}
|
||||
into('docs') {
|
||||
@@ -173,5 +174,5 @@ artifacts {
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '1.10-rc-2'
|
||||
gradleVersion = '1.12'
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,10 +2,11 @@
|
||||
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:3.3.3"
|
||||
|
||||
optional "net.sf.ehcache:ehcache-core:$ehcacheVersion"
|
||||
|
||||
|
||||
+10
-16
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>spring-security-cas</name>
|
||||
<description>spring-security-cas</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,47 +42,41 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</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.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -94,7 +88,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -138,7 +132,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -150,7 +144,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
+20
-3
@@ -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/j_spring_security_cas_check")
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
+48
-2
@@ -15,12 +15,18 @@
|
||||
*/
|
||||
package org.springframework.security.cas.web.authentication;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
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
|
||||
@@ -33,20 +39,33 @@ import org.springframework.security.cas.ServiceProperties;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class ServiceAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,
|
||||
ServiceAuthenticationDetails> {
|
||||
ServiceAuthenticationDetails>, ApplicationContextAware {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Pattern artifactPattern;
|
||||
|
||||
private ServiceProperties serviceProperties;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Creates an implementation that uses the default CAS artifactParameterName.
|
||||
* @deprecated Use ServiceAuthenticationDetailsSource(ServiceProperties)
|
||||
*/
|
||||
@Deprecated
|
||||
public ServiceAuthenticationDetailsSource() {
|
||||
this(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(ServiceProperties serviceProperties) {
|
||||
this(serviceProperties,ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an implementation that uses the specified artifactParameterName
|
||||
*
|
||||
@@ -54,11 +73,27 @@ public class ServiceAuthenticationDetailsSource implements AuthenticationDetails
|
||||
* the artifactParameterName that is removed from the current
|
||||
* URL. The result becomes the service url. Cannot be null and
|
||||
* cannot be an empty String.
|
||||
* @deprecated Use ServiceAuthenticationDetailsSource(ServiceProperties,String)
|
||||
*/
|
||||
public ServiceAuthenticationDetailsSource(final String artifactParameterName) {
|
||||
this.artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(artifactParameterName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(ServiceProperties serviceProperties, String artifactParameterName) {
|
||||
Assert.notNull(serviceProperties, "serviceProperties cannot be null");
|
||||
this.serviceProperties = serviceProperties;
|
||||
this.artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(artifactParameterName);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
@@ -66,6 +101,17 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
if(serviceProperties == null) {
|
||||
serviceProperties = applicationContext.getBean(ServiceProperties.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
+63
-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,82 @@ 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 getServiceUrlDoesNotUseHostHeaderPassivity() {
|
||||
casServiceUrl = "https://example.com/j_spring_security_cas";
|
||||
request.setServerName("evil.com");
|
||||
ServiceAuthenticationDetails details = loadServiceAuthenticationDetails("defaultserviceauthenticationdetails-passivity.xml");
|
||||
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
-1
@@ -14,7 +14,7 @@ Import-Template:
|
||||
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.beans.*;version="${springRange}",
|
||||
org.springframework.cache.*;version="${springRange}";resolution:=optional,
|
||||
org.springframework.context.*;version="${springRange}",
|
||||
org.springframework.dao;version="${springRange}",
|
||||
|
||||
@@ -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,6 +19,7 @@ dependencies {
|
||||
optional project(':spring-security-web'),
|
||||
project(':spring-security-ldap'),
|
||||
project(':spring-security-openid'),
|
||||
project(':spring-security-aspects'),
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-webmvc:$springVersion",
|
||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||
|
||||
+31
-30
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>spring-security-config</name>
|
||||
<description>spring-security-config</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,12 +42,6 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
@@ -58,31 +52,31 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -105,52 +99,59 @@
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-openid</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.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>3.2.13.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>3.2.13.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>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -271,7 +272,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -289,7 +290,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -301,31 +302,31 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-support</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-core</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4-common</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-reflect</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -379,25 +380,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+42
-11
@@ -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,12 @@ 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;
|
||||
@@ -58,6 +65,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +83,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupRoleAttribute("group")
|
||||
}
|
||||
}
|
||||
@@ -93,6 +102,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupSearchFilter("ou=groupName");
|
||||
}
|
||||
}
|
||||
@@ -111,6 +121,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.rolePrefix("role_")
|
||||
}
|
||||
}
|
||||
@@ -121,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
|
||||
@@ -131,30 +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:
|
||||
PasswordEncoderConfig.PE = Mock(PasswordEncoder)
|
||||
loadConfig(PasswordEncoderConfig)
|
||||
when:
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("admin","password")).authorities.collect { it.authority }.sort() == ["ROLE_ADMIN","ROLE_USER"]
|
||||
PasswordEncoderConfig.PE.matches(_, _) << true
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class PasswordEncoderConfig extends BaseLdapServerConfig {
|
||||
static PasswordEncoder PE
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.passwordEncoder(PE)
|
||||
.passwordEncoder(new BCryptPasswordEncoder())
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
@@ -167,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)
|
||||
}
|
||||
|
||||
static Integer port;
|
||||
|
||||
static int getPort() {
|
||||
if(port == null) {
|
||||
ServerSocket socket = new ServerSocket(0)
|
||||
port = socket.localPort
|
||||
socket.close()
|
||||
}
|
||||
port
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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
|
||||
@Configuration
|
||||
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"))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -56,7 +56,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
|
||||
|
||||
@@ -68,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
|
||||
+9
-3
@@ -56,6 +56,8 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers =
|
||||
new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();
|
||||
|
||||
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<SecurityConfigurer<O, B>>();
|
||||
|
||||
private final Map<Class<Object>,Object> sharedObjects = new HashMap<Class<Object>,Object>();
|
||||
|
||||
private final boolean allowConfigurersOfSameType;
|
||||
@@ -122,9 +124,9 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
|
||||
throws Exception {
|
||||
add(configurer);
|
||||
configurer.addObjectPostProcessor(objectPostProcessor);
|
||||
configurer.setBuilder((B) this);
|
||||
add(configurer);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@@ -198,7 +200,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
configs.add(configurer);
|
||||
this.configurers.put(clazz, configs);
|
||||
if(buildState.isInitializing()) {
|
||||
configurer.init((B)this);
|
||||
this.configurersAddedInInitializing.add(configurer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,7 +365,11 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
private void init() throws Exception {
|
||||
Collection<SecurityConfigurer<O,B>> configurers = getConfigurers();
|
||||
|
||||
for(SecurityConfigurer<O,B> configurer : configurers ) {
|
||||
for (SecurityConfigurer<O, B> configurer : configurers) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
|
||||
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public class AuthenticationConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
|
||||
public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
|
||||
return new EnableGlobalAuthenticationAutowiredConfigurer(context);
|
||||
}
|
||||
|
||||
|
||||
+42
-21
@@ -42,6 +42,9 @@ 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}.
|
||||
*
|
||||
@@ -61,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;
|
||||
|
||||
@@ -150,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;
|
||||
}
|
||||
@@ -221,21 +226,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> passwordEncoder(final org.springframework.security.crypto.password.PasswordEncoder passwordEncoder) {
|
||||
Assert.notNull(passwordEncoder, "passwordEncoder must not be null.");
|
||||
passwordEncoder(new PasswordEncoder() {
|
||||
public String encodePassword(String rawPass, Object salt) {
|
||||
checkSalt(salt);
|
||||
return passwordEncoder.encode(rawPass);
|
||||
}
|
||||
|
||||
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
|
||||
checkSalt(salt);
|
||||
return passwordEncoder.matches(rawPass, encPass);
|
||||
}
|
||||
|
||||
private void checkSalt(Object salt) {
|
||||
Assert.isNull(salt, "Salt value must be null when used with crypto module PasswordEncoder");
|
||||
}
|
||||
});
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -402,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;
|
||||
|
||||
@@ -447,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
|
||||
*/
|
||||
@@ -507,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;
|
||||
}
|
||||
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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.method.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* Registers an
|
||||
* {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
|
||||
* AnnotationAwareAspectJAutoProxyCreator} against the current
|
||||
* {@link BeanDefinitionRegistry} as appropriate based on a given @
|
||||
* {@link EnableGlobalMethodSecurity} annotation.
|
||||
*
|
||||
* <p>
|
||||
* Note: This class is necessary because AspectJAutoProxyRegistrar only supports
|
||||
* EnableAspectJAutoProxy.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
class GlobalMethodSecurityAspectJAutoProxyRegistrar implements
|
||||
ImportBeanDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* Register, escalate, and configure the AspectJ auto proxy creator based on
|
||||
* the value of the @{@link EnableGlobalMethodSecurity#proxyTargetClass()}
|
||||
* attribute on the importing {@code @Configuration} class.
|
||||
*/
|
||||
public void registerBeanDefinitions(
|
||||
AnnotationMetadata importingClassMetadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
|
||||
AopConfigUtils
|
||||
.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
|
||||
|
||||
Map<String, Object> annotationAttributes = importingClassMetadata
|
||||
.getAnnotationAttributes(EnableGlobalMethodSecurity.class
|
||||
.getName());
|
||||
AnnotationAttributes enableAJAutoProxy = AnnotationAttributes
|
||||
.fromMap(annotationAttributes);
|
||||
|
||||
if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.method.configuration;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect;
|
||||
|
||||
/**
|
||||
* Creates the AnnotationSecurityAspect for use with AspectJ based security.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
class GlobalMethodSecurityAspectJConfiguration {
|
||||
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@Bean
|
||||
public AnnotationSecurityAspect annotationSecurityAspect(@Qualifier("methodSecurityInterceptor") MethodInterceptor methodSecurityInterceptor) {
|
||||
AnnotationSecurityAspect result = AnnotationSecurityAspect.aspectOf();
|
||||
result.setSecurityInterceptor((AspectJMethodSecurityInterceptor )methodSecurityInterceptor);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+13
-11
@@ -24,10 +24,8 @@ 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.ApplicationContext;
|
||||
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 +46,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;
|
||||
@@ -87,8 +86,8 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
private AuthenticationManagerBuilder auth;
|
||||
private boolean disableAuthenticationRegistry;
|
||||
private AnnotationAttributes enableMethodSecurity;
|
||||
private ApplicationContext context;
|
||||
private MethodSecurityExpressionHandler expressionHandler;
|
||||
private AuthenticationConfiguration authenticationConfiguration;
|
||||
|
||||
/**
|
||||
* Creates the default MethodInterceptor which is a MethodSecurityInterceptor using the following methods to
|
||||
@@ -111,7 +110,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
|
||||
@@ -353,14 +352,13 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators.get(0));
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
|
||||
this.authenticationConfiguration = authenticationConfiguration;
|
||||
@Autowired
|
||||
public void setApplicationContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private AuthenticationConfiguration getAuthenticationConfiguration() {
|
||||
Assert.notNull(authenticationConfiguration, "authenticationConfiguration cannot be null");
|
||||
return authenticationConfiguration;
|
||||
return context.getBean(AuthenticationConfiguration.class);
|
||||
}
|
||||
|
||||
private boolean 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
-1
@@ -48,7 +48,7 @@ final class GlobalMethodSecuritySelector implements ImportSelector {
|
||||
|
||||
AdviceMode mode = attributes.getEnum("mode");
|
||||
String autoProxyClassName = AdviceMode.PROXY == mode ? AutoProxyRegistrar.class.getName()
|
||||
: GlobalMethodSecurityAspectJAutoProxyRegistrar.class.getName();
|
||||
: GlobalMethodSecurityAspectJConfiguration.class.getName();
|
||||
if(skipMethodSecurityConfiguration) {
|
||||
return new String[] { autoProxyClassName };
|
||||
}
|
||||
|
||||
+15
@@ -25,6 +25,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for specifying which
|
||||
@@ -51,6 +52,20 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return requestMatchers(ANY_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
|
||||
* instances.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use for any
|
||||
* {@link HttpMethod}.
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C antMatchers(HttpMethod method) {
|
||||
return antMatchers(method, new String[] { "/**" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} instances.
|
||||
*
|
||||
|
||||
+2
-2
@@ -113,7 +113,7 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends S
|
||||
* been added using {@link #addFilterAfter(Filter, Class)} or
|
||||
* {@link #addFilterBefore(Filter, Class)}.
|
||||
*
|
||||
* @param filter the {@link Filter} to register before the type {@code afterFilter}
|
||||
* @param filter the {@link Filter} to register after the type {@code afterFilter}
|
||||
* @param afterFilter the Class of the known {@link Filter}.
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
@@ -171,4 +171,4 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends S
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
*/
|
||||
H addFilter(Filter filter);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1000,7 +1000,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* .and()
|
||||
* .formLogin()
|
||||
* .and()
|
||||
* .channelSecurity()
|
||||
* .requiresChannel()
|
||||
* .anyRequest().requiresSecure();
|
||||
* }
|
||||
*
|
||||
|
||||
+6
@@ -40,6 +40,7 @@ import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
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 +73,11 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Bean
|
||||
public static DelegatingApplicationListener delegatingApplicationListener() {
|
||||
return new DelegatingApplicationListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
|
||||
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
|
||||
|
||||
+2
-1
@@ -151,7 +151,8 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
|
||||
* @return the default {@code AccessDecisionManager}
|
||||
*/
|
||||
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
|
||||
return new AffirmativeBased(getDecisionVoters(http));
|
||||
AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
|
||||
return postProcess(result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
+6
-1
@@ -32,12 +32,13 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
|
||||
@@ -167,6 +168,10 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
if(authenticationDetailsSource != null) {
|
||||
basicAuthenticationFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
}
|
||||
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
|
||||
if(rememberMeServices != null) {
|
||||
basicAuthenticationFilter.setRememberMeServices(rememberMeServices);
|
||||
}
|
||||
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
|
||||
http.addFilter(basicAuthenticationFilter);
|
||||
}
|
||||
|
||||
+11
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpSession;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
@@ -98,6 +99,16 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if {@link SecurityContextLogoutHandler} should clear the {@link Authentication} at the time of logout.
|
||||
* @param clearAuthentication true {@link SecurityContextLogoutHandler} should clear the {@link Authentication} (default), or false otherwise.
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
*/
|
||||
public LogoutConfigurer<H> clearAuthentication(boolean clearAuthentication) {
|
||||
contextLogoutHandler.setClearAuthentication(clearAuthentication);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL that triggers log out to occur (default is "/logout"). If CSRF
|
||||
* protection is enabled (default), then the request must also be a POST.
|
||||
|
||||
+38
-6
@@ -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;
|
||||
@@ -83,11 +88,12 @@ import org.springframework.util.Assert;
|
||||
* @see ConcurrentSessionFilter
|
||||
*/
|
||||
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<SessionManagementConfigurer<H>,H> {
|
||||
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = createDefaultSessionFixationProtectionStrategy();
|
||||
private final SessionAuthenticationStrategy DEFAULT_SESSION_FIXATION_STRATEGY = createDefaultSessionFixationProtectionStrategy();
|
||||
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = DEFAULT_SESSION_FIXATION_STRATEGY;
|
||||
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 +373,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 +395,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 +450,16 @@ 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(DEFAULT_SESSION_FIXATION_STRATEGY == sessionFixationAuthenticationStrategy) {
|
||||
sessionFixationAuthenticationStrategy = postProcess(sessionFixationAuthenticationStrategy);
|
||||
}
|
||||
if(isConcurrentSessionControlEnabled()) {
|
||||
SessionRegistry sessionRegistry = getSessionRegistry(http);
|
||||
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
|
||||
concurrentSessionControlStrategy.setMaximumSessions(maximumSessions);
|
||||
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(maxSessionsPreventsLogin);
|
||||
@@ -466,6 +476,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
|
||||
|
||||
+1
-1
@@ -208,7 +208,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.",
|
||||
|
||||
+45
@@ -16,7 +16,12 @@
|
||||
package org.springframework.security.config.annotation.authentication.configuration;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactoryBean
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
@@ -325,4 +330,44 @@ class AuthenticationConfigurationTests extends BaseSpringSpec {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2822: Cannot Force Authentication already built"() {
|
||||
setup:
|
||||
loadConfig(Sec2822WebSecurity,Sec2822UseAuth,Sec2822Config)
|
||||
when:
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.getAuthenticationManager()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(AuthenticationConfiguration)
|
||||
static class Sec2822Config {}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class Sec2822WebSecurity extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Sec2822UseAuth {
|
||||
@Autowired
|
||||
public void useAuthenticationManager(AuthenticationConfiguration auth) {
|
||||
auth.authenticationManager
|
||||
}
|
||||
|
||||
// Ensures that Sec2822UseAuth is initialized before Sec2822WebSecurity
|
||||
// must have additional GlobalAuthenticationConfigurerAdapter to trigger SEC-2822
|
||||
@Bean
|
||||
public static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
|
||||
new BootGlobalAuthenticationConfigurerAdapter()
|
||||
}
|
||||
|
||||
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { }
|
||||
}
|
||||
}
|
||||
+66
@@ -15,6 +15,13 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.method.configuration
|
||||
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor
|
||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
|
||||
import javax.sql.DataSource
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat
|
||||
import static org.junit.Assert.fail
|
||||
|
||||
@@ -339,4 +346,63 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2815: @EnableGlobalMethodSecurity does not trigger eager initialization of Beans in GlobalAuthenticationConfigurer"() {
|
||||
setup:
|
||||
Sec2815Config.dataSource = Mock(DataSource)
|
||||
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
|
||||
loadConfig(Sec2815Config)
|
||||
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
|
||||
context.getBean(MockBeanPostProcessor).beforeInit['dataSource']
|
||||
context.getBean(MockBeanPostProcessor).afterInit['dataSource']
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class Sec2815Config {
|
||||
static DataSource dataSource;
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MockBeanPostProcessor mockBeanPostProcessor() {
|
||||
new MockBeanPostProcessor()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
dataSource
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
|
||||
@Autowired
|
||||
DataSource dataSource
|
||||
|
||||
@Override
|
||||
void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class MockBeanPostProcessor implements BeanPostProcessor {
|
||||
Map<String,Object> beforeInit = new HashMap<String,Object>()
|
||||
Map<String,Object> afterInit = new HashMap<String,Object>()
|
||||
|
||||
@Override
|
||||
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
beforeInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
|
||||
@Override
|
||||
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
afterInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -15,11 +15,14 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.method.configuration
|
||||
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat
|
||||
import static org.junit.Assert.fail
|
||||
|
||||
import java.lang.reflect.Method
|
||||
|
||||
import org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect
|
||||
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
@@ -188,8 +191,8 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(AspectJModeConfig)
|
||||
then:
|
||||
AnnotationAwareAspectJAutoProxyCreator autoProxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator)
|
||||
autoProxyCreator.proxyTargetClass == true
|
||||
context.getBean(AnnotationSecurityAspect)
|
||||
context.getBean(AspectJMethodSecurityInterceptor)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -201,8 +204,8 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,AspectJModeExtendsGMSCConfig)
|
||||
then:
|
||||
AnnotationAwareAspectJAutoProxyCreator autoProxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator)
|
||||
autoProxyCreator.proxyTargetClass == false
|
||||
context.getBean(AnnotationSecurityAspect)
|
||||
context.getBean(AspectJMethodSecurityInterceptor)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
+8
-1
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
package org.springframework.security.config.annotation.web.configuration
|
||||
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
@@ -342,4 +344,9 @@ class WebSecurityConfigurationTests extends BaseSpringSpec {
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class ChildConfig extends WebSecurityConfigurerAdapter { }
|
||||
|
||||
def "SEC-2773: delegatingApplicationListener is static method"() {
|
||||
expect: 'delegatingApplicationListener to prevent premature instantiation of WebSecurityConfiguration'
|
||||
Modifier.isStatic(WebSecurityConfiguration.metaClass.methods.find { it.name == 'delegatingApplicationListener'}.modifiers)
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -237,6 +237,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
|
||||
setup:
|
||||
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfTokenRepositoryConfig)
|
||||
request.method = "POST"
|
||||
request.getSession()
|
||||
@@ -391,6 +392,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
|
||||
def "csrf disables POST requests from RequestCache"() {
|
||||
setup:
|
||||
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
@@ -417,6 +419,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
|
||||
def "csrf enables GET requests with RequestCache"() {
|
||||
setup:
|
||||
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
@@ -464,6 +467,13 @@ class CsrfConfigurerTests extends BaseSpringSpec {
|
||||
}
|
||||
}
|
||||
|
||||
def 'SEC-2749: requireCsrfProtectionMatcher null'() {
|
||||
when:
|
||||
new CsrfConfigurer<>().requireCsrfProtectionMatcher(null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def clearCsrfToken() {
|
||||
request.removeAllParameters()
|
||||
}
|
||||
|
||||
+49
-1
@@ -19,8 +19,12 @@ import static org.springframework.security.config.annotation.web.configurers.Exp
|
||||
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor
|
||||
import org.springframework.context.ApplicationListener
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.access.event.AuthorizedEvent
|
||||
import org.springframework.security.access.vote.AffirmativeBased
|
||||
@@ -31,7 +35,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurerConfigs.CustomExpressionRootConfig;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurerConfigs.CustomExpressionRootConfig
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
|
||||
|
||||
@@ -540,4 +544,48 @@ public class ExpressionUrlAuthorizationConfigurerTests extends BaseSpringSpec {
|
||||
then: "custom bean expression denies access"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "SEC-3011: Default AccessDecisionManager postProcessed"() {
|
||||
when:
|
||||
loadConfig(Sec3011Config)
|
||||
then:
|
||||
context.getBean(MockBeanPostProcessor).beans.find { it instanceof AccessDecisionManager }
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class Sec3011Config extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
}
|
||||
|
||||
@Bean
|
||||
static MockBeanPostProcessor mbpp() {
|
||||
return new MockBeanPostProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
static class MockBeanPostProcessor implements BeanPostProcessor {
|
||||
List<Object> beans = new ArrayList<Object>();
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean,
|
||||
String beanName) throws BeansException {
|
||||
beans.add(bean);
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean,
|
||||
String beanName) throws BeansException {
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -24,6 +24,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
|
||||
|
||||
@@ -133,4 +134,29 @@ class HttpBasicConfigurerTests extends BaseSpringSpec {
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-3019: Basic Authentication uses RememberMe Config"() {
|
||||
when:
|
||||
loadConfig(BasicUsesRememberMeConfig)
|
||||
then:
|
||||
findFilter(BasicAuthenticationFilter).rememberMeServices == findFilter(RememberMeAuthenticationFilter).rememberMeServices
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class BasicUsesRememberMeConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic().and()
|
||||
.rememberMe()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
-9
@@ -15,19 +15,20 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import org.springframework.context.ApplicationListener
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockHttpSession
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.core.session.SessionRegistry
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
|
||||
import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent
|
||||
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||
import org.springframework.security.web.context.SecurityContextRepository
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter
|
||||
import org.springframework.security.web.session.SessionManagementFilter
|
||||
|
||||
@@ -141,6 +142,29 @@ class NamespaceSessionManagementTests extends BaseSpringSpec {
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2913: Default JavaConfig session fixation AuthenticationStrategy has NullEventPublisher"() {
|
||||
setup:
|
||||
loadConfig(SFPPostProcessedConfig)
|
||||
when:
|
||||
findSessionAuthenticationStrategy(SessionFixationProtectionStrategy).onSessionChange("id", new MockHttpSession(), new TestingAuthenticationToken("u","p","ROLE_USER"))
|
||||
then:
|
||||
context.getBean(MockEventListener).events
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class SFPPostProcessedConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.sessionManagement()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MockEventListener eventListener() {
|
||||
new MockEventListener()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/session-management@session-fixation-protection=newSession"() {
|
||||
when:
|
||||
loadConfig(SFPNewSessionSessionManagementConfig)
|
||||
@@ -163,4 +187,13 @@ class NamespaceSessionManagementTests extends BaseSpringSpec {
|
||||
.newSession()
|
||||
}
|
||||
}
|
||||
|
||||
static class MockEventListener implements ApplicationListener<SessionFixationProtectionEvent> {
|
||||
List<SessionFixationProtectionEvent> events = []
|
||||
|
||||
public void onApplicationEvent(SessionFixationProtectionEvent event) {
|
||||
events.add(event)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+18
-1
@@ -21,7 +21,7 @@ import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver
|
||||
import org.springframework.security.config.annotation.AnyObjectPostProcessor
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
@@ -33,11 +33,13 @@ import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy
|
||||
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy
|
||||
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy
|
||||
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||
import org.springframework.security.web.context.SecurityContextRepository
|
||||
import org.springframework.security.web.savedrequest.RequestCache
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter
|
||||
import org.springframework.security.web.session.HttpSessionDestroyedEvent
|
||||
import org.springframework.security.web.session.SessionManagementFilter
|
||||
|
||||
/**
|
||||
@@ -154,12 +156,14 @@ class SessionManagementConfigurerTests extends BaseSpringSpec {
|
||||
def 'session fixation and enable concurrency control'() {
|
||||
setup: "context where session fixation is disabled and concurrency control is enabled"
|
||||
loadConfig(ConcurrencyControlConfig)
|
||||
def authenticatedSession
|
||||
when: "authenticate successfully"
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password","password")
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
authenticatedSession = request.session
|
||||
then: "authentication is sucessful"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
@@ -173,6 +177,17 @@ class SessionManagementConfigurerTests extends BaseSpringSpec {
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == '/login?error'
|
||||
when: 'SEC-2574: When Session Expires and authentication attempted'
|
||||
context.publishEvent(new HttpSessionDestroyedEvent(authenticatedSession))
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password","password")
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "authentication is successful"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@@ -217,6 +232,8 @@ class SessionManagementConfigurerTests extends BaseSpringSpec {
|
||||
1 * opp.postProcess(_ as CompositeSessionAuthenticationStrategy) >> {CompositeSessionAuthenticationStrategy o -> o}
|
||||
and: "RegisterSessionAuthenticationStrategy is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as RegisterSessionAuthenticationStrategy) >> {RegisterSessionAuthenticationStrategy o -> o}
|
||||
and: "SessionFixationProtectionStrategy is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as SessionFixationProtectionStrategy) >> {SessionFixationProtectionStrategy o -> o}
|
||||
}
|
||||
|
||||
def "use sharedObject trustResolver"() {
|
||||
|
||||
@@ -119,6 +119,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
@@ -153,6 +154,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
@@ -252,6 +254,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.method = "POST"
|
||||
request.setParameter("j_username","user")
|
||||
|
||||
+20
@@ -172,6 +172,26 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
||||
assertHeaders(response, ['X-Frame-Options':'ALLOW-FROM https://example.com'])
|
||||
}
|
||||
|
||||
def 'http headers frame-options ALLOW-FROM with whitelist strategy'() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'headers'() {
|
||||
'frame-options'(policy : 'ALLOW-FROM', strategy: 'whitelist', value : 'https://example.com')
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
def hf = getFilter(HeaderWriterFilter)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
|
||||
def request = new MockHttpServletRequest()
|
||||
request.setParameter("from", "https://example.com");
|
||||
hf.doFilter(request, response, new MockFilterChain())
|
||||
|
||||
then:
|
||||
assertHeaders(response, ['X-Frame-Options':'ALLOW-FROM https://example.com'])
|
||||
}
|
||||
|
||||
def 'http headers header a=b'() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.configurers;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class AuthorizeRequestsTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-3135
|
||||
@Test
|
||||
public void antMatchersMethodAndNoPatterns() throws Exception {
|
||||
loadConfig(AntMatchersNoPatternsConfig.class);
|
||||
request.setMethod("POST");
|
||||
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.POST).denyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(configs);
|
||||
context.refresh();
|
||||
|
||||
context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.configurers;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class HttpSecurityAntMatchersTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-3135
|
||||
@Test
|
||||
public void antMatchersMethodAndNoPatterns() throws Exception {
|
||||
loadConfig(AntMatchersNoPatternsConfig.class);
|
||||
request.setMethod("POST");
|
||||
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requestMatchers()
|
||||
.antMatchers(HttpMethod.POST)
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(configs);
|
||||
context.refresh();
|
||||
|
||||
context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.configurers;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class HttpSecurityLogoutTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-2848
|
||||
@Test
|
||||
public void clearAuthenticationFalse() throws Exception {
|
||||
loadConfig(ClearAuthenticationFalseConfig.class);
|
||||
|
||||
SecurityContext currentContext = SecurityContextHolder.createEmptyContext();
|
||||
currentContext.setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"));
|
||||
|
||||
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, currentContext);
|
||||
request.setMethod("POST");
|
||||
request.setServletPath("/logout");
|
||||
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
assertThat(currentContext.getAuthentication()).isNotNull();
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class ClearAuthenticationFalseConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
.logout()
|
||||
.clearAuthentication(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(configs);
|
||||
context.refresh();
|
||||
|
||||
context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.http.customconfigurer;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class CustomConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,HttpSecurity> {
|
||||
|
||||
@Value("${permitAllPattern}")
|
||||
private String permitAllPattern;
|
||||
|
||||
private String loginPage = "/login";
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.config.annotation.SecurityConfigurerAdapter#init(org.springframework.security.config.annotation.SecurityBuilder)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(HttpSecurity http) throws Exception {
|
||||
// autowire this bean
|
||||
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
|
||||
context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers(permitAllPattern).permitAll()
|
||||
.anyRequest().authenticated();
|
||||
|
||||
if(http.getConfigurer(FormLoginConfigurer.class) == null) {
|
||||
// only apply if formLogin() was not invoked by the user
|
||||
http
|
||||
.formLogin()
|
||||
.loginPage(loginPage);
|
||||
}
|
||||
}
|
||||
|
||||
public CustomConfigurer loginPage(String loginPage) {
|
||||
this.loginPage = loginPage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static CustomConfigurer customConfigurer() {
|
||||
return new CustomConfigurer();
|
||||
}
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.http.customconfigurer;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.springframework.security.config.http.customconfigurer.CustomConfigurer.customConfigurer;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class CustomHttpSecurityConfigurerTests {
|
||||
@Autowired
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
request.setMethod("GET");
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customConfiguerPermitAll() throws Exception {
|
||||
loadContext(Config.class);
|
||||
|
||||
request.setPathInfo("/public/something");
|
||||
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customConfiguerFormLogin() throws Exception {
|
||||
loadContext(Config.class);
|
||||
request.setPathInfo("/requires-authentication");
|
||||
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
assertThat(response.getRedirectedUrl()).endsWith("/custom");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customConfiguerCustomizeDisablesCsrf() throws Exception {
|
||||
loadContext(ConfigCustomize.class);
|
||||
request.setPathInfo("/public/something");
|
||||
request.setMethod("POST");
|
||||
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customConfiguerCustomizeFormLogin() throws Exception {
|
||||
loadContext(ConfigCustomize.class);
|
||||
request.setPathInfo("/requires-authentication");
|
||||
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
assertThat(response.getRedirectedUrl()).endsWith("/other");
|
||||
}
|
||||
|
||||
private void loadContext(Class<?> clazz) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(clazz);
|
||||
context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class Config extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.apply(customConfigurer())
|
||||
.loginPage("/custom");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
|
||||
// Typically externalize this as a properties file
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("permitAllPattern", "/public/**");
|
||||
|
||||
PropertyPlaceholderConfigurer propertyPlaceholderConfigurer = new PropertyPlaceholderConfigurer();
|
||||
propertyPlaceholderConfigurer.setProperties(properties);
|
||||
return propertyPlaceholderConfigurer;
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ConfigCustomize extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.apply(customConfigurer())
|
||||
.and()
|
||||
.csrf().disable()
|
||||
.formLogin()
|
||||
.loginPage("/other");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
|
||||
// Typically externalize this as a properties file
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("permitAllPattern", "/public/**");
|
||||
|
||||
PropertyPlaceholderConfigurer propertyPlaceholderConfigurer = new PropertyPlaceholderConfigurer();
|
||||
propertyPlaceholderConfigurer.setProperties(properties);
|
||||
return propertyPlaceholderConfigurer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ Import-Template:
|
||||
org.openid4java.*;version="${openid4javaRange}";resolution:=optional,
|
||||
org.springframework.security.access.*;version="${secRange}",
|
||||
org.springframework.security.authentication.*;version="${secRange}",
|
||||
org.springframework.security.context.*;version="${secRange}";resolution:=optional,
|
||||
org.springframework.security.core.*;version="${secRange}",
|
||||
org.springframework.security.crypto.bcrypt.*;version="${secRange}",
|
||||
org.springframework.security.crypto.password.*;version="${secRange}",
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'aopalliance:aopalliance:1.0',
|
||||
compile springCoreDependency,
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
|
||||
+16
-22
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>spring-security-core</name>
|
||||
<description>spring-security-core</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,12 +42,6 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
@@ -58,25 +52,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -88,7 +82,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -122,14 +116,14 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.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>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -184,7 +178,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -196,7 +190,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -208,7 +202,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-support</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -220,7 +214,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-core</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -232,7 +226,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -244,7 +238,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4-common</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -256,7 +250,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-reflect</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -280,7 +274,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
||||
+8
-2
@@ -46,8 +46,14 @@ public abstract class AbstractMethodSecurityMetadataSource implements MethodSecu
|
||||
if (target != null) {
|
||||
targetClass = target instanceof Class<?> ? (Class<?>)target : AopProxyUtils.ultimateTargetClass(target);
|
||||
}
|
||||
|
||||
return getAttributes(mi.getMethod(), targetClass);
|
||||
Collection<ConfigAttribute> attrs = getAttributes(mi.getMethod(), targetClass);
|
||||
if(attrs != null && !attrs.isEmpty()) {
|
||||
return attrs;
|
||||
}
|
||||
if(target != null && !(target instanceof Class<?>)) {
|
||||
attrs = getAttributes(mi.getMethod(), target.getClass());
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Object must be a non-null MethodInvocation");
|
||||
|
||||
@@ -92,6 +92,9 @@ public class RoleVoter implements AccessDecisionVoter<Object> {
|
||||
}
|
||||
|
||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
|
||||
if(authentication == null) {
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
int result = ACCESS_ABSTAIN;
|
||||
Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
|
||||
|
||||
|
||||
+48
-15
@@ -19,8 +19,15 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Wraps a delegate {@link Callable} with logic for setting up a {@link SecurityContext} before invoking the delegate
|
||||
* {@link Callable} and then removing the {@link SecurityContext} after the delegate has completed.
|
||||
* <p>
|
||||
* Wraps a delegate {@link Callable} with logic for setting up a
|
||||
* {@link SecurityContext} before invoking the delegate {@link Callable} and
|
||||
* then removing the {@link SecurityContext} after the delegate has completed.
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is a {@link SecurityContext} that already exists, it will be
|
||||
* restored after the {@link #call()} method is invoked.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
@@ -29,41 +36,67 @@ public final class DelegatingSecurityContextCallable<V> implements Callable<V> {
|
||||
|
||||
private final Callable<V> delegate;
|
||||
|
||||
private final SecurityContext securityContext;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DelegatingSecurityContextCallable} with a specific {@link SecurityContext}.
|
||||
* @param delegate the delegate {@link DelegatingSecurityContextCallable} to run with the specified
|
||||
* {@link SecurityContext}. Cannot be null.
|
||||
* @param securityContext the {@link SecurityContext} to establish for the delegate {@link Callable}. Cannot be
|
||||
* null.
|
||||
* The {@link SecurityContext} that the delegate {@link Callable} will be
|
||||
* ran as.
|
||||
*/
|
||||
public DelegatingSecurityContextCallable(Callable<V> delegate, SecurityContext securityContext) {
|
||||
private final SecurityContext delegateSecurityContext;
|
||||
|
||||
/**
|
||||
* The {@link SecurityContext} that was on the {@link SecurityContextHolder}
|
||||
* prior to being set to the delegateSecurityContext.
|
||||
*/
|
||||
private SecurityContext originalSecurityContext;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DelegatingSecurityContextCallable} with a specific
|
||||
* {@link SecurityContext}.
|
||||
* @param delegate the delegate {@link DelegatingSecurityContextCallable} to run with
|
||||
* the specified {@link SecurityContext}. Cannot be null.
|
||||
* @param securityContext the {@link SecurityContext} to establish for the delegate
|
||||
* {@link Callable}. Cannot be null.
|
||||
*/
|
||||
public DelegatingSecurityContextCallable(Callable<V> delegate,
|
||||
SecurityContext securityContext) {
|
||||
Assert.notNull(delegate, "delegate cannot be null");
|
||||
Assert.notNull(securityContext, "securityContext cannot be null");
|
||||
this.delegate = delegate;
|
||||
this.securityContext = securityContext;
|
||||
this.delegateSecurityContext = securityContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DelegatingSecurityContextCallable} with the {@link SecurityContext} from the
|
||||
* {@link SecurityContextHolder}.
|
||||
* @param delegate the delegate {@link Callable} to run under the current {@link SecurityContext}. Cannot be null.
|
||||
* Creates a new {@link DelegatingSecurityContextCallable} with the
|
||||
* {@link SecurityContext} from the {@link SecurityContextHolder}.
|
||||
* @param delegate the delegate {@link Callable} to run under the current
|
||||
* {@link SecurityContext}. Cannot be null.
|
||||
*/
|
||||
public DelegatingSecurityContextCallable(Callable<V> delegate) {
|
||||
this(delegate, SecurityContextHolder.getContext());
|
||||
}
|
||||
|
||||
public V call() throws Exception {
|
||||
this.originalSecurityContext = SecurityContextHolder.getContext();
|
||||
|
||||
try {
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
SecurityContextHolder.setContext(delegateSecurityContext);
|
||||
return delegate.call();
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
|
||||
if(emptyContext.equals(originalSecurityContext)) {
|
||||
SecurityContextHolder.clearContext();
|
||||
} else {
|
||||
SecurityContextHolder.setContext(originalSecurityContext);
|
||||
}
|
||||
this.originalSecurityContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DelegatingSecurityContextCallable} and with the given {@link Callable} and
|
||||
* {@link SecurityContext}, but if the securityContext is null will defaults to the current {@link SecurityContext}
|
||||
|
||||
+48
-14
@@ -17,8 +17,16 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Wraps a delegate {@link Runnable} with logic for setting up a {@link SecurityContext} before invoking the delegate
|
||||
* {@link Runnable} and then removing the {@link SecurityContext} after the delegate has completed.
|
||||
* <p>
|
||||
* Wraps a delegate {@link Runnable} with logic for setting up a {@link SecurityContext}
|
||||
* before invoking the delegate {@link Runnable} and then removing the
|
||||
* {@link SecurityContext} after the delegate has completed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If there is a {@link SecurityContext} that already exists, it will be
|
||||
* restored after the {@link #run()} method is invoked.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
@@ -27,40 +35,66 @@ public final class DelegatingSecurityContextRunnable implements Runnable {
|
||||
|
||||
private final Runnable delegate;
|
||||
|
||||
private final SecurityContext securityContext;
|
||||
/**
|
||||
* The {@link SecurityContext} that the delegate {@link Runnable} will be
|
||||
* ran as.
|
||||
*/
|
||||
private final SecurityContext delegateSecurityContext;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DelegatingSecurityContextRunnable} with a specific {@link SecurityContext}.
|
||||
* @param delegate the delegate {@link Runnable} to run with the specified {@link SecurityContext}. Cannot be null.
|
||||
* @param securityContext the {@link SecurityContext} to establish for the delegate {@link Runnable}. Cannot be
|
||||
* null.
|
||||
* The {@link SecurityContext} that was on the {@link SecurityContextHolder}
|
||||
* prior to being set to the delegateSecurityContext.
|
||||
*/
|
||||
public DelegatingSecurityContextRunnable(Runnable delegate, SecurityContext securityContext) {
|
||||
private SecurityContext originalSecurityContext;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DelegatingSecurityContextRunnable} with a specific
|
||||
* {@link SecurityContext}.
|
||||
* @param delegate the delegate {@link Runnable} to run with the specified
|
||||
* {@link SecurityContext}. Cannot be null.
|
||||
* @param securityContext the {@link SecurityContext} to establish for the delegate
|
||||
* {@link Runnable}. Cannot be null.
|
||||
*/
|
||||
public DelegatingSecurityContextRunnable(Runnable delegate,
|
||||
SecurityContext securityContext) {
|
||||
Assert.notNull(delegate, "delegate cannot be null");
|
||||
Assert.notNull(securityContext, "securityContext cannot be null");
|
||||
this.delegate = delegate;
|
||||
this.securityContext = securityContext;
|
||||
this.delegateSecurityContext = securityContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DelegatingSecurityContextRunnable} with the {@link SecurityContext} from the
|
||||
* {@link SecurityContextHolder}.
|
||||
* @param delegate the delegate {@link Runnable} to run under the current {@link SecurityContext}. Cannot be null.
|
||||
* Creates a new {@link DelegatingSecurityContextRunnable} with the
|
||||
* {@link SecurityContext} from the {@link SecurityContextHolder}.
|
||||
* @param delegate the delegate {@link Runnable} to run under the current
|
||||
* {@link SecurityContext}. Cannot be null.
|
||||
*/
|
||||
public DelegatingSecurityContextRunnable(Runnable delegate) {
|
||||
this(delegate, SecurityContextHolder.getContext());
|
||||
}
|
||||
|
||||
public void run() {
|
||||
this.originalSecurityContext = SecurityContextHolder.getContext();
|
||||
|
||||
try {
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
SecurityContextHolder.setContext(delegateSecurityContext);
|
||||
delegate.run();
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
|
||||
if(emptyContext.equals(originalSecurityContext)) {
|
||||
SecurityContextHolder.clearContext();
|
||||
} else {
|
||||
SecurityContextHolder.setContext(originalSecurityContext);
|
||||
}
|
||||
this.originalSecurityContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating a {@link DelegatingSecurityContextRunnable}.
|
||||
*
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.context;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.SmartApplicationListener;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used for delegating to a number of SmartApplicationListener instances. This is useful when needing to register an
|
||||
* SmartApplicationListener with the ApplicationContext programmatically.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class DelegatingApplicationListener implements ApplicationListener<ApplicationEvent> {
|
||||
private List<SmartApplicationListener> listeners = new ArrayList<SmartApplicationListener>();
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if(event == null) {
|
||||
return;
|
||||
}
|
||||
for(SmartApplicationListener listener : listeners) {
|
||||
Object source = event.getSource();
|
||||
if(source != null && listener.supportsEventType(event.getClass()) && listener.supportsSourceType(source.getClass())) {
|
||||
listener.onApplicationEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new SmartApplicationListener to use.
|
||||
*
|
||||
* @param smartApplicationListener the SmartApplicationListener to use. Cannot be null.
|
||||
*/
|
||||
public void addListener(SmartApplicationListener smartApplicationListener) {
|
||||
Assert.notNull(smartApplicationListener, "smartApplicationListener cannot be null");
|
||||
listeners.add(smartApplicationListener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
package org.springframework.security.core;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Generic implementation of version comparison.
|
||||
*
|
||||
* NOTE: This is a copy from https://svn.apache.org/repos/asf/maven/maven-3/tags/maven-3.1.0/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java
|
||||
*
|
||||
* <p>Features:
|
||||
* <ul>
|
||||
* <li>mixing of '<code>-</code>' (dash) and '<code>.</code>' (dot) separators,</li>
|
||||
* <li>transition between characters and digits also constitutes a separator:
|
||||
* <code>1.0alpha1 => [1, 0, alpha, 1]</code></li>
|
||||
* <li>unlimited number of version components,</li>
|
||||
* <li>version components in the text can be digits or strings,</li>
|
||||
* <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering.
|
||||
* Well-known qualifiers (case insensitive) are:<ul>
|
||||
* <li><code>alpha</code> or <code>a</code></li>
|
||||
* <li><code>beta</code> or <code>b</code></li>
|
||||
* <li><code>milestone</code> or <code>m</code></li>
|
||||
* <li><code>rc</code> or <code>cr</code></li>
|
||||
* <li><code>snapshot</code></li>
|
||||
* <li><code>(the empty string)</code> or <code>ga</code> or <code>final</code></li>
|
||||
* <li><code>sp</code></li>
|
||||
* </ul>
|
||||
* Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
|
||||
* </li>
|
||||
* <li>a dash usually precedes a qualifier, and is always less important than something preceded with a dot.</li>
|
||||
* </ul></p>
|
||||
*
|
||||
* @see <a href="https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">"Versioning" on Maven Wiki</a>
|
||||
* @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
|
||||
* @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
|
||||
*/
|
||||
class ComparableVersion
|
||||
implements Comparable<ComparableVersion>
|
||||
{
|
||||
private String value;
|
||||
|
||||
private String canonical;
|
||||
|
||||
private ListItem items;
|
||||
|
||||
private interface Item
|
||||
{
|
||||
final int INTEGER_ITEM = 0;
|
||||
final int STRING_ITEM = 1;
|
||||
final int LIST_ITEM = 2;
|
||||
|
||||
int compareTo( Item item );
|
||||
|
||||
int getType();
|
||||
|
||||
boolean isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a numeric item in the version item list.
|
||||
*/
|
||||
private static class IntegerItem
|
||||
implements Item
|
||||
{
|
||||
private static final BigInteger BigInteger_ZERO = new BigInteger( "0" );
|
||||
|
||||
private final BigInteger value;
|
||||
|
||||
public static final IntegerItem ZERO = new IntegerItem();
|
||||
|
||||
private IntegerItem()
|
||||
{
|
||||
this.value = BigInteger_ZERO;
|
||||
}
|
||||
|
||||
public IntegerItem( String str )
|
||||
{
|
||||
this.value = new BigInteger( str );
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return INTEGER_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return BigInteger_ZERO.equals( value );
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
return BigInteger_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
|
||||
}
|
||||
|
||||
switch ( item.getType() )
|
||||
{
|
||||
case INTEGER_ITEM:
|
||||
return value.compareTo( ( (IntegerItem) item ).value );
|
||||
|
||||
case STRING_ITEM:
|
||||
return 1; // 1.1 > 1-sp
|
||||
|
||||
case LIST_ITEM:
|
||||
return 1; // 1.1 > 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a string in the version item list, usually a qualifier.
|
||||
*/
|
||||
private static class StringItem
|
||||
implements Item
|
||||
{
|
||||
private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" };
|
||||
|
||||
private static final List<String> _QUALIFIERS = Arrays.asList( QUALIFIERS );
|
||||
|
||||
private static final Properties ALIASES = new Properties();
|
||||
static
|
||||
{
|
||||
ALIASES.put( "ga", "" );
|
||||
ALIASES.put( "final", "" );
|
||||
ALIASES.put( "cr", "rc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
|
||||
* the version older than one without a qualifier, or more recent.
|
||||
*/
|
||||
private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) );
|
||||
|
||||
private String value;
|
||||
|
||||
public StringItem( String value, boolean followedByDigit )
|
||||
{
|
||||
if ( followedByDigit && value.length() == 1 )
|
||||
{
|
||||
// a1 = alpha-1, b1 = beta-1, m1 = milestone-1
|
||||
switch ( value.charAt( 0 ) )
|
||||
{
|
||||
case 'a':
|
||||
value = "alpha";
|
||||
break;
|
||||
case 'b':
|
||||
value = "beta";
|
||||
break;
|
||||
case 'm':
|
||||
value = "milestone";
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.value = ALIASES.getProperty( value , value );
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return STRING_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comparable value for a qualifier.
|
||||
*
|
||||
* This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical ordering.
|
||||
*
|
||||
* just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1
|
||||
* or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character,
|
||||
* so this is still fast. If more characters are needed then it requires a lexical sort anyway.
|
||||
*
|
||||
* @param qualifier
|
||||
* @return an equivalent value that can be used with lexical comparison
|
||||
*/
|
||||
public static String comparableQualifier( String qualifier )
|
||||
{
|
||||
int i = _QUALIFIERS.indexOf( qualifier );
|
||||
|
||||
return i == -1 ? ( _QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i );
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
// 1-rc < 1, 1-ga > 1
|
||||
return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX );
|
||||
}
|
||||
switch ( item.getType() )
|
||||
{
|
||||
case INTEGER_ITEM:
|
||||
return -1; // 1.any < 1.1 ?
|
||||
|
||||
case STRING_ITEM:
|
||||
return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) );
|
||||
|
||||
case LIST_ITEM:
|
||||
return -1; // 1.any < 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a version list item. This class is used both for the global item list and for sub-lists (which start
|
||||
* with '-(number)' in the version specification).
|
||||
*/
|
||||
private static class ListItem
|
||||
extends ArrayList<Item>
|
||||
implements Item
|
||||
{
|
||||
public int getType()
|
||||
{
|
||||
return LIST_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return ( size() == 0 );
|
||||
}
|
||||
|
||||
void normalize()
|
||||
{
|
||||
for( ListIterator<Item> iterator = listIterator( size() ); iterator.hasPrevious(); )
|
||||
{
|
||||
Item item = iterator.previous();
|
||||
if ( item.isNull() )
|
||||
{
|
||||
iterator.remove(); // remove null trailing items: 0, "", empty list
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
if ( size() == 0 )
|
||||
{
|
||||
return 0; // 1-0 = 1- (normalize) = 1
|
||||
}
|
||||
Item first = get( 0 );
|
||||
return first.compareTo( null );
|
||||
}
|
||||
switch ( item.getType() )
|
||||
{
|
||||
case INTEGER_ITEM:
|
||||
return -1; // 1-1 < 1.0.x
|
||||
|
||||
case STRING_ITEM:
|
||||
return 1; // 1-1 > 1-sp
|
||||
|
||||
case LIST_ITEM:
|
||||
Iterator<Item> left = iterator();
|
||||
Iterator<Item> right = ( (ListItem) item ).iterator();
|
||||
|
||||
while ( left.hasNext() || right.hasNext() )
|
||||
{
|
||||
Item l = left.hasNext() ? left.next() : null;
|
||||
Item r = right.hasNext() ? right.next() : null;
|
||||
|
||||
// if this is shorter, then invert the compare and mul with -1
|
||||
int result = l == null ? -1 * r.compareTo( l ) : l.compareTo( r );
|
||||
|
||||
if ( result != 0 )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder( "(" );
|
||||
for( Iterator<Item> iter = iterator(); iter.hasNext(); )
|
||||
{
|
||||
buffer.append( iter.next() );
|
||||
if ( iter.hasNext() )
|
||||
{
|
||||
buffer.append( ',' );
|
||||
}
|
||||
}
|
||||
buffer.append( ')' );
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public ComparableVersion( String version )
|
||||
{
|
||||
parseVersion( version );
|
||||
}
|
||||
|
||||
public final void parseVersion( String version )
|
||||
{
|
||||
this.value = version;
|
||||
|
||||
items = new ListItem();
|
||||
|
||||
version = version.toLowerCase( Locale.ENGLISH );
|
||||
|
||||
ListItem list = items;
|
||||
|
||||
Stack<Item> stack = new Stack<Item>();
|
||||
stack.push( list );
|
||||
|
||||
boolean isDigit = false;
|
||||
|
||||
int startIndex = 0;
|
||||
|
||||
for ( int i = 0; i < version.length(); i++ )
|
||||
{
|
||||
char c = version.charAt( i );
|
||||
|
||||
if ( c == '.' )
|
||||
{
|
||||
if ( i == startIndex )
|
||||
{
|
||||
list.add( IntegerItem.ZERO );
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
|
||||
}
|
||||
startIndex = i + 1;
|
||||
}
|
||||
else if ( c == '-' )
|
||||
{
|
||||
if ( i == startIndex )
|
||||
{
|
||||
list.add( IntegerItem.ZERO );
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
|
||||
}
|
||||
startIndex = i + 1;
|
||||
|
||||
if ( isDigit )
|
||||
{
|
||||
list.normalize(); // 1.0-* = 1-*
|
||||
|
||||
if ( ( i + 1 < version.length() ) && Character.isDigit( version.charAt( i + 1 ) ) )
|
||||
{
|
||||
// new ListItem only if previous were digits and new char is a digit,
|
||||
// ie need to differentiate only 1.1 from 1-1
|
||||
list.add( list = new ListItem() );
|
||||
|
||||
stack.push( list );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( Character.isDigit( c ) )
|
||||
{
|
||||
if ( !isDigit && i > startIndex )
|
||||
{
|
||||
list.add( new StringItem( version.substring( startIndex, i ), true ) );
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
isDigit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isDigit && i > startIndex )
|
||||
{
|
||||
list.add( parseItem( true, version.substring( startIndex, i ) ) );
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
isDigit = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( version.length() > startIndex )
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex ) ) );
|
||||
}
|
||||
|
||||
while ( !stack.isEmpty() )
|
||||
{
|
||||
list = (ListItem) stack.pop();
|
||||
list.normalize();
|
||||
}
|
||||
|
||||
canonical = items.toString();
|
||||
}
|
||||
|
||||
private static Item parseItem( boolean isDigit, String buf )
|
||||
{
|
||||
return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false );
|
||||
}
|
||||
|
||||
public int compareTo( ComparableVersion o )
|
||||
{
|
||||
return items.compareTo( o.items );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean equals( Object o )
|
||||
{
|
||||
return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical );
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return canonical.hashCode();
|
||||
}
|
||||
}
|
||||
+12
-3
@@ -23,7 +23,7 @@ public class SpringSecurityCoreVersion {
|
||||
*/
|
||||
public static final long SERIAL_VERSION_UID = 320L;
|
||||
|
||||
static final String MIN_SPRING_VERSION = "3.2.8.RELEASE";
|
||||
static final String MIN_SPRING_VERSION = "3.2.13.RELEASE";
|
||||
|
||||
static {
|
||||
performVersionChecks();
|
||||
@@ -38,6 +38,15 @@ public class SpringSecurityCoreVersion {
|
||||
* Performs version checks
|
||||
*/
|
||||
private static void performVersionChecks() {
|
||||
performVersionChecks(MIN_SPRING_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform version checks with specific min Spring Version
|
||||
*
|
||||
* @param minSpringVersion
|
||||
*/
|
||||
private static void performVersionChecks(String minSpringVersion) {
|
||||
// Check Spring Compatibility
|
||||
String springVersion = SpringVersion.getVersion();
|
||||
String version = getVersion();
|
||||
@@ -47,8 +56,8 @@ public class SpringSecurityCoreVersion {
|
||||
}
|
||||
|
||||
logger.info("You are running with Spring Security Core " + version);
|
||||
if (springVersion.compareTo(MIN_SPRING_VERSION) < 0) {
|
||||
logger.warn("**** You are advised to use Spring " + MIN_SPRING_VERSION +
|
||||
if (new ComparableVersion(springVersion).compareTo(new ComparableVersion(minSpringVersion)) < 0) {
|
||||
logger.warn("**** You are advised to use Spring " + minSpringVersion +
|
||||
" or later with this version. You are running: " + springVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
AbstractAccessDecisionManager.accessDenied=Zugriff verweigert
|
||||
AbstractLdapAuthenticationProvider.emptyPassword=Ung\u00FCltige Benutzerberechtigungen
|
||||
AbstractLdapAuthenticationProvider.emptyPassword=Ung\u00FCltige Anmeldedaten
|
||||
AbstractSecurityInterceptor.authenticationNotFound=Im SecurityContext wurde keine Authentifikation gefunden
|
||||
AbstractUserDetailsAuthenticationProvider.badCredentials=Ung\u00FCltige Benutzerberechtigungen
|
||||
AbstractUserDetailsAuthenticationProvider.credentialsExpired=Die G\u00FCltigkeit der Benutzerberechtigungen ist abgelaufen
|
||||
AbstractUserDetailsAuthenticationProvider.badCredentials=Ung\u00FCltige Anmeldedaten
|
||||
AbstractUserDetailsAuthenticationProvider.credentialsExpired=Die G\u00FCltigkeit der Anmeldedaten ist abgelaufen
|
||||
AbstractUserDetailsAuthenticationProvider.disabled=Der Benutzer ist deaktiviert
|
||||
AbstractUserDetailsAuthenticationProvider.expired=Die G\u00FCltigkeit des Benutzerkontos ist abgelaufen
|
||||
AbstractUserDetailsAuthenticationProvider.locked=Das Benutzerkonto ist gesperrt
|
||||
AbstractUserDetailsAuthenticationProvider.onlySupports=Nur UsernamePasswordAuthenticationToken wird unterst\u00FCtzt
|
||||
AccountStatusUserDetailsChecker.credentialsExpired=Die G\u00FCltigkeit der Benutzerberechtigungen ist abgelaufen
|
||||
AccountStatusUserDetailsChecker.credentialsExpired=Die G\u00FCltigkeit der Anmeldedaten ist abgelaufen
|
||||
AccountStatusUserDetailsChecker.disabled=Der Benutzer ist deaktiviert
|
||||
AccountStatusUserDetailsChecker.expired=Die G\u00FCltigkeit des Benutzerkontos ist abgelaufen
|
||||
AccountStatusUserDetailsChecker.locked=Das Benutzerkonto ist gesperrt
|
||||
AclEntryAfterInvocationProvider.noPermission=Authentifikation {0} hat KEINE Berechtigungen bez\u00FCglich des Dom\u00E4nen-Objekts {1}
|
||||
AnonymousAuthenticationProvider.incorrectKey=Das angegebene AnonymousAuthenticationToken enth\u00E4lt nicht den erwarteten Schl\u00FCssel
|
||||
BindAuthenticator.badCredentials=Ung\u00FCltige Benutzerberechtigungen
|
||||
BindAuthenticator.emptyPassword=Ung\u00FCltige Benutzerberechtigungen
|
||||
BindAuthenticator.badCredentials=Ung\u00FCltige Anmeldedaten
|
||||
BindAuthenticator.emptyPassword=Ung\u00FCltige Anmeldedaten
|
||||
CasAuthenticationProvider.incorrectKey=Das angegebene CasAuthenticationToken enth\u00E4lt nicht den erwarteten Schl\u00FCssel
|
||||
CasAuthenticationProvider.noServiceTicket=Es konnte kein CAS Service-Ticket zur Pr\u00FCfung geliefert werden
|
||||
ConcurrentSessionControlStrategy.exceededAllowed=Die maximale Sitzungs-Anzahl von {0} f\u00FCr diesen Nutzer wurde \u00FCberschritten
|
||||
@@ -30,14 +30,14 @@ DigestAuthenticationFilter.nonceNotTwoTokens=Nonce sollte zwei Elemente beinhalt
|
||||
DigestAuthenticationFilter.usernameNotFound=Benutzername {0} wurde nicht gefunden
|
||||
#JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
|
||||
#JdbcDaoImpl.notFound=User {0} not found
|
||||
LdapAuthenticationProvider.badCredentials=Ung\u00FCltige Benutzerberechtigungen
|
||||
LdapAuthenticationProvider.credentialsExpired=Die G\u00FCltigkeit der Benutzerberechtigungen ist abgelaufen
|
||||
LdapAuthenticationProvider.badCredentials=Ung\u00FCltige Anmeldedaten
|
||||
LdapAuthenticationProvider.credentialsExpired=Die G\u00FCltigkeit der Anmeldedaten ist abgelaufen
|
||||
LdapAuthenticationProvider.disabled=Der Benutzer ist deaktiviert
|
||||
LdapAuthenticationProvider.expired=Die G\u00FCltigkeit des Benutzerkontos ist abgelaufen
|
||||
LdapAuthenticationProvider.locked=Das Benutzerkonto ist gesperrt
|
||||
LdapAuthenticationProvider.emptyUsername=Ein leerer Benutzername ist nicht erlaubt
|
||||
LdapAuthenticationProvider.onlySupports=Nur UsernamePasswordAuthenticationToken wird unterst\u00FCtzt
|
||||
PasswordComparisonAuthenticator.badCredentials=Ung\u00FCltige Benutzerberechtigungen
|
||||
PasswordComparisonAuthenticator.badCredentials=Ung\u00FCltige Anmeldedaten
|
||||
#PersistentTokenBasedRememberMeServices.cookieStolen=Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
|
||||
ProviderManager.providerNotFound=F\u00FCr {0} wurde kein AuthenticationProvider gefunden
|
||||
RememberMeAuthenticationProvider.incorrectKey=Das angegebene RememberMeAuthenticationToken enth\u00E4lt nicht den erwarteten Schl\u00FCssel
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
AbstractAccessDecisionManager.accessDenied=Access is denied
|
||||
AbstractLdapAuthenticationProvider.emptyPassword=Empty Password
|
||||
AbstractSecurityInterceptor.authenticationNotFound=An Authentication object was not found in the SecurityContext
|
||||
AbstractUserDetailsAuthenticationProvider.badCredentials=Bad credentials
|
||||
AbstractUserDetailsAuthenticationProvider.credentialsExpired=User credentials have expired
|
||||
AbstractUserDetailsAuthenticationProvider.disabled=User is disabled
|
||||
AbstractUserDetailsAuthenticationProvider.expired=User account has expired
|
||||
AbstractUserDetailsAuthenticationProvider.locked=User account is locked
|
||||
AbstractUserDetailsAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported
|
||||
AccountStatusUserDetailsChecker.credentialsExpired=User credentials have expired
|
||||
AccountStatusUserDetailsChecker.disabled=User is disabled
|
||||
AccountStatusUserDetailsChecker.expired=User account has expired
|
||||
AccountStatusUserDetailsChecker.locked=User account is locked
|
||||
AclEntryAfterInvocationProvider.noPermission=Authentication {0} has NO permissions to the domain object {1}
|
||||
AnonymousAuthenticationProvider.incorrectKey=The presented AnonymousAuthenticationToken does not contain the expected key
|
||||
BindAuthenticator.badCredentials=Bad credentials
|
||||
BindAuthenticator.emptyPassword=Empty Password
|
||||
CasAuthenticationProvider.incorrectKey=The presented CasAuthenticationToken does not contain the expected key
|
||||
CasAuthenticationProvider.noServiceTicket=Failed to provide a CAS service ticket to validate
|
||||
ConcurrentSessionControlStrategy.exceededAllowed=Maximum sessions of {0} for this principal exceeded
|
||||
DigestAuthenticationFilter.incorrectRealm=Response realm name {0} does not match system realm name of {1}
|
||||
DigestAuthenticationFilter.incorrectResponse=Incorrect response
|
||||
DigestAuthenticationFilter.missingAuth=Missing mandatory digest value for 'auth' QOP; received header {0}
|
||||
DigestAuthenticationFilter.missingMandatory=Missing mandatory digest value; received header {0}
|
||||
DigestAuthenticationFilter.nonceCompromised=Nonce token compromised {0}
|
||||
DigestAuthenticationFilter.nonceEncoding=Nonce is not encoded in Base64; received nonce {0}
|
||||
DigestAuthenticationFilter.nonceExpired=Nonce has expired/timed out
|
||||
DigestAuthenticationFilter.nonceNotNumeric=Nonce token should have yielded a numeric first token, but was {0}
|
||||
DigestAuthenticationFilter.nonceNotTwoTokens=Nonce should have yielded two tokens but was {0}
|
||||
DigestAuthenticationFilter.usernameNotFound=Username {0} not found
|
||||
JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
|
||||
JdbcDaoImpl.notFound=User {0} not found
|
||||
LdapAuthenticationProvider.badCredentials=Bad credentials
|
||||
LdapAuthenticationProvider.credentialsExpired=User credentials have expired
|
||||
LdapAuthenticationProvider.disabled=User is disabled
|
||||
LdapAuthenticationProvider.expired=User account has expired
|
||||
LdapAuthenticationProvider.locked=User account is locked
|
||||
LdapAuthenticationProvider.emptyUsername=Empty username not allowed
|
||||
LdapAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported
|
||||
PasswordComparisonAuthenticator.badCredentials=Bad credentials
|
||||
PersistentTokenBasedRememberMeServices.cookieStolen=Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
|
||||
ProviderManager.providerNotFound=No AuthenticationProvider found for {0}
|
||||
RememberMeAuthenticationProvider.incorrectKey=The presented RememberMeAuthenticationToken does not contain the expected key
|
||||
RunAsImplAuthenticationProvider.incorrectKey=The presented RunAsUserToken does not contain the expected key
|
||||
SubjectDnX509PrincipalExtractor.noMatching=No matching pattern was found in subjectDN: {0}
|
||||
SwitchUserFilter.noCurrentUser=No current user associated with this request
|
||||
SwitchUserFilter.noOriginalAuthentication=Could not find original Authentication object
|
||||
+124
-3
@@ -1,5 +1,21 @@
|
||||
/*
|
||||
* 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.access.annotation;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -7,10 +23,10 @@ import java.util.Collection;
|
||||
import javax.annotation.security.PermitAll;
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
@@ -58,7 +74,87 @@ public class Jsr250MethodDefinitionSourceTests {
|
||||
assertEquals("ADMIN", accessAttributes.toArray()[0].toString());
|
||||
}
|
||||
|
||||
//~ Inner Classes ======================================================================================================
|
||||
// JSR-250 Spec Tests
|
||||
|
||||
/**
|
||||
* Class-level annotations only affect the class they annotate and their members, that
|
||||
* is, its methods and fields. They never affect a member declared by a superclass,
|
||||
* even if it is not hidden or overridden by the class in question.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void classLevelAnnotationsOnlyAffectTheClassTheyAnnotateAndTheirMembers() throws Exception {
|
||||
Child target = new Child();
|
||||
MockMethodInvocation mi = new MockMethodInvocation(target, target.getClass(), "notOverriden");
|
||||
|
||||
Collection<ConfigAttribute> accessAttributes = mds.getAttributes(mi);
|
||||
assertThat(accessAttributes).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void classLevelAnnotationsOnlyAffectTheClassTheyAnnotateAndTheirMembersOverriden() throws Exception {
|
||||
Child target = new Child();
|
||||
MockMethodInvocation mi = new MockMethodInvocation(target, target.getClass(), "overriden");
|
||||
|
||||
Collection<ConfigAttribute> accessAttributes = mds.getAttributes(mi);
|
||||
assertEquals(1, accessAttributes.size());
|
||||
assertEquals("DERIVED", accessAttributes.toArray()[0].toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void classLevelAnnotationsImpactMemberLevel() throws Exception {
|
||||
Child target = new Child();
|
||||
MockMethodInvocation mi = new MockMethodInvocation(target, target.getClass(), "defaults");
|
||||
|
||||
Collection<ConfigAttribute> accessAttributes = mds.getAttributes(mi);
|
||||
assertEquals(1, accessAttributes.size());
|
||||
assertEquals("DERIVED", accessAttributes.toArray()[0].toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void classLevelAnnotationsIgnoredByExplicitMemberAnnotation() throws Exception {
|
||||
Child target = new Child();
|
||||
MockMethodInvocation mi = new MockMethodInvocation(target, target.getClass(), "explicitMethod");
|
||||
|
||||
Collection<ConfigAttribute> accessAttributes = mds.getAttributes(mi);
|
||||
assertEquals(1, accessAttributes.size());
|
||||
assertEquals("EXPLICIT", accessAttributes.toArray()[0].toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* The interfaces implemented by a class never contribute annotations to the class
|
||||
* itself or any of its members.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void interfacesNeverContributeAnnotationsMethodLevel() throws Exception {
|
||||
Parent target = new Parent();
|
||||
MockMethodInvocation mi = new MockMethodInvocation(target, target.getClass(), "interfaceMethod");
|
||||
|
||||
Collection<ConfigAttribute> accessAttributes = mds.getAttributes(mi);
|
||||
assertThat(accessAttributes).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interfacesNeverContributeAnnotationsClassLevel() throws Exception {
|
||||
Parent target = new Parent();
|
||||
MockMethodInvocation mi = new MockMethodInvocation(target, target.getClass(), "notOverriden");
|
||||
|
||||
Collection<ConfigAttribute> accessAttributes = mds.getAttributes(mi);
|
||||
assertThat(accessAttributes).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annotationsOnOverriddenMemberIgnored() throws Exception {
|
||||
Child target = new Child();
|
||||
MockMethodInvocation mi = new MockMethodInvocation(target, target.getClass(), "overridenIgnored");
|
||||
|
||||
Collection<ConfigAttribute> accessAttributes = mds.getAttributes(mi);
|
||||
assertEquals(1, accessAttributes.size());
|
||||
assertEquals("DERIVED", accessAttributes.toArray()[0].toString());
|
||||
}
|
||||
|
||||
//~ Inner Classes ======================================================================================================
|
||||
|
||||
public static class A {
|
||||
|
||||
@@ -78,4 +174,29 @@ public class Jsr250MethodDefinitionSourceTests {
|
||||
@RolesAllowed("ADMIN")
|
||||
public void adminMethod() {}
|
||||
}
|
||||
|
||||
// JSR-250 Spec
|
||||
|
||||
@RolesAllowed("IPARENT")
|
||||
interface IParent {
|
||||
@RolesAllowed("INTERFACEMETHOD")
|
||||
void interfaceMethod();
|
||||
}
|
||||
|
||||
static class Parent implements IParent {
|
||||
public void interfaceMethod() {}
|
||||
public void notOverriden() {}
|
||||
public void overriden() {}
|
||||
@RolesAllowed("OVERRIDENIGNORED")
|
||||
public void overridenIgnored() {}
|
||||
}
|
||||
|
||||
@RolesAllowed("DERIVED")
|
||||
class Child extends Parent {
|
||||
public void overriden() {}
|
||||
public void overridenIgnored() {}
|
||||
public void defaults() {}
|
||||
@RolesAllowed("EXPLICIT")
|
||||
public void explicitMethod() {}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-8
@@ -14,13 +14,11 @@
|
||||
*/
|
||||
package org.springframework.security.access.annotation;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
@@ -28,7 +26,17 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.annotation.sec2150.MethodInvocationFactory;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
|
||||
/**
|
||||
@@ -178,6 +186,14 @@ public class SecuredAnnotationSecurityMetadataSourceTests {
|
||||
assertEquals("CUSTOM", attrs[0].getAttribute());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void proxyFactoryInterfaceAttributesFound() throws Exception {
|
||||
MockMethodInvocation mi = MethodInvocationFactory.createSec2150MethodInvocation();
|
||||
Collection<ConfigAttribute> attributes = mds.getAttributes(mi);
|
||||
assertThat(attributes.size()).isEqualTo(1);
|
||||
assertThat(attributes).onProperty("attribute").containsOnly("ROLE_PERSON");
|
||||
}
|
||||
|
||||
// Inner classes
|
||||
class Department extends Entity {
|
||||
public Department(String name) {
|
||||
@@ -190,6 +206,7 @@ public class SecuredAnnotationSecurityMetadataSourceTests {
|
||||
Department someUserMethod3(Department dept);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
class DepartmentServiceImpl extends BusinessServiceImpl<Department> implements DepartmentService {
|
||||
@Secured({"ROLE_ADMIN"})
|
||||
public Department someUserMethod3(final Department dept) {
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.access.annotation.sec2150;
|
||||
|
||||
public interface CrudRepository {
|
||||
|
||||
Iterable<Object> findAll();
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.access.annotation.sec2150;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
|
||||
public class MethodInvocationFactory {
|
||||
|
||||
/**
|
||||
* In order to reproduce the bug for SEC-2150, we must have a proxy object
|
||||
* that implements TargetSourceAware and implements our annotated interface.
|
||||
*
|
||||
* @return
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public static MockMethodInvocation createSec2150MethodInvocation() throws NoSuchMethodException {
|
||||
ProxyFactory factory = new ProxyFactory(new Class[] {PersonRepository.class});
|
||||
factory.setTargetClass(CrudRepository.class);
|
||||
PersonRepository repository = (PersonRepository) factory.getProxy();
|
||||
return new MockMethodInvocation(repository, PersonRepository.class , "findAll");
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.access.annotation.sec2150;
|
||||
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
/**
|
||||
* Note that JSR-256 states that annotations have no impact when placed on
|
||||
* interfaces, so SEC-2150 is not impacted by JSR-256 support.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
@Secured("ROLE_PERSON")
|
||||
@PreAuthorize("hasRole('ROLE_PERSON')")
|
||||
public interface PersonRepository extends CrudRepository {}
|
||||
+18
-1
@@ -1,23 +1,31 @@
|
||||
package org.springframework.security.access.expression.method;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.annotation.sec2150.MethodInvocationFactory;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.access.prepost.PreFilter;
|
||||
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -148,6 +156,15 @@ public class PrePostAnnotationSecurityMetadataSourceTests {
|
||||
assertEquals(1, attrs.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void proxyFactoryInterfaceAttributesFound() throws Exception {
|
||||
MockMethodInvocation mi = MethodInvocationFactory.createSec2150MethodInvocation();
|
||||
Collection<ConfigAttribute> attributes = mds.getAttributes(mi);
|
||||
assertThat(attributes.size()).isEqualTo(1);
|
||||
Expression expression = (Expression) ReflectionTestUtils.getField(attributes.iterator().next(),"authorizeExpression");
|
||||
assertThat(expression.getExpressionString()).isEqualTo("hasRole('ROLE_PERSON')");
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
public static interface ReturnVoid {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.springframework.security.access.vote;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.fest.assertions.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
@@ -21,4 +22,13 @@ public class RoleVoterTests {
|
||||
// Vote on attribute list that has two attributes A and C (i.e. only one matching)
|
||||
assertEquals(AccessDecisionVoter.ACCESS_GRANTED, voter.vote(userAB, this, SecurityConfig.createList("A","C")));
|
||||
}
|
||||
|
||||
// SEC-3128
|
||||
@Test
|
||||
public void nullAuthenticationDenies() {
|
||||
RoleVoter voter = new RoleVoter();
|
||||
voter.setRolePrefix("");
|
||||
Authentication notAuthenitcated = null;
|
||||
assertThat(voter.vote(notAuthenitcated, this, SecurityConfig.createList("A"))).isEqualTo(AccessDecisionVoter.ACCESS_DENIED);
|
||||
}
|
||||
}
|
||||
|
||||
+46
-9
@@ -17,6 +17,9 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -45,9 +48,14 @@ public class DelegatingSecurityContextCallableTests {
|
||||
|
||||
private Callable<Object> callable;
|
||||
|
||||
private ExecutorService executor;
|
||||
|
||||
private SecurityContext originalSecurityContext;
|
||||
|
||||
@Before
|
||||
@SuppressWarnings("serial")
|
||||
public void setUp() throws Exception {
|
||||
originalSecurityContext = SecurityContextHolder.createEmptyContext();
|
||||
when(delegate.call()).thenAnswer(new Returns(callableResult) {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
@@ -55,6 +63,7 @@ public class DelegatingSecurityContextCallableTests {
|
||||
return super.answer(invocation);
|
||||
}
|
||||
});
|
||||
executor = Executors.newFixedThreadPool(1);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -88,15 +97,27 @@ public class DelegatingSecurityContextCallableTests {
|
||||
|
||||
@Test
|
||||
public void call() throws Exception {
|
||||
callable = new DelegatingSecurityContextCallable<Object>(delegate, securityContext);
|
||||
assertWrapped(callable.call());
|
||||
callable = new DelegatingSecurityContextCallable<Object>(delegate,
|
||||
securityContext);
|
||||
assertWrapped(callable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callDefaultSecurityContext() throws Exception {
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
callable = new DelegatingSecurityContextCallable<Object>(delegate);
|
||||
SecurityContextHolder.clearContext(); // ensure callable is what sets up the SecurityContextHolder
|
||||
SecurityContextHolder.clearContext(); // ensure callable is what sets up the
|
||||
// SecurityContextHolder
|
||||
assertWrapped(callable);
|
||||
}
|
||||
|
||||
// SEC-3031
|
||||
@Test
|
||||
public void callOnSameThread() throws Exception {
|
||||
originalSecurityContext = securityContext;
|
||||
SecurityContextHolder.setContext(originalSecurityContext);
|
||||
callable = new DelegatingSecurityContextCallable<Object>(delegate,
|
||||
securityContext);
|
||||
assertWrapped(callable.call());
|
||||
}
|
||||
|
||||
@@ -116,19 +137,35 @@ public class DelegatingSecurityContextCallableTests {
|
||||
public void createNullSecurityContext() throws Exception {
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
callable = DelegatingSecurityContextCallable.create(delegate, null);
|
||||
SecurityContextHolder.clearContext(); // ensure callable is what sets up the SecurityContextHolder
|
||||
assertWrapped(callable.call());
|
||||
SecurityContextHolder.clearContext(); // ensure callable is what sets up the
|
||||
// SecurityContextHolder
|
||||
assertWrapped(callable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void create() throws Exception {
|
||||
callable = DelegatingSecurityContextCallable.create(delegate, securityContext);
|
||||
assertWrapped(callable.call());
|
||||
assertWrapped(callable);
|
||||
}
|
||||
|
||||
private void assertWrapped(Object actualResult) throws Exception {
|
||||
assertThat(actualResult).isEqualTo(callableResult);
|
||||
// --- toString
|
||||
|
||||
// SEC-2682
|
||||
@Test
|
||||
public void toStringDelegates() {
|
||||
callable = new DelegatingSecurityContextCallable<Object>(delegate,
|
||||
securityContext);
|
||||
assertThat(callable.toString()).isEqualTo(delegate.toString());
|
||||
}
|
||||
|
||||
private void assertWrapped(Callable<Object> callable) throws Exception {
|
||||
Future<Object> submit = executor.submit(callable);
|
||||
assertWrapped(submit.get());
|
||||
}
|
||||
|
||||
private void assertWrapped(Object callableResult) throws Exception {
|
||||
verify(delegate).call();
|
||||
assertThat(SecurityContextHolder.getContext()).isEqualTo(SecurityContextHolder.createEmptyContext());
|
||||
assertThat(SecurityContextHolder.getContext()).isEqualTo(
|
||||
originalSecurityContext);
|
||||
}
|
||||
}
|
||||
+53
-16
@@ -16,6 +16,10 @@ import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -24,6 +28,8 @@ import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.support.ExecutorServiceAdapter;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
@@ -43,15 +49,21 @@ public class DelegatingSecurityContextRunnableTests {
|
||||
|
||||
private Runnable runnable;
|
||||
|
||||
private ExecutorService executor;
|
||||
|
||||
private SecurityContext originalSecurityContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
originalSecurityContext = SecurityContextHolder.createEmptyContext();
|
||||
doAnswer(new Answer<Object>() {
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
assertThat(SecurityContextHolder.getContext()).isEqualTo(securityContext);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.when(delegate).run();
|
||||
}).when(delegate).run();
|
||||
|
||||
executor = Executors.newFixedThreadPool(1);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -86,17 +98,27 @@ public class DelegatingSecurityContextRunnableTests {
|
||||
@Test
|
||||
public void call() throws Exception {
|
||||
runnable = new DelegatingSecurityContextRunnable(delegate, securityContext);
|
||||
runnable.run();
|
||||
assertWrapped();
|
||||
assertWrapped(runnable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callDefaultSecurityContext() throws Exception {
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
runnable = new DelegatingSecurityContextRunnable(delegate);
|
||||
SecurityContextHolder.clearContext(); // ensure runnable is what sets up the SecurityContextHolder
|
||||
runnable.run();
|
||||
assertWrapped();
|
||||
SecurityContextHolder.clearContext(); // ensure runnable is what sets up the
|
||||
// SecurityContextHolder
|
||||
assertWrapped(runnable);
|
||||
}
|
||||
|
||||
// SEC-3031
|
||||
@Test
|
||||
public void callOnSameThread() throws Exception {
|
||||
originalSecurityContext = securityContext;
|
||||
SecurityContextHolder.setContext(originalSecurityContext);
|
||||
executor = synchronousExecutor();
|
||||
runnable = new DelegatingSecurityContextRunnable(delegate,
|
||||
securityContext);
|
||||
assertWrapped(runnable);
|
||||
}
|
||||
|
||||
// --- create ---
|
||||
@@ -112,23 +134,38 @@ public class DelegatingSecurityContextRunnableTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNullSecurityContext() {
|
||||
public void createNullSecurityContext() throws Exception {
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
runnable = DelegatingSecurityContextRunnable.create(delegate, null);
|
||||
SecurityContextHolder.clearContext(); // ensure runnable is what sets up the SecurityContextHolder
|
||||
runnable.run();
|
||||
assertWrapped();
|
||||
SecurityContextHolder.clearContext(); // ensure runnable is what sets up the
|
||||
// SecurityContextHolder
|
||||
assertWrapped(runnable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void create() {
|
||||
public void create() throws Exception {
|
||||
runnable = DelegatingSecurityContextRunnable.create(delegate, securityContext);
|
||||
runnable.run();
|
||||
assertWrapped();
|
||||
assertWrapped(runnable);
|
||||
}
|
||||
|
||||
private void assertWrapped() {
|
||||
// --- toString
|
||||
|
||||
// SEC-2682
|
||||
@Test
|
||||
public void toStringDelegates() {
|
||||
runnable = new DelegatingSecurityContextRunnable(delegate, securityContext);
|
||||
assertThat(runnable.toString()).isEqualTo(delegate.toString());
|
||||
}
|
||||
|
||||
private void assertWrapped(Runnable runnable) throws Exception {
|
||||
Future<?> submit = executor.submit(runnable);
|
||||
submit.get();
|
||||
verify(delegate).run();
|
||||
assertThat(SecurityContextHolder.getContext()).isEqualTo(SecurityContextHolder.createEmptyContext());
|
||||
assertThat(SecurityContextHolder.getContext()).isEqualTo(
|
||||
originalSecurityContext);
|
||||
}
|
||||
|
||||
private static ExecutorService synchronousExecutor() {
|
||||
return new ExecutorServiceAdapter(new SyncTaskExecutor());
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package org.springframework.security.context;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.SmartApplicationListener;
|
||||
import org.springframework.security.core.session.SessionDestroyedEvent;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DelegatingApplicationListenerTests {
|
||||
@Mock
|
||||
SmartApplicationListener delegate;
|
||||
|
||||
ApplicationEvent event;
|
||||
|
||||
DelegatingApplicationListener listener;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
event = new ApplicationEvent(this) {};
|
||||
listener = new DelegatingApplicationListener();
|
||||
listener.addListener(delegate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processEventNull() {
|
||||
listener.onApplicationEvent(null);
|
||||
|
||||
verify(delegate,never()).onApplicationEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processEventSuccess() {
|
||||
when(delegate.supportsEventType(event.getClass())).thenReturn(true);
|
||||
when(delegate.supportsSourceType(event.getSource().getClass())).thenReturn(true);
|
||||
listener.onApplicationEvent(event);
|
||||
|
||||
verify(delegate).onApplicationEvent(event);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processEventEventTypeNotSupported() {
|
||||
when(delegate.supportsSourceType(event.getSource().getClass())).thenReturn(true);
|
||||
listener.onApplicationEvent(event);
|
||||
|
||||
verify(delegate,never()).onApplicationEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processEventSourceTypeNotSupported() {
|
||||
when(delegate.supportsEventType(event.getClass())).thenReturn(true);
|
||||
listener.onApplicationEvent(event);
|
||||
|
||||
verify(delegate,never()).onApplicationEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void addNull() {
|
||||
listener.addListener(null);
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -34,6 +34,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
import org.springframework.core.SpringVersion;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Checks that the embedded version information is up to date.
|
||||
@@ -128,6 +129,20 @@ public class SpringSecurityCoreVersionTests {
|
||||
verify(logger, never()).warn(any());
|
||||
}
|
||||
|
||||
// SEC-2697
|
||||
@Test
|
||||
public void noWarnIfSpringPatchVersionDoubleDigits() throws Exception {
|
||||
String minSpringVersion = "3.2.8.RELEASE";
|
||||
spy(SpringSecurityCoreVersion.class);
|
||||
spy(SpringVersion.class);
|
||||
when(SpringSecurityCoreVersion.getVersion()).thenReturn("3.2.0.RELEASE");
|
||||
when(SpringVersion.getVersion()).thenReturn("3.2.10.RELEASE");
|
||||
|
||||
performChecks(minSpringVersion);
|
||||
|
||||
verify(logger, never()).warn(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noLoggingIfPropertySet() throws Exception {
|
||||
spy(SpringSecurityCoreVersion.class);
|
||||
@@ -149,4 +164,7 @@ public class SpringSecurityCoreVersionTests {
|
||||
Whitebox.invokeMethod(SpringSecurityCoreVersion.class, "performVersionChecks");
|
||||
}
|
||||
|
||||
private void performChecks(String minSpringVersion) throws Exception {
|
||||
Whitebox.invokeMethod(SpringSecurityCoreVersion.class, "performVersionChecks", minSpringVersion);
|
||||
}
|
||||
}
|
||||
|
||||
+24
-5
@@ -23,16 +23,18 @@ import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link org.springframework.security.core.SpringSecurityMessageSource}.
|
||||
*/
|
||||
public class SpringSecurityMessageSourceTests extends TestCase {
|
||||
//~ Methods ========================================================================================================
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void testOperation() {
|
||||
SpringSecurityMessageSource msgs = new SpringSecurityMessageSource();
|
||||
assertEquals("\u4E0D\u5141\u8BB8\u8BBF\u95EE", msgs.getMessage("AbstractAccessDecisionManager.accessDenied", null, Locale.SIMPLIFIED_CHINESE));
|
||||
assertEquals("\u4E0D\u5141\u8BB8\u8BBF\u95EE", msgs.getMessage(
|
||||
"AbstractAccessDecisionManager.accessDenied", null,
|
||||
Locale.SIMPLIFIED_CHINESE));
|
||||
}
|
||||
|
||||
public void testReplacableLookup() {
|
||||
@@ -42,11 +44,28 @@ public class SpringSecurityMessageSourceTests extends TestCase {
|
||||
|
||||
// Cause a message to be generated
|
||||
MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
assertEquals("Le jeton nonce est compromis FOOBAR",
|
||||
messages.getMessage("DigestAuthenticationFilter.nonceCompromised", new Object[] {"FOOBAR"},
|
||||
assertEquals("Le jeton nonce est compromis FOOBAR", messages.getMessage(
|
||||
"DigestAuthenticationFilter.nonceCompromised", new Object[] { "FOOBAR" },
|
||||
"ERROR - FAILED TO LOOKUP"));
|
||||
|
||||
// Revert to original Locale
|
||||
LocaleContextHolder.setLocale(before);
|
||||
}
|
||||
|
||||
// SEC-3013
|
||||
public void germanSystemLocaleWithEnglishLocaleContextHolder() {
|
||||
Locale beforeSystem = Locale.getDefault();
|
||||
Locale.setDefault(Locale.GERMAN);
|
||||
|
||||
Locale beforeHolder = LocaleContextHolder.getLocale();
|
||||
LocaleContextHolder.setLocale(Locale.US);
|
||||
|
||||
MessageSourceAccessor msgs = SpringSecurityMessageSource.getAccessor();
|
||||
assertEquals("Access is denied", msgs.getMessage(
|
||||
"AbstractAccessDecisionManager.accessDenied", "Ooops"));
|
||||
|
||||
// Revert to original Locale
|
||||
Locale.setDefault(beforeSystem);
|
||||
LocaleContextHolder.setLocale(beforeHolder);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-21
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>spring-security-crypto</name>
|
||||
<description>spring-security-crypto</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,25 +42,7 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
@@ -89,7 +71,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -101,7 +83,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+73
-18
@@ -22,19 +22,24 @@ import static org.springframework.security.crypto.encrypt.CipherUtils.newSecretK
|
||||
import static org.springframework.security.crypto.util.EncodingUtils.concatenate;
|
||||
import static org.springframework.security.crypto.util.EncodingUtils.subArray;
|
||||
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.springframework.security.crypto.codec.Hex;
|
||||
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
|
||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||
|
||||
/**
|
||||
* Encryptor that uses 256-bit AES encryption.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Dave Syer
|
||||
*/
|
||||
final class AesBytesEncryptor implements BytesEncryptor {
|
||||
|
||||
@@ -46,58 +51,108 @@ final class AesBytesEncryptor implements BytesEncryptor {
|
||||
|
||||
private final BytesKeyGenerator ivGenerator;
|
||||
|
||||
private CipherAlgorithm alg;
|
||||
|
||||
private static final String AES_CBC_ALGORITHM = "AES/CBC/PKCS5Padding";
|
||||
|
||||
private static final String AES_GCM_ALGORITHM = "AES/GCM/NoPadding";
|
||||
|
||||
public enum CipherAlgorithm {
|
||||
|
||||
CBC(AES_CBC_ALGORITHM, NULL_IV_GENERATOR), GCM(AES_GCM_ALGORITHM, KeyGenerators
|
||||
.secureRandom(16));
|
||||
|
||||
private BytesKeyGenerator ivGenerator;
|
||||
private String name;
|
||||
|
||||
private CipherAlgorithm(String name, BytesKeyGenerator ivGenerator) {
|
||||
this.name = name;
|
||||
this.ivGenerator = ivGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public AlgorithmParameterSpec getParameterSpec(byte[] iv) {
|
||||
return this == CBC ? new IvParameterSpec(iv) : new GCMParameterSpec(128, iv);
|
||||
}
|
||||
|
||||
public Cipher createCipher() {
|
||||
return newCipher(this.toString());
|
||||
}
|
||||
|
||||
public BytesKeyGenerator defaultIvGenerator() {
|
||||
return this.ivGenerator;
|
||||
}
|
||||
}
|
||||
|
||||
public AesBytesEncryptor(String password, CharSequence salt) {
|
||||
this(password, salt, null);
|
||||
}
|
||||
|
||||
public AesBytesEncryptor(String password, CharSequence salt, BytesKeyGenerator ivGenerator) {
|
||||
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt), 1024, 256);
|
||||
public AesBytesEncryptor(String password, CharSequence salt,
|
||||
BytesKeyGenerator ivGenerator) {
|
||||
this(password, salt, ivGenerator, CipherAlgorithm.CBC);
|
||||
}
|
||||
|
||||
public AesBytesEncryptor(String password, CharSequence salt,
|
||||
BytesKeyGenerator ivGenerator, CipherAlgorithm alg) {
|
||||
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt),
|
||||
1024, 256);
|
||||
SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
|
||||
this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
|
||||
encryptor = newCipher(AES_ALGORITHM);
|
||||
decryptor = newCipher(AES_ALGORITHM);
|
||||
this.ivGenerator = ivGenerator != null ? ivGenerator : NULL_IV_GENERATOR;
|
||||
this.alg = alg;
|
||||
this.encryptor = alg.createCipher();
|
||||
this.decryptor = alg.createCipher();
|
||||
this.ivGenerator = ivGenerator != null ? ivGenerator : alg.defaultIvGenerator();
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] bytes) {
|
||||
synchronized (encryptor) {
|
||||
byte[] iv = ivGenerator.generateKey();
|
||||
initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
||||
byte[] encrypted = doFinal(encryptor, bytes);
|
||||
return ivGenerator != NULL_IV_GENERATOR ? concatenate(iv, encrypted) : encrypted;
|
||||
synchronized (this.encryptor) {
|
||||
byte[] iv = this.ivGenerator.generateKey();
|
||||
initCipher(this.encryptor, Cipher.ENCRYPT_MODE, this.secretKey,
|
||||
this.alg.getParameterSpec(iv));
|
||||
byte[] encrypted = doFinal(this.encryptor, bytes);
|
||||
return this.ivGenerator != NULL_IV_GENERATOR ? concatenate(iv, encrypted)
|
||||
: encrypted;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] encryptedBytes) {
|
||||
synchronized (decryptor) {
|
||||
synchronized (this.decryptor) {
|
||||
byte[] iv = iv(encryptedBytes);
|
||||
initCipher(decryptor, Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
||||
return doFinal(decryptor, ivGenerator != NULL_IV_GENERATOR ? encrypted(encryptedBytes, iv.length) : encryptedBytes);
|
||||
initCipher(this.decryptor, Cipher.DECRYPT_MODE, this.secretKey,
|
||||
this.alg.getParameterSpec(iv));
|
||||
return doFinal(
|
||||
this.decryptor,
|
||||
this.ivGenerator != NULL_IV_GENERATOR ? encrypted(encryptedBytes,
|
||||
iv.length) : encryptedBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private byte[] iv(byte[] encrypted) {
|
||||
return ivGenerator != NULL_IV_GENERATOR ? subArray(encrypted, 0, ivGenerator.getKeyLength()) : NULL_IV_GENERATOR.generateKey();
|
||||
return this.ivGenerator != NULL_IV_GENERATOR ? subArray(encrypted, 0,
|
||||
this.ivGenerator.getKeyLength()) : NULL_IV_GENERATOR.generateKey();
|
||||
}
|
||||
|
||||
private byte[] encrypted(byte[] encryptedBytes, int ivLength) {
|
||||
return subArray(encryptedBytes, ivLength, encryptedBytes.length);
|
||||
}
|
||||
|
||||
private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
|
||||
|
||||
private static final BytesKeyGenerator NULL_IV_GENERATOR = new BytesKeyGenerator() {
|
||||
|
||||
private final byte[] VALUE = new byte[16];
|
||||
|
||||
public int getKeyLength() {
|
||||
return VALUE.length;
|
||||
return this.VALUE.length;
|
||||
}
|
||||
|
||||
public byte[] generateKey() {
|
||||
return VALUE;
|
||||
return this.VALUE;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -15,57 +15,100 @@
|
||||
*/
|
||||
package org.springframework.security.crypto.encrypt;
|
||||
|
||||
import org.springframework.security.crypto.encrypt.AesBytesEncryptor.CipherAlgorithm;
|
||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||
|
||||
/**
|
||||
* Factory for commonly used encryptors.
|
||||
* Defines the public API for constructing {@link BytesEncryptor} and {@link TextEncryptor} implementations.
|
||||
* Factory for commonly used encryptors. Defines the public API for constructing
|
||||
* {@link BytesEncryptor} and {@link TextEncryptor} implementations.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class Encryptors {
|
||||
|
||||
/**
|
||||
* Creates a standard password-based bytes encryptor using 256 bit AES encryption.
|
||||
* Derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2).
|
||||
* Salts the password to prevent dictionary attacks against the key.
|
||||
* The provided salt is expected to be hex-encoded; it should be random and at least 8 bytes in length.
|
||||
* Also applies a random 16 byte initialization vector to ensure each encrypted message will be unique.
|
||||
* Requires Java 6.
|
||||
* Creates a standard password-based bytes encryptor using 256 bit AES encryption with
|
||||
* Galois Counter Mode (GCM). Derives the secret key using PKCS #5's PBKDF2
|
||||
* (Password-Based Key Derivation Function #2). Salts the password to prevent
|
||||
* dictionary attacks against the key. The provided salt is expected to be
|
||||
* hex-encoded; it should be random and at least 8 bytes in length. Also applies a
|
||||
* random 16 byte initialization vector to ensure each encrypted message will be
|
||||
* unique. Requires Java 6.
|
||||
*
|
||||
* @param password the password used to generate the encryptor's secret key; should not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the key
|
||||
* @param password the password used to generate the encryptor's secret key; should
|
||||
* not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||
* key
|
||||
*
|
||||
* @see #standard(CharSequence, CharSequence) which uses the slightly weaker CBC mode
|
||||
* (instead of GCM)
|
||||
*/
|
||||
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
|
||||
return new AesBytesEncryptor(password.toString(), salt, KeyGenerators.secureRandom(16));
|
||||
public static BytesEncryptor stronger(CharSequence password, CharSequence salt) {
|
||||
return new AesBytesEncryptor(password.toString(), salt,
|
||||
KeyGenerators.secureRandom(16), CipherAlgorithm.GCM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text encryptor that uses standard password-based encryption.
|
||||
* Encrypted text is hex-encoded.
|
||||
* Creates a standard password-based bytes encryptor using 256 bit AES encryption.
|
||||
* Derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation
|
||||
* Function #2). Salts the password to prevent dictionary attacks against the key. The
|
||||
* provided salt is expected to be hex-encoded; it should be random and at least 8
|
||||
* bytes in length. Also applies a random 16 byte initialization vector to ensure each
|
||||
* encrypted message will be unique. Requires Java 6.
|
||||
*
|
||||
* @param password the password used to generate the encryptor's secret key; should not be shared
|
||||
* @param password the password used to generate the encryptor's secret key; should
|
||||
* not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||
* key
|
||||
*/
|
||||
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
|
||||
return new AesBytesEncryptor(password.toString(), salt,
|
||||
KeyGenerators.secureRandom(16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text encryptor that uses "stronger" password-based encryption. Encrypted
|
||||
* text is hex-encoded.
|
||||
*
|
||||
* @param password the password used to generate the encryptor's secret key; should
|
||||
* not be shared
|
||||
* @see Encryptors#stronger(CharSequence, CharSequence)
|
||||
*/
|
||||
public static TextEncryptor delux(CharSequence password, CharSequence salt) {
|
||||
return new HexEncodingTextEncryptor(stronger(password, salt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text encryptor that uses "standard" password-based encryption. Encrypted
|
||||
* text is hex-encoded.
|
||||
*
|
||||
* @param password the password used to generate the encryptor's secret key; should
|
||||
* not be shared
|
||||
* @see Encryptors#standard(CharSequence, CharSequence)
|
||||
*/
|
||||
public static TextEncryptor text(CharSequence password, CharSequence salt) {
|
||||
return new HexEncodingTextEncryptor(standard(password, salt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an encryptor for queryable text strings that uses standard password-based encryption.
|
||||
* Uses a 16-byte all-zero initialization vector so encrypting the same data results in the same encryption result.
|
||||
* This is done to allow encrypted data to be queried against.
|
||||
* Encrypted text is hex-encoded.
|
||||
* Creates an encryptor for queryable text strings that uses standard password-based
|
||||
* encryption. Uses a 16-byte all-zero initialization vector so encrypting the same
|
||||
* data results in the same encryption result. This is done to allow encrypted data to
|
||||
* be queried against. Encrypted text is hex-encoded.
|
||||
*
|
||||
* @param password the password used to generate the encryptor's secret key; should not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the secret key
|
||||
* @param password the password used to generate the encryptor's secret key; should
|
||||
* not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||
* secret key
|
||||
*/
|
||||
public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
|
||||
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(), salt));
|
||||
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(),
|
||||
salt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text encryptor that performs no encryption.
|
||||
* Useful for developer testing environments where working with plain text strings is desired for simplicity.
|
||||
* Creates a text encryptor that performs no encryption. Useful for developer testing
|
||||
* environments where working with plain text strings is desired for simplicity.
|
||||
*/
|
||||
public static TextEncryptor noOpText() {
|
||||
return NO_OP_TEXT_INSTANCE;
|
||||
|
||||
@@ -17,19 +17,19 @@ package org.springframework.security.crypto.password;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
/**
|
||||
* Helper for working with the MessageDigest API.
|
||||
*
|
||||
* Performs the configured number of iterations of the hashing algorithm per digest to aid in protecting against brute force attacks.
|
||||
* Performs the configured number of iterations of the hashing algorithm per digest to aid
|
||||
* in protecting against brute force attacks.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
final class Digester {
|
||||
|
||||
private final MessageDigest messageDigest;
|
||||
private final String algorithm;
|
||||
|
||||
private final int iterations;
|
||||
|
||||
@@ -39,21 +39,26 @@ final class Digester {
|
||||
* @param iterations the number of times to apply the digest algorithm to the input
|
||||
*/
|
||||
public Digester(String algorithm, int iterations) {
|
||||
try {
|
||||
messageDigest = MessageDigest.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("No such hashing algorithm", e);
|
||||
}
|
||||
|
||||
// eagerly validate the algorithm
|
||||
createDigest(algorithm);
|
||||
this.algorithm = algorithm;
|
||||
this.iterations = iterations;
|
||||
}
|
||||
|
||||
public byte[] digest(byte[] value) {
|
||||
synchronized (messageDigest) {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
value = messageDigest.digest(value);
|
||||
}
|
||||
return value;
|
||||
MessageDigest messageDigest = createDigest(algorithm);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
value = messageDigest.digest(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static MessageDigest createDigest(String algorithm) {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("No such hashing algorithm", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-2
@@ -5,10 +5,28 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EncryptorsTests {
|
||||
|
||||
@Test
|
||||
public void stronger() throws Exception {
|
||||
Assume.assumeTrue("GCM must be available for this test", isAesGcmAvailable());
|
||||
|
||||
BytesEncryptor encryptor = Encryptors.stronger("password", "5c0744940b5c369b");
|
||||
byte[] result = encryptor.encrypt("text".getBytes("UTF-8"));
|
||||
assertNotNull(result);
|
||||
assertFalse(new String(result).equals("text"));
|
||||
assertEquals("text", new String(encryptor.decrypt(result)));
|
||||
assertFalse(new String(result).equals(new String(encryptor.encrypt("text"
|
||||
.getBytes()))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void standard() throws Exception {
|
||||
BytesEncryptor encryptor = Encryptors.standard("password", "5c0744940b5c369b");
|
||||
@@ -16,7 +34,20 @@ public class EncryptorsTests {
|
||||
assertNotNull(result);
|
||||
assertFalse(new String(result).equals("text"));
|
||||
assertEquals("text", new String(encryptor.decrypt(result)));
|
||||
assertFalse(new String(result).equals(new String(encryptor.encrypt("text".getBytes()))));
|
||||
assertFalse(new String(result).equals(new String(encryptor.encrypt("text"
|
||||
.getBytes()))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferred() {
|
||||
Assume.assumeTrue("GCM must be available for this test", isAesGcmAvailable());
|
||||
|
||||
TextEncryptor encryptor = Encryptors.delux("password", "5c0744940b5c369b");
|
||||
String result = encryptor.encrypt("text");
|
||||
assertNotNull(result);
|
||||
assertFalse(result.equals("text"));
|
||||
assertEquals("text", encryptor.decrypt(result));
|
||||
assertFalse(result.equals(encryptor.encrypt("text")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -31,7 +62,8 @@ public class EncryptorsTests {
|
||||
|
||||
@Test
|
||||
public void queryableText() {
|
||||
TextEncryptor encryptor = Encryptors.queryableText("password", "5c0744940b5c369b");
|
||||
TextEncryptor encryptor = Encryptors
|
||||
.queryableText("password", "5c0744940b5c369b");
|
||||
String result = encryptor.encrypt("text");
|
||||
assertNotNull(result);
|
||||
assertFalse(result.equals("text"));
|
||||
@@ -45,4 +77,13 @@ public class EncryptorsTests {
|
||||
assertEquals("text", encryptor.encrypt("text"));
|
||||
assertEquals("text", encryptor.decrypt("text"));
|
||||
}
|
||||
|
||||
private boolean isAesGcmAvailable() {
|
||||
try {
|
||||
Cipher.getInstance("AES/GCM/NoPadding");
|
||||
return true;
|
||||
} catch (GeneralSecurityException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ We can view the user name, but how are we able to log out? Below you can see how
|
||||
</form>
|
||||
----
|
||||
|
||||
If you try to log out right now the request will fail. The reason is that Spring Security is protecting against CSRF attakcks and there is no CSRF token include in our request. Update our configuration to use the `@EnableWebMvcSecurity` annotation which will do the same as `@EnableWebMvcSecurity` and provide integration with Spring MVC. Among other things, it will ensure our CSRF Token is included in our forms automatically when using Thymleaf 2.1+ or Spring MVC taglibs.
|
||||
If you try to log out right now the request will fail. The reason is that Spring Security is protecting against CSRF attacks and there is no CSRF token include in our request. Update our configuration to use the `@EnableWebMvcSecurity` annotation which will do the same as `@EnableWebSecurity` and provide integration with Spring MVC. Among other things, it will ensure our CSRF Token is included in our forms automatically when using Thymleaf 2.1+ or Spring MVC taglibs.
|
||||
|
||||
.src/main/java/org/springframework/security/samples/config/SecurityConfig.java
|
||||
[source,java]
|
||||
|
||||
@@ -691,7 +691,7 @@ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
|
||||
|
||||
==== LDAP Authentication
|
||||
|
||||
You can find the updates to suppport LDAP based authentication. The https://github.com/spring-projects/spring-security/tree/master/samples/lda-jc[ldap-jc sample] provides a complete example of using LDAP based authentication.
|
||||
You can find the updates to suppport LDAP based authentication. The https://github.com/spring-projects/spring-security/tree/master/samples/ldap-jc[ldap-jc sample] provides a complete example of using LDAP based authentication.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@@ -2320,7 +2320,7 @@ Notice that the filter is actually a `DelegatingFilterProxy`, and not the class
|
||||
|
||||
[[filter-chain-proxy]]
|
||||
=== FilterChainProxy
|
||||
Spring Security's web infrastructure should only be used by delegating to an instance of `FilterChainProxy`. The security filters should not be used by themselves. In theory you could declare each Spring Security filter bean that you require in your application context file and add a corresponding `DelegatingFilterProxy` entry to `web.xml` for each filter, making sure that they are ordered correctly, but this would be cumbersome and would clutter up the `web.xml` file quickly if you have a lot of filters. `FilterChainProxy` lets us add a single entry to `web.xml` and deal entirely with the application context file for managing our web security beans. It is wired using a`DelegatingFilterProxy`, just like in the example above, but with the `filter-name` set to the bean name "filterChainProxy". The filter chain is then declared in the application context with the same bean name. Here's an example:
|
||||
Spring Security's web infrastructure should only be used by delegating to an instance of `FilterChainProxy`. The security filters should not be used by themselves. In theory you could declare each Spring Security filter bean that you require in your application context file and add a corresponding `DelegatingFilterProxy` entry to `web.xml` for each filter, making sure that they are ordered correctly, but this would be cumbersome and would clutter up the `web.xml` file quickly if you have a lot of filters. `FilterChainProxy` lets us add a single entry to `web.xml` and deal entirely with the application context file for managing our web security beans. It is wired using a `DelegatingFilterProxy`, just like in the example above, but with the `filter-name` set to the bean name "filterChainProxy". The filter chain is then declared in the application context with the same bean name. Here's an example:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
@@ -2902,7 +2902,10 @@ create table persistent_logins (username varchar(64) not null,
|
||||
|
||||
[[remember-me-impls]]
|
||||
=== Remember-Me Interfaces and Implementations
|
||||
Remember-me authentication is not used with basic authentication, given it is often not used with `HttpSession` s. Remember-me is used with `UsernamePasswordAuthenticationFilter`, and is implemented via hooks in the `AbstractAuthenticationProcessingFilter` superclass. The hooks will invoke a concrete `RememberMeServices` at the appropriate times. The interface looks like this:
|
||||
Remember-me is used with `UsernamePasswordAuthenticationFilter`, and is implemented via hooks in the `AbstractAuthenticationProcessingFilter` superclass.
|
||||
It is also used within `BasicAuthenticationFilter`.
|
||||
The hooks will invoke a concrete `RememberMeServices` at the appropriate times.
|
||||
The interface looks like this:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@@ -3559,14 +3562,14 @@ public class WebSecurityConfig extends
|
||||
http
|
||||
// ...
|
||||
.headers()
|
||||
.hsts();
|
||||
.httpStrictTransportSecurity();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[[headers-frame-options]]
|
||||
==== X-Frame-Options
|
||||
Allowing your website to be added to a frame can be a security issue. For example, using clever CSS styling users could be tricked into clicking on something that they were not intending (http://www.youtube.com/watch?v=3mk0RySeNsU[video demo]). For example, a user that is logged into their bank might click a button that grants access to other users. This sort of attack is known ashttp://en.wikipedia.org/wiki/Clickjacking[Clickjacking].
|
||||
Allowing your website to be added to a frame can be a security issue. For example, using clever CSS styling users could be tricked into clicking on something that they were not intending (http://www.youtube.com/watch?v=3mk0RySeNsU[video demo]). For example, a user that is logged into their bank might click a button that grants access to other users. This sort of attack is known as http://en.wikipedia.org/wiki/Clickjacking[Clickjacking].
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
@@ -3701,8 +3704,8 @@ public class WebSecurityConfig extends
|
||||
http
|
||||
// ...
|
||||
.headers()
|
||||
.addHeaderWriter(new StaticHeaderWriter("X-Content-Security-Policy","default-src 'self'"))
|
||||
.addHeaderWriter(new StaticHeaderWriter("X-WebKit-CSP","default-src 'self'"));
|
||||
.addHeaderWriter(new StaticHeadersWriter("X-Content-Security-Policy","default-src 'self'"))
|
||||
.addHeaderWriter(new StaticHeadersWriter("X-WebKit-CSP","default-src 'self'"));
|
||||
}
|
||||
}
|
||||
----
|
||||
@@ -3764,7 +3767,7 @@ At times you may want to only write a header for certain requests. For example,
|
||||
<!-- ... -->
|
||||
|
||||
<headers>
|
||||
<header header-ref="headerWriter"/>
|
||||
<header ref="headerWriter"/>
|
||||
</headers>
|
||||
</http>
|
||||
|
||||
@@ -4857,7 +4860,7 @@ Often a more complicated strategy than simple DN-matching is required to locate
|
||||
|
||||
[[ldap-searchobjects-filter]]
|
||||
===== FilterBasedLdapUserSearch
|
||||
This bean uses an LDAP filter to match the user object in the directory. The process is explained in the Javadoc for the corresponding search method on thehttp://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name,%20java.lang.String,%20java.lang.Object[],%20javax.naming.directory.SearchControls)[JDK DirContext class]. As explained there, the search filter can be supplied with parameters. For this class, the only valid parameter is `{0}` which will be replaced with the user's login name.
|
||||
This bean uses an LDAP filter to match the user object in the directory. The process is explained in the Javadoc for the corresponding search method on the http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name,%20java.lang.String,%20java.lang.Object[],%20javax.naming.directory.SearchControls)[JDK DirContext class]. As explained there, the search filter can be supplied with parameters. For this class, the only valid parameter is `{0}` which will be replaced with the user's login name.
|
||||
|
||||
|
||||
[[ldap-authorities]]
|
||||
@@ -5559,7 +5562,9 @@ The next step is to specify `serviceProperties` and the `authenticationDetailsSo
|
||||
<property name="serviceProperties" ref="serviceProperties"/>
|
||||
<property name="authenticationDetailsSource">
|
||||
<bean class=
|
||||
"org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
|
||||
"org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
|
||||
<constructor-arg ref="serviceProperties"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
@@ -6059,7 +6064,9 @@ public Callable<String> processUpload(final MultipartFile file) {
|
||||
More technically speaking, Spring Security integrates with `WebAsyncManager`. The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` at the time `startCallableProcessing` is invoked.
|
||||
====
|
||||
|
||||
There is no automatic integration with a `DeferredResult` that is returned by controllers. This is because `DeferredResult` is processed by the users and thus there is no way of automatically integrating with it. However, you can still use <<concurrency-support>> to provide transparent integration with Spring Security.
|
||||
There is no automatic integration with a `DeferredResult` that is returned by controllers.
|
||||
This is because `DeferredResult` is processed by the users and thus there is no way of automatically integrating with it.
|
||||
However, you can still use <<concurrency,Concurrency Support>> to provide transparent integration with Spring Security.
|
||||
|
||||
[[mvc-csrf]]
|
||||
=== Spring MVC and CSRF Integration
|
||||
@@ -6802,12 +6809,12 @@ The `name` of the header.
|
||||
|
||||
|
||||
[[nsa-header-value]]
|
||||
* **header-value**
|
||||
* **value**
|
||||
The `value` of the header to add.
|
||||
|
||||
|
||||
[[nsa-header-ref]]
|
||||
* **header-ref**
|
||||
* **ref**
|
||||
Reference to a custom implementation of the `HeaderWriter` interface.
|
||||
|
||||
|
||||
@@ -7081,6 +7088,8 @@ Lists the access attributes which will be stored in the `FilterInvocationSecurit
|
||||
* **filters**
|
||||
Can only take the value "none". This will cause any matching request to bypass the Spring Security filter chain entirely. None of the rest of the `<http>` configuration will have any effect on the request and there will be no security context available for its duration. Access to secured methods during the request will fail.
|
||||
|
||||
NOTE: This property is invalid for <<nsa-filter-security-metadata-source,filter-security-metadata-source>>
|
||||
|
||||
|
||||
[[nsa-intercept-url-method]]
|
||||
* **method**
|
||||
@@ -7098,6 +7107,8 @@ Can be "http" or "https" depending on whether a particular URL pattern should be
|
||||
|
||||
If a `<port-mappings>` configuration is added, this will be used to by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP/HTTPS.
|
||||
|
||||
NOTE: This property is invalid for <<nsa-filter-security-metadata-source,filter-security-metadata-source>>
|
||||
|
||||
|
||||
[[nsa-jee]]
|
||||
==== <jee>
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=3.2.4.CI-SNAPSHOT
|
||||
version=3.2.9.RELEASE
|
||||
|
||||
@@ -21,7 +21,7 @@ ext.hsqlVersion = '2.3.1'
|
||||
ext.slf4jVersion = '1.7.5'
|
||||
ext.logbackVersion = '0.9.29'
|
||||
ext.cglibVersion = '2.2'
|
||||
ext.powerMockVersion = '1.5.1'
|
||||
ext.powerMockVersion = '1.6.2'
|
||||
ext.servletApiVersion = '3.0.1'
|
||||
ext.seleniumVersion = '2.33.0'
|
||||
ext.groovyVersion = '2.0.5'
|
||||
@@ -49,6 +49,17 @@ ext.powerMockDependencies = [
|
||||
"org.powermock:powermock-reflect:$powerMockVersion"
|
||||
]
|
||||
|
||||
ext.springCoreDependency = [
|
||||
dependencies.create("org.springframework:spring-core:$springVersion") {
|
||||
exclude(group: 'commons-logging', module: 'commons-logging')
|
||||
}
|
||||
]
|
||||
|
||||
ext.jstlDependencies = [
|
||||
"javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:$jstlVersion",
|
||||
"org.apache.taglibs:taglibs-standard-jstlel:1.2.1"
|
||||
]
|
||||
|
||||
ext.apachedsDependencies = [
|
||||
"org.apache.directory.server:apacheds-core:$apacheDsVersion",
|
||||
"org.apache.directory.server:apacheds-core-entry:$apacheDsVersion",
|
||||
@@ -61,7 +72,7 @@ ext.apachedsDependencies = [
|
||||
ext.bundlorProperties = [
|
||||
version: version,
|
||||
secRange: "[$version, 3.3.0)",
|
||||
springRange: "[$springVersion, 3.3.0)",
|
||||
springRange: "[$springVersion, 5)",
|
||||
aspectjRange: '[1.6.0, 1.8.0)',
|
||||
casRange: '[3.1.1, 3.2.0)',
|
||||
cloggingRange: '[1.0.4, 2.0.0)',
|
||||
@@ -111,12 +122,8 @@ check.dependsOn integrationTest
|
||||
dependencies {
|
||||
optional 'commons-logging:commons-logging:1.1.1'
|
||||
|
||||
compile ("org.springframework:spring-core:$springVersion") {
|
||||
exclude(group: 'commons-logging', module: 'commons-logging')
|
||||
}
|
||||
|
||||
testCompile 'junit:junit:4.11',
|
||||
'org.mockito:mockito-core:1.9.5',
|
||||
'org.mockito:mockito-core:1.10.19',
|
||||
"org.springframework:spring-test:$springVersion",
|
||||
'org.easytesting:fest-assert:1.4'
|
||||
|
||||
@@ -216,6 +223,11 @@ project.eclipseClasspath.doFirst {
|
||||
}
|
||||
}
|
||||
|
||||
project.idea.module {
|
||||
scopes.TEST.plus += [project.configurations.integrationTestRuntime]
|
||||
testSourceDirs += sourceSets.integrationTest.resources.srcDirs
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apply plugin: 'tomcat'
|
||||
|
||||
dependencies {
|
||||
def tomcatVersion = '7.0.42'
|
||||
def tomcatVersion = '7.0.54'
|
||||
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
|
||||
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
|
||||
tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Dec 11 17:49:08 CST 2013
|
||||
#Wed Jun 11 13:57:21 CDT 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-rc-2-bin.zip
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-bin.zip
|
||||
|
||||
+11
-29
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>itest-context</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>itest-context</name>
|
||||
<description>itest-context</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,12 +42,6 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
@@ -64,43 +58,31 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -143,7 +125,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -155,25 +137,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+12
-30
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>itest-web</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>itest-web</name>
|
||||
<description>itest-web</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,35 +42,17 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -135,7 +117,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -171,49 +153,49 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-taglibs</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion"
|
||||
|
||||
+8
-14
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<name>spring-security-ldap</name>
|
||||
<description>spring-security-ldap</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -42,12 +42,6 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
@@ -76,25 +70,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.2.4.CI-SNAPSHOT</version>
|
||||
<version>3.2.9.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -106,7 +100,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -186,7 +180,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -204,7 +198,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.2.8.RELEASE</version>
|
||||
<version>3.2.13.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user