1
0
mirror of synced 2026-09-09 02:39:53 +00:00

Compare commits

...

64 Commits

Author SHA1 Message Date
Spring Buildmaster 4619705e37 Release version 3.2.0.RELEASE 2013-12-16 11:27:09 -08:00
Rob Winch f09ce267b3 Polish MVC doc 2013-12-16 12:30:25 -06:00
Rob Winch 374aceed2b Polish form.asc 2013-12-16 11:13:23 -06:00
Rob Winch df703e0189 Polish hellomvc.asc 2013-12-16 10:39:18 -06:00
Rob Winch 8c580dc170 SEC-2444: Polish Thymeleaf for samples 2013-12-16 09:51:00 -06:00
Rob Winch 5205bf57c6 SEC-2453: Create 403 CSRF FAQ Entry 2013-12-16 09:02:02 -06:00
Rob Winch 994117ad75 SEC-2436: Fix CsrfConfigurerNoWebMvcTests 2013-12-14 14:48:47 -06:00
Rob Winch b7041ed00e SEC-2436: Add @EnableWebMvcSecurity 2013-12-14 14:40:01 -06:00
Rob Winch 053c890a69 SEC-2450: WebSecurityConfigurerAdapter have default Order of 100 2013-12-14 13:00:48 -06:00
Rob Winch 7838e3eeca SEC-2447: JdbcMutableAclServiceTests should invoke aclCache.clearCache() 2013-12-14 10:19:06 -06:00
Rob Winch 2df5541905 SEC-2448: Update to HSQL 2.3.1 2013-12-14 10:19:06 -06:00
Rob Winch 04fac30d75 SEC-2449: <ldap-server> default port should fallback to dynamic value 2013-12-14 10:19:06 -06:00
Rob Winch 54ffa28bde remove apacheDSWorkDir since custom tmp dir is created 2013-12-13 16:38:35 -06:00
Rob Winch ca1080fb96 SEC-2439: HttpSessionCsrfTokenRepository setHeaderName sets header instead of parameter 2013-12-13 15:47:28 -06:00
Rob Winch 4708287ad3 SEC-2444: Convert Java Config samples to thymeleaf and tiles 2013-12-13 15:47:28 -06:00
Rob Winch 0d12397662 SEC-2385: Polish Gradle Spring 4 usage doc 2013-12-12 08:20:37 -06:00
Rob Winch a34178bc40 SEC-2434: Update to Spring 3.2.6 and Spring 4.0 GA 2013-12-12 08:16:59 -06:00
Rob Winch aaa7cec32e SEC-2326: CsrfRequestDataValueProcessor implements RequestDataValueProcessor
Previously there was unecessary complexity in CsrfRequestDataValueProcessor
due to the non-passive changes in RequestDataValueProcessor. Now it simply
implements the interface with the methods for both versions of the interface.
This works since linking happens at runtime.
2013-12-12 08:07:22 -06:00
Rob Winch 6f9085dd5d SEC-2435: Update to Gradle 1.10-rc-2 2013-12-11 17:52:41 -06:00
Rob Winch 7f714ebb23 SEC-2422: Session timeout detection with CSRF protection 2013-12-11 17:38:17 -06:00
Rob Winch 00d668dc5c SEC-2431: UrlAuthorizationConfigurer missing <HttpSecurity> in doc 2013-12-11 11:07:05 -06:00
Rob Winch 035067caf4 SEC-2385: Polish Gradle Spring 4 usage doc 2013-12-11 08:08:51 -06:00
Rob Winch 0da9b6c64b Update to spring.io 2013-12-09 16:51:45 -06:00
Rob Winch 418bb57323 SEC-2430: Enable artifactoryPublish on bom 2013-12-09 16:29:29 -06:00
Rob Winch 4672c2a1f7 SEC-2430: Add Maven BOM 2013-12-09 15:51:49 -06:00
Rob Winch 4460e84b29 Updates to pom.xml author and repo 2013-12-09 08:57:30 -06:00
Rob Winch 548ed4e14a Update samples to declare repository already added 2013-12-06 14:46:52 -06:00
Rob Winch 6be4de854a Ensure artifactory uses customized pom 2013-12-06 14:46:52 -06:00
Rob Winch feeb380b51 Polish Guides 2013-12-06 11:12:07 -06:00
Rob Winch ec524da6cb SEC-2416: Fix Hello MVC guide 2013-12-05 15:47:38 -06:00
Rob Winch fc6fc19eed Fix guides 2013-12-05 13:16:59 -06:00
Rob Winch fa39ecd719 SEC-2367: ProviderManager rethrows InternalAuthenticationServiceExceptions 2013-12-04 16:19:33 -06:00
Rob Winch 7e274ea5b6 Fix typo in InternalAuthenticationServiceException javadoc 2013-12-04 16:18:59 -06:00
Rob Winch 8e8bdad8e6 SEC-2386: Remove stack for AuthenticationManagerBuilder with no authenticationProviders 2013-12-04 15:53:32 -06:00
Rob Winch f2fdc9d1f5 SEC-2425: Add Test for EnableGlobalMethodSecurity works on parent config 2013-12-04 14:54:56 -06:00
Rob Winch 74a6303b6f SEC-2385: Document how to use with Spring 4 2013-12-04 12:38:45 -06:00
Rob Winch be15213819 SEC-2388: Deploy spring-security-samples-messages-jc 2013-12-03 13:03:15 -06:00
Rob Winch 595b16d836 SEC-2377: Fix tests 2013-12-03 11:48:25 -06:00
Rob Winch 2a632a061e SEC-2377: Hhandle EnableWebSecurity in both child & parent ApplicationContext 2013-12-03 10:45:25 -06:00
Rob Winch 4308e72573 Polish CSRF log in caveat with link 2013-12-03 09:27:49 -06:00
Rob Winch b8cc42e3a3 SEC-2426: Add CSRF and logout with non-post example 2013-12-03 09:07:54 -06:00
Rob Winch ab08d99a52 SEC-2421: Remove filterProcessUrl from UsernamePasswordAuthenticationFilter doc 2013-12-02 16:47:57 -06:00
Rob Winch 135df149a3 SEC-2423: Document differences between defaults in Java & XML Config 2013-12-02 16:37:52 -06:00
Mat Booth c6a534cad8 SEC-2418: Minor fix to toString method in LdapUserDetailsImpl 2013-12-02 12:00:09 -06:00
Rob Winch 0b996c669f SEC-2424: Document ObjectPostProcessor 2013-12-02 10:17:08 -06:00
Rob Winch 13c5af5b91 SEC-2407: Better error message for missing securityFilterChainBuilders 2013-11-26 10:12:55 -06:00
Rob Winch e97758dd3a SEC-2412: Update to propdeps-plugin:0.0.5 2013-11-25 17:00:34 -06:00
Rob Winch 209cf317d6 SEC-2411: Update to Gradle 1.9 2013-11-25 16:57:42 -06:00
Rob Winch 5641ab98c1 SEC-2410: AclFormattingUtils.printBinary handles negative 2013-11-22 13:10:50 -06:00
Rob Winch c7b93e6cee SEC-2404: Fix CSRF config tests 2013-11-21 15:35:26 -06:00
Rob Winch 59e13e7bbb SEC-2404: CsrfAuthenticationStrategy creates new valid CsrfToken 2013-11-21 15:12:08 -06:00
Rob Winch 5a59c74d02 SEC-2327: Document SecurityExpressionRoot 2013-11-20 16:59:05 -06:00
Rob Winch 5bc6f64b03 SEC-2405: Added tests for OBJECT_FACTORIES 2013-11-20 14:04:15 -06:00
Mattias Hellborg Arthursson bc6fc518d3 SEC-2405: Use DirContextAdapter directly from search. Configure OBJECT_FACTORIES on DirContext created for ActiveDirectory. 2013-11-20 13:51:51 -06:00
Rob Winch 9dbe30c81d SEC-2165: remember-me@token-validity-seconds can be parameterized 2013-11-15 14:58:53 -06:00
Rob Winch 2d2f91484d SEC-2350: Fix broken test 2013-11-15 14:01:35 -06:00
Rob Winch afddb5eb39 SEC-2373: Update XSD doc to state security="none" 2013-11-15 13:50:49 -06:00
Rob Winch 1745715865 SEC-2350: Remove warning whe using Spring 4 2013-11-15 13:43:43 -06:00
Rob Winch 6382b6341a SEC-2355: Add test to validate intercept-url PATCH works 2013-11-15 11:57:47 -06:00
Collin Peters 85cd5627b6 SEC-2355: Add PATCH to intercept-url xsd 2013-11-15 11:46:34 -06:00
Rob Winch 4944e602cb SEC-2402: Reference cleanup
* Fix link rendering in CSRF section
* Remove static from MultiHttpSecurityConfig sample
* Decrease indention since can render w/ PDF now
* Remove invalid characters
2013-11-15 10:50:08 -06:00
Rob Winch f1f3acdf75 Fix guides spec 2013-11-01 14:21:37 -05:00
Rob Winch 2c8946c406 Next development version 2013-11-01 14:20:55 -05:00
Spring Buildmaster 9c703a3051 Release version 3.2.0.RC2 2013-11-01 14:20:49 -05:00
313 changed files with 3529 additions and 83529 deletions
+1
View File
@@ -19,3 +19,4 @@ build/
*.iws
.gradle/
atlassian-ide-plugin.xml
/samples
+18 -24
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-acl</name>
<description>spring-security-acl</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-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.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -88,13 +82,13 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -132,7 +126,7 @@
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -150,19 +144,19 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -98,7 +98,7 @@ public abstract class AclFormattingUtils {
}
private static String printBinary(int i, char on, char off) {
String s = Integer.toString(i, 2);
String s = Integer.toBinaryString(i);
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
@@ -119,6 +119,9 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
* @param acl containing the ACEs to insert
*/
protected void createEntries(final MutableAcl acl) {
if(acl.getEntries().isEmpty()) {
return;
}
jdbcTemplate.batchUpdate(insertEntry,
new BatchPreparedStatementSetter() {
public int getBatchSize() {
@@ -124,4 +124,12 @@ public class AclFormattingUtilsTests extends TestCase {
Assert.assertEquals("............................xxxx", AclFormattingUtils.printBinary(15, 'x'));
}
public void testPrintBinaryNegative() {
Assert.assertEquals("*...............................", AclFormattingUtils.printBinary(0x80000000));
}
public void testPrintBinaryMinusOne() {
Assert.assertEquals("********************************", AclFormattingUtils.printBinary(0xffffffff));
}
}
@@ -105,6 +105,7 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
jdbcTemplate.execute("drop table acl_object_identity");
jdbcTemplate.execute("drop table acl_class");
jdbcTemplate.execute("drop table acl_sid");
aclCache.clearCache();
}
@Test
+14 -20
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-aspects</name>
<description>spring-security-aspects</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,35 +42,29 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -132,13 +126,13 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
+9
View File
@@ -0,0 +1,9 @@
apply plugin: 'maven-bom'
apply from: "$rootDir/gradle/maven-deployment.gradle"
generatePom.enabled = false
sonarRunner.skipProject = true
mavenBom {
projects = coreModuleProjects
}
+9 -6
View File
@@ -5,11 +5,12 @@ buildscript {
maven { url "http://repo.springsource.org/plugins-release" }
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3")
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.5")
classpath("org.springframework.build.gradle:bundlor-plugin:0.1.2")
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:0.9.8")
classpath('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')
}
}
@@ -24,11 +25,13 @@ allprojects {
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
ext.springVersion = '3.2.6.RELEASE'
ext.spring4Version = '4.0.0.RELEASE'
group = 'org.springframework.security'
repositories {
maven { url "http://repo.springsource.org/libs-snapshot" }
mavenCentral()
maven { url "http://repo.springsource.org/plugins-release" }
maven { url "http://repo.terracotta.org/maven2/" }
}
@@ -51,7 +54,7 @@ sonarRunner {
}
// Set up different subproject lists for individual configuration
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'manual' && project.name != 'guides' }
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'manual' && project.name != 'guides' && project.name != 'spring-security-bom' }
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
@@ -76,7 +79,7 @@ configure(allprojects - javaProjects) {
}
}
configure(subprojects - coreModuleProjects) {
configure(subprojects - coreModuleProjects - project(':spring-security-samples-messages-jc') - project(':spring-security-bom')) {
tasks.findByPath("artifactoryPublish")?.enabled = false
sonarRunner {
skipProject = true
@@ -106,7 +109,7 @@ configure(coreModuleProjects) {
configurations.spring4TestRuntime {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'org.springframework') {
details.useVersion '4.0.0.RC1'
details.useVersion spring4Version
}
if (details.requested.name == 'ehcache') {
details.useVersion '2.6.5'
@@ -185,5 +188,5 @@ artifacts {
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
gradleVersion = '1.10-rc-2'
}
@@ -0,0 +1,19 @@
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.*
import org.gradle.api.tasks.*
import org.gradle.api.tasks.TaskAction
public class MavenBomPlugin implements Plugin<Project> {
static String MAVEN_BOM_TASK_NAME = "mavenBom"
public void apply(Project project) {
project.plugins.apply(JavaPlugin)
project.plugins.apply(MavenPlugin)
project.task(MAVEN_BOM_TASK_NAME, type: MavenBomTask, group: 'Generate', description: 'Configures the pom as a Maven Build of Materials (BOM)')
project.install.dependsOn project.mavenBom
}
}
@@ -0,0 +1,55 @@
import groovy.xml.MarkupBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.*
public class MavenBomTask extends DefaultTask {
Set<Project> projects
File bomFile
public MavenBomTask() {
this.group = "Generate"
this.description = "Generates a Maven Build of Materials (BOM). See http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Importing_Dependencies"
this.projects = project.subprojects
this.bomFile = project.file("${->project.buildDir}/maven-bom/${->project.name}-${->project.version}.txt")
}
@TaskAction
public void configureBom() {
project.configurations.archives.artifacts.clear()
bomFile.parentFile.mkdirs()
bomFile.write("Maven Build of Materials (BOM). See http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Importing_Dependencies")
project.artifacts {
// work around GRADLE-2406 by attaching text artifact
archives(bomFile)
}
project.install {
repositories.mavenInstaller {
pom.whenConfigured {
packaging = "pom"
withXml {
asNode().children().last() + {
delegate.dependencyManagement {
delegate.dependencies {
projects.sort { dep -> "$dep.group:$dep.name" }.each { p ->
delegate.dependency {
delegate.groupId(p.group)
delegate.artifactId(p.name)
delegate.version(p.version)
}
}
}
}
}
}
}
}
}
}
}
@@ -0,0 +1 @@
implementation-class=MavenBomPlugin
+15 -21
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-cas</name>
<description>spring-security-cas</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.jasig.cas.client</groupId>
@@ -58,31 +52,31 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -94,7 +88,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -150,7 +144,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
+1 -5
View File
@@ -52,7 +52,7 @@ dependencies {
}
testRuntime "hsqldb:hsqldb:$hsqlVersion",
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:2.2"
}
@@ -60,10 +60,6 @@ test {
inputs.file file("$rootDir/docs/manual/src/docbook/appendix-namespace.xml")
}
integrationTest {
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
}
rncToXsd {
rncDir = file('src/main/resources/org/springframework/security/config/')
xsdDir = rncDir
+30 -36
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-config</name>
<description>spring-security-config</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-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.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -108,49 +102,49 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@@ -172,12 +166,6 @@
<version>0.9.29</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
@@ -256,6 +244,12 @@
<version>4.1.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
@@ -331,25 +325,25 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -12,7 +12,10 @@
*/
package org.springframework.security.config.ldap;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.ServerSocket;
import org.junit.After;
import org.junit.Test;
@@ -50,10 +53,11 @@ public class LdapServerBeanDefinitionParserTests {
}
@Test
public void useOfUrlAttributeCreatesCorrectContextSource() {
public void useOfUrlAttributeCreatesCorrectContextSource() throws Exception {
int port = getDefaultPort();
// Create second "server" with a url pointing at embedded one
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='33388'/>" +
"<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='" + port + "'/>" +
"<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:" + port + "/dc=springframework,dc=org' />");
// Check the default context source is still there.
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
@@ -83,4 +87,16 @@ public class LdapServerBeanDefinitionParserTests {
assertEquals("classpath*:*.ldif", ReflectionTestUtils.getField(dsContainer, "ldifResources"));
}
private int getDefaultPort() throws IOException {
ServerSocket server = null;
try {
server = new ServerSocket(0);
return server.getLocalPort();
} finally {
try {
server.close();
} catch(IOException e) {}
}
}
}
@@ -39,7 +39,7 @@ public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
object = doBuild();
return object;
}
throw new IllegalStateException("This object has already been built");
throw new AlreadyBuiltException("This object has already been built");
}
/**
@@ -0,0 +1,31 @@
/*
* 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;
/**
* Thrown when {@link AbstractSecurityBuilder#build()} is two or more times.
*
* @author Rob Winch
* @since 3.2
*/
public class AlreadyBuiltException extends IllegalStateException {
public AlreadyBuiltException(String message) {
super(message);
}
private static final long serialVersionUID = -5891004752785553015L;
}
@@ -29,7 +29,7 @@ public interface SecurityBuilder<O> {
* Builds the object and returns it or null.
*
* @return the Object to be built or null if the implementation allows it.
* @throws Exception if an error occured when building the Object
* @throws Exception if an error occurred when building the Object
*/
O build() throws Exception;
}
@@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.authentication.builders;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
@@ -45,6 +47,7 @@ import org.springframework.util.Assert;
* @since 3.2
*/
public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder> implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
private final Log logger = LogFactory.getLog(getClass());
private AuthenticationManager parentAuthenticationManager;
private List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>();
@@ -218,6 +221,10 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
@Override
protected ProviderManager performBuild() throws Exception {
if(authenticationProviders.isEmpty() && parentAuthenticationManager == null) {
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
if(eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
@@ -280,7 +280,10 @@ public final class WebSecurity extends
@Override
protected Filter performBuild() throws Exception {
Assert.state(!securityFilterChainBuilders.isEmpty(), "At least one SecurityFilterBuilder needs to be specified. Invoke FilterChainProxyBuilder.securityFilterChains");
Assert.state(!securityFilterChainBuilders.isEmpty(),
"At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. More advanced users can invoke "
+ WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(chainSize);
for(RequestMatcher ignoredRequest : ignoredRequests) {
@@ -77,7 +77,7 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class,AuthenticationConfiguration.class, SpringWebMvcImportSelector.class})
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class,AuthenticationConfiguration.class})
public @interface EnableWebSecurity {
/**
@@ -1,39 +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.web.configuration;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
/**
* Used by {@link EnableWebSecurity} to conditionaly import
* {@link WebMvcSecurityConfiguration} when the DispatcherServlet is present on the
* classpath.
*
* @author Rob Winch
* @since 3.2
*/
class SpringWebMvcImportSelector implements ImportSelector {
/* (non-Javadoc)
* @see org.springframework.context.annotation.ImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
boolean webmvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", getClass().getClassLoader());
return webmvcPresent ? new String[] {"org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration"} : new String[] {};
}
}
@@ -34,6 +34,7 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.AlreadyBuiltException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
@@ -87,7 +88,11 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
if(!hasConfigurers) {
throw new IllegalStateException("At least one non-null instance of "+ WebSecurityConfigurer.class.getSimpleName()+" must be exposed as a @Bean when using @EnableWebSecurity. Hint try extending "+ WebSecurityConfigurerAdapter.class.getSimpleName());
}
return webSecurity.build();
try {
return webSecurity.build();
} catch (AlreadyBuiltException e) {
return webSecurity.getObject();
}
}
/**
@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
@@ -53,6 +54,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
*
* @author Rob Winch
*/
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
private final Log logger = LogFactory.getLog(WebSecurityConfigurerAdapter.class);
@@ -15,14 +15,22 @@
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.LinkedHashMap;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfLogoutHandler;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
@@ -50,6 +58,7 @@ import org.springframework.util.Assert;
* <li>
* {@link ExceptionHandlingConfigurer#accessDeniedHandler(AccessDeniedHandler)}
* is used to determine how to handle CSRF attempts</li>
* <li>{@link InvalidSessionStrategy}</li>
* </ul>
*
* @author Rob Winch
@@ -100,12 +109,9 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>> extends Abst
if(requireCsrfProtectionMatcher != null) {
filter.setRequireCsrfProtectionMatcher(requireCsrfProtectionMatcher);
}
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
if(exceptionConfig != null) {
AccessDeniedHandler accessDeniedHandler = exceptionConfig.getAccessDeniedHandler();
if(accessDeniedHandler != null) {
filter.setAccessDeniedHandler(accessDeniedHandler);
}
AccessDeniedHandler accessDeniedHandler = createAccessDeniedHandler(http);
if(accessDeniedHandler != null) {
filter.setAccessDeniedHandler(accessDeniedHandler);
}
LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
if(logoutConfigurer != null) {
@@ -118,4 +124,70 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>> extends Abst
filter = postProcess(filter);
http.addFilter(filter);
}
/**
* Gets the default {@link AccessDeniedHandler} from the
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler()} or create a
* {@link AccessDeniedHandlerImpl} if not available.
*
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
@SuppressWarnings("unchecked")
private AccessDeniedHandler getDefaultAccessDeniedHandler(H http) {
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
AccessDeniedHandler handler = null;
if(exceptionConfig != null) {
handler = exceptionConfig.getAccessDeniedHandler();
}
if(handler == null) {
handler = new AccessDeniedHandlerImpl();
}
return handler;
}
/**
* Gets the default {@link InvalidSessionStrategy} from the
* {@link SessionManagementConfigurer#getInvalidSessionStrategy()} or null
* if not available.
*
* @param http
* the {@link HttpSecurityBuilder}
* @return the {@link InvalidSessionStrategy}
*/
@SuppressWarnings("unchecked")
private InvalidSessionStrategy getInvalidSessionStrategy(H http) {
SessionManagementConfigurer<H> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
if(sessionManagement == null) {
return null;
}
return sessionManagement.getInvalidSessionStrategy();
}
/**
* Creates the {@link AccessDeniedHandler} from the result of
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} and
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)}. If
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)} is non-null, then
* a {@link DelegatingAccessDeniedHandler} is used in combination with
* {@link InvalidSessionAccessDeniedHandler} and the
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)}. Otherwise,
* only {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} is used.
*
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
private AccessDeniedHandler createAccessDeniedHandler(H http) {
InvalidSessionStrategy invalidSessionStrategy = getInvalidSessionStrategy(http);
AccessDeniedHandler defaultAccessDeniedHandler = getDefaultAccessDeniedHandler(http);
if(invalidSessionStrategy == null) {
return defaultAccessDeniedHandler;
}
InvalidSessionAccessDeniedHandler invalidSessionDeniedHandler = new InvalidSessionAccessDeniedHandler(invalidSessionStrategy);
LinkedHashMap<Class<? extends AccessDeniedException>, AccessDeniedHandler> handlers =
new LinkedHashMap<Class<? extends AccessDeniedException>, AccessDeniedHandler>();
handlers.put(MissingCsrfTokenException.class, invalidSessionDeniedHandler);
return new DelegatingAccessDeniedHandler(handlers, defaultAccessDeniedHandler);
}
}
@@ -42,6 +42,7 @@ import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
import org.springframework.util.Assert;
@@ -66,6 +67,7 @@ import org.springframework.util.Assert;
* <li>{@link RequestCache}</li>
* <li>{@link SecurityContextRepository}</li>
* <li>{@link SessionManagementConfigurer}</li>
* <li>{@link InvalidSessionStrategy}</li>
* </ul>
*
* <h2>Shared Objects Used</h2>
@@ -83,6 +85,7 @@ import org.springframework.util.Assert;
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<SessionManagementConfigurer<H>,H> {
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = createDefaultSessionFixationProtectionStrategy();
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private InvalidSessionStrategy invalidSessionStrategy;
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<SessionAuthenticationStrategy>();
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
private Integer maximumSessions;
@@ -365,6 +368,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
}
}
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
@@ -375,7 +379,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
sessionManagementFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(sessionAuthenticationErrorUrl));
}
if(invalidSessionUrl != null) {
sessionManagementFilter.setInvalidSessionStrategy(new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl));
sessionManagementFilter.setInvalidSessionStrategy(getInvalidSessionStrategy());
}
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if(trustResolver != null) {
@@ -391,6 +395,23 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
}
}
/**
* Gets the {@link InvalidSessionStrategy} to use. If
* {@link #invalidSessionUrl} is null, returns null otherwise
* {@link SimpleRedirectInvalidSessionStrategy} is used.
*
* @return the {@link InvalidSessionStrategy} to use
*/
InvalidSessionStrategy getInvalidSessionStrategy() {
if(invalidSessionUrl == null) {
return null;
}
if(invalidSessionStrategy == null) {
invalidSessionStrategy = new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl);
}
return invalidSessionStrategy;
}
/**
* Gets the {@link SessionCreationPolicy}. Can not be null.
* @return the {@link SessionCreationPolicy}
@@ -27,6 +27,7 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -48,10 +49,10 @@ import org.springframework.util.Assert;
* <pre>
* protected void configure(HttpSecurity http) throws Exception {
* http
* .apply(new UrlAuthorizationConfigurer()).getRegistry()
* .antMatchers("/users**","/sessions/**").hasRole("USER")
* .antMatchers("/signup").hasRole("ANONYMOUS")
* .anyRequest().hasRole("USER")
* .apply(new UrlAuthorizationConfigurer<HttpSecurity>()).getRegistry()
* .antMatchers("/users**","/sessions/**").hasRole("USER")
* .antMatchers("/signup").hasRole("ANONYMOUS")
* .anyRequest().hasRole("USER");
* }
* </pre>
*
@@ -0,0 +1,37 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.servlet.configuration;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Add this annotation to an {@code @Configuration} class to have the Spring Security
* configuration integrate with Spring MVC.
*
* @author Rob Winch
* @since 3.2
*/
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import(WebMvcSecurityConfiguration.class)
public @interface EnableWebMvcSecurity {
}
@@ -13,12 +13,13 @@
* 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.servlet.configuration;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
@@ -38,7 +39,8 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
* @since 3.2
*/
@Configuration
class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@EnableWebSecurity
public class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(
@@ -48,6 +50,6 @@ class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@Bean
public RequestDataValueProcessor requestDataValueProcessor() {
return CsrfRequestDataValueProcessor.create();
return new CsrfRequestDataValueProcessor();
}
}
@@ -15,17 +15,26 @@
*/
package org.springframework.security.config.http;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfLogoutHandler;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -44,12 +53,12 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_REPOSITORY = "token-repository-ref";
private String csrfRepositoryRef;
private BeanDefinition csrfFilter;
public BeanDefinition parse(Element element, ParserContext pc) {
boolean webmvcPresent = ClassUtils.isPresent(DISPATCHER_SERVLET_CLASS_NAME, getClass().getClassLoader());
if(webmvcPresent) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(CsrfRequestDataValueProcessor.class);
beanDefinition.setFactoryMethodName("create");
BeanComponentDefinition componentDefinition =
new BeanComponentDefinition(beanDefinition, REQUEST_DATA_VALUE_PROCESSOR);
pc.registerBeanComponent(componentDefinition);
@@ -58,21 +67,64 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
String matcherRef = element.getAttribute(ATT_MATCHER);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(CsrfFilter.class);
if(!StringUtils.hasText(csrfRepositoryRef)) {
RootBeanDefinition csrfTokenRepository = new RootBeanDefinition(HttpSessionCsrfTokenRepository.class);
csrfRepositoryRef = pc.getReaderContext().generateBeanName(csrfTokenRepository);
pc.registerBeanComponent(new BeanComponentDefinition(csrfTokenRepository, csrfRepositoryRef));
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(CsrfFilter.class);
builder.addConstructorArgReference(csrfRepositoryRef);
if(StringUtils.hasText(matcherRef)) {
builder.addPropertyReference("requireCsrfProtectionMatcher", matcherRef);
}
return builder.getBeanDefinition();
csrfFilter = builder.getBeanDefinition();
return csrfFilter;
}
/**
* Populate the AccessDeniedHandler on the {@link CsrfFilter}
*
* @param invalidSessionStrategy the {@link InvalidSessionStrategy} to use
* @param defaultDeniedHandler the {@link AccessDeniedHandler} to use
*/
void initAccessDeniedHandler(BeanDefinition invalidSessionStrategy, BeanMetadataElement defaultDeniedHandler) {
BeanMetadataElement accessDeniedHandler = createAccessDeniedHandler(invalidSessionStrategy, defaultDeniedHandler);
csrfFilter.getPropertyValues().addPropertyValue("accessDeniedHandler", accessDeniedHandler);
}
/**
* Creates the {@link AccessDeniedHandler} from the result of
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} and
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)}. If
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)} is non-null, then
* a {@link DelegatingAccessDeniedHandler} is used in combination with
* {@link InvalidSessionAccessDeniedHandler} and the
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)}. Otherwise,
* only {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} is used.
*
* @param invalidSessionStrategy the {@link InvalidSessionStrategy} to use
* @param defaultDeniedHandler the {@link AccessDeniedHandler} to use
*
* @return the {@link BeanMetadataElement} that is the {@link AccessDeniedHandler} to populate on the {@link CsrfFilter}
*/
private BeanMetadataElement createAccessDeniedHandler(BeanDefinition invalidSessionStrategy, BeanMetadataElement defaultDeniedHandler) {
if(invalidSessionStrategy == null) {
return defaultDeniedHandler;
}
ManagedMap<Class<? extends AccessDeniedException>,BeanDefinition> handlers =
new ManagedMap<Class<? extends AccessDeniedException>, BeanDefinition>();
BeanDefinitionBuilder invalidSessionHandlerBldr = BeanDefinitionBuilder.rootBeanDefinition(InvalidSessionAccessDeniedHandler.class);
invalidSessionHandlerBldr.addConstructorArgValue(invalidSessionStrategy);
handlers.put(MissingCsrfTokenException.class, invalidSessionHandlerBldr.getBeanDefinition());
BeanDefinitionBuilder deniedBldr = BeanDefinitionBuilder.rootBeanDefinition(DelegatingAccessDeniedHandler.class);
deniedBldr.addConstructorArgValue(handlers);
deniedBldr.addConstructorArgValue(defaultDeniedHandler);
return deniedBldr.getBeanDefinition();
}
BeanDefinition getCsrfAuthenticationStrategy() {
@@ -130,6 +130,10 @@ class HttpConfigurationBuilder {
private BeanMetadataElement csrfLogoutHandler;
private BeanMetadataElement csrfAuthStrategy;
private CsrfBeanDefinitionParser csrfParser;
private BeanDefinition invalidSession;
public HttpConfigurationBuilder(Element element, ParserContext pc,
BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) {
this.httpElt = element;
@@ -200,8 +204,8 @@ class HttpConfigurationBuilder {
}
void setAccessDeniedHandler(BeanMetadataElement accessDeniedHandler) {
if(csrfFilter != null) {
csrfFilter.getPropertyValues().add("accessDeniedHandler", accessDeniedHandler);
if(csrfParser != null ) {
csrfParser.initAccessDeniedHandler(this.invalidSession, accessDeniedHandler);
}
}
@@ -381,7 +385,10 @@ class HttpConfigurationBuilder {
}
if (StringUtils.hasText(invalidSessionUrl)) {
sessionMgmtFilter.addPropertyValue("invalidSessionStrategy", new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl));
BeanDefinitionBuilder invalidSessionBldr = BeanDefinitionBuilder.rootBeanDefinition(SimpleRedirectInvalidSessionStrategy.class);
invalidSessionBldr.addConstructorArgValue(invalidSessionUrl);
invalidSession = invalidSessionBldr.getBeanDefinition();
sessionMgmtFilter.addPropertyValue("invalidSessionStrategy", invalidSession);
}
sessionMgmtFilter.addConstructorArgReference(sessionAuthStratRef);
@@ -637,14 +644,16 @@ class HttpConfigurationBuilder {
}
private void createCsrfFilter() {
private CsrfBeanDefinitionParser createCsrfFilter() {
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.CSRF);
if (elmt != null) {
CsrfBeanDefinitionParser csrfParser = new CsrfBeanDefinitionParser();
this.csrfFilter = csrfParser.parse(elmt, pc);
csrfParser = new CsrfBeanDefinitionParser();
csrfFilter = csrfParser.parse(elmt, pc);
this.csrfAuthStrategy = csrfParser.getCsrfAuthenticationStrategy();
this.csrfLogoutHandler = csrfParser.getCsrfLogoutHandler();
return csrfParser;
}
return null;
}
BeanMetadataElement getCsrfLogoutHandler() {
@@ -132,12 +132,12 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
}
if (tokenValiditySet) {
int tokenValidity = Integer.parseInt(tokenValiditySeconds);
if (tokenValidity < 0 && isPersistent) {
boolean isTokenValidityNegative = tokenValiditySeconds.startsWith("-");
if (isTokenValidityNegative && isPersistent) {
pc.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" +
" a persistent remember-me token repository", source);
}
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValidity);
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValiditySeconds);
}
if (remembermeParameterSet) {
@@ -1,5 +1,8 @@
package org.springframework.security.config.ldap;
import java.io.IOException;
import java.net.ServerSocket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -9,6 +12,7 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.BeanIds;
import org.springframework.security.ldap.server.ApacheDSContainer;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -40,7 +44,8 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
/** Defines the port the LDAP_PROVIDER server should run on */
public static final String ATT_PORT = "port";
public static final String OPT_DEFAULT_PORT = "33389";
private static final int DEFAULT_PORT = 33389;
public static final String OPT_DEFAULT_PORT = String.valueOf(DEFAULT_PORT);
public BeanDefinition parse(Element elt, ParserContext parserContext) {
@@ -101,7 +106,10 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
String port = element.getAttribute(ATT_PORT);
if (!StringUtils.hasText(port)) {
port = OPT_DEFAULT_PORT;
port = getDefaultPort();
if(logger.isDebugEnabled()) {
logger.debug("Using default port of " + port);
}
}
String url = "ldap://127.0.0.1:" + port + "/" + suffix;
@@ -134,4 +142,26 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
return (RootBeanDefinition) contextSource.getBeanDefinition();
}
private String getDefaultPort() {
ServerSocket serverSocket = null;
try {
try {
serverSocket = new ServerSocket(DEFAULT_PORT);
} catch (IOException e) {
try {
serverSocket = new ServerSocket(0);
} catch(IOException e2) {
return String.valueOf(DEFAULT_PORT);
}
}
return String.valueOf(serverSocket.getLocalPort());
} finally {
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {}
}
}
}
}
@@ -280,7 +280,7 @@ http-firewall =
element http-firewall {ref}
http =
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "secured" attribute to "false".
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler?) }
http.attlist &=
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
@@ -868,7 +868,7 @@
<xs:documentation>Container element for HTTP security configuration. Multiple elements can now be defined,
each with a specific pattern to which the enclosed security configuration applies. A
pattern can also be configured to bypass Spring Security's filters completely by setting
the "secured" attribute to "false".
the "security" attribute to "none".
</xs:documentation>
</xs:annotation>
<xs:complexType>
@@ -280,7 +280,7 @@ http-firewall =
element http-firewall {ref}
http =
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "secured" attribute to "false".
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf?) }
http.attlist &=
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
@@ -357,7 +357,7 @@ intercept-url.attlist &=
attribute access {xsd:token}?
intercept-url.attlist &=
## The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.
attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "TRACE"}?
attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "PATCH" | "TRACE"}?
intercept-url.attlist &=
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
@@ -572,7 +572,7 @@ remember-me.attlist &=
remember-me.attlist &=
## The period (in seconds) for which the remember-me cookie should be valid.
attribute token-validity-seconds {xsd:integer}?
attribute token-validity-seconds {xsd:string}?
remember-me.attlist &=
## Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful remember-me authentication.
@@ -868,7 +868,7 @@
<xs:documentation>Container element for HTTP security configuration. Multiple elements can now be defined,
each with a specific pattern to which the enclosed security configuration applies. A
pattern can also be configured to bypass Spring Security's filters completely by setting
the "secured" attribute to "false".
the "security" attribute to "none".
</xs:documentation>
</xs:annotation>
<xs:complexType>
@@ -1248,6 +1248,7 @@
<xs:enumeration value="OPTIONS"/>
<xs:enumeration value="POST"/>
<xs:enumeration value="PUT"/>
<xs:enumeration value="PATCH"/>
<xs:enumeration value="TRACE"/>
</xs:restriction>
</xs:simpleType>
@@ -1795,7 +1796,7 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="token-validity-seconds" type="xs:integer">
<xs:attribute name="token-validity-seconds" type="xs:string">
<xs:annotation>
<xs:documentation>The period (in seconds) for which the remember-me cookie should be valid.
</xs:documentation>
@@ -19,6 +19,7 @@ import static org.fest.assertions.Assertions.assertThat
import static org.junit.Assert.fail
import org.aopalliance.intercept.MethodInterceptor
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
@@ -270,4 +271,34 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
new MethodSecurityServiceImpl()
}
}
def "SEC-2425: EnableGlobalMethodSecurity works on superclass"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(ParentConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
static class ChildConfig extends ParentConfig {}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class ParentConfig {
@Autowired
protected void configurGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
}
@@ -27,6 +27,9 @@ import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import org.springframework.core.annotation.AnnotationAwareOrderComparator
import org.springframework.core.annotation.Order
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.AuthenticationTrustResolver
@@ -283,4 +286,18 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
return TR
}
}
def "WebSecurityConfigurerAdapter has Ordered between 0 and lowest priority"() {
when:
def lowestConfig = new LowestPriorityWebSecurityConfig()
def defaultConfig = new DefaultOrderWebSecurityConfig()
def compare = new AnnotationAwareOrderComparator()
then: "the default ordering is between 0 and lowest priority (Boot adapters)"
compare.compare(lowestConfig, defaultConfig) > 0
}
class DefaultOrderWebSecurityConfig extends WebSecurityConfigurerAdapter {}
@Order(Ordered.LOWEST_PRECEDENCE)
class LowestPriorityWebSecurityConfig extends WebSecurityConfigurerAdapter {}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.builders;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.UrlAuthorizationConfigurer;
@Configuration
@EnableWebSecurity
public class DisableUseExpressionsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
// This config is also on UrlAuthorizationConfigurer javadoc
http
.apply(new UrlAuthorizationConfigurer<HttpSecurity>()).getRegistry()
.antMatchers("/users**","/sessions/**").hasRole("USER")
.antMatchers("/signup").hasRole("ANONYMOUS")
.anyRequest().hasRole("USER");
}
}
@@ -501,16 +501,4 @@ public class NamespaceHttpTests extends BaseSpringSpec {
findFilter(FilterSecurityInterceptor).securityMetadataSource.class == DefaultFilterInvocationSecurityMetadataSource
findFilter(FilterSecurityInterceptor).accessDecisionManager.decisionVoters.collect { it.class } == [RoleVoter, AuthenticatedVoter]
}
@Configuration
@EnableWebSecurity
static class DisableUseExpressionsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.apply(new UrlAuthorizationConfigurer()).getRegistry()
.antMatchers("/users**","/sessions/**").hasRole("USER")
.antMatchers("/signup").hasRole("ANONYMOUS")
.anyRequest().hasRole("USER")
}
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration.sec2377;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.configuration.sec2377.a.*
import org.springframework.security.config.annotation.web.configuration.sec2377.b.*
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext
public class Sec2377Tests extends BaseSpringSpec {
def "SEC-2377: Error reporting with multiple EnableWebSecurity from other packages"() {
when:
AnnotationConfigWebApplicationContext parent = new AnnotationConfigWebApplicationContext()
parent.register(Sec2377AConfig)
parent.refresh()
AnnotationConfigWebApplicationContext child = new AnnotationConfigWebApplicationContext()
child.register(Sec2377BConfig)
child.parent = parent
child.refresh()
then:
noExceptionThrown();
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration.sec2377.a;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
@Configuration
public class Sec2377AConfig extends WebSecurityConfigurerAdapter {
}
@@ -0,0 +1,25 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration.sec2377.b;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@EnableWebSecurity
@Configuration
public class Sec2377BConfig {
}
@@ -0,0 +1,51 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.event.AuthorizedEvent;
import org.springframework.security.config.annotation.ObjectPostProcessor;
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.access.intercept.FilterSecurityInterceptor;
@Configuration
@EnableWebSecurity
public class AuthorizedRequestsWithPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ApplicationListener<AuthorizedEvent> AL;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().permitAll()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
fsi.setPublishAuthorizationSuccess(true);
return fsi;
}
});
}
@Bean
public ApplicationListener<AuthorizedEvent> applicationListener() {
return AL;
}
}
@@ -18,19 +18,21 @@ package org.springframework.security.config.annotation.web.configurers
import javax.servlet.http.HttpServletResponse
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.config.annotation.BaseSpringSpec
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.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.web.access.AccessDeniedHandler
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import org.springframework.security.web.csrf.CsrfFilter
import org.springframework.security.web.csrf.CsrfTokenRepository
import org.springframework.security.web.util.matcher.RequestMatcher
import org.springframework.web.servlet.support.RequestDataValueProcessor
import spock.lang.Unroll;
import spock.lang.Unroll
/**
*
@@ -69,7 +71,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
}
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
@@ -100,6 +102,37 @@ class CsrfConfigurerTests extends BaseSpringSpec {
}
}
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
setup:
loadConfig(InvalidSessionUrlConfig)
request.session.clearAttributes()
request.setParameter("_csrf","abc")
request.method = "POST"
when: "No existing expected CsrfToken (session times out) and a POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the session timeout page page"
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/error/sessionError"
when: "Existing expected CsrfToken and a POST (invalid token provided)"
response = new MockHttpServletResponse()
request = new MockHttpServletRequest(session: request.session, method:'POST')
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access Denied occurs"
response.status == HttpServletResponse.SC_FORBIDDEN
}
@Configuration
@EnableWebSecurity
static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().and()
.sessionManagement()
.invalidSessionUrl("/error/sessionError")
}
}
def "csrf requireCsrfProtectionMatcher"() {
setup:
RequireCsrfProtectionMatcherConfig.matcher = Mock(RequestMatcher)
@@ -158,7 +191,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
def "csrf clears on login"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
loadConfig(CsrfTokenRepositoryConfig)
request.method = "POST"
request.getSession()
@@ -169,7 +202,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "/"
1 * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
(1.._) * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
}
@Configuration
@@ -282,7 +315,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
@@ -293,7 +326,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default success because we don't want csrf attempts made prior to authentication to pass"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/"
}
@@ -308,7 +341,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
@@ -319,7 +352,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to original URL since it was a GET"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/some-url"
}
@@ -20,7 +20,9 @@ import static org.springframework.security.config.annotation.web.configurers.Exp
import javax.servlet.http.HttpServletResponse
import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.event.AuthorizedEvent
import org.springframework.security.access.vote.AffirmativeBased
import org.springframework.security.authentication.RememberMeAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
@@ -462,4 +464,15 @@ public class ExpressionUrlAuthorizationConfigurerTests extends BaseSpringSpec {
then:
noExceptionThrown()
}
def "AuthorizedRequests withPostProcessor"() {
setup:
ApplicationListener al = Mock()
AuthorizedRequestsWithPostProcessorConfig.AL = al
loadConfig(AuthorizedRequestsWithPostProcessorConfig)
when:
springSecurityFilterChain.doFilter(request, response, chain)
then:
1 * al.onApplicationEvent(_ as AuthorizedEvent)
}
}
@@ -174,6 +174,28 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
response.redirectedUrl == "http://localhost/some-url"
}
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
setup:
httpAutoConfig {
'csrf'()
'session-management'('invalid-session-url': '/error/sessionError')
}
createAppContext()
request.setParameter("_csrf","abc")
request.method = "POST"
when: "No existing expected CsrfToken (session times out) and a POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the session timeout page page"
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/error/sessionError"
when: "Existing expected CsrfToken and a POST (invalid token provided)"
response = new MockHttpServletResponse()
request = new MockHttpServletRequest(session: request.session, method:'POST')
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access Denied occurs"
response.status == HttpServletResponse.SC_FORBIDDEN
}
def "csrf requireCsrfProtectionMatcher"() {
setup:
httpAutoConfig {
@@ -235,7 +257,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
verify(repo).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
verify(repo, atLeastOnce()).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
}
def "csrf clears on logout"() {
@@ -17,7 +17,10 @@ package org.springframework.security.config.http;
import java.security.Principal
import javax.servlet.Filter
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException
import org.springframework.beans.factory.BeanCreationException
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
@@ -98,4 +101,27 @@ class InterceptUrlConfigTests extends AbstractHttpConfigTests {
attrsPost.size() == 1
attrsPost.contains(new SecurityConfig("ROLE_USER"))
}
def "SEC-2355: intercept-url support patch"() {
setup:
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
MockHttpServletResponse response = new MockHttpServletResponse()
MockFilterChain chain = new MockFilterChain()
xml.http() {
'http-basic'()
'intercept-url'(pattern: '/**', 'method':'PATCH',access: 'ROLE_ADMIN')
}
createAppContext()
when: 'Method other than PATCH is used'
springSecurityFilterChain.doFilter(request,response,chain)
then: 'The response is OK'
response.status == HttpServletResponse.SC_OK
when: 'Method of PATCH is used'
request = new MockHttpServletRequest(method:'PATCH')
response = new MockHttpServletResponse()
chain = new MockFilterChain()
springSecurityFilterChain.doFilter(request, response, chain)
then: 'The response is unauthorized'
response.status == HttpServletResponse.SC_UNAUTHORIZED
}
}
@@ -17,6 +17,10 @@ package org.springframework.security.config.http
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML
import javax.sql.DataSource
import org.springframework.beans.FatalBeanException
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
import org.springframework.security.TestDataSource
import org.springframework.security.authentication.ProviderManager
@@ -26,7 +30,7 @@ import org.springframework.security.util.FieldUtils
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
import org.springframework.security.web.authentication.logout.LogoutFilter
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices
import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices
@@ -154,6 +158,32 @@ class RememberMeConfigTests extends AbstractHttpConfigTests {
rememberMeServices().tokenValiditySeconds == -1
}
def 'remember-me@token-validity-seconds denies for persistent implementation'() {
setup:
httpAutoConfig () {
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'dataSource' : 'dataSource')
}
mockBean(DataSource)
when:
createAppContext(AUTH_PROVIDER_XML)
then:
thrown(FatalBeanException)
}
def 'SEC-2165: remember-me@token-validity-seconds allows property placeholders'() {
when:
httpAutoConfig () {
'remember-me'('key': 'ourkey', 'token-validity-seconds':'${security.rememberme.ttl}')
}
xml.'b:bean'(class: PropertyPlaceholderConfigurer.name) {
'b:property'(name:'properties', value:'security.rememberme.ttl=30')
}
createAppContext(AUTH_PROVIDER_XML)
then:
rememberMeServices().tokenValiditySeconds == 30
}
def rememberMeSecureCookieAttributeIsSetCorrectly() {
httpAutoConfig () {
'remember-me'('key': 'ourkey', 'use-secure-cookie':'true')
@@ -34,7 +34,7 @@ public class DataSourcePopulator implements InitializingBean {
public void afterPropertiesSet() throws Exception {
Assert.notNull(template, "dataSource required");
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL);");
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) NOT NULL,ENABLED BOOLEAN NOT NULL);");
template.execute("CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
@@ -16,30 +16,21 @@
package org.springframework.security.config.annotation.web.configurers;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
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.util.ClassUtils;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
/**
* @author Rob Winch
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassUtils.class})
public class CsrfConfigurerNoWebMvcTests {
ConfigurableApplicationContext context;
@@ -52,24 +43,30 @@ public class CsrfConfigurerNoWebMvcTests {
@Test
public void missingDispatcherServletPreventsCsrfRequestDataValueProcessor() {
spy(ClassUtils.class);
when(ClassUtils.isPresent(eq("org.springframework.web.servlet.DispatcherServlet"), any(ClassLoader.class))).thenReturn(false);
loadContext(CsrfDefaultsConfig.class);
loadContext(EnableWebConfig.class);
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isFalse();
}
@Test
public void findDispatcherServletPreventsCsrfRequestDataValueProcessor() {
loadContext(CsrfDefaultsConfig.class);
loadContext(EnableWebMvcConfig.class);
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
}
@EnableWebSecurity
@Configuration
static class CsrfDefaultsConfig extends WebSecurityConfigurerAdapter {
static class EnableWebConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
@EnableWebMvcSecurity
@Configuration
static class EnableWebMvcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
+1 -1
View File
@@ -30,7 +30,7 @@ dependencies {
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
powerMockDependencies
testRuntime "hsqldb:hsqldb:$hsqlVersion",
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:$cglibVersion"
}
+22 -28
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-core</name>
<description>spring-security-core</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-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.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -88,7 +82,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -122,14 +116,14 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@@ -151,12 +145,6 @@
<version>3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -169,6 +157,12 @@
<version>1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
@@ -220,7 +214,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -12,30 +12,91 @@ import org.springframework.security.core.Authentication;
*/
public interface SecurityExpressionOperations {
/**
* Gets the {@link Authentication} used for evaluating the expressions
* @return the {@link Authentication} for evaluating the expressions
*/
Authentication getAuthentication();
/**
* Determines if the {@link #getAuthentication()} has a particular authority within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAuthority(String)}.
* @param authority the authority to test (i.e. "ROLE_USER")
* @return true if the authority is found, else false
*/
boolean hasAuthority(String authority);
/**
* Determines if the {@link #getAuthentication()} has any of the specified authorities within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAnyRole(String...)}.
* @param authorities the authorities to test (i.e. "ROLE_USER", "ROLE_ADMIN")
* @return true if any of the authorities is found, else false
*/
boolean hasAnyAuthority(String... authorities);
/**
* Determines if the {@link #getAuthentication()} has a particular authority within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAuthority(String)}.
* @param authority the authority to test (i.e. "ROLE_USER")
* @return true if the authority is found, else false
*/
boolean hasRole(String role);
/**
* Determines if the {@link #getAuthentication()} has any of the specified authorities within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAnyAuthority(String...)}.
* @param authorities the authorities to test (i.e. "ROLE_USER", "ROLE_ADMIN")
* @return true if any of the authorities is found, else false
*/
boolean hasAnyRole(String... roles);
/**
* Always grants access.
* @return true
*/
boolean permitAll();
/**
* Always denies access
* @return false
*/
boolean denyAll();
/**
* Determines if the {@link #getAuthentication()} is anonymous
* @return true if the user is anonymous, else false
*/
boolean isAnonymous();
/**
* Determines ifthe {@link #getAuthentication()} is authenticated
* @return true if the {@link #getAuthentication()} is authenticated, else false
*/
boolean isAuthenticated();
/**
* Determines if the {@link #getAuthentication()} was authenticated using remember me
* @return true if the {@link #getAuthentication()} authenticated using remember me, else false
*/
boolean isRememberMe();
/**
* Determines if the {@link #getAuthentication()} authenticated without the use of remember me
* @return true if the {@link #getAuthentication()} authenticated without the use of remember me, else false
*/
boolean isFullyAuthenticated();
/**
* Determines if the {@link #getAuthentication()} has permission to access the target given the permission
* @param target the target domain object to check permission on
* @param permission the permission to check on the domain object (i.e. "read", "write", etc).
* @return true if permission is granted to the {@link #getAuthentication()}, else false
*/
boolean hasPermission(Object target, Object permission);
/**
* Determines if the {@link #getAuthentication()} has permission to access the domain object with a given id, type, and permission.
* @param targetId the identifier of the domain object to determine access
* @param targetType the type (i.e. com.example.domain.Message)
* @param permission the perission to check on the domain object (i.e. "read", "write", etc)
* @return true if permission is granted to the {@link #getAuthentication()}, else false
*/
boolean hasPermission(Object targetId, String targetType, Object permission);
}
@@ -5,7 +5,6 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.context.ApplicationContext;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolver;
@@ -38,11 +37,15 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
public final String delete = "delete";
public final String admin = "administration";
public SecurityExpressionRoot(Authentication a) {
if (a == null) {
/**
* Creates a new instance
* @param authentication the {@link Authentication} to use. Cannot be null.
*/
public SecurityExpressionRoot(Authentication authentication) {
if (authentication == null) {
throw new IllegalArgumentException("Authentication object cannot be null");
}
this.authentication = a;
this.authentication = authentication;
}
public final boolean hasAuthority(String authority) {
@@ -97,6 +100,10 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication);
}
/**
* Convenience method to access {@link Authentication#getPrincipal()} from {@link #getAuthentication()}
* @return
*/
public Object getPrincipal() {
return authentication.getPrincipal();
}
@@ -17,7 +17,7 @@ package org.springframework.security.authentication;
* Thrown if an authentication request could not be processed due to a system problem that occurred internally. It
* differs from {@link AuthenticationServiceException} in that it would not be thrown if an external system has an
* internal error or failure. This ensures that we can handle errors that are within our control distinctly from errors
* of other systems. The advantage to this distinction is that the unrusted external system should not be able to fill
* of other systems. The advantage to this distinction is that the untrusted external system should not be able to fill
* up logs and cause excessive IO. However, an internal system should report errors.
* </p>
* <p>
@@ -163,6 +163,9 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to invalid account status
throw e;
} catch (InternalAuthenticationServiceException e) {
prepareException(e, authentication);
throw e;
} catch (AuthenticationException e) {
lastException = e;
}
@@ -23,9 +23,7 @@ public class SpringSecurityCoreVersion {
*/
public static final long SERIAL_VERSION_UID = 320L;
static final String SPRING_MAJOR_VERSION = "3";
static final String MIN_SPRING_VERSION = "3.2.4.RELEASE";
static final String MIN_SPRING_VERSION = "3.2.6.RELEASE";
static {
performVersionChecks();
@@ -49,18 +47,20 @@ public class SpringSecurityCoreVersion {
}
logger.info("You are running with Spring Security Core " + version);
if (!springVersion.startsWith(SPRING_MAJOR_VERSION)) {
logger.warn("*** Spring Major version '" + SPRING_MAJOR_VERSION +
"' expected, but you are running with version: " + springVersion +
". Please check your classpath for unwanted jar files.");
}
if (springVersion.compareTo(MIN_SPRING_VERSION) < 0) {
logger.warn("**** You are advised to use Spring " + MIN_SPRING_VERSION +
" or later with this version. You are running: " + springVersion);
}
}
/**
* Disable if springVersion and springSecurityVersion are the same to allow
* working with Uber Jars.
*
* @param springVersion
* @param springSecurityVersion
* @return
*/
private static boolean disableChecks(String springVersion, String springSecurityVersion) {
if(springVersion == null || springVersion.equals(springSecurityVersion)) {
return true;
@@ -49,7 +49,7 @@ public class PopulatedDatabase {
JdbcTemplate template = new JdbcTemplate(dataSource);
template.execute(
"CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL)");
"CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) NOT NULL,ENABLED BOOLEAN NOT NULL)");
template.execute(
"CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME))");
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY)");
@@ -287,6 +287,20 @@ public class ProviderManagerTests {
verify(publisher).publishAuthenticationFailure(expected, authReq);
}
// SEC-2367
@Test
public void providerThrowsInternalAuthenticationServiceException() {
InternalAuthenticationServiceException expected = new InternalAuthenticationServiceException("Expected");
ProviderManager mgr = new ProviderManager(
Arrays.asList(createProviderWhichThrows(expected), createProviderWhichThrows(new BadCredentialsException("Oops"))), null);
final Authentication authReq = mock(Authentication.class);
try {
mgr.authenticate(authReq);
fail("Expected Exception");
} catch(InternalAuthenticationServiceException success) {}
}
private AuthenticationProvider createProviderWhichThrows(final AuthenticationException e) {
AuthenticationProvider provider = mock(AuthenticationProvider.class);
when(provider.supports(any(Class.class))).thenReturn(true);
@@ -17,6 +17,7 @@ package org.springframework.security.core;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -24,7 +25,9 @@ import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import org.apache.commons.logging.Log;
import org.junit.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
@@ -110,7 +113,19 @@ public class SpringSecurityCoreVersionTests {
performChecks();
verify(logger, times(2)).warn(any());
verify(logger, times(1)).warn(any());
}
@Test
public void noWarnIfSpringVersionLarger() throws Exception {
spy(SpringSecurityCoreVersion.class);
spy(SpringVersion.class);
when(SpringSecurityCoreVersion.getVersion()).thenReturn("3.2.0.RELEASE");
when(SpringVersion.getVersion()).thenReturn("4.0.0.RELEASE");
performChecks();
verify(logger, never()).warn(any());
}
@Test
+10 -16
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-crypto</name>
<description>spring-security-crypto</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,17 +42,11 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -101,7 +95,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
+2
View File
@@ -25,6 +25,8 @@ project('manual') {
doctype: 'book',
numbered: '',
'spring-security-version' : project.version,
'spring-version' : springVersion,
'spring4-version' : spring4Version,
revnumber : project.version
]
]
+39 -29
View File
@@ -1,36 +1,46 @@
apply plugin: 'asciidoctor'
import org.asciidoctor.gradle.*
file("src/asciidoc").eachFileMatch(~/.*\.asc/) { file->
task "asciidoctor-${file.name}"(type: AsciidoctorTask) {
sourceDocumentName = file
options = [
eruby: 'erubis',
eruby: 'erubis',
attributes: [
copycss : '',
icons : 'font',
'source-highlighter': 'prettify',
sectanchors : '',
toc2: '',
idprefix: '',
idseparator: '-',
doctype: 'book',
'spring-security-version' : project.version,
revnumber : project.version
]
]
}
}
task asciidoctor {
group = 'Documentation'
description = "Generates the asciidoc for $project.name"
dependsOn tasks.matching { t -> t.name.startsWith('asciidoctor-') }
asciidoctor {
baseDir = file('src/asciidoc')
options = [
eruby: 'erubis',
eruby: 'erubis',
attributes: [
copycss : '',
icons : 'font',
'source-highlighter': 'prettify',
sectanchors : '',
toc: '',
'toc-placement' : 'preamble',
idprefix: '',
idseparator: '-',
doctype: 'book',
'spring-security-version' : project.version,
'download-url' : getDownloadUrl(),
'include-maven-repository' : getMavenRepositoryInclude(),
revnumber : project.version
]
]
}
ext.spec = copySpec {
into ('guides') {
from("$buildDir/asciidoctor/dist/html5/")
from(asciidoctor.outputDir)
exclude 'build', 'Guardfile'
}
}
def getDownloadUrl() {
snapshotBuild ? "https://github.com/SpringSource/spring-security/archive/master.zip" : "https://github.com/spring-projects/spring-security/archive/${project.version}.zip"
}
def getMavenRepositoryInclude() {
if(snapshotBuild) {
return "_includes/maven-repository-snapshot.asc"
} else if(releaseBuild) {
return "_includes/maven-repository-release.asc"
} else {
return "_includes/maven-repository-milestone.asc"
}
}
+4 -1
View File
@@ -3,7 +3,10 @@ require 'erb'
guard 'shell' do
watch(/^.*\.asc$/) {|m|
Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'toc' => '', 'idprefix' => '', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'toc-placement' => 'preamble', 'spring-security-version' => '3.2.0.CI-SNAPSHOT', 'revnumber' => '3.2.0.CI-SNAPSHOT' })
Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'toc' => '', 'idprefix' => '', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'toc-placement' => 'preamble', 'revnumber' => '3.2.0.CI-SNAPSHOT',
'spring-security-version' => '3.2.0.CI-SNAPSHOT',
'download-url' => 'https://github.com/SpringSource/spring-security/archive/master.zip',
'include-maven-repository' => '_includes/maven-repository-snapshot.asc' })
}
end
@@ -1,22 +0,0 @@
==== Basic authentication
We stated that Spring Security supported both form and HTTP Basic authentication, but how does Spring Security know when to use one and not the other? When using HTTP Basic, the user should receive a HTTP 401 response, but when we visit our application in our web browser we are redirected to a login page. The reason for this is because Spring Security uses content negotiation to determine which type of authentication to use. For example, if we specified our *Accept* header to be _application/json_ the result would be an HTTP 401.
You can use any tool you prefer (i.e. curl), but the instructions in this section we will use https://www.google.com/intl/en/chrome/browser/[Google Chrome] and the https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en[Postman - REST Client] to make an _application/json_ request to our application.
* Open Google Chrome and launch the Postman - REST Client extension
* Enter _http://localhost:8080/sample/_ into the request URL field
* Select the *Headers* button
* Enter _Accept_ into the *Header* input
* Enter _application/json_ into the *Value* field
* Presss the *Send* button
Observe that we get an HTTP Status of 401 instead of our redirect. Now lets try entering our user name and password.
* Select the *Basic Auth* tab
* Enter _user_ for the *Username*
* Enter _password_ for the *Password*
* Click the *Refresh headers* button
* Click the *Send* button
This time you should see the HTML of our secured page.
@@ -16,4 +16,4 @@ You should see an error message stating that authentication failed. Now try ente
You should now see the page that we wanted to secure.
NOTE: The reason we can successfully authenticate with *Username* _user_ and *Password* _password_ is because that is what we configured in our <<security-config-java,`SecurityConfig`>>.
NOTE: The reason we can successfully authenticate with *Username* _user_ and *Password* _password_ is because that is what we configured in our <<security-config-java,SecurityConfig>>.
@@ -1,25 +1,12 @@
== Securing the application
Before securing your application, it is important to ensure that the existing application works as we did in <<running-the-{starter-appname}-application>>. Now that the application runs without security, we are ready to add security to our application. This section demonstrates the minimal steps to add Spring Security to a Spring MVC application.
Before securing your application, it is important to ensure that the existing application works as we did in <<running-the-{starter-appname}-application>>. Now that the application runs without security, we are ready to add security to our application. This section demonstrates the minimal steps to add Spring Security to our application.
=== Updating your dependencies
You will need to ensure you have added the dependencies. Spring Security milestones and release candidates are available in the https://github.com/SpringSource/spring-framework/wiki/SpringSource-repository-FAQ[Spring Milestone Repository]. In short, if you are using Maven and using a milestone or release candidates ensure you have the following repository in your pom.xml:
include::../{include-maven-repository}[]
.pom.xml
[source,xml]
----
<repositories>
<!-- ... possibly other repository elements ... -->
<repository>
<id>spring-libs-milestone</id>
<name>Spring Milestone Repository</name>
<url>http://repo.springsource.org/milestone</url>
</repository>
</repositories>
----
You will then need to include the Spring Security dependencies
In order to use Spring Security you must add the necessary dependencies. For the sample we will add the following Spring Security dependencies:
.pom.xml
[source,xml]
@@ -64,9 +51,8 @@ The next step is to create a Spring Security configuration.
package org.springframework.security.samples.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.*;
@Configuration
@@ -83,7 +69,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
----
[[servlet-api-integration]]
The <<security-config-java,`SecurityConfig`>> will:
The <<security-config-java,SecurityConfig>> will:
* Require authentication to every URL in your application
* Generate a login form for you
@@ -1,61 +0,0 @@
== Setting up the sample
This section outlines how to setup a workspace within STS so that you can follow along with this guide. The next section outlines generic steps for how to apply Spring Security to your existing application. While you could simply apply the steps to your existing application, we encourage you to follow along with this guide as is to reduce the complexity.
=== Obtaining the sample projects
There are multiple ways in which you can obtain the source. We have highlighted a few ways below:
* <<downloading-from-github>>
* <<cloning-from-github>>
==== Downloading from github
You can download the source from github.
* https://github.com/SpringSource/spring-security/archive/master.zip[Development Version]
* https://github.com/SpringSource/spring-security/releases[Released Versions]
Extract the zip to a known location and remember it as _SPRING_SECURITY_HOME_. You are now ready to <<import-the-{starter-appname}-sample-application>>
==== Cloning from github
If you wish you can also obtain the source by cloning from github. For example, if you have a git client installed you can type the following:
----
cd ~/git/
git clone https://github.com/SpringSource/spring-security.git
----
In this example, the code will be placed at "~/git/spring-security". Remember this location as _SPRING_SECURITY_HOME_.
=== Import the {starter-appname} sample application
In oder to follow along, we encourage you to import the {starter-appname} sample application into your IDE. You may use any IDE you prefer, but the instructions in the guide will assume you are using Spring Tool Suite (STS).
TIP: The completed sample application can be found at _SPRING_SECURITY_HOME_/{completed-appname}
* If you do not have STS installed, download STS from http://www.springsource.org/spring-tool-suite-download For performance reasons, we prefer the release based on Eclipse Juno.
* Start STS and import the sample applications into STS using the following steps:
** *File->Import*
** *Existing Maven Projects*
** Click *Next >*
** Click *Browse...*
** Navigate to the samples (i.e. _SPRING_SECURITY_HOME_/samples/{starter-appname}) and click *OK*
** Click *Finish*
=== Running the {starter-appname} application
In the following exerecise we will be modifying the _spring-security-samples-{starter-appname}_ application. Before we make any changes, it is best to verify that the sample works properly. Perform the following steps to ensure that _spring-security-samples-{starter-appname}_ works.
* Right click on the _spring-security-samples-{starter-appname}_ application
* Select *Run As->Run on Server*
* Select the latest tc Server (i.e. v2.9)
* Click *Finish*
include::{verify-starter-app-include}[]
Once you have verified the application runs, stop the application server using the following steps:
* In the Servers view select the latest tc Server
* Click the stop button (a red square) to stop the application server
@@ -1 +0,0 @@
A page stating *TODO Secure this* should be displayed at http://localhost:8080/sample/
@@ -1,5 +0,0 @@
Verify the application is working:
* A page displaying a user's inbox can be seen at http://localhost:8080/sample/
* Try clicking on the Compose link and creating a message. The message details should be displayed.
* Now click on the Inbox link and see the message listed. You can click on the summary link to see the details displayed again.
@@ -0,0 +1,14 @@
In order to resolve Spring Security milestones and release candidates add the Spring Milestone repository. For our example, the repository has already been added for you. In the event you were working on another application, you would need to ensure you add the following to your pom:
.pom.xml
[source,xml]
----
<repositories>
<!-- ... possibly other repository elements ... -->
<repository>
<id>spring-milestone</id>
<name>Spring Milestone Repository</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
----
@@ -0,0 +1 @@
Spring Security GA releases are included within Maven Central, so no additional Maven repositories are necessary.
@@ -0,0 +1,14 @@
In order to resolve Spring Security SNAPSHOT dependencies add the Spring Snapshot repository. For our example, the repository has already been added for you. In the event you were working on another application, you would need to ensure you add the following to your pom:
.pom.xml
[source,xml]
----
<repositories>
<!-- ... possibly other repository elements ... -->
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/snapshot</url>
</repository>
</repositories>
----
@@ -0,0 +1,40 @@
////
Variables:
starter-appname: the name of the module users should start with to complete the excercise
completed-appname: the name of the module that contains the completed application
download-url: the URL to download the Spring Security distribution
////
== Setting up the sample
This section outlines how to setup a workspace within https://spring.io/tools/sts[Spring Tool Suite (STS)] so that you can follow along with this guide. The next section outlines generic steps for how to apply Spring Security to your existing application. While you could simply apply the steps to your existing application, we encourage you to follow along with this guide as is to reduce the complexity.
=== Obtaining the sample projects
Extract the {download-url}[Spring Security Distribution] to a known location and remember it as _SPRING_SECURITY_HOME_.
=== Import the {starter-appname} sample application
In order to follow along, we encourage you to import the {starter-appname} sample application into your IDE. You may use any IDE you prefer, but the instructions in the guide will assume you are using Spring Tool Suite (STS).
TIP: The completed sample application can be found at _SPRING_SECURITY_HOME_/samples/{completed-appname}
* If you do not have STS installed, download STS from https://spring.io/tools
* Start STS and import the sample applications into STS using the following steps:
** *File->Import*
** *Existing Maven Projects*
** Click *Next >*
** Click *Browse...*
** Navigate to the samples (i.e. _SPRING_SECURITY_HOME_/samples/{starter-appname}) and click *OK*
** Click *Finish*
=== Running the {starter-appname} application
In the following exercise we will be modifying the _spring-security-samples-{starter-appname}_ application. Before we make any changes, it is best to verify that the sample works properly. Perform the following steps to ensure that _spring-security-samples-{starter-appname}_ works.
* Right click on the _spring-security-samples-{starter-appname}_ application
* Select *Run As->Run on Server*
* Select the latest tc Server
* Click *Finish*
+48 -53
View File
@@ -2,17 +2,23 @@
:author: Rob Winch
:starter-appname: hellomvc-jc
:completed-appname: form-jc
:include-dir: src/asciidoc/_hello-includes
:verify-starter-app-include: ../_form-includes/verify-app.asc
:include-dir: _includes
This guide builds off of link:hellomvc.html[Hello Spring MVC Security Java Config] to explain how to configure and use a custom login form with Spring Security Java Configuration.
include::{include-dir}/setting-up-the-sample.asc[]
Verify the application is working:
* A page displaying a user's inbox can be seen at http://localhost:8080/sample/ after authenticating with the *username* _user_ and the *password* _password_.
* Try clicking on the Compose link and creating a message. The message details should be displayed.
* Now click on the Inbox link and see the message listed. You can click on the summary link to see the details displayed again.
= Overriding the default configure(HttpSecurity) method
As we saw in link:hellomvc.html[Hello Spring MVC Security Java Config], Spring Security's `WebSecurityConfigurerAdapter` provides some convenient defaults to get our application
up and running quickly. However, our login form does not match the rest of our application. Let's see how we can update our configuration to use a custom form.
up and running quickly. However, our login form does not look like the rest of our application. Let's see how we can update our configuration to use a custom form.
== Default configure(HttpSecurity)
@@ -46,8 +52,10 @@ We will want to ensure we compensate for overriding these defaults in our update
----
// ...
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@@ -94,7 +102,7 @@ To fix this we need to instruct Spring Security to allow anyone to access the */
// ...
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@@ -112,11 +120,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
----
The `permitAll()` statement instructs Spring Security to allow any access to any URL (i.e. */login* and */login?error*) associated to `formLogin()`.
The method `formLogin().permitAll()` statement instructs Spring Security to allow any access to any URL (i.e. */login* and */login?error*) associated to `formLogin()`.
NOTE: Granting access to the `formLogin()` URLs is not done by default since Spring Security needs to make certain assumptions about what is allowed and what is not. To be secure, it is best to ensure granting access to resources is explicit.
Start up the server and try visiting http://localhost:8080/sample/ to see the updates to our configuration. You should now get a 404 error stating that */login* cannot be found.
Start up the server and try visiting http://localhost:8080/sample/ to see the updates to our configuration. You should now get a 500 error stating **Error resolving template "login"**.
= Creating a login page
@@ -144,71 +152,54 @@ public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
@Bean
public InternalResourceViewResolver jspxViewResolver() {
InternalResourceViewResolver result = new InternalResourceViewResolver();
result.setPrefix("/WEB-INF/views/");
result.setSuffix(".jspx");
return result;
}
}
----
== Creating a login view
Our existing configuration means that all we need to do is create a *login.jspx* file with the following contents:
Our existing configuration means that all we need to do is create a *login.html* file with the following contents:
.src/main/webapp/WEB-INF/views/login.jspx
.src/main/resources/views/login.html
[source,xml]
----
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:spring="http://www.springframework.org/tags"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:form="http://www.springframework.org/tags/form" version="2.0">
<jsp:directive.page language="java" contentType="text/html" />
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Please Login</title>
</head>
<body>
<c:url value="/login" var="loginUrl"/>
<form:form name="f" action="${loginUrl}" method="post"> <1>
<fieldset>
<legend>Please Login</legend>
<c:if test="${param.error != null}"> <2>
<div class="alert alert-error">
<html xmlns:th="http://www.thymeleaf.org" xmlns:tiles="http://www.thymeleaf.org">
<head>
<title tiles:fragment="title">Messages : Create</title>
</head>
<body>
<div tiles:fragment="content">
<form name="f" th:action="@{/login}" method="post"> <1>
<fieldset>
<legend>Please Login</legend>
<div th:if="${param.error}" class="alert alert-error"> <2>
Invalid username and password.
</div>
</c:if>
<c:if test="${param.logout != null}"> <3>
<div class="alert alert-success">
<div th:if="${param.logout}" class="alert alert-success"> <3>
You have been logged out.
</div>
</c:if>
<label for="username">Username</label>
<input type="text" id="username" name="username"/> <4>
<label for="password">Password</label>
<input type="password" id="password" name="password"/> <5>
<div class="form-actions">
<button type="submit" class="btn">Log in</button>
</div>
</fieldset>
</form:form>
</body>
<label for="username">Username</label>
<input type="text" id="username" name="username"/> <4>
<label for="password">Password</label>
<input type="password" id="password" name="password"/> <5>
<div class="form-actions">
<button type="submit" class="btn">Log in</button>
</div>
</fieldset>
</form>
</div>
</body>
</html>
</jsp:root>
----
<1> The URL we submit our username and password to is the same URL as our login form (i.e. */login*), but a *POST* instead of a *GET*.
<2> When authentication fails, the browser is redirected to */login?error* so we can display an error message by detecting if the parameter *error* is non-null.
<3> When we are successfully loged out, the browser is redirected to */login?logout* so we can display an logout success message by detecting if the parameter *logout* is non-null.
<3> When we are successfully logged out, the browser is redirected to */login?logout* so we can display an logout success message by detecting if the parameter *logout* is non-null.
<4> The username should be present on the HTTP parameter username
<5> The password should be present on the HTTP parameter password
IMPORTANT: Do not display details about why authentication failed. For example, we do not want to display that the user does not exist as this will tell an attacker that they should try a different username.
TIP: We use Spring Web MVC's <form:form> tag to automatically add the CSRF token to our form. We could also manually add the CSRF token using `<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>`.
TIP: We use Thymeleaf to automatically add the CSRF token to our form. If we were not using Thymleaf or Spring MVCs taglib we could also manually add the CSRF token using `<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>`.
Start up the server and try visiting http://localhost:8080/sample/ to see the updates to our configuration. We now see our login page, but it does not look very pretty. The issue is that we have not granted access to the css files.
@@ -222,7 +213,7 @@ We need to update our configuration to allow anyone to access our resources and
// ...
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@@ -248,8 +239,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
<2> As you might expect, `logout().permitAll()` allows any user to request logout and view logout success URL.
Start up the server and try visiting http://localhost:8080/sample/ to see the updates to our configuration. We now see a custom login page that looks like the rest of our application.
Restart the server and try visiting http://localhost:8080/sample/ to see the updates to our configuration. We now see a custom login page that looks like the rest of our application.
* Try entering an invalid username and password. You will see our error message is displayed.
* Try entering a valid username and password. You will be authenticated successfully.
* Try entering a valid username (user) and password (password). You will be authenticated successfully.
* Try clicking the Log Out button. You will see our logout success message
== Conclusion
You should now know how to add a custom login form using Spring Security's Java Configuration. To learn more refer to the link:index.html[Spring Security Guides index page].
+47 -56
View File
@@ -2,14 +2,21 @@
:author: Rob Winch
:starter-appname: insecuremvc
:completed-appname: hellomvc-jc
:include-dir: src/asciidoc/_hello-includes
:verify-starter-app-include: verify-insecuremvc-app.asc
:include-dir: _includes
:hello-include-dir: _hello-includes
This guide provides instructions on how to add Spring Security to an existing Spring MVC application without the use of XML.
include::{include-dir}/setting-up-the-sample.asc[]
include::{include-dir}/secure-the-application.asc[]
Verify the application is working:
* A page displaying a user's inbox can be seen at http://localhost:8080/sample/
* Try clicking on the Compose link and creating a message. The message details should be displayed.
* Now click on the Inbox link and see the message listed. You can click on the summary link to see the details displayed again.
include::{hello-include-dir}/secure-the-application.asc[]
=== Registering Spring Security with the war
@@ -18,35 +25,32 @@ We have created the Spring Security configuration, but we still need to register
* Right click the _spring-security-samples-{starter-appname}_ project the Package Explorer view
* Select *New->Class*
* Enter _org.springframework.security.samples.config_ for the *Package*
* Enter _SecurityWebApplicationInitializer_ for the *Name*
* Enter MessageSecurityWebApplicationInitializer for the *Name*
* Click *Finish*
* Replace the file with the following contents:
.src/main/java/org/springframework/security/samples/config/SecurityWebApplicationInitializer.java
.src/main/java/org/springframework/security/samples/config/MessageSecurityWebApplicationInitializer.java
[source,java]
----
package org.springframework.security.samples.config;
import org.springframework.core.annotation.*;
import org.springframework.security.web.context.*;
@Order(2)
public class MessageSecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
----
The `MessageSecurityWebApplicationInitializer` will automatically register the springSecurityFilterChain Filter for every URL in your application. We add `@Order(2)` so the springSecurityFilterChain is inserted before our Sitemesh Filter declared in <<message-web-application-inititializer-java, MessageWebApplicationInitializer.java>>
The `MessageSecurityWebApplicationInitializer` will automatically register the springSecurityFilterChain Filter for every URL in your application. If Filters are added within other `WebApplicationInitializer` instances we can use `@Order` to control the ordering of the Filter instances.
=== Verify SecurityConfig is loaded
Just because <<security-config-java,`SecurityConfig`>> exists, does not mean that our Spring application knows about it. In this instance, our Spring root application context is initialized using MessageWebApplicationInitializer which is included with our spring-security-samples-messages-jc project. You can find a snippet of it below:
Just because <<security-config-java,SecurityConfig>> exists, does not mean that our Spring application knows about it. In this instance, our Spring root application context is initialized using MessageWebApplicationInitializer which is included with our spring-security-samples-messages-jc project. You can find a snippet of it below:
[[message-web-application-inititializer-java]]
.MessageWebApplicationInitializer.java
[source,java]
----
@Order(1)
public class MessageWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@@ -66,81 +70,68 @@ You will notice it is loading the `RootConfiguration` class which is also includ
[source,java]
----
@Configuration
@ComponentScan(value = "org.springframework.security.samples.config",
excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = RootConfiguration.class))
@ComponentScan
public class RootConfiguration {
}
----
The `@ComponentScan` is loading all configuration in the org.springframework.security.samples.config package. Since <<security-config-java,`SecurityConfig`>> is in this package, it will be loaded with our existing setup and there is nothing more to do.
The `@ComponentScan` is loading all configuration within the same package (and child packags) as `RootConfiguration`. Since <<security-config-java,SecurityConfig>> is in this package, it will be loaded with our existing setup and there is nothing more to do.
NOTE: Had <<security-config-java,`SecurityConfig`>> not been loaded, we could have used an `@Import(SecurityConfig)` above the class definition of <<root-configuration-java,`RootConfiguration`>> or added <<security-config-java,`SecurityConfig`>> as one of the results for `getRootConfigClasses()`.
NOTE: Had <<security-config-java,SecurityConfig>> not been loaded, we could have used an `@Import(SecurityConfig)` above the class definition of <<root-configuration-java,RootConfiguration>> or added <<security-config-java,SecurityConfig>> as one of the results for `getRootConfigClasses()`.
include::{include-dir}/exploring-the-secured-application.asc[]
include::{hello-include-dir}/exploring-the-secured-application.asc[]
==== Displaying the user name
Now that we have authenticated, let's update the application to display the username if the user is authenticated. Update main.jsp to contain the following snippet:
Now that we have authenticated, let's see how our application is displaying the username if the user is authenticated.
.src/main/webapp/WEB-INF/decorators/main.jsp
.messages-jc/src/main/resources/views/layout.html
[source,html]
[subs="verbatim,quotes"]
----
<div class="nav-collapse collapse">
*<c:if test="${pageContext.request.remoteUser != null}">
<p class="navbar-text pull-right">
<c:out value="${pageContext.request.remoteUser}"/>
<div th:if="${#httpServletRequest.remoteUser != null}">
<p th:text="${#httpServletRequest.remoteUser}">
sample_user
</p>
</c:if>*
<ul class="nav">
<c:url var="inboxUrl" value="/"/>
<li><a href="${inboxUrl}">Inbox</a></li>
<c:url var="composeUrl" value="/?form"/>
<li><a href="${composeUrl}">Compose</a></li>
</ul>
</div>
----
WARNING: The `<c:out />` tag ensures the username is escaped to avoid http://en.wikipedia.org/wiki/Cross-site_scripting[XSS vulnerabilities] Regardless of how an application renders user inputed values, it should ensure that the values are properly escaped.
In our samples we use http://www.thymeleaf.org/[Thymeleaf], but any view technology will work. Any technology can inspect the `HttpServletRequest#getRemoteUser()` to view the current user since Spring Security integrates with the <<servlet-api-integration,Servlet API methods>>.
Refresh the page at http://localhost:8080/sample/ and you will see the user name displayed. This works because Spring Security integrates with the <<servlet-api-integration,Servlet API methods>>
WARNING: The Thymeleaf ensures the username is escaped to avoid http://en.wikipedia.org/wiki/Cross-site_scripting[XSS vulnerabilities] Regardless of how an application renders user inputed values, it should ensure that the values are properly escaped.
==== Logging out
Now that we can view the user name, let's update the application to allow logging out. Update the body of index.jsp to contain a log out link as shown below:
We can view the user name, but how are we able to log out? Below you can see how we are able to log out.
.src/main/webapp/index.jsp
.messages-jc/src/main/resources/views/layout.html
[source,html]
[subs="verbatim,quotes"]
----
<div class="nav-collapse collapse">
*<c:if test="${pageContext.request.remoteUser != null}">
<c:url var="logoutUrl" value="/logout"/>
<form:form class="navbar-form pull-right" action="${logoutUrl}" method="post">
<input type="submit" value="Log out" />
</form:form>
</c:if>*
<p class="navbar-text pull-right">
<c:out value="${pageContext.request.remoteUser}"/>
</p>
<ul class="nav">
<c:url var="inboxUrl" value="/"/>
<li><a href="${inboxUrl}">Inbox</a></li>
<c:url var="composeUrl" value="/?form"/>
<li><a href="${composeUrl}">Compose</a></li>
</ul>
</div>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Log out" />
</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.
.src/main/java/org/springframework/security/samples/config/SecurityConfig.java
[source,java]
----
import org.springframework.security.config.annotation.web.servlet.configuration.*;
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
----
In order to help protect against http://en.wikipedia.org/wiki/Cross-site_request_forgery[CSRF attacks], by default, Spring Security Java Configuration log out requires:
* the HTTP method must be a POST
* the CSRF token must be added to the request. Since we are using Spring MVC, the CSRF token is automatically added as a hidden input for you (view the source to see it). If you were not using Spring MVC, you can access the CsrfToken on the ServletRequest using the attribute _csrf
* the CSRF token must be added to the request. Since we have used `@EnableWebMvcSecurity` and are using Thymeleaf, the CSRF token is automatically added as a hidden input for you (view the source to see it).
Refresh the page at http://localhost:8080/sample/ and you will see the log out button. Click the button and see that the application logs you out successfully.
NOTE: If you were not using Spring MVC taglibs or Thymeleaf, you can access the CsrfToken on the ServletRequest using the attribute _csrf. You can find an example of including the CSRF token in a JSP within the link:helloworld.html[Hello Spring Security Java Config].
include::{include-dir}/basic-authentication.asc[]
Restart the application server and click the Log out button and see that the application logs you out successfully.
== Conclusion
You should now now how to secure your application using Spring Security without using any XML. Next, we will see how to link:form.html[customize our login form].
You should now know how to secure your application using Spring Security without using any XML. Next, we will see how to link:form.html[customize our login form].
+18 -11
View File
@@ -2,14 +2,21 @@
:author: Rob Winch
:starter-appname: insecure
:completed-appname: helloworld-jc
:include-dir: src/asciidoc/_hello-includes
:verify-starter-app-include: verify-insecure-app.asc
:include-dir: _includes
:hello-include-dir: _hello-includes
This guide provides instructions on how to add Spring Security to an existing application without the use of XML.
include::{include-dir}/setting-up-the-sample.asc[]
include::{include-dir}/secure-the-application.asc[]
Verify the application is working by ensuring a page stating *TODO Secure this* is displayed at http://localhost:8080/sample/
Once you have verified the application runs, stop the application server using the following steps:
* In the Servers view select the latest tc Server
* Click the stop button (a red square) to stop the application server
include::{hello-include-dir}/secure-the-application.asc[]
=== Registering Spring Security with the war
@@ -41,11 +48,11 @@ public class SecurityWebApplicationInitializer
The `SecurityWebApplicationInitializer` will do the following things:
* Automatically register the springSecurityFilterChain Filter for every URL in your application
* Add a ContextLoaderListener that loads the <<security-config-java,`SecurityConfig`>>.
* Add a ContextLoaderListener that loads the <<security-config-java,SecurityConfig>>.
NOTE: Since we were not already using Spring, this is a simple way to add our <<security-config-java,`SecurityConfig`>>. If we were already using Spring, then we should add our <<security-config-java,`SecurityConfig`>> with the reset of our Spring configuration (i.e. a subclass of AbstractContextLoaderInitializer or AbstractDispatcherServletInitializer) and use the default constructor instead.
NOTE: Since we were not already using Spring, this is a simple way to add our <<security-config-java,SecurityConfig>>. If we were already using Spring, then we should add our <<security-config-java,SecurityConfig>> with the reset of our Spring configuration (i.e. a subclass of AbstractContextLoaderInitializer or AbstractDispatcherServletInitializer) and use the default constructor instead.
include::{include-dir}/exploring-the-secured-application.asc[]
include::{hello-include-dir}/exploring-the-secured-application.asc[]
==== Displaying the user name
@@ -70,7 +77,7 @@ Refresh the page at http://localhost:8080/sample/ and you will see the user name
==== Logging out
Now that we can view the user name, let's update the application to allow logging out. Update the body of index.jsp to contain a log out link as shown below:
Now that we can view the user name, let's update the application to allow logging out. Update the body of index.jsp to contain a log out form as shown below:
.src/main/webapp/index.jsp
[source,html]
@@ -93,12 +100,12 @@ Now that we can view the user name, let's update the application to allow loggin
In order to help protect against http://en.wikipedia.org/wiki/Cross-site_request_forgery[CSRF attacks], by default, Spring Security Java Configuration log out requires:
* the HTTP method must be a POST
* the CSRF token must be added to the request You can access it on the ServletRequest using the attribute _csrf as illustrated above. If you were using Spring MVC, the CSRF token is automatically added as a hidden input for you.
* the CSRF token must be added to the request You can access it on the ServletRequest using the attribute _csrf as illustrated above.
NOTE: If you were using Spring MVC's tag library or Thymeleaf, the CSRF token is automatically added as a hidden input for you.
Refresh the page at http://localhost:8080/sample/ and you will see the log out button. Click the logout button and see that the application logs you out successfully.
include::{include-dir}/basic-authentication.asc[]
== Conclusion
You should now now how to secure your application using Spring Security without using any XML.
You should now know how to secure your application using Spring Security without using any XML. To learn more refer to the link:index.html[Spring Security Guides index page].
+1 -1
View File
@@ -1,7 +1,7 @@
= Spring Security Guides
Rob Winch
These are set by step guides on how to use Spring Security.
These are step by step guides on how to use Spring Security.
== Hello World
+1 -1
View File
@@ -3,7 +3,7 @@ require 'erb'
guard 'shell' do
watch(/^.*\.adoc$/) {|m|
Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'idprefix' => '', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'doctype' => 'book','toc2' => '', 'spring-security-version' => '3.2.0.CI-SNAPSHOT', 'revnumber' => '3.2.0.CI-SNAPSHOT' })
Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'idprefix' => '', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'doctype' => 'book','toc2' => '', 'spring-security-version' => '3.2.0.CI-SNAPSHOT','spring-version' => '3.2.0.RELEASE','spring4-version' => '4.0.0.RELEASE', 'revnumber' => '3.2.0.CI-SNAPSHOT', 'numbered'=>'' })
}
end
+6
View File
@@ -70,6 +70,7 @@ From a Spring Security perspective, the first thing you should do is follow the
.. <<faq-session-listener-missing>>
.. <<faq-unwanted-session-creation>>
. Miscellaneous
.. <<403-csrf>>
.. <<faq-no-security-on-forward>>
.. <<faq-method-security-in-web-context>>
.. <<faq-no-filters-no-context>>
@@ -206,6 +207,11 @@ This usually means that the user's application is creating a session somewhere,
If you are having trouble working out where a session is being created, you can add some debugging code to track down the location(s). One way to do this would be to add a `javax.servlet.http.HttpSessionListener` to your application, which calls `Thread.dumpStack()` in the `sessionCreated` method.
[[403-csrf]]
=== I get a 403 Forbidden when performing a POST
If an HTTP 403 Forbidden is returned for HTTP POST, but works for HTTP GET then the issue is most likely related to http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#csrf[CSRF]. Either provide the CSRF Token or disable CSRF protection (not recommended).
[[faq-no-security-on-forward]]
=== I'm forwarding a request to another URL using the RequestDispatcher, but my security constraints aren't being applied.
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
version=3.2.0.CI-SNAPSHOT
version=3.2.0.RELEASE
+6 -2
View File
@@ -11,14 +11,13 @@ apply plugin: 'propdeps-eclipse'
sourceCompatibility = 1.5
targetCompatibility = 1.5
ext.springVersion = '3.2.4.RELEASE'
ext.springLdapVersion = '1.3.2.RELEASE'
ext.ehcacheVersion = '1.6.2'
ext.aspectjVersion = '1.6.10'
ext.apacheDsVersion = '1.5.5'
ext.jstlVersion = '1.2'
ext.jettyVersion = '6.1.26'
ext.hsqlVersion = '1.8.0.10'
ext.hsqlVersion = '2.3.1'
ext.slf4jVersion = '1.7.5'
ext.logbackVersion = '0.9.29'
ext.cglibVersion = '2.2'
@@ -28,6 +27,7 @@ ext.seleniumVersion = '2.33.0'
ext.groovyVersion = '2.0.5'
ext.spockVersion = '0.7-groovy-2.0'
ext.gebVersion = '0.9.0'
ext.thymeleafVersion = '2.1.2.RELEASE'
ext.powerMockDependencies = [
"org.powermock:powermock-core:$powerMockVersion",
@@ -204,3 +204,7 @@ task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}
artifacts {
archives javadocJar
}
+19 -11
View File
@@ -9,7 +9,6 @@ task sourceJar(type: Jar) {
artifacts {
archives sourceJar
archives javadocJar
}
// Configuration for SpringSource s3 maven deployer
@@ -21,7 +20,9 @@ dependencies {
}
install {
customizePom(repositories.mavenInstaller.pom, project)
repositories.mavenInstaller {
customizePom(pom, project)
}
}
def customizePom(pom, gradleProject) {
@@ -42,10 +43,10 @@ def customizePom(pom, gradleProject) {
packaging = "war"
}
description = gradleProject.name
url = 'http://springsource.org/spring-security'
url = 'http://spring.io/spring-security'
organization {
name = 'SpringSource'
url = 'http://springsource.org/'
name = 'spring.io'
url = 'http://spring.io/'
}
licenses {
license {
@@ -55,15 +56,15 @@ def customizePom(pom, gradleProject) {
}
}
scm {
url = 'https://github.com/SpringSource/spring-security'
connection = 'scm:git:git://github.com/SpringSource/spring-security'
developerConnection = 'scm:git:git://github.com/SpringSource/spring-security'
url = 'https://github.com/spring-projects/spring-security'
connection = 'scm:git:git://github.com/spring-projects/spring-security'
developerConnection = 'scm:git:git://github.com/spring-projects/spring-security'
}
developers {
developer {
id = 'rwinch'
name = 'Rob Winch'
email = 'rwinch@vmware.com'
email = 'rwinch@gopivotal.com'
}
}
if(isWar) {
@@ -71,11 +72,18 @@ def customizePom(pom, gradleProject) {
'm2eclipse.wtp.contextRoot' '/' + project.war.baseName
}
}
if(!project.releaseBuild) {
if(project.snapshotBuild) {
repositories {
repository {
id 'spring-snasphot'
url 'http://repo.springsource.org/libs-snapshot'
url 'https://repo.spring.io/snapshot'
}
}
} else if(!project.releaseBuild) {
repositories {
repository {
id 'spring-milestone'
url 'https://repo.spring.io/milestone'
}
}
}
Binary file not shown.
+2 -2
View File
@@ -1,6 +1,6 @@
#Tue Sep 24 11:43:41 CDT 2013
#Wed Dec 11 17:49:08 CST 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-bin.zip
distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-rc-2-bin.zip
+18 -24
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>itest-context</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>itest-context</name>
<description>itest-context</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>aopalliance</groupId>
@@ -64,31 +58,31 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -100,7 +94,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -155,25 +149,25 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
+19 -25
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>itest-web</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>itest-web</name>
<description>itest-web</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,23 +42,17 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -70,7 +64,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -149,49 +143,49 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
-2
View File
@@ -29,13 +29,11 @@ integrationTest {
include('**/ApacheDSServerIntegrationTests.class')
// exclude('**/OpenLDAPIntegrationTestSuite.class')
maxParallelForks = 1
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
}
// Runs a server for running the integration tests against (from an IDE, for example)
task(ldapServer, dependsOn: 'integrationTestClasses', type: JavaExec) {
classpath = sourceSets.integrationTest.runtimeClasspath
main = 'org.springframework.security.ldap.ApacheDSServerIntegrationTests'
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
}
+14 -20
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-ldap</name>
<description>spring-security-ldap</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-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.0.CI-SNAPSHOT</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -106,7 +100,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -204,7 +198,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -21,7 +21,7 @@ import org.springframework.security.ldap.userdetails.LdapUserDetailsManagerTests
DefaultLdapAuthoritiesPopulatorTests.class,
LdapUserDetailsManagerTests.class,
DefaultSpringSecurityContextSourceTests.class,
SpringSecurityLdapTemplateTests.class
SpringSecurityLdapTemplateITests.class
}
)
public final class ApacheDSServerIntegrationTests {
@@ -33,7 +33,7 @@ import org.springframework.security.crypto.codec.Utf8;
/**
* @author Luke Taylor
*/
public class SpringSecurityLdapTemplateTests extends AbstractLdapIntegrationTests {
public class SpringSecurityLdapTemplateITests extends AbstractLdapIntegrationTests {
//~ Instance fields ================================================================================================
private SpringSecurityLdapTemplate template;
@@ -1,10 +1,11 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/*
* 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
* 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,
@@ -12,23 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.ldap;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.naming.CompositeName;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.PartialResultException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
@@ -42,6 +28,18 @@ import org.springframework.ldap.core.LdapEncoder;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.util.Assert;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.PartialResultException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Extension of Spring LDAP's LdapTemplate class which adds extra functionality required by Spring Security.
@@ -55,6 +53,7 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
private static final Log logger = LogFactory.getLog(SpringSecurityLdapTemplate.class);
public static final String[] NO_ATTRS = new String[0];
private static final boolean RETURN_OBJECT = true;
//~ Instance fields ================================================================================================
@@ -207,7 +206,7 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
String base, String filter, Object[] params) throws NamingException {
final DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
final DistinguishedName searchBaseDn = new DistinguishedName(base);
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, searchControls);
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, buildControls(searchControls));
if (logger.isDebugEnabled()) {
logger.debug("Searching for entry under DN '" + ctxBaseDn
@@ -218,17 +217,13 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
try {
while (resultsEnum.hasMore()) {
SearchResult searchResult = resultsEnum.next();
// Work out the DN of the matched entry
DistinguishedName dn = new DistinguishedName(new CompositeName(searchResult.getName()));
if (base.length() > 0) {
dn.prepend(searchBaseDn);
}
DirContextAdapter dca = (DirContextAdapter) searchResult.getObject();
Assert.notNull(dca, "No object returned by search, DirContext is not correctly configured");
if (logger.isDebugEnabled()) {
logger.debug("Found DN: " + dn);
logger.debug("Found DN: " + dca.getDn());
}
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
results.add(dca);
}
} catch (PartialResultException e) {
LdapUtils.closeEnumeration(resultsEnum);
@@ -246,6 +241,21 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
return results.iterator().next();
}
/**
* We need to make sure the search controls has the return object flag set to true, in order for
* the search to return DirContextAdapter instances.
* @param originalControls
* @return
*/
private static SearchControls buildControls(SearchControls originalControls) {
return new SearchControls(originalControls.getSearchScope(),
originalControls.getCountLimit(),
originalControls.getTimeLimit(),
originalControls.getReturningAttributes(),
RETURN_OBJECT,
originalControls.getDerefLinkFlag());
}
/**
* Sets the search controls which will be used for search operations by the template.
*
@@ -15,6 +15,7 @@ package org.springframework.security.ldap.authentication.ad;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
@@ -174,6 +175,7 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends AbstractLda
env.put(Context.PROVIDER_URL, bindUrl);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.OBJECT_FACTORIES, DefaultDirObjectFactory.class.getName());
try {
return contextFactory.createContext(env);
@@ -133,7 +133,7 @@ public class LdapUserDetailsImpl implements LdapUserDetails, PasswordPolicyData
sb.append("CredentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
if (this.getAuthorities() != null) {
if (this.getAuthorities() != null && !this.getAuthorities().isEmpty()) {
sb.append("Granted Authorities: ");
boolean first = true;
@@ -0,0 +1,68 @@
/*
* 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.ldap;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import javax.naming.NamingEnumeration;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DistinguishedName;
@RunWith(MockitoJUnitRunner.class)
public class SpringSecurityLdapTemplateTests {
@Mock
private DirContext ctx;
@Captor
private ArgumentCaptor<SearchControls> searchControls;
@Mock
private NamingEnumeration<SearchResult> resultsEnum;
@Mock
private SearchResult searchResult;
// SEC-2405
@Test
public void searchForSingleEntryInternalAllowsReferrals() throws Exception {
String base = "";
String filter = "";
String searchResultName = "ldap://example.com/dc=springframework,dc=org";
Object[] params = new Object[] {};
DirContextAdapter searchResultObject = mock(DirContextAdapter.class);
when(ctx.search(any(DistinguishedName.class), eq(filter), eq(params), searchControls.capture())).thenReturn(resultsEnum);
when(resultsEnum.hasMore()).thenReturn(true, false);
when(resultsEnum.next()).thenReturn(searchResult);
when(searchResult.getName()).thenReturn(searchResultName);
when(searchResult.getObject()).thenReturn(searchResultObject);
SpringSecurityLdapTemplate.searchForSingleEntryInternal(ctx, mock(SearchControls.class), base, filter, params);
assertThat(searchControls.getValue().getReturningObjFlag()).isTrue();
}
}
@@ -12,16 +12,14 @@
*/
package org.springframework.security.ldap.authentication.ad;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.ContextFactory;
import org.apache.directory.shared.ldap.util.EmptyEnumeration;
import org.hamcrest.BaseMatcher;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.ldap.core.DirContextAdapter;
@@ -33,8 +31,6 @@ import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import javax.naming.AuthenticationException;
import javax.naming.CommunicationException;
@@ -45,7 +41,15 @@ import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import java.util.*;
import java.util.Hashtable;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.ContextFactory;
/**
* @author Luke Taylor
@@ -75,7 +79,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
when(ctx.getNameInNamespace()).thenReturn("");
DirContextAdapter dca = new DirContextAdapter();
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", null, dca.getAttributes());
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", dca, dca.getAttributes());
when(ctx.search(any(Name.class), any(String.class), any(Object[].class), any(SearchControls.class)))
.thenReturn(new MockNamingEnumeration(sr))
.thenReturn(new MockNamingEnumeration(sr));
@@ -88,8 +92,6 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
dca.addAttributeValue("memberOf","CN=Admin,CN=Users,DC=mydomain,DC=eu");
sr.setAttributes(dca.getAttributes());
result = provider.authenticate(joe);
assertEquals(1, result.getAuthorities().size());
@@ -102,7 +104,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
when(ctx.getNameInNamespace()).thenReturn("");
DirContextAdapter dca = new DirContextAdapter();
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", null, dca.getAttributes());
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", dca, dca.getAttributes());
when(ctx.search(eq(new DistinguishedName("DC=mydomain,DC=eu")), any(String.class), any(Object[].class), any(SearchControls.class)))
.thenReturn(new MockNamingEnumeration(sr));
provider.contextFactory = createContextFactoryReturning(ctx);
@@ -149,7 +151,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
NamingEnumeration<SearchResult> searchResults = mock(NamingEnumeration.class);
when(searchResults.hasMore()).thenReturn(true,true,false);
SearchResult searchResult = mock(SearchResult.class);
when(searchResult.getName()).thenReturn("ou=1","ou=2");
when(searchResult.getObject()).thenReturn(new DirContextAdapter("ou=1"),new DirContextAdapter("ou=2"));
when(searchResults.next()).thenReturn(searchResult);
when(ctx.search(any(Name.class), any(String.class), any(Object[].class), any(SearchControls.class)))
.thenReturn(searchResults );

Some files were not shown because too many files have changed in this diff Show More