Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b0c21dfef | |||
| 8301bd6276 | |||
| 1872d94aa1 | |||
| 46611872db | |||
| b6cbdde0cb | |||
| 71e1702224 | |||
| 80ccd2b285 | |||
| 02c1f02f2a | |||
| 21a664b2eb | |||
| 9a2d0c2cb5 | |||
| 73b62497a3 | |||
| 09aba3906c | |||
| 57cfff6f5c | |||
| b7b6b2bac7 | |||
| 8602ae3863 | |||
| 8737fe3acb | |||
| 27faad3402 | |||
| aaa7bd90b2 | |||
| 295e0ded18 | |||
| 304f12fb63 | |||
| 8cbe232fbf | |||
| 5ac106808e | |||
| 8c605516b3 | |||
| e6e168f127 | |||
| 6d6c2d31ef | |||
| 8f6aecac9b | |||
| 0760bb947b | |||
| 9d2e2ca11d | |||
| 6354c7e052 | |||
| 42cdaa0ce2 | |||
| eda60b72b1 | |||
| 0d198d42ae | |||
| f000aaa7e8 | |||
| 634e340d80 | |||
| 4c8e9e2d7e | |||
| e518adbef1 | |||
| 59b69f6f48 | |||
| b8e50c0933 | |||
| 677576ea8b | |||
| 91153df78d | |||
| 1b0ac9c785 | |||
| 8c9159f273 | |||
| 4c8b0faa88 | |||
| 5a5b62e2cb | |||
| 6ac8588144 | |||
| 5690f1c581 | |||
| 87cf27ab7c | |||
| 41e06152b3 | |||
| a7e21318bf | |||
| bc6aae132b | |||
| b46ae6ac62 | |||
| 317da55cd0 | |||
| 9e751e22c8 | |||
| 4d65b35827 | |||
| 9831980bc2 |
@@ -4,5 +4,8 @@ target/
|
|||||||
.settings/
|
.settings/
|
||||||
build/
|
build/
|
||||||
*.log
|
*.log
|
||||||
|
*.log.1
|
||||||
|
.DS_Store
|
||||||
|
*.iml
|
||||||
.gradle/
|
.gradle/
|
||||||
gradle.properties
|
gradle.properties
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ dependencies {
|
|||||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||||
"org.springframework:spring-aop:$springVersion",
|
"org.springframework:spring-aop:$springVersion",
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-tx:$springVersion",
|
"org.springframework:spring-tx:$springVersion",
|
||||||
"org.springframework:spring-jdbc:$springVersion"
|
"org.springframework:spring-jdbc:$springVersion"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':spring-security-core'),
|
||||||
|
"org.springframework:spring-beans:$springVersion",
|
||||||
|
"org.springframework:spring-context:$springVersion"
|
||||||
|
}
|
||||||
+4
-8
@@ -5,16 +5,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<artifactId>spring-security-aspects</artifactId>
|
<artifactId>spring-security-aspects</artifactId>
|
||||||
<name>Spring Security - Aspects</name>
|
<name>Spring Security - Aspects</name>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.aspectj</groupId>
|
<groupId>org.aspectj</groupId>
|
||||||
<artifactId>aspectjweaver</artifactId>
|
<artifactId>aspectjweaver</artifactId>
|
||||||
@@ -22,7 +18,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-core</artifactId>
|
<artifactId>spring-security-core</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
@@ -39,12 +35,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.aspectj</groupId>
|
<groupId>org.aspectj</groupId>
|
||||||
<artifactId>aspectjrt</artifactId>
|
<artifactId>aspectjrt</artifactId>
|
||||||
<version>1.6.5</version>
|
<version>1.6.8</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.aspectj</groupId>
|
<groupId>org.aspectj</groupId>
|
||||||
<artifactId>aspectjtools</artifactId>
|
<artifactId>aspectjtools</artifactId>
|
||||||
<version>1.6.5</version>
|
<version>1.6.8</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<executions>
|
<executions>
|
||||||
|
|||||||
+18
-8
@@ -2,11 +2,12 @@ package org.springframework.security.access.intercept.aspectj.aspect;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.security.access.annotation.Secured;
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.security.access.prepost.*;
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
|
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
|
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concrete AspectJ transaction aspect using Spring Security @Secured annotation
|
* Concrete AspectJ aspect using Spring Security @Secured annotation
|
||||||
* for JDK 1.5+.
|
* for JDK 1.5+.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
@@ -16,8 +17,8 @@ import org.springframework.security.access.intercept.aspectj.AspectJSecurityInte
|
|||||||
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
|
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
|
||||||
*
|
*
|
||||||
* @author Mike Wiesner
|
* @author Mike Wiesner
|
||||||
* @since 1.0
|
* @author Luke Taylor
|
||||||
* @version $Id$
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public aspect AnnotationSecurityAspect implements InitializingBean {
|
public aspect AnnotationSecurityAspect implements InitializingBean {
|
||||||
|
|
||||||
@@ -34,11 +35,19 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
|
|||||||
private pointcut executionOfSecuredMethod() :
|
private pointcut executionOfSecuredMethod() :
|
||||||
execution(* *(..)) && @annotation(Secured);
|
execution(* *(..)) && @annotation(Secured);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches the execution of any method with Pre/Post annotations.
|
||||||
|
*/
|
||||||
|
private pointcut executionOfPrePostAnnotatedMethod() :
|
||||||
|
execution(* *(..)) && (@annotation(PreAuthorize) || @annotation(PreFilter)
|
||||||
|
|| @annotation(PostAuthorize) || @annotation(PostFilter));
|
||||||
|
|
||||||
private pointcut securedMethodExecution() :
|
private pointcut securedMethodExecution() :
|
||||||
executionOfAnyPublicMethodInAtSecuredType() ||
|
executionOfAnyPublicMethodInAtSecuredType() ||
|
||||||
executionOfSecuredMethod();
|
executionOfSecuredMethod() ||
|
||||||
|
executionOfPrePostAnnotatedMethod();
|
||||||
|
|
||||||
private AspectJSecurityInterceptor securityInterceptor;
|
private AspectJMethodSecurityInterceptor securityInterceptor;
|
||||||
|
|
||||||
Object around(): securedMethodExecution() {
|
Object around(): securedMethodExecution() {
|
||||||
if (this.securityInterceptor == null) {
|
if (this.securityInterceptor == null) {
|
||||||
@@ -54,13 +63,14 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
|
|||||||
return this.securityInterceptor.invoke(thisJoinPoint, callback);
|
return this.securityInterceptor.invoke(thisJoinPoint, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
|
public void setSecurityInterceptor(AspectJMethodSecurityInterceptor securityInterceptor) {
|
||||||
this.securityInterceptor = securityInterceptor;
|
this.securityInterceptor = securityInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (this.securityInterceptor == null)
|
if (this.securityInterceptor == null) {
|
||||||
throw new IllegalArgumentException("securityInterceptor required");
|
throw new IllegalArgumentException("securityInterceptor required");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
package org.springframework.security.access.intercept.aspectj.aspect;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.springframework.security.access.AccessDecisionManager;
|
||||||
|
import org.springframework.security.access.AccessDecisionVoter;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
|
||||||
|
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||||
|
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
|
||||||
|
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
|
||||||
|
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
||||||
|
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
|
||||||
|
import org.springframework.security.access.vote.AffirmativeBased;
|
||||||
|
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @since 3.0.3
|
||||||
|
*/
|
||||||
|
public class AnnotationSecurityAspectTests {
|
||||||
|
private @Mock AccessDecisionManager adm;
|
||||||
|
private @Mock AuthenticationManager authman;
|
||||||
|
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
|
||||||
|
// private TestingAuthenticationToken bob = new TestingAuthenticationToken("bob", "", "ROLE_B");
|
||||||
|
private AspectJMethodSecurityInterceptor interceptor;
|
||||||
|
private SecuredImpl secured = new SecuredImpl();
|
||||||
|
private PrePostSecured prePostSecured = new PrePostSecured();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public final void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
interceptor = new AspectJMethodSecurityInterceptor();
|
||||||
|
interceptor.setAccessDecisionManager(adm);
|
||||||
|
interceptor.setAuthenticationManager(authman);
|
||||||
|
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
|
||||||
|
AnnotationSecurityAspect secAspect = AnnotationSecurityAspect.aspectOf();
|
||||||
|
secAspect.setSecurityInterceptor(interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void clearContext() {
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void securedInterfaceMethodAllowsAllAccess() throws Exception {
|
||||||
|
secured.securedMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||||
|
public void securedClassMethodDeniesUnauthenticatedAccess() throws Exception {
|
||||||
|
secured.securedClassMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void securedClassMethodAllowsAccessToRoleA() throws Exception {
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||||
|
secured.securedClassMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEC-1262
|
||||||
|
@Test(expected=AccessDeniedException.class)
|
||||||
|
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||||
|
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
|
||||||
|
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
|
||||||
|
AffirmativeBased adm = new AffirmativeBased();
|
||||||
|
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
|
||||||
|
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
|
||||||
|
adm.setDecisionVoters(Arrays.asList(voters));
|
||||||
|
interceptor.setAccessDecisionManager(adm);
|
||||||
|
prePostSecured.denyAllMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecuredInterface {
|
||||||
|
@Secured("ROLE_X")
|
||||||
|
void securedMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SecuredImpl implements SecuredInterface {
|
||||||
|
|
||||||
|
// Not really secured because AspectJ doesn't inherit annotations from interfaces
|
||||||
|
public void securedMethod() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Secured("ROLE_A")
|
||||||
|
public void securedClassMethod() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrePostSecured {
|
||||||
|
|
||||||
|
@PreAuthorize("denyAll")
|
||||||
|
public void denyAllMethod() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+132
-192
@@ -1,137 +1,35 @@
|
|||||||
import java.util.jar.Manifest
|
apply plugin: 'base'
|
||||||
import org.gradle.api.tasks.bundling.GradleManifest
|
|
||||||
|
|
||||||
apply id: 'base'
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
version = '3.0.2.RELEASE'
|
version = '3.0.3.RELEASE'
|
||||||
releaseBuild = version.endsWith('RELEASE')
|
releaseBuild = version.endsWith('RELEASE')
|
||||||
snapshotBuild = version.endsWith('SNAPSHOT')
|
snapshotBuild = version.endsWith('SNAPSHOT')
|
||||||
|
|
||||||
group = 'org.springframework.security'
|
group = 'org.springframework.security'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenRepo name:'Local', urls:'file:///Users/luke/.m2/repository'
|
mavenRepo name:'Local', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
// mavenRepo name:'SpringSource Milestone Repo', urls:'http://repository.springsource.com/maven/bundles/milestone'
|
mavenRepo name: 'SpringSource Milestone Repo', urls: 'http://repository.springsource.com/maven/bundles/milestone'
|
||||||
|
mavenRepo name: 'SpringSource Maven Snapshot Repo', urls: 'http://maven.springframework.org/snapshot/'
|
||||||
|
mavenRepo name: 'SpringSource Enterprise Release', urls: 'http://repository.springsource.com/maven/bundles/release'
|
||||||
|
mavenRepo name: 'SpringSource Enterprise External', urls: 'http://repository.springsource.com/maven/bundles/external'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(javaProjects()) {
|
configure(javaProjects) {
|
||||||
apply id: 'java'
|
apply from: "$rootDir/gradle/javaprojects.gradle"
|
||||||
|
apply from: "$rootDir/gradle/maven.gradle"
|
||||||
springVersion = '3.0.1.RELEASE'
|
|
||||||
springLdapVersion = '1.3.0.RELEASE'
|
|
||||||
ehcacheVersion = '1.6.2'
|
|
||||||
aspectjVersion = '1.6.8'
|
|
||||||
apacheDsVersion = '1.5.5'
|
|
||||||
jstlVersion = '1.1.2'
|
|
||||||
jettyVersion = '6.1.22'
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
bundlor
|
|
||||||
provided
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile 'commons-logging:commons-logging:1.1.1'
|
|
||||||
|
|
||||||
testCompile 'junit:junit:4.7',
|
|
||||||
'org.mockito:mockito-core:1.7',
|
|
||||||
'org.jmock:jmock:2.5.1',
|
|
||||||
'org.jmock:jmock-junit4:2.5.1',
|
|
||||||
'org.hamcrest:hamcrest-core:1.1',
|
|
||||||
'org.hamcrest:hamcrest-library:1.1',
|
|
||||||
"org.springframework:spring-test:$springVersion"
|
|
||||||
bundlor 'com.springsource.bundlor:com.springsource.bundlor.ant:1.0.0.RC1',
|
|
||||||
'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RC1',
|
|
||||||
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RC1'
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
compileClasspath = compileClasspath + configurations.provided
|
|
||||||
}
|
|
||||||
test {
|
|
||||||
compileClasspath = compileClasspath + configurations.provided
|
|
||||||
runtimeClasspath = runtimeClasspath + configurations.provided
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea", '-Xms128m', '-Xmx500m', '-XX:MaxPermSize=128m', '-XX:+HeapDumpOnOutOfMemoryError'])
|
|
||||||
}
|
|
||||||
|
|
||||||
task bundlor (dependsOn: compileJava) << {
|
|
||||||
if (!dependsOnTaskDidWork()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ant.taskdef(resource: 'com/springsource/bundlor/ant/antlib.xml', classpath: configurations.bundlor.asPath)
|
|
||||||
File template = new File(projectDir, 'template.mf')
|
|
||||||
mkdir(buildDir, 'bundlor')
|
|
||||||
if (template.exists()) {
|
|
||||||
ant.bundlor(inputPath: sourceSets.main.classesDir, outputPath: "$buildDir/bundlor", manifestTemplatePath: template) {
|
|
||||||
property(name: 'version', value: "$version")
|
|
||||||
property(name: 'spring.version', value: "$springVersion")
|
|
||||||
}
|
|
||||||
// See GRADLE-395 for support for using an existing manifest
|
|
||||||
jar.manifest = new GradleManifest(new Manifest(new File("$buildDir/bundlor/META-INF/MANIFEST.MF").newInputStream()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jar.dependsOn bundlor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(javaProjects()) {
|
configure(coreModuleProjects) {
|
||||||
apply id: 'maven'
|
apply from: "$rootDir/gradle/bundlor.gradle"
|
||||||
|
|
||||||
// Create a source jar for uploading
|
|
||||||
task sourceJar(type: Jar) {
|
|
||||||
classifier = 'sources'
|
|
||||||
from sourceSets.main.java
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
deployerJars
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
archives sourceJar
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:2.0.1.BUILD-SNAPSHOT"
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadArchives {
|
|
||||||
repositories.mavenDeployer {
|
|
||||||
configuration = configurations.deployerJars
|
|
||||||
if (releaseBuild) {
|
|
||||||
// "mavenSyncRepoDir" should be set in properties
|
|
||||||
repository(url: mavenSyncRepoDir)
|
|
||||||
} else {
|
|
||||||
s3credentials = [userName: s3AccessKey, passphrase: s3SecretAccessKey]
|
|
||||||
repository(url: "s3://maven.springframework.org/milestone") {
|
|
||||||
authentication(s3credentials)
|
|
||||||
}
|
|
||||||
snapshotRepository(url: "s3://maven.springframework.org/snapshot") {
|
|
||||||
authentication(s3credentials)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conf2ScopeMappings.addMapping(1, configurations.provided, "provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
configure(coreModuleProjects()) {
|
|
||||||
// Gives better names in structure101 jar diagram
|
// Gives better names in structure101 jar diagram
|
||||||
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
|
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
configure (aspectjProjects) {
|
||||||
// Required for ant s3 task
|
apply from: "$rootDir/gradle/aspectj.gradle"
|
||||||
mavenRepo name: "s2.com release", urls: "http://repository.springsource.com/maven/bundles/release"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
@@ -143,62 +41,75 @@ dependencies {
|
|||||||
"net.java.dev.jets3t:jets3t:0.6.1"
|
"net.java.dev.jets3t:jets3t:0.6.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
def docsDir = new File(project(':manual').buildDir, 'docs')
|
|
||||||
|
|
||||||
task apidocs(type: Javadoc) {
|
task apidocs(type: Javadoc) {
|
||||||
destinationDir = new File(buildDir, 'apidocs')
|
destinationDir = new File(buildDir, 'apidocs')
|
||||||
title = "Spring Security $version API"
|
title = "Spring Security $version API"
|
||||||
optionsFile = file("$buildDir/tmp/javadoc.options")
|
optionsFile = file("$buildDir/tmp/javadoc.options")
|
||||||
|
|
||||||
source coreModuleProjects().collect { project ->
|
source coreModuleProjects.collect {project ->
|
||||||
project.sourceSets.main.allJava
|
project.sourceSets.main.allJava
|
||||||
}
|
}
|
||||||
|
|
||||||
classpath = files(coreModuleProjects().collect { project ->
|
classpath = files(coreModuleProjects.collect {project ->
|
||||||
project.sourceSets.main.compileClasspath })
|
project.sourceSets.main.compileClasspath
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
task apitar(type: Tar, dependsOn: apidocs) {
|
task docSiteLogin(type: Login) {
|
||||||
compression = Compression.BZIP2
|
if (project.hasProperty('sshHost')) {
|
||||||
|
host = project.property('sshHost')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define remoteSiteDir and sshHost in gradle.properties
|
||||||
|
def remoteDocsDir = null
|
||||||
|
|
||||||
|
if (hasProperty('remoteSiteDir')) {
|
||||||
|
remoteDocsDir="$remoteSiteDir/docs/3.0.x"
|
||||||
|
}
|
||||||
|
|
||||||
|
task uploadApidocs(type: TarUpload) {
|
||||||
|
dependsOn apidocs
|
||||||
classifier = 'apidocs'
|
classifier = 'apidocs'
|
||||||
|
remoteDir = remoteDocsDir
|
||||||
|
login = docSiteLogin
|
||||||
|
|
||||||
into('apidocs') {
|
into('apidocs') {
|
||||||
from apidocs.destinationDir
|
from apidocs.destinationDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task doctar(type: Tar, dependsOn: ':manual:doc') {
|
def docsDir = new File(project(':manual').buildDir, 'docs')
|
||||||
compression = Compression.BZIP2
|
|
||||||
|
task uploadDoc(type: TarUpload) {
|
||||||
|
dependsOn ':manual:doc'
|
||||||
classifier = 'doc'
|
classifier = 'doc'
|
||||||
|
remoteDir = remoteDocsDir
|
||||||
|
login = docSiteLogin
|
||||||
|
|
||||||
into('reference') {
|
into('reference') {
|
||||||
from docsDir
|
from docsDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def username;
|
task uploadFaq(type: TarUpload) {
|
||||||
def password;
|
dependsOn ':faq:docbookHtmlSingle'
|
||||||
|
classifier = 'faq'
|
||||||
|
if (project.hasProperty('remoteSiteDir')) {
|
||||||
|
remoteDir = project.property('remoteSiteDir')
|
||||||
|
}
|
||||||
|
login = docSiteLogin
|
||||||
|
|
||||||
task login << {
|
def faqDir = new File(project(':faq').buildDir, 'docs')
|
||||||
ant.input("Please enter the ssh username for host '$sshHost'", addproperty: "ssh.username")
|
|
||||||
ant.input("Please enter the ssh password '$sshHost'", addproperty: "ssh.password")
|
into('faq') {
|
||||||
username = ant.properties['ssh.username']
|
from faqDir
|
||||||
password = ant.properties['ssh.password']
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task uploadApidocs (dependsOn: login) << {
|
task dist(type: Zip) {
|
||||||
ant.scp(file: apitar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
|
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${apitar.archiveName}")
|
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${apitar.archiveName}")
|
|
||||||
}
|
|
||||||
|
|
||||||
task uploadManual (dependsOn: login) << {
|
|
||||||
ant.scp(file: doctar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
|
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${doctar.archiveName}")
|
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${doctar.archiveName}")
|
|
||||||
}
|
|
||||||
|
|
||||||
task dist (type: Zip) {
|
|
||||||
def zipRootDir = "${project.name}-$version"
|
def zipRootDir = "${project.name}-$version"
|
||||||
into (zipRootDir) {
|
into(zipRootDir) {
|
||||||
into('docs/apidocs') {
|
into('docs/apidocs') {
|
||||||
from apidocs.destinationDir
|
from apidocs.destinationDir
|
||||||
}
|
}
|
||||||
@@ -206,61 +117,90 @@ task dist (type: Zip) {
|
|||||||
from docsDir
|
from docsDir
|
||||||
}
|
}
|
||||||
into('dist') {
|
into('dist') {
|
||||||
from coreModuleProjects().collect { project -> project.libsDir }
|
from coreModuleProjects.collect {project -> project.libsDir }
|
||||||
from project(':spring-security-samples-tutorial').libsDir
|
from project(':spring-security-samples-tutorial').libsDir
|
||||||
from project(':spring-security-samples-contacts').libsDir
|
from project(':spring-security-samples-contacts').libsDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dist.dependsOn apidocs, ':manual:doc'
|
dist {
|
||||||
dist.dependsOn subprojects.collect { "$it.path:assemble" }
|
dependsOn apidocs, ':manual:doc', subprojects.collect { "$it.path:assemble" }
|
||||||
|
doLast {
|
||||||
dist.doLast {
|
ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
|
||||||
ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task uploadDist << {
|
task uploadDist(type: UploadDist) {
|
||||||
def shaFile = file("${dist.archivePath}.sha1")
|
archiveFile = dist.archivePath
|
||||||
assert dist.archivePath.isFile()
|
shaFile = "${dist.archivePath}.sha1" as File
|
||||||
assert shaFile.isFile()
|
archiveName = dist.archiveName
|
||||||
ant.taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: configurations.antlibs.asPath)
|
classpath = configurations.antlibs
|
||||||
ant.s3(accessKey: s3AccessKey, secretKey: s3SecretAccessKey) {
|
}
|
||||||
upload(bucketName: 'dist.springframework.org', file: dist.archivePath,
|
|
||||||
toFile: releaseType() + "/SEC/${dist.archiveName}", publicRead: 'true') {
|
def getJavaProjects() {
|
||||||
metadata(name: 'project.name', value: 'Spring Security')
|
subprojects.findAll {project -> project.name != 'faq' && project.name != 'manual' }
|
||||||
metadata(name: 'release.type', value: releaseType())
|
}
|
||||||
metadata(name: 'bundle.version', value: version)
|
|
||||||
metadata(name: 'package.file.name', value: dist.archiveName)
|
def getSampleProjects() {
|
||||||
|
subprojects.findAll {project -> project.name.startsWith('spring-security-samples') }
|
||||||
|
}
|
||||||
|
|
||||||
|
def getItestProjects() {
|
||||||
|
subprojects.findAll {project -> project.name.startsWith('itest') }
|
||||||
|
}
|
||||||
|
|
||||||
|
def getCoreModuleProjects() {
|
||||||
|
javaProjects - sampleProjects - itestProjects - aspectjProjects
|
||||||
|
}
|
||||||
|
|
||||||
|
def getAspectjProjects() {
|
||||||
|
subprojects.findAll {project -> project.name == 'spring-security-aspects' || project.name == 'spring-security-samples-aspectj'}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UploadDist extends DefaultTask {
|
||||||
|
@InputFile
|
||||||
|
File shaFile
|
||||||
|
|
||||||
|
@InputFile
|
||||||
|
File archiveFile
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String archiveName
|
||||||
|
|
||||||
|
@InputFiles
|
||||||
|
def classpath
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
def upload() {
|
||||||
|
def accessKey = project.s3AccessKey
|
||||||
|
def secretKey = project.s3SecretAccessKey
|
||||||
|
def version = project.version
|
||||||
|
|
||||||
|
project.ant {
|
||||||
|
taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: classpath.asPath)
|
||||||
|
s3(accessKey: accessKey, secretKey: secretKey) {
|
||||||
|
upload(bucketName: 'dist.springframework.org', file: archiveFile,
|
||||||
|
toFile: releaseType() + "/SEC/${archiveName}", publicRead: 'true') {
|
||||||
|
metadata(name: 'project.name', value: 'Spring Security')
|
||||||
|
metadata(name: 'release.type', value: releaseType())
|
||||||
|
metadata(name: 'bundle.version', value: version)
|
||||||
|
metadata(name: 'package.file.name', value: archiveName)
|
||||||
|
}
|
||||||
|
upload(bucketName: 'dist.springframework.org', file: shaFile,
|
||||||
|
toFile: releaseType() + "/SEC/${archiveName}.sha1", publicRead: 'true')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def releaseType() {
|
||||||
|
if (project.releaseBuild) {
|
||||||
|
'release'
|
||||||
|
} else if (project.snapshotBuild) {
|
||||||
|
'snapshot'
|
||||||
|
} else {
|
||||||
|
'milestone'
|
||||||
}
|
}
|
||||||
upload(bucketName: 'dist.springframework.org', file: shaFile,
|
|
||||||
toFile: releaseType() + "/SEC/${dist.archiveName}.sha1", publicRead: 'true')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def javaProjects() {
|
|
||||||
subprojects.findAll { project -> project.name != 'faq' && project.name != 'manual' }
|
|
||||||
}
|
|
||||||
|
|
||||||
def sampleProjects() {
|
|
||||||
subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
|
|
||||||
}
|
|
||||||
|
|
||||||
def itestProjects() {
|
|
||||||
subprojects.findAll { project -> project.name.startsWith('itest') }
|
|
||||||
}
|
|
||||||
|
|
||||||
def coreModuleProjects() {
|
|
||||||
javaProjects() - sampleProjects() - itestProjects()
|
|
||||||
}
|
|
||||||
|
|
||||||
def releaseType() {
|
|
||||||
if (releaseBuild) {
|
|
||||||
'release'
|
|
||||||
} else if (snapshotBuild) {
|
|
||||||
'snapshot'
|
|
||||||
} else {
|
|
||||||
'milestone'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apply plugin: 'groovy'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||||
|
mavenCentral()
|
||||||
|
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
def fopDeps = [ 'org.apache.xmlgraphics:fop:0.95-1@jar',
|
||||||
|
'org.apache.xmlgraphics:xmlgraphics-commons:1.3',
|
||||||
|
'org.apache.xmlgraphics:batik-bridge:1.7@jar',
|
||||||
|
'org.apache.xmlgraphics:batik-util:1.7@jar',
|
||||||
|
'org.apache.xmlgraphics:batik-css:1.7@jar',
|
||||||
|
'org.apache.xmlgraphics:batik-dom:1.7',
|
||||||
|
'org.apache.xmlgraphics:batik-svg-dom:1.7@jar',
|
||||||
|
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
|
||||||
|
groovy localGroovy()
|
||||||
|
compile gradleApi(),
|
||||||
|
'org.apache.xerces:resolver:2.9.1',
|
||||||
|
'saxon:saxon:6.5.3',
|
||||||
|
'org.apache.xerces:xercesImpl:2.9.1',
|
||||||
|
fopDeps
|
||||||
|
|
||||||
|
runtime 'net.sf.xslthl:xslthl:2.0.1',
|
||||||
|
'net.sf.docbook:docbook-xsl:1.75.2:resources@zip'
|
||||||
|
}
|
||||||
|
|
||||||
|
task ide(type: Copy) {
|
||||||
|
from configurations.runtime
|
||||||
|
into 'ide'
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.tasks.*;
|
||||||
|
import org.gradle.api.tasks.bundling.Tar;
|
||||||
|
import org.gradle.api.tasks.bundling.Compression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the Tar task, uploading the created archive to a remote directory, unpacking and deleting it.
|
||||||
|
* Requires Ant ssh (jsch) support.
|
||||||
|
*/
|
||||||
|
class TarUpload extends Tar {
|
||||||
|
@Input
|
||||||
|
String remoteDir
|
||||||
|
|
||||||
|
@Input
|
||||||
|
Login login
|
||||||
|
|
||||||
|
TarUpload() {
|
||||||
|
compression = Compression.BZIP2
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
void copy() {
|
||||||
|
super.copy();
|
||||||
|
upload();
|
||||||
|
}
|
||||||
|
|
||||||
|
def upload() {
|
||||||
|
String username = login.username
|
||||||
|
String password = login.password
|
||||||
|
String host = login.host
|
||||||
|
project.ant {
|
||||||
|
scp(file: archivePath, todir: "$username@$host:$remoteDir", password: password)
|
||||||
|
sshexec(host: host, username: username, password: password, command: "cd $remoteDir && tar -xjf $archiveName")
|
||||||
|
sshexec(host: host, username: username, password: password, command: "rm $remoteDir/$archiveName")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLogin(Login login) {
|
||||||
|
dependsOn(login)
|
||||||
|
this.login = login
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores login information for a remote host.
|
||||||
|
*/
|
||||||
|
class Login extends DefaultTask {
|
||||||
|
@Input
|
||||||
|
String host
|
||||||
|
String username
|
||||||
|
String password
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
login() {
|
||||||
|
project.ant {
|
||||||
|
input("Please enter the ssh username for host '$host'", addproperty: "user.$host")
|
||||||
|
input("Please enter the ssh password '$host'", addproperty: "pass.$host")
|
||||||
|
}
|
||||||
|
username = ant.properties["user.$host"]
|
||||||
|
password = ant.properties["pass.$host"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
package docbook;
|
||||||
|
|
||||||
|
import org.gradle.api.Plugin;
|
||||||
|
import org.gradle.api.GradleException;
|
||||||
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.Task;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.Action;
|
||||||
|
import org.gradle.api.tasks.*;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.apache.xml.resolver.CatalogManager;
|
||||||
|
import org.apache.xml.resolver.tools.CatalogResolver;
|
||||||
|
|
||||||
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
import javax.xml.transform.*;
|
||||||
|
import javax.xml.transform.sax.SAXSource;
|
||||||
|
import javax.xml.transform.sax.SAXResult;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.zip.*;
|
||||||
|
import java.net.*;
|
||||||
|
|
||||||
|
import org.apache.fop.apps.*;
|
||||||
|
|
||||||
|
import com.icl.saxon.TransformerFactoryImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gradle Docbook plugin implementation.
|
||||||
|
* <p>
|
||||||
|
* Creates three tasks: docbookHtml, docbookHtmlSingle and docbookPdf. Each task takes a single File on
|
||||||
|
* which it operates.
|
||||||
|
*/
|
||||||
|
class DocbookPlugin implements Plugin<Project> {
|
||||||
|
public void apply(Project project) {
|
||||||
|
// Add the plugin tasks to the project
|
||||||
|
Task docbookHtml = project.tasks.add('docbookHtml', DocbookHtml.class);
|
||||||
|
docbookHtml.setDescription('Generates chunked docbook html output');
|
||||||
|
|
||||||
|
Task docbookHtmlSingle = project.tasks.add('docbookHtmlSingle', Docbook.class);
|
||||||
|
docbookHtmlSingle.setDescription('Generates single page docbook html output')
|
||||||
|
docbookHtmlSingle.suffix = '-single'
|
||||||
|
|
||||||
|
Task docbookFoPdf = project.tasks.add("docbookFoPdf", DocbookFoPdf.class);
|
||||||
|
docbookFoPdf.setDescription('Generates PDF output');
|
||||||
|
docbookFoPdf.extension = 'fo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class Docbook extends DefaultTask {
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String extension = 'html';
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String suffix = '';
|
||||||
|
|
||||||
|
@Input
|
||||||
|
boolean XIncludeAware = true;
|
||||||
|
|
||||||
|
@Input
|
||||||
|
boolean highlightingEnabled = true;
|
||||||
|
|
||||||
|
String admonGraphicsPath;
|
||||||
|
|
||||||
|
@InputDirectory
|
||||||
|
File sourceDirectory = new File(project.getProjectDir(), "src/docbook");
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String sourceFileName;
|
||||||
|
|
||||||
|
@InputFile
|
||||||
|
File stylesheet;
|
||||||
|
|
||||||
|
@OutputDirectory
|
||||||
|
File docsDir = new File(project.getBuildDir(), "docs");
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
public final void transform() {
|
||||||
|
SAXParserFactory factory = new org.apache.xerces.jaxp.SAXParserFactoryImpl();
|
||||||
|
factory.setXIncludeAware(XIncludeAware);
|
||||||
|
docsDir.mkdirs();
|
||||||
|
|
||||||
|
File srcFile = new File(sourceDirectory, sourceFileName);
|
||||||
|
String outputFilename = srcFile.getName().substring(0, srcFile.getName().length() - 4) + suffix + '.' + extension;
|
||||||
|
|
||||||
|
File outputFile = new File(getDocsDir(), outputFilename);
|
||||||
|
|
||||||
|
Result result = new StreamResult(outputFile.getAbsolutePath());
|
||||||
|
CatalogResolver resolver = new CatalogResolver(createCatalogManager());
|
||||||
|
InputSource inputSource = new InputSource(srcFile.getAbsolutePath());
|
||||||
|
|
||||||
|
XMLReader reader = factory.newSAXParser().getXMLReader();
|
||||||
|
reader.setEntityResolver(resolver);
|
||||||
|
TransformerFactory transformerFactory = new TransformerFactoryImpl();
|
||||||
|
transformerFactory.setURIResolver(resolver);
|
||||||
|
URL url = stylesheet.toURL();
|
||||||
|
Source source = new StreamSource(url.openStream(), url.toExternalForm());
|
||||||
|
Transformer transformer = transformerFactory.newTransformer(source);
|
||||||
|
|
||||||
|
if (highlightingEnabled) {
|
||||||
|
File highlightingDir = new File(getProject().getBuildDir(), "highlighting");
|
||||||
|
if (!highlightingDir.exists()) {
|
||||||
|
highlightingDir.mkdirs();
|
||||||
|
extractHighlightFiles(highlightingDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
transformer.setParameter("highlight.xslthl.config", new File(highlightingDir, "xslthl-config.xml").toURI().toURL());
|
||||||
|
|
||||||
|
if (admonGraphicsPath != null) {
|
||||||
|
transformer.setParameter("admon.graphics", "1");
|
||||||
|
transformer.setParameter("admon.graphics.path", admonGraphicsPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preTransform(transformer, srcFile, outputFile);
|
||||||
|
|
||||||
|
transformer.transform(new SAXSource(reader, inputSource), result);
|
||||||
|
|
||||||
|
postTransform(outputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extractHighlightFiles(File toDir) {
|
||||||
|
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader();
|
||||||
|
URL[] urls = cl.getURLs();
|
||||||
|
URL docbookZip = null;
|
||||||
|
|
||||||
|
for (URL url : urls) {
|
||||||
|
if (url.toString().contains("docbook-xsl-")) {
|
||||||
|
docbookZip = url;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (docbookZip == null) {
|
||||||
|
throw new GradleException("Docbook zip file not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipFile zipFile = new ZipFile(new File(docbookZip.toURI()));
|
||||||
|
|
||||||
|
Enumeration e = zipFile.entries();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
ZipEntry ze = (ZipEntry) e.nextElement();
|
||||||
|
if (ze.getName().matches(".*/highlighting/.*\\.xml")) {
|
||||||
|
String filename = ze.getName().substring(ze.getName().lastIndexOf("/highlighting/") + 14);
|
||||||
|
copyFile(zipFile.getInputStream(ze), new File(toDir, filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFile(InputStream source, File destFile) {
|
||||||
|
destFile.createNewFile();
|
||||||
|
FileOutputStream to = null;
|
||||||
|
try {
|
||||||
|
to = new FileOutputStream(destFile);
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
while ((bytesRead = source.read(buffer)) > 0) {
|
||||||
|
to.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (source != null) {
|
||||||
|
source.close();
|
||||||
|
}
|
||||||
|
if (to != null) {
|
||||||
|
to.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void preTransform(Transformer transformer, File sourceFile, File outputFile) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void postTransform(File outputFile) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private CatalogManager createCatalogManager() {
|
||||||
|
CatalogManager manager = new CatalogManager();
|
||||||
|
manager.setIgnoreMissingProperties(true);
|
||||||
|
ClassLoader classLoader = this.getClass().getClassLoader();
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
String docbookCatalogName = "docbook/catalog.xml";
|
||||||
|
URL docbookCatalog = classLoader.getResource(docbookCatalogName);
|
||||||
|
|
||||||
|
if (docbookCatalog == null) {
|
||||||
|
throw new IllegalStateException("Docbook catalog " + docbookCatalogName + " could not be found in " + classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append(docbookCatalog.toExternalForm());
|
||||||
|
|
||||||
|
Enumeration enumeration = classLoader.getResources("/catalog.xml");
|
||||||
|
while (enumeration.hasMoreElements()) {
|
||||||
|
builder.append(';');
|
||||||
|
URL resource = (URL) enumeration.nextElement();
|
||||||
|
builder.append(resource.toExternalForm());
|
||||||
|
}
|
||||||
|
String catalogFiles = builder.toString();
|
||||||
|
manager.setCatalogFiles(catalogFiles);
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class DocbookHtml extends Docbook {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void preTransform(Transformer transformer, File sourceFile, File outputFile) {
|
||||||
|
String rootFilename = outputFile.getName();
|
||||||
|
rootFilename = rootFilename.substring(0, rootFilename.lastIndexOf('.'));
|
||||||
|
transformer.setParameter("root.filename", rootFilename);
|
||||||
|
transformer.setParameter("base.dir", outputFile.getParent() + File.separator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class DocbookFoPdf extends Docbook {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="http://xmlgraphics.apache.org/fop/0.95/embedding.html#render">From the FOP usage guide</a>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void postTransform(File foFile) {
|
||||||
|
FopFactory fopFactory = FopFactory.newInstance();
|
||||||
|
|
||||||
|
OutputStream out = null;
|
||||||
|
final File pdfFile = getPdfOutputFile(foFile);
|
||||||
|
logger.debug("Transforming 'fo' file "+ foFile + " to PDF: " + pdfFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
out = new BufferedOutputStream(new FileOutputStream(pdfFile));
|
||||||
|
|
||||||
|
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
|
||||||
|
|
||||||
|
TransformerFactory factory = TransformerFactory.newInstance();
|
||||||
|
Transformer transformer = factory.newTransformer();
|
||||||
|
|
||||||
|
Source src = new StreamSource(foFile);
|
||||||
|
|
||||||
|
Result res = new SAXResult(fop.getDefaultHandler());
|
||||||
|
|
||||||
|
transformer.transform(src, res);
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foFile.delete()) {
|
||||||
|
logger.warn("Failed to delete 'fo' file " + foFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getPdfOutputFile(File foFile) {
|
||||||
|
String name = foFile.getAbsolutePath();
|
||||||
|
return new File(name.substring(0, name.length() - 2) + "pdf");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
implementation-class=docbook.DocbookPlugin
|
||||||
+2
-2
@@ -2,12 +2,12 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile project(':spring-security-core'),
|
compile project(':spring-security-core'),
|
||||||
project(':spring-security-web'),
|
project(':spring-security-web'),
|
||||||
"javax.servlet:servlet-api:2.5",
|
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-tx:$springVersion",
|
"org.springframework:spring-tx:$springVersion",
|
||||||
"org.springframework:spring-web:$springVersion",
|
"org.springframework:spring-web:$springVersion",
|
||||||
"org.jasig.cas:cas-client-core:3.1.9",
|
"org.jasig.cas:cas-client-core:3.1.9",
|
||||||
"net.sf.ehcache:ehcache:$ehcacheVersion"
|
"net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||||
|
|
||||||
|
provided 'javax.servlet:servlet-api:2.5'
|
||||||
}
|
}
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-security-cas-client</artifactId>
|
<artifactId>spring-security-cas-client</artifactId>
|
||||||
<name>Spring Security - CAS support</name>
|
<name>Spring Security - CAS support</name>
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
|||||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||||
*/
|
*/
|
||||||
public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
|
public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
|
||||||
final Collection<GrantedAuthority> authorities, final UserDetails userDetails, final Assertion assertion) {
|
final Collection<? extends GrantedAuthority> authorities, final UserDetails userDetails, final Assertion assertion) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
|
|
||||||
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (credentials == null)
|
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (credentials == null)
|
||||||
|
|||||||
@@ -5,24 +5,20 @@ compileTestJava.dependsOn(':spring-security-core:compileTestJava')
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile project(':spring-security-core'),
|
compile project(':spring-security-core'),
|
||||||
project(':spring-security-web'),
|
project(':spring-security-web'),
|
||||||
"javax.servlet:servlet-api:2.5",
|
'aopalliance:aopalliance:1.0',
|
||||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||||
"org.springframework:spring-aop:$springVersion",
|
"org.springframework:spring-aop:$springVersion",
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-web:$springVersion",
|
"org.springframework:spring-web:$springVersion",
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-tx:$springVersion"
|
"org.springframework:spring-tx:$springVersion"
|
||||||
|
|
||||||
|
provided "javax.servlet:servlet-api:2.5"
|
||||||
|
|
||||||
testCompile project(':spring-security-ldap'),
|
testCompile project(':spring-security-ldap'),
|
||||||
project(':spring-security-openid'),
|
project(':spring-security-openid'),
|
||||||
files(this.project(':spring-security-core').sourceSets.test.classesDir),
|
files(this.project(':spring-security-core').sourceSets.test.classesDir),
|
||||||
'javax.annotation:jsr250-api:1.0',
|
'javax.annotation:jsr250-api:1.0',
|
||||||
'aopalliance:aopalliance:1.0',
|
|
||||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
||||||
"org.springframework:spring-jdbc:$springVersion"
|
"org.springframework:spring-jdbc:$springVersion"
|
||||||
}
|
}
|
||||||
|
|
||||||
task show << {
|
|
||||||
println dependencies
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
pushd src/main/resources/org/springframework/security/config/
|
pushd src/main/resources/org/springframework/security/config/
|
||||||
|
|
||||||
echo "Converting rnc file to xsd ..."
|
echo "Converting rnc file to xsd ..."
|
||||||
java -jar ~/bin/trang.jar spring-security-3.0.rnc spring-security-3.0.xsd
|
java -jar ~/bin/trang.jar spring-security-3.0.3.rnc spring-security-3.0.3.xsd
|
||||||
|
|
||||||
echo "Applying XSL transformation to xsd ..."
|
echo "Applying XSL transformation to xsd ..."
|
||||||
xsltproc --output spring-security-3.0.xsd spring-security.xsl spring-security-3.0.xsd
|
xsltproc --output spring-security-3.0.3.xsd spring-security.xsl spring-security-3.0.3.xsd
|
||||||
|
|
||||||
popd
|
popd
|
||||||
+2
-6
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<artifactId>spring-security-config</artifactId>
|
<artifactId>spring-security-config</artifactId>
|
||||||
@@ -41,10 +41,6 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-ldap</artifactId>
|
<artifactId>spring-security-ldap</artifactId>
|
||||||
@@ -76,7 +72,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
<version>1.5.10</version>
|
<version>1.6.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
+15
-5
@@ -45,6 +45,11 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
String name = pc.getDelegate().getLocalName(element);
|
String name = pc.getDelegate().getLocalName(element);
|
||||||
BeanDefinitionParser parser = parsers.get(name);
|
BeanDefinitionParser parser = parsers.get(name);
|
||||||
|
|
||||||
|
if (parser == null) {
|
||||||
|
// SEC-1455. Load parsers when required, not just on init().
|
||||||
|
loadParsers();
|
||||||
|
}
|
||||||
|
|
||||||
if (parser == null) {
|
if (parser == null) {
|
||||||
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
|
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
|
||||||
reportMissingWebClasses(name, pc, element);
|
reportMissingWebClasses(name, pc, element);
|
||||||
@@ -67,6 +72,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Elements.FILTER_CHAIN_MAP.equals(name)) {
|
if (Elements.FILTER_CHAIN_MAP.equals(name)) {
|
||||||
|
if (filterChainMapBDD == null) {
|
||||||
|
loadParsers();
|
||||||
|
}
|
||||||
if (filterChainMapBDD == null) {
|
if (filterChainMapBDD == null) {
|
||||||
reportMissingWebClasses(name, pc, node);
|
reportMissingWebClasses(name, pc, node);
|
||||||
}
|
}
|
||||||
@@ -91,8 +99,12 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
|
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void init() {
|
public void init() {
|
||||||
|
loadParsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void loadParsers() {
|
||||||
// Parsers
|
// Parsers
|
||||||
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
|
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
|
||||||
parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
|
parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
|
||||||
@@ -102,7 +114,6 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
|
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
|
||||||
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
||||||
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
|
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
|
||||||
// registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
|
|
||||||
|
|
||||||
// Only load the web-namespace parsers if the web classes are available
|
// Only load the web-namespace parsers if the web classes are available
|
||||||
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
|
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
|
||||||
@@ -110,7 +121,6 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||||
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||||
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
|
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
|
||||||
//registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,8 +139,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
|
|
||||||
private boolean matchesVersionInternal(Element element) {
|
private boolean matchesVersionInternal(Element element) {
|
||||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||||
return schemaLocation.matches("(?m).*spring-security-3.0.xsd.*")
|
return schemaLocation.matches("(?m).*spring-security-3\\.0.*xsd.*")
|
||||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
|| schemaLocation.matches("(?m).*spring-security\\.xsd.*")
|
||||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-20
@@ -1,18 +1,16 @@
|
|||||||
package org.springframework.security.config.authentication;
|
package org.springframework.security.config.authentication;
|
||||||
|
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
import org.springframework.security.config.Elements;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,9 +20,6 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
|
|||||||
static final String CACHE_REF = "cache-ref";
|
static final String CACHE_REF = "cache-ref";
|
||||||
public static final String CACHING_SUFFIX = ".caching";
|
public static final String CACHING_SUFFIX = ".caching";
|
||||||
|
|
||||||
/** UserDetailsService bean Id. For use in a stateful context (i.e. in AuthenticationProviderBDP) */
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
protected abstract String getBeanClassName(Element element);
|
protected abstract String getBeanClassName(Element element);
|
||||||
|
|
||||||
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
||||||
@@ -51,34 +46,33 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
|
|||||||
parserContext.registerBeanComponent(new BeanComponentDefinition(cachingUserService, beanId + CACHING_SUFFIX));
|
parserContext.registerBeanComponent(new BeanComponentDefinition(cachingUserService, beanId + CACHING_SUFFIX));
|
||||||
}
|
}
|
||||||
|
|
||||||
id = beanId;
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext pc)
|
||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
|
|
||||||
String id = element.getAttribute("id");
|
String id = element.getAttribute("id");
|
||||||
|
|
||||||
|
if (pc.isNested()) {
|
||||||
|
// We're inside an <authentication-provider> element
|
||||||
|
if (!StringUtils.hasText(id)) {
|
||||||
|
id = pc.getReaderContext().generateBeanName(definition);
|
||||||
|
}
|
||||||
|
BeanDefinition container = pc.getContainingBeanDefinition();
|
||||||
|
container.getPropertyValues().add("userDetailsService", new RuntimeBeanReference(id));
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.hasText(id)) {
|
if (StringUtils.hasText(id)) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Elements.AUTHENTICATION_PROVIDER.equals(element.getParentNode().getNodeName())) {
|
|
||||||
return parserContext.getReaderContext().generateBeanName(definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If top level, use the default name or throw an exception if already used
|
// If top level, use the default name or throw an exception if already used
|
||||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
|
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
|
||||||
throw new BeanDefinitionStoreException("No id supplied and another " +
|
throw new BeanDefinitionStoreException("No id supplied and another " +
|
||||||
"bean is already registered as " + BeanIds.USER_DETAILS_SERVICE);
|
"bean is already registered as " + BeanIds.USER_DETAILS_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BeanIds.USER_DETAILS_SERVICE;
|
return BeanIds.USER_DETAILS_SERVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -35,6 +35,7 @@ import org.w3c.dom.NodeList;
|
|||||||
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
|
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
private static final String ATT_ALIAS = "alias";
|
private static final String ATT_ALIAS = "alias";
|
||||||
private static final String ATT_REF = "ref";
|
private static final String ATT_REF = "ref";
|
||||||
|
private static final String ATT_ERASE_CREDENTIALS = "erase-credentials";
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
|
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
|
||||||
@@ -72,6 +73,11 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
|||||||
}
|
}
|
||||||
|
|
||||||
providerManagerBldr.addPropertyValue("providers", providers);
|
providerManagerBldr.addPropertyValue("providers", providers);
|
||||||
|
|
||||||
|
if ("true".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
|
||||||
|
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", true);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the default event publisher
|
// Add the default event publisher
|
||||||
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
|
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
|
||||||
String id = pc.getReaderContext().generateBeanName(publisher);
|
String id = pc.getReaderContext().generateBeanName(publisher);
|
||||||
|
|||||||
+16
-76
@@ -7,7 +7,6 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
|||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.Elements;
|
import org.springframework.security.config.Elements;
|
||||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.util.xml.DomUtils;
|
import org.springframework.util.xml.DomUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
@@ -21,14 +20,14 @@ import org.w3c.dom.Element;
|
|||||||
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
|
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
private static String ATT_USER_DETAILS_REF = "user-service-ref";
|
private static String ATT_USER_DETAILS_REF = "user-service-ref";
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
|
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
|
||||||
authProvider.setSource(parserContext.extractSource(element));
|
authProvider.setSource(pc.extractSource(element));
|
||||||
|
|
||||||
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
|
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
|
||||||
|
|
||||||
if (passwordEncoderElt != null) {
|
if (passwordEncoderElt != null) {
|
||||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, parserContext);
|
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, pc);
|
||||||
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||||
|
|
||||||
if (pep.getSaltSource() != null) {
|
if (pep.getSaltSource() != null) {
|
||||||
@@ -37,98 +36,39 @@ public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitio
|
|||||||
}
|
}
|
||||||
|
|
||||||
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
|
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
|
||||||
Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
|
if (userServiceElt == null) {
|
||||||
Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
|
userServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
|
||||||
|
}
|
||||||
|
if (userServiceElt == null) {
|
||||||
|
userServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
String ref = element.getAttribute(ATT_USER_DETAILS_REF);
|
String ref = element.getAttribute(ATT_USER_DETAILS_REF);
|
||||||
|
|
||||||
if (StringUtils.hasText(ref)) {
|
if (StringUtils.hasText(ref)) {
|
||||||
if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) {
|
if (userServiceElt != null) {
|
||||||
parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
|
pc.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
|
||||||
"elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" +
|
"elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" +
|
||||||
Elements.LDAP_USER_SERVICE + "'", element);
|
Elements.LDAP_USER_SERVICE + "'", element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authProvider.getPropertyValues().add("userDetailsService", new RuntimeBeanReference(ref));
|
||||||
} else {
|
} else {
|
||||||
// Use the child elements to create the UserDetailsService
|
// Use the child elements to create the UserDetailsService
|
||||||
AbstractUserDetailsServiceBeanDefinitionParser parser = null;
|
|
||||||
Element elt = null;
|
|
||||||
|
|
||||||
if (userServiceElt != null) {
|
if (userServiceElt != null) {
|
||||||
elt = userServiceElt;
|
pc.getDelegate().parseCustomElement(userServiceElt, authProvider);
|
||||||
parser = new UserServiceBeanDefinitionParser();
|
|
||||||
} else if (jdbcUserServiceElt != null) {
|
|
||||||
elt = jdbcUserServiceElt;
|
|
||||||
parser = new JdbcUserServiceBeanDefinitionParser();
|
|
||||||
} else if (ldapUserServiceElt != null) {
|
|
||||||
elt = ldapUserServiceElt;
|
|
||||||
parser = new LdapUserServiceBeanDefinitionParser();
|
|
||||||
} else {
|
} else {
|
||||||
parserContext.getReaderContext().error("A user-service is required", element);
|
pc.getReaderContext().error("A user-service is required", element);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.parse(elt, parserContext);
|
|
||||||
ref = parser.getId();
|
|
||||||
|
|
||||||
// Pinch the cache-ref from the UserDetailService element, if set.
|
// Pinch the cache-ref from the UserDetailService element, if set.
|
||||||
String cacheRef = elt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
|
String cacheRef = userServiceElt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
|
||||||
|
|
||||||
if (StringUtils.hasText(cacheRef)) {
|
if (StringUtils.hasText(cacheRef)) {
|
||||||
authProvider.getPropertyValues().addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
|
authProvider.getPropertyValues().addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref));
|
|
||||||
|
|
||||||
// We need to register the provider to access it in the post processor to check if it has a cache
|
|
||||||
// final String id = parserContext.getReaderContext().generateBeanName(authProvider);
|
|
||||||
// parserContext.getRegistry().registerBeanDefinition(id, authProvider);
|
|
||||||
// parserContext.registerComponent(new BeanComponentDefinition(authProvider, id));
|
|
||||||
|
|
||||||
|
|
||||||
// BeanDefinitionBuilder cacheResolverBldr = BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProviderCacheResolver.class);
|
|
||||||
// cacheResolverBldr.addConstructorArgValue(id);
|
|
||||||
// cacheResolverBldr.addConstructorArgValue(ref);
|
|
||||||
// cacheResolverBldr.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
|
||||||
// BeanDefinition cacheResolver = cacheResolverBldr.getBeanDefinition();
|
|
||||||
//
|
|
||||||
// String name = parserContext.getReaderContext().generateBeanName(cacheResolver);
|
|
||||||
// parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
|
|
||||||
// parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
|
|
||||||
|
|
||||||
// ConfigUtils.addAuthenticationProvider(parserContext, id, element);
|
|
||||||
|
|
||||||
return authProvider;
|
return authProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the registered user service bean has an associated cache and, if so, sets it on the
|
|
||||||
* authentication provider.
|
|
||||||
*/
|
|
||||||
// static class AuthenticationProviderCacheResolver implements BeanFactoryPostProcessor, Ordered {
|
|
||||||
// private String providerId;
|
|
||||||
// private String userServiceId;
|
|
||||||
//
|
|
||||||
// public AuthenticationProviderCacheResolver(String providerId, String userServiceId) {
|
|
||||||
// this.providerId = providerId;
|
|
||||||
// this.userServiceId = userServiceId;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
|
||||||
// RootBeanDefinition provider = (RootBeanDefinition) beanFactory.getBeanDefinition(providerId);
|
|
||||||
//
|
|
||||||
// String cachingId = userServiceId + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
|
||||||
//
|
|
||||||
// if (beanFactory.containsBeanDefinition(cachingId)) {
|
|
||||||
// RootBeanDefinition cachingUserService = (RootBeanDefinition) beanFactory.getBeanDefinition(cachingId);
|
|
||||||
//
|
|
||||||
// PropertyValue userCacheProperty = cachingUserService.getPropertyValues().getPropertyValue("userCache");
|
|
||||||
//
|
|
||||||
// provider.getPropertyValues().addPropertyValue(userCacheProperty);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public int getOrder() {
|
|
||||||
// return HIGHEST_PRECEDENCE;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -24,6 +24,7 @@ import org.w3c.dom.Element;
|
|||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||||
|
|
||||||
static final String ATT_PASSWORD = "password";
|
static final String ATT_PASSWORD = "password";
|
||||||
@@ -90,7 +91,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
|||||||
user.addConstructorArgValue(!locked);
|
user.addConstructorArgValue(!locked);
|
||||||
user.addConstructorArgValue(authorities.getBeanDefinition());
|
user.addConstructorArgValue(authorities.getBeanDefinition());
|
||||||
|
|
||||||
users.put(userName, user.getBeanDefinition());
|
users.put(userName.toLowerCase(), user.getBeanDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap.getPropertyValues().addPropertyValue("users", users);
|
userMap.getPropertyValues().addPropertyValue("users", users);
|
||||||
|
|||||||
+19
-14
@@ -81,7 +81,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
private String rememberMeServicesId;
|
private String rememberMeServicesId;
|
||||||
private BeanReference rememberMeProviderRef;
|
private BeanReference rememberMeProviderRef;
|
||||||
private BeanDefinition basicFilter;
|
private BeanDefinition basicFilter;
|
||||||
private BeanDefinition basicEntryPoint;
|
private BeanReference basicEntryPoint;
|
||||||
private RootBeanDefinition formFilter;
|
private RootBeanDefinition formFilter;
|
||||||
private BeanDefinition formEntryPoint;
|
private BeanDefinition formEntryPoint;
|
||||||
private RootBeanDefinition openIDFilter;
|
private RootBeanDefinition openIDFilter;
|
||||||
@@ -155,7 +155,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
|
|
||||||
if (formLoginElt != null || autoConfig) {
|
if (formLoginElt != null || autoConfig) {
|
||||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||||
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
|
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
|
||||||
|
|
||||||
parser.parse(formLoginElt, pc);
|
parser.parse(formLoginElt, pc);
|
||||||
formFilter = parser.getFilterBean();
|
formFilter = parser.getFilterBean();
|
||||||
@@ -163,7 +163,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (formFilter != null) {
|
if (formFilter != null) {
|
||||||
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||||
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||||
|
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
|
|
||||||
if (openIDLoginElt != null) {
|
if (openIDLoginElt != null) {
|
||||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||||
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
|
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
|
||||||
|
|
||||||
parser.parse(openIDLoginElt, pc);
|
parser.parse(openIDLoginElt, pc);
|
||||||
openIDFilter = parser.getFilterBean();
|
openIDFilter = parser.getFilterBean();
|
||||||
@@ -214,7 +214,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (openIDFilter != null) {
|
if (openIDFilter != null) {
|
||||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||||
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||||
// Required by login page filter
|
// Required by login page filter
|
||||||
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
|
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
|
||||||
@@ -256,25 +256,29 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RootBeanDefinition filter = null;
|
RootBeanDefinition filter = null;
|
||||||
RootBeanDefinition entryPoint = null;
|
|
||||||
|
|
||||||
if (basicAuthElt != null || autoConfig) {
|
if (basicAuthElt != null || autoConfig) {
|
||||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
||||||
entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
|
||||||
entryPoint.setSource(pc.extractSource(httpElt));
|
|
||||||
|
|
||||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
String entryPointId;
|
||||||
|
|
||||||
String entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
if (basicAuthElt != null && StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
|
||||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
basicEntryPoint = new RuntimeBeanReference(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
|
||||||
|
} else {
|
||||||
|
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||||
|
entryPoint.setSource(pc.extractSource(httpElt));
|
||||||
|
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||||
|
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||||
|
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||||
|
basicEntryPoint = new RuntimeBeanReference(entryPointId);
|
||||||
|
}
|
||||||
|
|
||||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||||
filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(entryPointId));
|
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
|
||||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
basicFilter = filter;
|
basicFilter = filter;
|
||||||
basicEntryPoint = entryPoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void createX509Filter(BeanReference authManager) {
|
void createX509Filter(BeanReference authManager) {
|
||||||
@@ -540,7 +544,8 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void createUserServiceInjector() {
|
void createUserServiceInjector() {
|
||||||
BeanDefinitionBuilder userServiceInjector = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
BeanDefinitionBuilder userServiceInjector =
|
||||||
|
BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||||
userServiceInjector.addConstructorArgValue(x509ProviderId);
|
userServiceInjector.addConstructorArgValue(x509ProviderId);
|
||||||
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
|
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
|
||||||
userServiceInjector.addConstructorArgValue(openIDProviderId);
|
userServiceInjector.addConstructorArgValue(openIDProviderId);
|
||||||
|
|||||||
+6
-2
@@ -31,7 +31,8 @@ public class FormLoginBeanDefinitionParser {
|
|||||||
private static final String DEF_FORM_LOGIN_TARGET_URL = "/";
|
private static final String DEF_FORM_LOGIN_TARGET_URL = "/";
|
||||||
|
|
||||||
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
|
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
|
||||||
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
|
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL =
|
||||||
|
DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
|
||||||
|
|
||||||
private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
|
private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
|
||||||
private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
|
private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
|
||||||
@@ -40,17 +41,19 @@ public class FormLoginBeanDefinitionParser {
|
|||||||
private final String filterClassName;
|
private final String filterClassName;
|
||||||
private final BeanReference requestCache;
|
private final BeanReference requestCache;
|
||||||
private final BeanReference sessionStrategy;
|
private final BeanReference sessionStrategy;
|
||||||
|
private final boolean allowSessionCreation;
|
||||||
|
|
||||||
private RootBeanDefinition filterBean;
|
private RootBeanDefinition filterBean;
|
||||||
private RootBeanDefinition entryPointBean;
|
private RootBeanDefinition entryPointBean;
|
||||||
private String loginPage;
|
private String loginPage;
|
||||||
|
|
||||||
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
||||||
BeanReference requestCache, BeanReference sessionStrategy) {
|
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation) {
|
||||||
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
||||||
this.filterClassName = filterClassName;
|
this.filterClassName = filterClassName;
|
||||||
this.requestCache = requestCache;
|
this.requestCache = requestCache;
|
||||||
this.sessionStrategy = sessionStrategy;
|
this.sessionStrategy = sessionStrategy;
|
||||||
|
this.allowSessionCreation = allowSessionCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeanDefinition parse(Element elt, ParserContext pc) {
|
public BeanDefinition parse(Element elt, ParserContext pc) {
|
||||||
@@ -135,6 +138,7 @@ public class FormLoginBeanDefinitionParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
|
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
|
||||||
|
failureHandler.addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||||
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
|
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -83,7 +83,7 @@ class HttpConfigurationBuilder {
|
|||||||
private final List<Element> interceptUrls;
|
private final List<Element> interceptUrls;
|
||||||
|
|
||||||
// Use ManagedMap to allow placeholder resolution
|
// Use ManagedMap to allow placeholder resolution
|
||||||
private ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap;
|
private ManagedMap<Object, List<BeanMetadataElement>> filterChainMap;
|
||||||
|
|
||||||
private BeanDefinition cpf;
|
private BeanDefinition cpf;
|
||||||
private BeanDefinition securityContextPersistenceFilter;
|
private BeanDefinition securityContextPersistenceFilter;
|
||||||
@@ -109,7 +109,7 @@ class HttpConfigurationBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void parseInterceptUrlsForEmptyFilterChains() {
|
void parseInterceptUrlsForEmptyFilterChains() {
|
||||||
filterChainMap = new ManagedMap<BeanDefinition, List<BeanMetadataElement>>();
|
filterChainMap = new ManagedMap<Object, List<BeanMetadataElement>>();
|
||||||
|
|
||||||
for (Element urlElt : interceptUrls) {
|
for (Element urlElt : interceptUrls) {
|
||||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||||
@@ -464,7 +464,7 @@ class HttpConfigurationBuilder {
|
|||||||
return allowSessionCreation;
|
return allowSessionCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManagedMap<BeanDefinition, List<BeanMetadataElement>> getFilterChainMap() {
|
public ManagedMap<Object, List<BeanMetadataElement>> getFilterChainMap() {
|
||||||
return filterChainMap;
|
return filterChainMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-5
@@ -12,6 +12,7 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
import org.springframework.beans.BeanMetadataElement;
|
import org.springframework.beans.BeanMetadataElement;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanReference;
|
import org.springframework.beans.factory.config.BeanReference;
|
||||||
|
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||||
@@ -135,10 +136,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
filterChain.add(od.bean);
|
filterChain.add(od.bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
|
ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
|
||||||
BeanDefinition universalMatch = new RootBeanDefinition(String.class);
|
filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
|
||||||
universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());
|
|
||||||
filterChainMap.put(universalMatch, filterChain);
|
|
||||||
|
|
||||||
registerFilterChainProxy(pc, filterChainMap, matcher, source);
|
registerFilterChainProxy(pc, filterChainMap, matcher, source);
|
||||||
|
|
||||||
@@ -168,6 +167,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
||||||
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||||
authManager.addPropertyValue("providers", authenticationProviders);
|
authManager.addPropertyValue("providers", authenticationProviders);
|
||||||
|
RootBeanDefinition clearCredentials = new RootBeanDefinition(MethodInvokingFactoryBean.class);
|
||||||
|
clearCredentials.getPropertyValues().addPropertyValue("targetObject", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||||
|
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
|
||||||
|
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
|
||||||
|
|
||||||
if (concurrencyController != null) {
|
if (concurrencyController != null) {
|
||||||
authManager.addPropertyValue("sessionController", concurrencyController);
|
authManager.addPropertyValue("sessionController", concurrencyController);
|
||||||
@@ -247,7 +250,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
return customFilters;
|
return customFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
|
private void registerFilterChainProxy(ParserContext pc, Map<Object, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
|
||||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-6
@@ -37,6 +37,7 @@ import org.springframework.security.access.expression.method.ExpressionBasedPreI
|
|||||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||||
|
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||||
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
||||||
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
|
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
|
||||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
||||||
@@ -76,6 +77,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
private static final String ATT_USE_SECURED = "secured-annotations";
|
private static final String ATT_USE_SECURED = "secured-annotations";
|
||||||
private static final String ATT_USE_PREPOST = "pre-post-annotations";
|
private static final String ATT_USE_PREPOST = "pre-post-annotations";
|
||||||
private static final String ATT_REF = "ref";
|
private static final String ATT_REF = "ref";
|
||||||
|
private static final String ATT_MODE = "mode";
|
||||||
private static final String ATT_ADVICE_ORDER = "order";
|
private static final String ATT_ADVICE_ORDER = "order";
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
@@ -90,6 +92,8 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||||
boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
|
boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
|
||||||
|
boolean useAspectJ = "aspectj".equals(element.getAttribute(ATT_MODE));
|
||||||
|
|
||||||
BeanDefinition preInvocationVoter = null;
|
BeanDefinition preInvocationVoter = null;
|
||||||
ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>();
|
ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>();
|
||||||
|
|
||||||
@@ -165,6 +169,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
|
DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
|
||||||
|
|
||||||
if (pointcutMap.size() > 0) {
|
if (pointcutMap.size() > 0) {
|
||||||
|
if (useAspectJ) {
|
||||||
|
pc.getReaderContext().error("You can't use AspectJ mode with protect-pointcut definitions", source);
|
||||||
|
}
|
||||||
// Only add it if there are actually any pointcuts defined.
|
// Only add it if there are actually any pointcuts defined.
|
||||||
BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
||||||
BeanReference ref = new RuntimeBeanReference(pc.getReaderContext().generateBeanName(mapBasedMetadataSource));
|
BeanReference ref = new RuntimeBeanReference(pc.getReaderContext().generateBeanName(mapBasedMetadataSource));
|
||||||
@@ -190,13 +197,22 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
}
|
}
|
||||||
|
|
||||||
String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
|
String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
|
||||||
|
|
||||||
BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId,
|
BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId,
|
||||||
metadataSource, afterInvocationProviders, source);
|
metadataSource, afterInvocationProviders, source, useAspectJ);
|
||||||
|
|
||||||
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
|
if (useAspectJ) {
|
||||||
|
BeanDefinitionBuilder aspect =
|
||||||
|
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
|
||||||
|
aspect.setFactoryMethod("aspectOf");
|
||||||
|
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
aspect.addPropertyValue("securityInterceptor", interceptor);
|
||||||
|
String id = pc.getReaderContext().registerWithGeneratedName(aspect.getBeanDefinition());
|
||||||
|
pc.registerBeanComponent(new BeanComponentDefinition(aspect.getBeanDefinition(), id));
|
||||||
|
} else {
|
||||||
|
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
|
||||||
|
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
|
||||||
|
}
|
||||||
|
|
||||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
|
|
||||||
pc.popAndRegisterContainingComponent();
|
pc.popAndRegisterContainingComponent();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -284,12 +300,16 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId,
|
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId,
|
||||||
String runAsManagerId, BeanReference metadataSource, List<BeanMetadataElement> afterInvocationProviders, Object source) {
|
String runAsManagerId, BeanReference metadataSource,
|
||||||
BeanDefinitionBuilder bldr = BeanDefinitionBuilder.rootBeanDefinition(MethodSecurityInterceptor.class);
|
List<BeanMetadataElement> afterInvocationProviders, Object source, boolean useAspectJ) {
|
||||||
|
BeanDefinitionBuilder bldr =
|
||||||
|
BeanDefinitionBuilder.rootBeanDefinition(useAspectJ ?
|
||||||
|
AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class);
|
||||||
bldr.getRawBeanDefinition().setSource(source);
|
bldr.getRawBeanDefinition().setSource(source);
|
||||||
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
|
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||||
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
|
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
|
||||||
bldr.addPropertyValue("securityMetadataSource", metadataSource);
|
bldr.addPropertyValue("securityMetadataSource", metadataSource);
|
||||||
|
|
||||||
if (StringUtils.hasText(runAsManagerId)) {
|
if (StringUtils.hasText(runAsManagerId)) {
|
||||||
bldr.addPropertyReference("runAsManager", runAsManagerId);
|
bldr.addPropertyReference("runAsManager", runAsManagerId);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -3,6 +3,7 @@ package org.springframework.security.config.method;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -44,7 +45,6 @@ import org.springframework.util.StringUtils;
|
|||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
|
|
||||||
private Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
private Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
||||||
private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
||||||
|
private Set<PointcutExpression> pointCutExpressions = new LinkedHashSet<PointcutExpression>();
|
||||||
private PointcutParser parser;
|
private PointcutParser parser;
|
||||||
|
|
||||||
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
||||||
@@ -88,10 +89,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
|
|
||||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||||
for (int i = 0; i < methods.length; i++) {
|
for (int i = 0; i < methods.length; i++) {
|
||||||
for (String ex : pointcutMap.keySet()) {
|
for (PointcutExpression expression : pointCutExpressions) {
|
||||||
// Parse the presented AspectJ pointcut expression
|
|
||||||
PointcutExpression expression = parser.parsePointcutExpression(ex);
|
|
||||||
|
|
||||||
// Try for the bean class directly
|
// Try for the bean class directly
|
||||||
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
||||||
// We've found the first expression that matches this method, so move onto the next method now
|
// We've found the first expression that matches this method, so move onto the next method now
|
||||||
@@ -134,6 +132,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
Assert.notNull(definition, "A List of ConfigAttributes is required");
|
Assert.notNull(definition, "A List of ConfigAttributes is required");
|
||||||
pointcutExpression = replaceBooleanOperators(pointcutExpression);
|
pointcutExpression = replaceBooleanOperators(pointcutExpression);
|
||||||
pointcutMap.put(pointcutExpression, definition);
|
pointcutMap.put(pointcutExpression, definition);
|
||||||
|
// Parse the presented AspectJ pointcut expression and add it to the cache
|
||||||
|
pointCutExpressions.add(parser.parsePointcutExpression(pointcutExpression));
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.0.3.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-3.0.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
http\://www.springframework.org/schema/security/spring-security-3.0.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
||||||
|
http\://www.springframework.org/schema/security/spring-security-3.0.3.xsd=org/springframework/security/config/spring-security-3.0.3.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
|
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||||
|
|||||||
+11
-2
@@ -208,6 +208,9 @@ global-method-security.attlist &=
|
|||||||
attribute order {xsd:token}?
|
attribute order {xsd:token}?
|
||||||
global-method-security.attlist &=
|
global-method-security.attlist &=
|
||||||
attribute proxy-target-class {boolean}?
|
attribute proxy-target-class {boolean}?
|
||||||
|
global-method-security.attlist &=
|
||||||
|
## Can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module.
|
||||||
|
attribute mode {"aspectj"}?
|
||||||
|
|
||||||
after-invocation-provider =
|
after-invocation-provider =
|
||||||
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
|
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
|
||||||
@@ -273,7 +276,7 @@ http.attlist &=
|
|||||||
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
|
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
|
||||||
attribute realm {xsd:token}?
|
attribute realm {xsd:token}?
|
||||||
http.attlist &=
|
http.attlist &=
|
||||||
## Allows a customized AuthenticationEntryPoint to be used.
|
## Allows a customized AuthenticationEntryPoint to be set on the ExceptionTranslationFilter.
|
||||||
attribute entry-point-ref {xsd:token}?
|
attribute entry-point-ref {xsd:token}?
|
||||||
http.attlist &=
|
http.attlist &=
|
||||||
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
||||||
@@ -416,7 +419,10 @@ filter-invocation-definition-source =
|
|||||||
|
|
||||||
http-basic =
|
http-basic =
|
||||||
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
|
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
|
||||||
element http-basic {empty}
|
element http-basic {http-basic.attlist, empty}
|
||||||
|
http-basic.attlist &=
|
||||||
|
## Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter.
|
||||||
|
attribute entry-point-ref {xsd:token}?
|
||||||
|
|
||||||
session-management =
|
session-management =
|
||||||
element session-management {session-management.attlist, concurrency-control?}
|
element session-management {session-management.attlist, concurrency-control?}
|
||||||
@@ -538,6 +544,9 @@ authentication-manager =
|
|||||||
authman.attlist &=
|
authman.attlist &=
|
||||||
## The alias you wish to use for the AuthenticationManager bean
|
## The alias you wish to use for the AuthenticationManager bean
|
||||||
attribute alias {xsd:ID}?
|
attribute alias {xsd:ID}?
|
||||||
|
authman.attlist &=
|
||||||
|
## If set to true, the AuthenticationManger will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated. Defaults to false.
|
||||||
|
attribute erase-credentials {boolean}?
|
||||||
|
|
||||||
authentication-provider =
|
authentication-provider =
|
||||||
## Indicates that the contained user-service should be used as an authentication source.
|
## Indicates that the contained user-service should be used as an authentication source.
|
||||||
+1381
File diff suppressed because it is too large
Load Diff
+14
@@ -53,6 +53,20 @@ public class AuthenticationManagerBeanDefinitionParserTests {
|
|||||||
assertEquals(1, listener.events.size());
|
assertEquals(1, listener.events.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void credentialsAreNotClearedByDefault() throws Exception {
|
||||||
|
setContext(CONTEXT, "3.0");
|
||||||
|
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||||
|
assertFalse(pm.isEraseCredentialsAfterAuthentication());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearCredentialsPropertyIsRespected() throws Exception {
|
||||||
|
setContext("<authentication-manager erase-credentials='true'/>", "3.0.3");
|
||||||
|
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||||
|
assertTrue(pm.isEraseCredentialsAfterAuthentication());
|
||||||
|
}
|
||||||
|
|
||||||
private void setContext(String context, String version) {
|
private void setContext(String context, String version) {
|
||||||
appContext = new InMemoryXmlApplicationContext(context, version, null);
|
appContext = new InMemoryXmlApplicationContext(context, version, null);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -77,12 +77,12 @@ public class UserServiceBeanDefinitionParserTests {
|
|||||||
setContext(
|
setContext(
|
||||||
"<user-service id='service'>" +
|
"<user-service id='service'>" +
|
||||||
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
|
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
|
||||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
|
" <user name='Bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
|
||||||
"</user-service>");
|
"</user-service>");
|
||||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||||
UserDetails joe = userService.loadUserByUsername("joe");
|
UserDetails joe = userService.loadUserByUsername("joe");
|
||||||
assertFalse(joe.isAccountNonLocked());
|
assertFalse(joe.isAccountNonLocked());
|
||||||
UserDetails bob = userService.loadUserByUsername("bob");
|
UserDetails bob = userService.loadUserByUsername("bOb");
|
||||||
assertFalse(bob.isEnabled());
|
assertFalse(bob.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
@@ -416,6 +416,21 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
assertFalse(fsi.isObserveOncePerRequest());
|
assertFalse(fsi.isObserveOncePerRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void httpBasicSupportsSeparateEntryPoint() throws Exception {
|
||||||
|
setContext("<http><http-basic entry-point-ref='ep' /></http>" +
|
||||||
|
"<b:bean id='ep' class='org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint'>" +
|
||||||
|
" <b:property name='realmName' value='whocares'/>" +
|
||||||
|
"</b:bean>" + AUTH_PROVIDER_XML);
|
||||||
|
|
||||||
|
BasicAuthenticationFilter baf = getFilter(BasicAuthenticationFilter.class);
|
||||||
|
assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(baf, "authenticationEntryPoint"));
|
||||||
|
// Since no other authentication system is in use, this should also end up on the ETF
|
||||||
|
ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
||||||
|
assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(etf, "authenticationEntryPoint"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void accessDeniedPageAttributeIsSupported() throws Exception {
|
public void accessDeniedPageAttributeIsSupported() throws Exception {
|
||||||
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||||
|
|||||||
+48
-6
@@ -16,12 +16,15 @@ import org.springframework.context.ApplicationContext;
|
|||||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||||
import org.springframework.context.support.StaticApplicationContext;
|
import org.springframework.context.support.StaticApplicationContext;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
|
import org.springframework.security.access.SecurityConfig;
|
||||||
import org.springframework.security.access.annotation.BusinessService;
|
import org.springframework.security.access.annotation.BusinessService;
|
||||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||||
import org.springframework.security.access.intercept.RunAsManagerImpl;
|
import org.springframework.security.access.intercept.RunAsManagerImpl;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
||||||
import org.springframework.security.access.vote.AffirmativeBased;
|
import org.springframework.security.access.vote.AffirmativeBased;
|
||||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||||
@@ -30,6 +33,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
|||||||
import org.springframework.security.config.ConfigTestUtils;
|
import org.springframework.security.config.ConfigTestUtils;
|
||||||
import org.springframework.security.config.PostProcessedMockUserDetailsService;
|
import org.springframework.security.config.PostProcessedMockUserDetailsService;
|
||||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
@@ -40,6 +44,8 @@ import org.springframework.security.util.FieldUtils;
|
|||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||||
|
private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob","bobspassword");
|
||||||
|
|
||||||
private AbstractXmlApplicationContext appContext;
|
private AbstractXmlApplicationContext appContext;
|
||||||
|
|
||||||
private BusinessService target;
|
private BusinessService target;
|
||||||
@@ -166,7 +172,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
" 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) " +
|
" 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) " +
|
||||||
" and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' " +
|
" and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' " +
|
||||||
" access='ROLE_USER'/>" +
|
" access='ROLE_USER'/>" +
|
||||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
"</global-method-security>" + AUTH_PROVIDER_XML
|
||||||
);
|
);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
// String method should not be protected
|
// String method should not be protected
|
||||||
@@ -231,7 +237,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
target.someAdminMethod();
|
target.someAdminMethod();
|
||||||
}
|
}
|
||||||
@@ -242,7 +248,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
List<String> arg = new ArrayList<String>();
|
List<String> arg = new ArrayList<String>();
|
||||||
arg.add("joe");
|
arg.add("joe");
|
||||||
@@ -261,7 +267,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
Object[] arg = new String[] {"joe", "bob", "sam"};
|
Object[] arg = new String[] {"joe", "bob", "sam"};
|
||||||
Object[] result = target.methodReturningAnArray(arg);
|
Object[] result = target.methodReturningAnArray(arg);
|
||||||
@@ -283,6 +289,33 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SEC-1450
|
||||||
|
@Test(expected=AuthenticationException.class)
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void genericsAreMatchedByProtectPointcut() throws Exception {
|
||||||
|
setContext(
|
||||||
|
"<b:bean id='target' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$ConcreteFoo'/>" +
|
||||||
|
"<global-method-security>" +
|
||||||
|
" <protect-pointcut expression='execution(* org..*Foo.foo(..))' access='ROLE_USER'/>" +
|
||||||
|
"</global-method-security>" + AUTH_PROVIDER_XML
|
||||||
|
);
|
||||||
|
Foo foo = (Foo) appContext.getBean("target");
|
||||||
|
foo.foo(new SecurityConfig("A"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEC-1448
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void genericsMethodArgumentNamesAreResolved() throws Exception {
|
||||||
|
setContext(
|
||||||
|
"<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>" +
|
||||||
|
"<global-method-security pre-post-annotations='enabled'/>" + AUTH_PROVIDER_XML
|
||||||
|
);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
|
Foo foo = (Foo) appContext.getBean("target");
|
||||||
|
foo.foo(new SecurityConfig("A"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runAsManagerIsSetCorrectly() throws Exception {
|
public void runAsManagerIsSetCorrectly() throws Exception {
|
||||||
StaticApplicationContext parent = new StaticApplicationContext();
|
StaticApplicationContext parent = new StaticApplicationContext();
|
||||||
@@ -305,6 +338,15 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
private void setContext(String context, ApplicationContext parent) {
|
private void setContext(String context, ApplicationContext parent) {
|
||||||
appContext = new InMemoryXmlApplicationContext(context, parent);
|
appContext = new InMemoryXmlApplicationContext(context, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Foo<T extends ConfigAttribute> {
|
||||||
|
void foo(T action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConcreteFoo implements Foo<SecurityConfig> {
|
||||||
|
@PreAuthorize("#action.attribute == 'A'")
|
||||||
|
public void foo(SecurityConfig action) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -22,11 +22,11 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
|
|||||||
Resource inMemoryXml;
|
Resource inMemoryXml;
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml) {
|
public InMemoryXmlApplicationContext(String xml) {
|
||||||
this(xml, "3.0", null);
|
this(xml, "3.0.3", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
||||||
this(xml, "3.0", parent);
|
this(xml, "3.0.3", parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
|
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ dependencies {
|
|||||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||||
"org.springframework:spring-aop:$springVersion",
|
"org.springframework:spring-aop:$springVersion",
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-expression:$springVersion",
|
"org.springframework:spring-expression:$springVersion",
|
||||||
"org.springframework:spring-jdbc:$springVersion",
|
"org.springframework:spring-jdbc:$springVersion",
|
||||||
|
|||||||
+1
-5
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<artifactId>spring-security-core</artifactId>
|
<artifactId>spring-security-core</artifactId>
|
||||||
@@ -65,10 +65,6 @@
|
|||||||
<artifactId>ehcache</artifactId>
|
<artifactId>ehcache</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-collections</groupId>
|
<groupId>commons-collections</groupId>
|
||||||
<artifactId>commons-collections</artifactId>
|
<artifactId>commons-collections</artifactId>
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Votes according to JSR 250.
|
* Votes according to JSR 250.
|
||||||
|
* <p>
|
||||||
|
* If no JSR-250 attributes are found, it will abstain, otherwise it will grant or deny access
|
||||||
|
* based on the attributes that are found.
|
||||||
*
|
*
|
||||||
* @param authentication The authentication object.
|
* @param authentication The authentication object.
|
||||||
* @param object The access object.
|
* @param object The access object.
|
||||||
@@ -44,6 +47,8 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
|||||||
* @return The vote.
|
* @return The vote.
|
||||||
*/
|
*/
|
||||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> definition) {
|
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> definition) {
|
||||||
|
boolean jsr250AttributeFound = false;
|
||||||
|
|
||||||
for (ConfigAttribute attribute : definition) {
|
for (ConfigAttribute attribute : definition) {
|
||||||
if (Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE.equals(attribute)) {
|
if (Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE.equals(attribute)) {
|
||||||
return ACCESS_GRANTED;
|
return ACCESS_GRANTED;
|
||||||
@@ -54,18 +59,17 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (supports(attribute)) {
|
if (supports(attribute)) {
|
||||||
|
jsr250AttributeFound = true;
|
||||||
// Attempt to find a matching granted authority
|
// Attempt to find a matching granted authority
|
||||||
for (GrantedAuthority authority : authentication.getAuthorities()) {
|
for (GrantedAuthority authority : authentication.getAuthorities()) {
|
||||||
if (attribute.getAttribute().equals(authority.getAuthority())) {
|
if (attribute.getAttribute().equals(authority.getAuthority())) {
|
||||||
return ACCESS_GRANTED;
|
return ACCESS_GRANTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No match - deny access
|
|
||||||
return ACCESS_DENIED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ACCESS_ABSTAIN;
|
return jsr250AttributeFound ? ACCESS_DENIED : ACCESS_ABSTAIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-2
@@ -3,11 +3,13 @@ package org.springframework.security.access.expression.method;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal security-specific EvaluationContext implementation which lazily adds the
|
* Internal security-specific EvaluationContext implementation which lazily adds the
|
||||||
@@ -18,6 +20,8 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||||
|
private static Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class);
|
||||||
|
|
||||||
private ParameterNameDiscoverer parameterNameDiscoverer;
|
private ParameterNameDiscoverer parameterNameDiscoverer;
|
||||||
private boolean argumentsAdded;
|
private boolean argumentsAdded;
|
||||||
private MethodInvocation mi;
|
private MethodInvocation mi;
|
||||||
@@ -58,10 +62,21 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
|||||||
|
|
||||||
private void addArgumentsAsVariables() {
|
private void addArgumentsAsVariables() {
|
||||||
Object[] args = mi.getArguments();
|
Object[] args = mi.getArguments();
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Object targetObject = mi.getThis();
|
Object targetObject = mi.getThis();
|
||||||
Method method = ClassUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
|
Method method = AopUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
|
||||||
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
|
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
|
||||||
|
|
||||||
|
if (paramNames == null) {
|
||||||
|
logger.warn("Unable to resolve method parameter names for method: " + method
|
||||||
|
+ ". Debug symbol information is required if you are using parameter names in expressions.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0; i < args.length; i++) {
|
for(int i=0; i < args.length; i++) {
|
||||||
super.setVariable(paramNames[i], args[i]);
|
super.setVariable(paramNames[i], args[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -6,8 +6,9 @@ package org.springframework.security.access.intercept.aspectj;
|
|||||||
* AspectJ processing to continue.
|
* AspectJ processing to continue.
|
||||||
*
|
*
|
||||||
* @author Mike Wiesner
|
* @author Mike Wiesner
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface AspectJAnnotationCallback {
|
public interface AspectJAnnotationCallback {
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
|||||||
+2
@@ -11,7 +11,9 @@ import org.aspectj.lang.JoinPoint;
|
|||||||
* AspectJ interceptor that supports @Aspect notation.
|
* AspectJ interceptor that supports @Aspect notation.
|
||||||
*
|
*
|
||||||
* @author Mike Wiesner
|
* @author Mike Wiesner
|
||||||
|
* @deprecated Use AspectJMethodSecurityInterceptor instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AspectJAnnotationSecurityInterceptor extends AbstractSecurityInterceptor {
|
public class AspectJAnnotationSecurityInterceptor extends AbstractSecurityInterceptor {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
package org.springframework.security.access.intercept.aspectj;
|
||||||
|
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.springframework.security.access.intercept.InterceptorStatusToken;
|
||||||
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AspectJ {@code JoinPoint} security interceptor which wraps the {@code JoinPoint} in a {@code MethodInvocation}
|
||||||
|
* adapter to make it compatible with security infrastructure classes which only support {@code MethodInvocation}s.
|
||||||
|
* <p>
|
||||||
|
* One of the {@code invoke} methods should be called from the {@code around()} advice in your aspect.
|
||||||
|
* Alternatively you can use one of the pre-defined aspects from the aspects module.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @since 3.0.3
|
||||||
|
*/
|
||||||
|
public final class AspectJMethodSecurityInterceptor extends MethodSecurityInterceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that is suitable for user with @Aspect notation.
|
||||||
|
*
|
||||||
|
* @param jp The AspectJ joint point being invoked which requires a security decision
|
||||||
|
* @return The returned value from the method invocation
|
||||||
|
* @throws Throwable if the invocation throws one
|
||||||
|
*/
|
||||||
|
public Object invoke(JoinPoint jp) throws Throwable {
|
||||||
|
return super.invoke(new MethodInvocationAdapter(jp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that is suitable for user with traditional AspectJ-code aspects.
|
||||||
|
*
|
||||||
|
* @param jp The AspectJ joint point being invoked which requires a security decision
|
||||||
|
* @param advisorProceed the advice-defined anonymous class that implements {@code AspectJCallback} containing
|
||||||
|
* a simple {@code return proceed();} statement
|
||||||
|
*
|
||||||
|
* @return The returned value from the method invocation
|
||||||
|
*/
|
||||||
|
public Object invoke(JoinPoint jp, AspectJCallback advisorProceed) {
|
||||||
|
Object result = null;
|
||||||
|
InterceptorStatusToken token = super.beforeInvocation(new MethodInvocationAdapter(jp));
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = advisorProceed.proceedWithObject();
|
||||||
|
} finally {
|
||||||
|
result = super.afterInvocation(token, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -37,7 +37,9 @@ import org.aspectj.lang.JoinPoint;
|
|||||||
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
|
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @deprecated Use AspectJMethodSecurityInterceptor instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {
|
public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
|
|||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package org.springframework.security.access.intercept.aspectj;
|
||||||
|
|
||||||
|
import java.lang.reflect.AccessibleObject;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.reflect.CodeSignature;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorates a JoinPoint to allow it to be used with method-security infrastructure
|
||||||
|
* classes which support {@code MethodInvocation} instances.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @since 3.0.3
|
||||||
|
*/
|
||||||
|
public final class MethodInvocationAdapter implements MethodInvocation {
|
||||||
|
private final ProceedingJoinPoint jp;
|
||||||
|
private final Method method;
|
||||||
|
private final Object target;
|
||||||
|
|
||||||
|
MethodInvocationAdapter(JoinPoint jp) {
|
||||||
|
this.jp = (ProceedingJoinPoint)jp;
|
||||||
|
if (jp.getTarget() != null) {
|
||||||
|
target = jp.getTarget();
|
||||||
|
} else {
|
||||||
|
// SEC-1295: target may be null if an ITD is in use
|
||||||
|
target = jp.getSignature().getDeclaringType();
|
||||||
|
}
|
||||||
|
String targetMethodName = jp.getStaticPart().getSignature().getName();
|
||||||
|
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
|
||||||
|
Class<?> declaringType = ((CodeSignature) jp.getStaticPart().getSignature()).getDeclaringType();
|
||||||
|
|
||||||
|
method = ClassUtils.getMethodIfAvailable(declaringType, targetMethodName, types);
|
||||||
|
Assert.notNull(method, "Could not obtain target method from JoinPoint: '"+ jp + "'");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Method getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getArguments() {
|
||||||
|
return jp.getArgs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessibleObject getStaticPart() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getThis() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object proceed() throws Throwable {
|
||||||
|
return jp.proceed();
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -3,8 +3,8 @@ package org.springframework.security.access.method;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract implementation of {@link MethodSecurityMetadataSource} that supports both Spring AOP and AspectJ and
|
* Abstract implementation of {@link MethodSecurityMetadataSource} that supports both Spring AOP and AspectJ and
|
||||||
@@ -29,7 +29,7 @@ public abstract class AbstractFallbackMethodSecurityMetadataSource extends Abstr
|
|||||||
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
|
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
|
||||||
// The method may be on an interface, but we need attributes from the target class.
|
// The method may be on an interface, but we need attributes from the target class.
|
||||||
// If the target class is null, the method will be unchanged.
|
// If the target class is null, the method will be unchanged.
|
||||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||||
// First try is the method in the target class.
|
// First try is the method in the target class.
|
||||||
Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
|
Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
|
|||||||
+7
-1
@@ -49,7 +49,13 @@ public abstract class AbstractMethodSecurityMetadataSource implements MethodSecu
|
|||||||
if (object instanceof MethodInvocation) {
|
if (object instanceof MethodInvocation) {
|
||||||
MethodInvocation mi = (MethodInvocation) object;
|
MethodInvocation mi = (MethodInvocation) object;
|
||||||
Object target = mi.getThis();
|
Object target = mi.getThis();
|
||||||
return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
|
Class<?> targetClass = null;
|
||||||
|
|
||||||
|
if (target != null) {
|
||||||
|
targetClass = target instanceof Class<?> ? (Class<?>)target : target.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAttributes(mi.getMethod(), targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object instanceof JoinPoint) {
|
if (object instanceof JoinPoint) {
|
||||||
|
|||||||
+55
-35
@@ -22,6 +22,7 @@ import java.util.Collections;
|
|||||||
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ import org.springframework.security.core.userdetails.UserDetails;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAuthenticationToken implements Authentication {
|
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private Object details;
|
private Object details;
|
||||||
@@ -49,7 +50,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the
|
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the
|
||||||
* principal represented by this authentication object.
|
* principal represented by this authentication object.
|
||||||
*/
|
*/
|
||||||
public AbstractAuthenticationToken(Collection<GrantedAuthority> authorities) {
|
public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
|
||||||
if (authorities == null) {
|
if (authorities == null) {
|
||||||
this.authorities = AuthorityUtils.NO_AUTHORITIES;
|
this.authorities = AuthorityUtils.NO_AUTHORITIES;
|
||||||
return;
|
return;
|
||||||
@@ -67,6 +68,55 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
public Collection<GrantedAuthority> getAuthorities() {
|
||||||
|
return authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
if (this.getPrincipal() instanceof UserDetails) {
|
||||||
|
return ((UserDetails) this.getPrincipal()).getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getPrincipal() instanceof Principal) {
|
||||||
|
return ((Principal)getPrincipal()).getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.getPrincipal() == null) ? "" : this.getPrincipal().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAuthenticated() {
|
||||||
|
return authenticated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthenticated(boolean authenticated) {
|
||||||
|
this.authenticated = authenticated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getDetails() {
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetails(Object details) {
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the {@code credentials}, {@code principal} and {@code details} objects, invoking the
|
||||||
|
* {@code eraseCredentials} method on any which implement {@link CredentialsContainer}.
|
||||||
|
*/
|
||||||
|
public void eraseCredentials() {
|
||||||
|
eraseSecret(getCredentials());
|
||||||
|
eraseSecret(getPrincipal());
|
||||||
|
eraseSecret(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void eraseSecret(Object secret) {
|
||||||
|
if (secret instanceof CredentialsContainer) {
|
||||||
|
((CredentialsContainer)secret).eraseCredentials();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof AbstractAuthenticationToken)) {
|
if (!(obj instanceof AbstractAuthenticationToken)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -109,26 +159,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
return this.isAuthenticated() == test.isAuthenticated();
|
return this.isAuthenticated() == test.isAuthenticated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<GrantedAuthority> getAuthorities() {
|
@Override
|
||||||
return authorities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getDetails() {
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
if (this.getPrincipal() instanceof UserDetails) {
|
|
||||||
return ((UserDetails) this.getPrincipal()).getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getPrincipal() instanceof Principal) {
|
|
||||||
return ((Principal)getPrincipal()).getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (this.getPrincipal() == null) ? "" : this.getPrincipal().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int code = 31;
|
int code = 31;
|
||||||
|
|
||||||
@@ -155,23 +186,12 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAuthenticated() {
|
@Override
|
||||||
return authenticated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthenticated(boolean authenticated) {
|
|
||||||
this.authenticated = authenticated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDetails(Object details) {
|
|
||||||
this.details = details;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(super.toString()).append(": ");
|
sb.append(super.toString()).append(": ");
|
||||||
sb.append("Principal: ").append(this.getPrincipal()).append("; ");
|
sb.append("Principal: ").append(this.getPrincipal()).append("; ");
|
||||||
sb.append("Password: [PROTECTED]; ");
|
sb.append("Credentials: [PROTECTED]; ");
|
||||||
sb.append("Authenticated: ").append(this.isAuthenticated()).append("; ");
|
sb.append("Authenticated: ").append(this.isAuthenticated()).append("; ");
|
||||||
sb.append("Details: ").append(this.getDetails()).append("; ");
|
sb.append("Details: ").append(this.getDetails()).append("; ");
|
||||||
|
|
||||||
|
|||||||
+32
-1
@@ -26,6 +26,7 @@ import org.springframework.context.MessageSourceAware;
|
|||||||
import org.springframework.context.support.MessageSourceAccessor;
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -42,10 +43,17 @@ import org.springframework.util.Assert;
|
|||||||
* <code>AuthenticationException</code>, the last <code>AuthenticationException</code> received will be used.
|
* <code>AuthenticationException</code>, the last <code>AuthenticationException</code> received will be used.
|
||||||
* If no provider returns a non-null response, or indicates it can even process an <code>Authentication</code>,
|
* If no provider returns a non-null response, or indicates it can even process an <code>Authentication</code>,
|
||||||
* the <code>ProviderManager</code> will throw a <code>ProviderNotFoundException</code>.
|
* the <code>ProviderManager</code> will throw a <code>ProviderNotFoundException</code>.
|
||||||
|
* A parent {@code AuthenticationManager} can also be set, and this will also be tried if none of the configured
|
||||||
|
* providers can perform the authentication. This is intended to support namespace configuration options though and
|
||||||
|
* is not a feature that should normally be required.
|
||||||
* <p>
|
* <p>
|
||||||
* The exception to this process is when a provider throws an {@link AccountStatusException}, in which case no
|
* The exception to this process is when a provider throws an {@link AccountStatusException}, in which case no
|
||||||
* further providers in the list will be queried.
|
* further providers in the list will be queried.
|
||||||
*
|
*
|
||||||
|
* Post-authentication, the credentials will be cleared from the returned {@code Authentication} object, if it
|
||||||
|
* implements the {@link CredentialsContainer} interface. This behaviour can be controlled by modifying the
|
||||||
|
* {@link #setEraseCredentialsAfterAuthentication(boolean) eraseCredentialsAfterAuthentication} property.
|
||||||
|
*
|
||||||
* <h2>Event Publishing</h2>
|
* <h2>Event Publishing</h2>
|
||||||
* <p>
|
* <p>
|
||||||
* Authentication event publishing is delegated to the configured {@link AuthenticationEventPublisher} which defaults
|
* Authentication event publishing is delegated to the configured {@link AuthenticationEventPublisher} which defaults
|
||||||
@@ -57,9 +65,10 @@ import org.springframework.util.Assert;
|
|||||||
* the <tt><http></tt> configuration, so you will receive events from the web part of your application automatically.
|
* the <tt><http></tt> configuration, so you will receive events from the web part of your application automatically.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that the implementation also publishes authentication failure events when it obtains an authentication result
|
* Note that the implementation also publishes authentication failure events when it obtains an authentication result
|
||||||
* (or an exception) from the "parent" <tt>AuthenticationManager</tt> if one has been set. So in this situation, the
|
* (or an exception) from the "parent" {@code AuthenticationManager} if one has been set. So in this situation, the
|
||||||
* parent should not generally be configured to publish events or there will be duplicates.
|
* parent should not generally be configured to publish events or there will be duplicates.
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*
|
*
|
||||||
@@ -76,6 +85,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
|||||||
private List<AuthenticationProvider> providers = Collections.emptyList();
|
private List<AuthenticationProvider> providers = Collections.emptyList();
|
||||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||||
private AuthenticationManager parent;
|
private AuthenticationManager parent;
|
||||||
|
private boolean eraseCredentialsAfterAuthentication = false;
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@@ -145,6 +155,11 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
|
||||||
|
// Authentication is complete. Remove credentials and other secret data from authentication
|
||||||
|
((CredentialsContainer)result).eraseCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
eventPublisher.publishAuthenticationSuccess(result);
|
eventPublisher.publishAuthenticationSuccess(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -193,6 +208,22 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
|||||||
this.eventPublisher = eventPublisher;
|
this.eventPublisher = eventPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to, a resulting {@code Authentication} which implements the {@code CredentialsContainer} interface
|
||||||
|
* will have its {@link CredentialsContainer#eraseCredentials() eraseCredentials} method called before it is returned
|
||||||
|
* from the {@code authenticate()} method.
|
||||||
|
*
|
||||||
|
* @param eraseSecretData set to {@literal false} to retain the credentials data in memory.
|
||||||
|
* Defaults to {@literal true}.
|
||||||
|
*/
|
||||||
|
public void setEraseCredentialsAfterAuthentication(boolean eraseSecretData) {
|
||||||
|
this.eraseCredentialsAfterAuthentication = eraseSecretData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEraseCredentialsAfterAuthentication() {
|
||||||
|
return eraseCredentialsAfterAuthentication;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link AuthenticationProvider} objects to be used for authentication.
|
* Sets the {@link AuthenticationProvider} objects to be used for authentication.
|
||||||
*
|
*
|
||||||
|
|||||||
+20
-19
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
package org.springframework.security.authentication;
|
package org.springframework.security.authentication;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
@@ -28,8 +27,9 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
* <code>GrantedAuthority</code>s that apply.
|
* <code>GrantedAuthority</code>s that apply.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
|
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final Object principal;
|
private final Object principal;
|
||||||
@@ -46,7 +46,7 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
|||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||||
*/
|
*/
|
||||||
public RememberMeAuthenticationToken(String key, Object principal, Collection<GrantedAuthority> authorities) {
|
public RememberMeAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
|
|
||||||
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
|
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
|
||||||
@@ -60,6 +60,23 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
|||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always returns an empty <code>String</code>
|
||||||
|
*
|
||||||
|
* @return an empty String
|
||||||
|
*/
|
||||||
|
public Object getCredentials() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyHash() {
|
||||||
|
return this.keyHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return this.principal;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!super.equals(obj)) {
|
if (!super.equals(obj)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -78,20 +95,4 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Always returns an empty <code>String</code>
|
|
||||||
*
|
|
||||||
* @return an empty String
|
|
||||||
*/
|
|
||||||
public Object getCredentials() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getKeyHash() {
|
|
||||||
return this.keyHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getPrincipal() {
|
|
||||||
return this.principal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -22,8 +22,8 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link org.springframework.security.core.Authentication} implementation that is designed for simple presentation of a
|
* An {@link org.springframework.security.core.Authentication} implementation that is designed for simple presentation
|
||||||
* username and password.
|
* of a username and password.
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>principal</code> and <code>credentials</code> should be set with an <code>Object</code> that provides
|
* The <code>principal</code> and <code>credentials</code> should be set with an <code>Object</code> that provides
|
||||||
* the respective property via its <code>Object.toString()</code> method. The simplest such <code>Object</code> to use
|
* the respective property via its <code>Object.toString()</code> method. The simplest such <code>Object</code> to use
|
||||||
@@ -34,8 +34,8 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final Object credentials;
|
|
||||||
private final Object principal;
|
private final Object principal;
|
||||||
|
private Object credentials;
|
||||||
|
|
||||||
//~ Constructors ===================================================================================================
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
|||||||
* @param credentials
|
* @param credentials
|
||||||
* @param authorities
|
* @param authorities
|
||||||
*/
|
*/
|
||||||
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<GrantedAuthority> authorities) {
|
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
this.principal = principal;
|
this.principal = principal;
|
||||||
this.credentials = credentials;
|
this.credentials = credentials;
|
||||||
@@ -94,4 +94,10 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
|||||||
|
|
||||||
super.setAuthenticated(false);
|
super.setAuthenticated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eraseCredentials() {
|
||||||
|
super.eraseCredentials();
|
||||||
|
credentials = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.springframework.security.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the implementing object contains sensitive data, which can be erased using the
|
||||||
|
* {@code eraseCredentials} method. Implementations are expected to invoke the method on any internal objects
|
||||||
|
* which may also implement this interface.
|
||||||
|
* <p>
|
||||||
|
* For internal framework use only. Users who are writing their own {@code AuthenticationProvider} implementations
|
||||||
|
* should create and return an appropriate {@code Authentication} object there, minus any sensitive data,
|
||||||
|
* rather than using this interface.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @since 3.0.3
|
||||||
|
*/
|
||||||
|
public interface CredentialsContainer {
|
||||||
|
void eraseCredentials();
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import java.util.SortedSet;
|
|||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,12 +34,18 @@ import org.springframework.util.Assert;
|
|||||||
* Implemented with value object semantics (immutable after construction, like a <code>String</code>).
|
* Implemented with value object semantics (immutable after construction, like a <code>String</code>).
|
||||||
* Developers may use this class directly, subclass it, or write their own {@link UserDetails} implementation from
|
* Developers may use this class directly, subclass it, or write their own {@link UserDetails} implementation from
|
||||||
* scratch.
|
* scratch.
|
||||||
|
* <p>
|
||||||
|
* {@code equals} and {@code hashcode} implementations are based on the {@code username} property only, as the
|
||||||
|
* intention is that lookups of the same user principal object (in a user registry, for example) will match
|
||||||
|
* where the objects represent the same user, not just when all the properties (authorities, password for
|
||||||
|
* example) are the same.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class User implements UserDetails {
|
public class User implements UserDetails, CredentialsContainer {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
private final String password;
|
private String password;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final Set<GrantedAuthority> authorities;
|
private final Set<GrantedAuthority> authorities;
|
||||||
private final boolean accountNonExpired;
|
private final boolean accountNonExpired;
|
||||||
@@ -81,7 +88,7 @@ public class User implements UserDetails {
|
|||||||
* <code>GrantedAuthority</code> collection
|
* <code>GrantedAuthority</code> collection
|
||||||
*/
|
*/
|
||||||
public User(String username, String password, boolean enabled, boolean accountNonExpired,
|
public User(String username, String password, boolean enabled, boolean accountNonExpired,
|
||||||
boolean credentialsNonExpired, boolean accountNonLocked, Collection<GrantedAuthority> authorities) {
|
boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
|
||||||
if (((username == null) || "".equals(username)) || (password == null)) {
|
if (((username == null) || "".equals(username)) || (password == null)) {
|
||||||
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
||||||
@@ -98,27 +105,6 @@ public class User implements UserDetails {
|
|||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public boolean equals(Object rhs) {
|
|
||||||
if (!(rhs instanceof User) || (rhs == null)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
User user = (User) rhs;
|
|
||||||
|
|
||||||
// We rely on constructor to guarantee any User has non-null
|
|
||||||
// authorities
|
|
||||||
if (!authorities.equals(user.authorities)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We rely on constructor to guarantee non-null username and password
|
|
||||||
return (this.getPassword().equals(user.getPassword()) && this.getUsername().equals(user.getUsername())
|
|
||||||
&& (this.isAccountNonExpired() == user.isAccountNonExpired())
|
|
||||||
&& (this.isAccountNonLocked() == user.isAccountNonLocked())
|
|
||||||
&& (this.isCredentialsNonExpired() == user.isCredentialsNonExpired())
|
|
||||||
&& (this.isEnabled() == user.isEnabled()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<GrantedAuthority> getAuthorities() {
|
public Collection<GrantedAuthority> getAuthorities() {
|
||||||
return authorities;
|
return authorities;
|
||||||
}
|
}
|
||||||
@@ -131,38 +117,8 @@ public class User implements UserDetails {
|
|||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public boolean isEnabled() {
|
||||||
int code = 9792;
|
return enabled;
|
||||||
|
|
||||||
for (GrantedAuthority authority : getAuthorities()) {
|
|
||||||
code = code * (authority.hashCode() % 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getPassword() != null) {
|
|
||||||
code = code * (this.getPassword().hashCode() % 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getUsername() != null) {
|
|
||||||
code = code * (this.getUsername().hashCode() % 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isAccountNonExpired()) {
|
|
||||||
code = code * -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isAccountNonLocked()) {
|
|
||||||
code = code * -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isCredentialsNonExpired()) {
|
|
||||||
code = code * -5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isEnabled()) {
|
|
||||||
code = code * -7;
|
|
||||||
}
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAccountNonExpired() {
|
public boolean isAccountNonExpired() {
|
||||||
@@ -170,18 +126,18 @@ public class User implements UserDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAccountNonLocked() {
|
public boolean isAccountNonLocked() {
|
||||||
return this.accountNonLocked;
|
return accountNonLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCredentialsNonExpired() {
|
public boolean isCredentialsNonExpired() {
|
||||||
return credentialsNonExpired;
|
return credentialsNonExpired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public void eraseCredentials() {
|
||||||
return enabled;
|
password = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<GrantedAuthority> authorities) {
|
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||||
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
|
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
|
||||||
// Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-717)
|
// Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-717)
|
||||||
SortedSet<GrantedAuthority> sortedAuthorities =
|
SortedSet<GrantedAuthority> sortedAuthorities =
|
||||||
@@ -211,7 +167,30 @@ public class User implements UserDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the supplied object is a {@code User} instance with the
|
||||||
|
* same {@code username} value.
|
||||||
|
* <p>
|
||||||
|
* In other words, the objects are equal if they have the same username, representing the
|
||||||
|
* same principal.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object rhs) {
|
||||||
|
if (rhs instanceof User) {
|
||||||
|
return username.equals(((User) rhs).username);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hashcode of the {@code username}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return username.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(super.toString()).append(": ");
|
sb.append(super.toString()).append(": ");
|
||||||
|
|||||||
+5
-1
@@ -29,10 +29,14 @@ import java.util.Properties;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves user details from an in-memory list created by the bean context.
|
* Retrieves user details from an in-memory list created in the application context.
|
||||||
|
* <p>
|
||||||
|
* Username lookups are case-insensitive.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class InMemoryDaoImpl implements UserDetailsService, InitializingBean {
|
public class InMemoryDaoImpl implements UserDetailsService, InitializingBean {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ import org.springframework.util.Assert;
|
|||||||
* Used by {@link InMemoryDaoImpl} to store a list of users and their corresponding granted authorities.
|
* Used by {@link InMemoryDaoImpl} to store a list of users and their corresponding granted authorities.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @deprecated Use a plain map instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class UserMap {
|
public class UserMap {
|
||||||
//~ Static fields/initializers =====================================================================================
|
//~ Static fields/initializers =====================================================================================
|
||||||
|
|
||||||
|
|||||||
+1
@@ -41,6 +41,7 @@ import java.util.Properties;
|
|||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class UserMapEditor extends PropertyEditorSupport {
|
public class UserMapEditor extends PropertyEditorSupport {
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package org.springframework.security.access.annotation;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.security.access.AccessDecisionVoter;
|
||||||
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
|
import org.springframework.security.access.SecurityConfig;
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
*/
|
||||||
|
public class Jsr250VoterTests {
|
||||||
|
|
||||||
|
// SEC-1443
|
||||||
|
@Test
|
||||||
|
public void supportsMultipleRolesCorrectly() throws Exception {
|
||||||
|
List<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>();
|
||||||
|
Jsr250Voter voter = new Jsr250Voter();
|
||||||
|
|
||||||
|
attrs.add(new Jsr250SecurityConfig("A"));
|
||||||
|
attrs.add(new Jsr250SecurityConfig("B"));
|
||||||
|
attrs.add(new Jsr250SecurityConfig("C"));
|
||||||
|
|
||||||
|
assertEquals(AccessDecisionVoter.ACCESS_GRANTED,
|
||||||
|
voter.vote(new TestingAuthenticationToken("user", "pwd", "A"), new Object(), attrs));
|
||||||
|
assertEquals(AccessDecisionVoter.ACCESS_GRANTED,
|
||||||
|
voter.vote(new TestingAuthenticationToken("user", "pwd", "B"), new Object(), attrs));
|
||||||
|
assertEquals(AccessDecisionVoter.ACCESS_GRANTED,
|
||||||
|
voter.vote(new TestingAuthenticationToken("user", "pwd", "C"), new Object(), attrs));
|
||||||
|
|
||||||
|
assertEquals(AccessDecisionVoter.ACCESS_DENIED,
|
||||||
|
voter.vote(new TestingAuthenticationToken("user", "pwd", "NONE"), new Object(), attrs));
|
||||||
|
|
||||||
|
assertEquals(AccessDecisionVoter.ACCESS_ABSTAIN,
|
||||||
|
voter.vote(new TestingAuthenticationToken("user", "pwd", "A"), new Object(),
|
||||||
|
SecurityConfig.createList("A","B","C")));
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
-34
@@ -15,26 +15,28 @@
|
|||||||
|
|
||||||
package org.springframework.security.access.intercept.aspectj;
|
package org.springframework.security.access.intercept.aspectj;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.jmock.Expectations;
|
|
||||||
import org.jmock.Mockery;
|
|
||||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.springframework.security.MockJoinPoint;
|
import org.springframework.security.MockJoinPoint;
|
||||||
import org.springframework.security.TargetObject;
|
import org.springframework.security.TargetObject;
|
||||||
import org.springframework.security.access.AccessDecisionManager;
|
import org.springframework.security.access.AccessDecisionManager;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.access.SecurityConfig;
|
import org.springframework.security.access.SecurityConfig;
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
|
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
|
|
||||||
import org.springframework.security.access.method.MethodSecurityMetadataSource;
|
import org.springframework.security.access.method.MethodSecurityMetadataSource;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
|
||||||
@@ -42,33 +44,33 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||||||
* Tests {@link AspectJSecurityInterceptor}.
|
* Tests {@link AspectJSecurityInterceptor}.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class AspectJSecurityInterceptorTests {
|
public class AspectJSecurityInterceptorTests {
|
||||||
private Mockery jmock = new JUnit4Mockery();
|
|
||||||
private TestingAuthenticationToken token;
|
private TestingAuthenticationToken token;
|
||||||
private AspectJSecurityInterceptor interceptor;
|
private AspectJSecurityInterceptor interceptor;
|
||||||
private AccessDecisionManager adm;
|
private @Mock AccessDecisionManager adm;
|
||||||
private MethodSecurityMetadataSource mds;
|
private @Mock MethodSecurityMetadataSource mds;
|
||||||
private AuthenticationManager authman;
|
private @Mock AuthenticationManager authman;
|
||||||
private AspectJCallback aspectJCallback;
|
private @Mock AspectJCallback aspectJCallback;
|
||||||
private JoinPoint joinPoint;
|
private JoinPoint joinPoint;
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public final void setUp() throws Exception {
|
public final void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
SecurityContextHolder.clearContext();
|
SecurityContextHolder.clearContext();
|
||||||
token = new TestingAuthenticationToken("Test", "Password");
|
token = new TestingAuthenticationToken("Test", "Password");
|
||||||
interceptor = new AspectJSecurityInterceptor();
|
interceptor = new AspectJSecurityInterceptor();
|
||||||
adm = jmock.mock(AccessDecisionManager.class);
|
|
||||||
authman = jmock.mock(AuthenticationManager.class);
|
|
||||||
mds = jmock.mock(MethodSecurityMetadataSource.class);
|
|
||||||
interceptor.setAccessDecisionManager(adm);
|
interceptor.setAccessDecisionManager(adm);
|
||||||
interceptor.setAuthenticationManager(authman);
|
interceptor.setAuthenticationManager(authman);
|
||||||
interceptor.setSecurityMetadataSource(mds);
|
interceptor.setSecurityMetadataSource(mds);
|
||||||
Method method = TargetObject.class.getMethod("countLength", new Class[] {String.class});
|
Method method = TargetObject.class.getMethod("countLength", new Class[] {String.class});
|
||||||
joinPoint = new MockJoinPoint(new TargetObject(), method);
|
joinPoint = new MockJoinPoint(new TargetObject(), method);
|
||||||
aspectJCallback = jmock.mock(AspectJCallback.class);
|
when(mds.getAttributes(any(JoinPoint.class))).thenReturn(SecurityConfig.createList("ROLE_USER"));
|
||||||
|
when(authman.authenticate(token)).thenReturn(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -77,33 +79,23 @@ public class AspectJSecurityInterceptorTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void callbackIsInvokedWhenPermissionGranted() throws Exception {
|
public void callbackIsInvokedWhenPermissionGranted() throws Exception {
|
||||||
jmock.checking(new Expectations() {{
|
|
||||||
oneOf(mds).getAttributes(with(any(JoinPoint.class))); will (returnValue(SecurityConfig.createList("ROLE_USER")));
|
|
||||||
oneOf(authman).authenticate(token); will(returnValue(token));
|
|
||||||
oneOf(adm).decide(with(token), with(aNonNull(JoinPoint.class)), with(aNonNull(List.class)));
|
|
||||||
oneOf(aspectJCallback).proceedWithObject();
|
|
||||||
}});
|
|
||||||
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(token);
|
SecurityContextHolder.getContext().setAuthentication(token);
|
||||||
interceptor.invoke(joinPoint, aspectJCallback);
|
interceptor.invoke(joinPoint, aspectJCallback);
|
||||||
jmock.assertIsSatisfied();
|
verify(aspectJCallback).proceedWithObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Test(expected=AccessDeniedException.class)
|
@Test
|
||||||
public void callbackIsNotInvokedWhenPermissionDenied() throws Exception {
|
public void callbackIsNotInvokedWhenPermissionDenied() throws Exception {
|
||||||
jmock.checking(new Expectations() {{
|
doThrow(new AccessDeniedException("denied")).when(adm).decide(any(Authentication.class), any(), any(Collection.class));
|
||||||
oneOf(mds).getAttributes(with(any(JoinPoint.class))); will (returnValue(SecurityConfig.createList("ROLE_USER")));
|
|
||||||
oneOf(authman).authenticate(token); will(returnValue(token));
|
|
||||||
oneOf(adm).decide(with(token), with(aNonNull(JoinPoint.class)), with(aNonNull(List.class)));
|
|
||||||
will(throwException(new AccessDeniedException("denied")));
|
|
||||||
never(aspectJCallback).proceedWithObject();
|
|
||||||
}});
|
|
||||||
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(token);
|
SecurityContextHolder.getContext().setAuthentication(token);
|
||||||
interceptor.invoke(joinPoint, aspectJCallback);
|
try {
|
||||||
jmock.assertIsSatisfied();
|
interceptor.invoke(joinPoint, aspectJCallback);
|
||||||
|
fail("Expected AccessDeniedException");
|
||||||
|
} catch (AccessDeniedException expected) {
|
||||||
|
}
|
||||||
|
verify(aspectJCallback, never()).proceedWithObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-4
@@ -28,7 +28,6 @@ import org.springframework.context.MessageSource;
|
|||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link ProviderManager}.
|
* Tests {@link ProviderManager}.
|
||||||
@@ -40,14 +39,33 @@ public class ProviderManagerTests {
|
|||||||
|
|
||||||
@Test(expected=ProviderNotFoundException.class)
|
@Test(expected=ProviderNotFoundException.class)
|
||||||
public void authenticationFailsWithUnsupportedToken() throws Exception {
|
public void authenticationFailsWithUnsupportedToken() throws Exception {
|
||||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
Authentication token = new AbstractAuthenticationToken (null) {
|
||||||
AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
|
public Object getCredentials() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
ProviderManager mgr = makeProviderManager();
|
ProviderManager mgr = makeProviderManager();
|
||||||
mgr.setMessageSource(mock(MessageSource.class));
|
mgr.setMessageSource(mock(MessageSource.class));
|
||||||
mgr.authenticate(token);
|
mgr.authenticate(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void credentialsAreNotClearedByDefault() throws Exception {
|
||||||
|
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password");
|
||||||
|
ProviderManager mgr = makeProviderManager();
|
||||||
|
Authentication result = mgr.authenticate(token);
|
||||||
|
assertNotNull(result.getCredentials());
|
||||||
|
|
||||||
|
mgr.setEraseCredentialsAfterAuthentication(true);
|
||||||
|
token = new UsernamePasswordAuthenticationToken("Test", "Password");
|
||||||
|
result = mgr.authenticate(token);
|
||||||
|
assertNull(result.getCredentials());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authenticationSucceedsWithSupportedTokenAndReturnsExpectedObject() throws Exception {
|
public void authenticationSucceedsWithSupportedTokenAndReturnsExpectedObject() throws Exception {
|
||||||
final Authentication a = mock(Authentication.class);
|
final Authentication a = mock(Authentication.class);
|
||||||
@@ -126,6 +144,7 @@ public class ProviderManagerTests {
|
|||||||
request.setDetails(details);
|
request.setDetails(details);
|
||||||
|
|
||||||
Authentication result = authMgr.authenticate(request);
|
Authentication result = authMgr.authenticate(request);
|
||||||
|
assertNotNull(result.getCredentials());
|
||||||
assertSame(details, result.getDetails());
|
assertSame(details, result.getDetails());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +297,8 @@ public class ProviderManagerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean supports(Class<? extends Object> authentication) {
|
public boolean supports(Class<? extends Object> authentication) {
|
||||||
if (TestingAuthenticationToken.class.isAssignableFrom(authentication)) {
|
if (TestingAuthenticationToken.class.isAssignableFrom(authentication) ||
|
||||||
|
UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ import static org.junit.Assert.*;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
@@ -37,24 +39,24 @@ public class UserTests {
|
|||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEquals() {
|
public void equalsReturnsTrueIfUsernamesAreTheSame() {
|
||||||
User user1 = new User("rod", "koala", true, true, true, true,ROLE_12);
|
User user1 = new User("rod", "koala", true, true, true, true, ROLE_12);
|
||||||
|
|
||||||
assertFalse(user1.equals(null));
|
assertFalse(user1.equals(null));
|
||||||
assertFalse(user1.equals("A STRING"));
|
assertFalse(user1.equals("A STRING"));
|
||||||
assertTrue(user1.equals(user1));
|
assertTrue(user1.equals(user1));
|
||||||
assertTrue(user1.equals(new User("rod", "koala", true, true, true, true,ROLE_12)));
|
assertTrue(user1.equals(new User("rod", "notthesame", true, true, true, true, ROLE_12)));
|
||||||
// Equal as the new User will internally sort the GrantedAuthorities in the correct order, before running equals()
|
}
|
||||||
assertTrue(user1.equals(new User("rod", "koala", true, true, true, true,
|
|
||||||
AuthorityUtils.createAuthorityList("ROLE_TWO","ROLE_ONE"))));
|
@Test
|
||||||
assertFalse(user1.equals(new User("DIFFERENT_USERNAME", "koala", true, true, true, true, ROLE_12)));
|
public void hashLookupOnlyDependsOnUsername() throws Exception {
|
||||||
assertFalse(user1.equals(new User("rod", "DIFFERENT_PASSWORD", true, true, true, true, ROLE_12)));
|
User user1 = new User("rod", "koala", true, true, true, true, ROLE_12);
|
||||||
assertFalse(user1.equals(new User("rod", "koala", false, true, true, true, ROLE_12)));
|
Set<UserDetails> users = new HashSet<UserDetails>();
|
||||||
assertFalse(user1.equals(new User("rod", "koala", true, false, true, true, ROLE_12)));
|
users.add(user1);
|
||||||
assertFalse(user1.equals(new User("rod", "koala", true, true, false, true, ROLE_12)));
|
|
||||||
assertFalse(user1.equals(new User("rod", "koala", true, true, true, false, ROLE_12)));
|
assertTrue(users.contains(new User("rod", "koala", true, true, true, true, ROLE_12)));
|
||||||
assertFalse(user1.equals(new User("rod", "koala", true, true, true, true,
|
assertTrue(users.contains(new User("rod", "anotherpass", false, false, false, false, AuthorityUtils.createAuthorityList("ROLE_X"))));
|
||||||
AuthorityUtils.createAuthorityList("ROLE_ONE"))));
|
assertFalse(users.contains(new User("bod", "koala", true, true, true, true, ROLE_12)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -116,9 +118,9 @@ public class UserTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserIsEnabled() throws Exception {
|
public void enabledFlagIsFalseForDisabledAccount() throws Exception {
|
||||||
UserDetails user = new User("rod", "koala", false, true, true, true, ROLE_12);
|
UserDetails user = new User("rod", "koala", false, true, true, true, ROLE_12);
|
||||||
assertTrue(!user.isEnabled());
|
assertFalse(user.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+2
-14
@@ -30,26 +30,14 @@ import java.util.Properties;
|
|||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class InMemoryDaoTests extends TestCase {
|
public class InMemoryDaoTests extends TestCase {
|
||||||
//~ Constructors ===================================================================================================
|
|
||||||
|
|
||||||
public InMemoryDaoTests() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InMemoryDaoTests(String arg0) {
|
|
||||||
super(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
junit.textui.TestRunner.run(InMemoryDaoTests.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserMap makeUserMap() {
|
private UserMap makeUserMap() {
|
||||||
UserMapEditor editor = new UserMapEditor();
|
UserMapEditor editor = new UserMapEditor();
|
||||||
editor.setAsText("rod=koala,ROLE_ONE,ROLE_TWO,enabled\r\nscott=wombat,ROLE_ONE,ROLE_TWO,enabled");
|
editor.setAsText("rod=koala,ROLE_ONE,ROLE_TWO,enabled\nScott=wombat,ROLE_ONE,ROLE_TWO,enabled");
|
||||||
|
|
||||||
return (UserMap) editor.getValue();
|
return (UserMap) editor.getValue();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -27,6 +27,7 @@ import org.springframework.security.core.userdetails.memory.UserMapEditor;
|
|||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class UserMapEditorTests extends TestCase {
|
public class UserMapEditorTests extends TestCase {
|
||||||
//~ Constructors ===================================================================================================
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
|
|||||||
+9
-6
@@ -15,13 +15,13 @@
|
|||||||
|
|
||||||
package org.springframework.security.core.userdetails.memory;
|
package org.springframework.security.core.userdetails.memory;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.core.userdetails.memory.UserMap;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,9 +29,10 @@ import org.springframework.security.core.userdetails.memory.UserMap;
|
|||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class UserMapTests extends TestCase {
|
@SuppressWarnings("deprecation")
|
||||||
|
public class UserMapTests {
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
@Test
|
||||||
public void testAddAndRetrieveUser() {
|
public void testAddAndRetrieveUser() {
|
||||||
UserDetails rod = new User("rod", "koala", true, true, true, true,
|
UserDetails rod = new User("rod", "koala", true, true, true, true,
|
||||||
AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"));
|
AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"));
|
||||||
@@ -50,7 +51,8 @@ public class UserMapTests extends TestCase {
|
|||||||
assertEquals(peter, map.getUser("peter"));
|
assertEquals(peter, map.getUser("peter"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNullUserCannotBeAdded() {
|
@Test
|
||||||
|
public void nullUserCannotBeAdded() {
|
||||||
UserMap map = new UserMap();
|
UserMap map = new UserMap();
|
||||||
assertEquals(0, map.getUserCount());
|
assertEquals(0, map.getUserCount());
|
||||||
|
|
||||||
@@ -62,7 +64,8 @@ public class UserMapTests extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUnknownUserIsNotRetrieved() {
|
@Test
|
||||||
|
public void unknownUserIsNotRetrieved() {
|
||||||
UserDetails rod = new User("rod", "koala", true, true, true, true,
|
UserDetails rod = new User("rod", "koala", true, true, true, true,
|
||||||
AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"));
|
AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"));
|
||||||
UserMap map = new UserMap();
|
UserMap map = new UserMap();
|
||||||
|
|||||||
+5
-3
@@ -1,10 +1,12 @@
|
|||||||
apply id: 'base'
|
apply plugin: 'base'
|
||||||
apply id: 'docbook'
|
apply plugin: 'docbook'
|
||||||
|
|
||||||
defaultTasks 'docbookHtmlSingle'
|
defaultTasks 'docbookHtmlSingle'
|
||||||
|
|
||||||
docbookSrcFileName = 'faq.xml'
|
[docbookHtml, docbookFoPdf, docbookHtmlSingle]*.sourceFileName = 'faq.xml'
|
||||||
|
|
||||||
docbookHtmlSingle.stylesheet = new File(projectDir, 'src/xsl/html-single-custom.xsl')
|
docbookHtmlSingle.stylesheet = new File(projectDir, 'src/xsl/html-single-custom.xsl')
|
||||||
|
docbookHtmlSingle.suffix = ''
|
||||||
|
|
||||||
docbookHtmlSingle.doLast {
|
docbookHtmlSingle.doLast {
|
||||||
resourcesDir = new File(projectDir, 'src/resources')
|
resourcesDir = new File(projectDir, 'src/resources')
|
||||||
|
|||||||
@@ -1,101 +1,101 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
xmlns:xslthl="http://xslthl.sf.net"
|
xmlns:xslthl="http://xslthl.sf.net"
|
||||||
exclude-result-prefixes="xslthl"
|
exclude-result-prefixes="xslthl"
|
||||||
version='1.0'>
|
version='1.0'>
|
||||||
|
|
||||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
|
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
|
||||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/highlight.xsl"/>
|
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/highlight.xsl"/>
|
||||||
|
|
||||||
<!--xsl:param name="use.id.as.filename">'1'</xsl:param-->
|
<!--xsl:param name="use.id.as.filename">'1'</xsl:param-->
|
||||||
|
|
||||||
<!-- Use code syntax highlighting -->
|
<!-- Use code syntax highlighting -->
|
||||||
<xsl:param name="highlight.source">1</xsl:param>
|
<xsl:param name="highlight.source">1</xsl:param>
|
||||||
|
|
||||||
<!-- Extensions
|
<!-- Extensions
|
||||||
<xsl:param name="use.extensions">1</xsl:param>
|
<xsl:param name="use.extensions">1</xsl:param>
|
||||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||||
<xsl:param name="callout.extensions">1</xsl:param>
|
<xsl:param name="callout.extensions">1</xsl:param>
|
||||||
-->
|
-->
|
||||||
<!-- Activate Graphics
|
<!-- Activate Graphics
|
||||||
<xsl:param name="admon.graphics" select="1"/>
|
<xsl:param name="admon.graphics" select="1"/>
|
||||||
<xsl:param name="admon.graphics.path">images/</xsl:param>
|
<xsl:param name="admon.graphics.path">images/</xsl:param>
|
||||||
<xsl:param name="admon.graphics.extension">.gif</xsl:param>
|
<xsl:param name="admon.graphics.extension">.gif</xsl:param>
|
||||||
<xsl:param name="callout.graphics" select="1" />
|
<xsl:param name="callout.graphics" select="1" />
|
||||||
<xsl:param name="callout.defaultcolumn">120</xsl:param>
|
<xsl:param name="callout.defaultcolumn">120</xsl:param>
|
||||||
<xsl:param name="callout.graphics.path">images/callouts/</xsl:param>
|
<xsl:param name="callout.graphics.path">images/callouts/</xsl:param>
|
||||||
<xsl:param name="callout.graphics.extension">.gif</xsl:param>
|
<xsl:param name="callout.graphics.extension">.gif</xsl:param>
|
||||||
-->
|
-->
|
||||||
<xsl:param name="table.borders.with.css" select="1"/>
|
<xsl:param name="table.borders.with.css" select="1"/>
|
||||||
<xsl:param name="html.stylesheet">css/faq.css</xsl:param>
|
<xsl:param name="html.stylesheet">css/faq.css</xsl:param>
|
||||||
<xsl:param name="html.stylesheet.type">text/css</xsl:param>
|
<xsl:param name="html.stylesheet.type">text/css</xsl:param>
|
||||||
|
|
||||||
<!--xsl:param name="generate.toc">book toc,title</xsl:param-->
|
<!--xsl:param name="generate.toc">book toc,title</xsl:param-->
|
||||||
<!--
|
<!--
|
||||||
<xsl:param name="admonition.title.properties">text-align: left</xsl:param>
|
<xsl:param name="admonition.title.properties">text-align: left</xsl:param>
|
||||||
|
|
||||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||||
<xsl:param name="table.footnote.number.format" select="'1'"/>
|
<xsl:param name="table.footnote.number.format" select="'1'"/>
|
||||||
-->
|
-->
|
||||||
<xsl:template match='xslthl:keyword' mode="xslthl">
|
<xsl:template match='xslthl:keyword' mode="xslthl">
|
||||||
<span class="hl-keyword"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-keyword"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match='xslthl:comment' mode="xslthl">
|
<xsl:template match='xslthl:comment' mode="xslthl">
|
||||||
<span class="hl-comment"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-comment"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match='xslthl:oneline-comment' mode="xslthl">
|
<xsl:template match='xslthl:oneline-comment' mode="xslthl">
|
||||||
<span class="hl-comment"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-comment"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match='xslthl:multiline-comment' mode="xslthl">
|
<xsl:template match='xslthl:multiline-comment' mode="xslthl">
|
||||||
<span class="hl-multiline-comment"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-multiline-comment"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match='xslthl:tag' mode="xslthl">
|
<xsl:template match='xslthl:tag' mode="xslthl">
|
||||||
<span class="hl-tag"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-tag"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match='xslthl:attribute' mode="xslthl">
|
<xsl:template match='xslthl:attribute' mode="xslthl">
|
||||||
<span class="hl-attribute"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-attribute"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match='xslthl:value' mode="xslthl">
|
<xsl:template match='xslthl:value' mode="xslthl">
|
||||||
<span class="hl-value"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-value"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match='xslthl:string' mode="xslthl">
|
<xsl:template match='xslthl:string' mode="xslthl">
|
||||||
<span class="hl-string"><xsl:apply-templates mode="xslthl"/></span>
|
<span class="hl-string"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<!-- Google Analytics -->
|
<!-- Google Analytics -->
|
||||||
<xsl:template name="user.head.content">
|
<xsl:template name="user.head.content">
|
||||||
<xsl:comment>Begin Google Analytics code</xsl:comment>
|
<xsl:comment>Begin Google Analytics code</xsl:comment>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var pageTracker = _gat._getTracker("UA-2728886-3");
|
var pageTracker = _gat._getTracker("UA-2728886-3");
|
||||||
pageTracker._setDomainName("none");
|
pageTracker._setDomainName("none");
|
||||||
pageTracker._setAllowLinker(true);
|
pageTracker._setAllowLinker(true);
|
||||||
pageTracker._trackPageview();
|
pageTracker._trackPageview();
|
||||||
</script>
|
</script>
|
||||||
<xsl:comment>End Google Analytics code</xsl:comment>
|
<xsl:comment>End Google Analytics code</xsl:comment>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<!-- Loopfuse -->
|
<!-- Loopfuse -->
|
||||||
<xsl:template name="user.footer.content">
|
<xsl:template name="user.footer.content">
|
||||||
<xsl:comment>Begin LoopFuse code</xsl:comment>
|
<xsl:comment>Begin LoopFuse code</xsl:comment>
|
||||||
<script src="http://loopfuse.net/webrecorder/js/listen.js" type="text/javascript">
|
<script src="http://loopfuse.net/webrecorder/js/listen.js" type="text/javascript">
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
_lf_cid = "LF_48be82fa";
|
_lf_cid = "LF_48be82fa";
|
||||||
_lf_remora();
|
_lf_remora();
|
||||||
</script>
|
</script>
|
||||||
<xsl:comment>End LoopFuse code</xsl:comment>
|
<xsl:comment>End LoopFuse code</xsl:comment>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
</xsl:stylesheet>
|
</xsl:stylesheet>
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
apply id: 'base'
|
apply plugin: 'base'
|
||||||
apply id: 'docbook'
|
apply plugin: 'docbook'
|
||||||
|
|
||||||
|
[docbookHtml, docbookFoPdf, docbookHtmlSingle]*.sourceFileName = 'springsecurity.xml';
|
||||||
|
|
||||||
docbookSrcFileName = 'springsecurity.xml'
|
|
||||||
docbookHtml.stylesheet = new File(projectDir, 'src/xsl/html-custom.xsl')
|
docbookHtml.stylesheet = new File(projectDir, 'src/xsl/html-custom.xsl')
|
||||||
|
docbookHtmlSingle.stylesheet = new File(projectDir, 'src/xsl/html-single-custom.xsl')
|
||||||
docbookFoPdf.stylesheet = new File(projectDir, 'src/xsl/pdf-custom.xsl')
|
docbookFoPdf.stylesheet = new File(projectDir, 'src/xsl/pdf-custom.xsl')
|
||||||
def imagesDir = new File(projectDir, 'src/docbook/images');
|
def imagesDir = new File(projectDir, 'src/docbook/images');
|
||||||
docbookFoPdf.admonGraphicsPath = "${imagesDir}/"
|
docbookFoPdf.admonGraphicsPath = "${imagesDir}/"
|
||||||
|
|
||||||
task doc (dependsOn: [docbookHtml, docbookFoPdf]) << {
|
task doc (dependsOn: [docbookHtml, docbookHtmlSingle, docbookFoPdf]) << {
|
||||||
resourcesDir = new File(projectDir, 'src/resources')
|
resourcesDir = new File(projectDir, 'src/resources')
|
||||||
ant {
|
ant {
|
||||||
docsDir = new File(buildDir, 'docs')
|
docsDir = new File(buildDir, 'docs')
|
||||||
|
|||||||
@@ -459,7 +459,12 @@
|
|||||||
instance for use in your own configuration. Its use is described in the
|
instance for use in your own configuration. Its use is described in the
|
||||||
<link xlink:href="#ns-auth-manager">namespace introduction</link>. All elements which create
|
<link xlink:href="#ns-auth-manager">namespace introduction</link>. All elements which create
|
||||||
<interfacename>AuthenticationProvider</interfacename> instances should be children of this
|
<interfacename>AuthenticationProvider</interfacename> instances should be children of this
|
||||||
element.</para>
|
element.</para>
|
||||||
|
<para>
|
||||||
|
The element also exposes an <literal>erase-credentials</literal> attribute which maps
|
||||||
|
to the <literal>eraseCredentialsAfterAuthentication</literal> property of
|
||||||
|
the <classname>ProviderManager</classname>. This is discussed in the
|
||||||
|
<link xlink:href="#core-services-erasing-credentials">Core Services</link> chapter.</para>
|
||||||
<section>
|
<section>
|
||||||
<title>The <literal><authentication-provider></literal> Element</title>
|
<title>The <literal><authentication-provider></literal> Element</title>
|
||||||
<para> Unless used with a <literal>ref</literal> attribute, this element is shorthand for configuring a
|
<para> Unless used with a <literal>ref</literal> attribute, this element is shorthand for configuring a
|
||||||
|
|||||||
@@ -292,7 +292,7 @@
|
|||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive
|
<para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive
|
||||||
authentication using <link xlink:href="ns-entry-point-ref"
|
authentication using <link xlink:href="#ns-entry-point-ref"
|
||||||
><literal>entry-point-ref</literal></link>. </para>
|
><literal>entry-point-ref</literal></link>. </para>
|
||||||
<para>The <classname>CasAuthenticationFilter</classname> has very similar properties to the
|
<para>The <classname>CasAuthenticationFilter</classname> has very similar properties to the
|
||||||
<classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based logins).
|
<classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based logins).
|
||||||
|
|||||||
@@ -97,7 +97,29 @@
|
|||||||
<interfacename>SaltSource</interfacename> enables the passwords to be populated
|
<interfacename>SaltSource</interfacename> enables the passwords to be populated
|
||||||
with a "salt", which enhances the security of the passwords in the authentication
|
with a "salt", which enhances the security of the passwords in the authentication
|
||||||
repository. These will be discussed in more detail <link
|
repository. These will be discussed in more detail <link
|
||||||
xlink:href="core-services-password-encodin">below</link>. </para>
|
xlink:href="#core-services-password-encoding">below</link>. </para>
|
||||||
|
</section>
|
||||||
|
<section xml:id="core-services-erasing-credentials">
|
||||||
|
<title>Erasing Credentials on Successful Authentication</title>
|
||||||
|
<para>
|
||||||
|
From Spring Security 3.0.3, you can configure the <classname>ProviderManager</classname>
|
||||||
|
will attempt to clear any sensitive credentials information from the
|
||||||
|
<interfacename>Authentication</interfacename> object which is returned by a successful
|
||||||
|
authentication request, to prevent information like passwords being retained longer
|
||||||
|
than necessary. This feature is controlled by the <literal>eraseCredentialsAfterAuthentication</literal>
|
||||||
|
property on <classname>ProviderManager</classname>. It is off by default.
|
||||||
|
See the Javadoc for more information.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
This may cause issues when you are using a cache of user objects, for example, to
|
||||||
|
improve performance in a stateless application. If the <interfacename>Authentication</interfacename>
|
||||||
|
contains a reference to an object in the cache (such as a <interfacename>UserDetails</interfacename>
|
||||||
|
instance) and this has its credentials removed, then it will no longer be possible to authenticate
|
||||||
|
against the cached value. You need to take this into account if you are using a cache. An obvious
|
||||||
|
solution is to make a copy of the object first, either in the cache implementation or in
|
||||||
|
the <interfacename>AuthenticationProvider</interfacename> which creates the returned
|
||||||
|
<interfacename>Authentication</interfacename> object.
|
||||||
|
</para>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@@ -28,7 +28,8 @@
|
|||||||
that are available. We would recommend that you try out the <link
|
that are available. We would recommend that you try out the <link
|
||||||
xlink:href="http://www.springsource.com/products/sts">SpringSource Tool Suite</link> as it
|
xlink:href="http://www.springsource.com/products/sts">SpringSource Tool Suite</link> as it
|
||||||
has special features for working with standard Spring namespaces. </para>
|
has special features for working with standard Spring namespaces. </para>
|
||||||
<para> To start using the security namespace in your application context, all you need to do is
|
<para> To start using the security namespace in your application context, you first need to make
|
||||||
|
sure that the <literal>spring-security-config</literal> jar is on your classpath. Then all you need to do is
|
||||||
add the schema declaration to your application context file: <programlisting language="xml">
|
add the schema declaration to your application context file: <programlisting language="xml">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
http://www.springframework.org/schema/security
|
http://www.springframework.org/schema/security
|
||||||
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
|
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
|
||||||
...
|
...
|
||||||
</beans>
|
</beans>
|
||||||
]]></programlisting> In many of the examples you will see (and in the sample) applications, we
|
]]></programlisting> In many of the examples you will see (and in the sample) applications, we
|
||||||
@@ -52,7 +53,7 @@
|
|||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
http://www.springframework.org/schema/security
|
http://www.springframework.org/schema/security
|
||||||
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
|
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
|
||||||
...
|
...
|
||||||
</beans:beans>
|
</beans:beans>
|
||||||
]]></programlisting> We'll assume this syntax is being used from now on in this chapter. </para>
|
]]></programlisting> We'll assume this syntax is being used from now on in this chapter. </para>
|
||||||
@@ -329,8 +330,10 @@
|
|||||||
]]>
|
]]>
|
||||||
</programlisting> where <literal>myAuthenticationProvider</literal> is the name of a
|
</programlisting> where <literal>myAuthenticationProvider</literal> is the name of a
|
||||||
bean in your application context which implements
|
bean in your application context which implements
|
||||||
<interfacename>AuthenticationProvider</interfacename>. See <xref linkend="ns-auth-manager"
|
<interfacename>AuthenticationProvider</interfacename>. You can use multiple
|
||||||
/> for more on information on how the Spring Security
|
<literal>authentication-provider</literal> elements, in which case they will be checked
|
||||||
|
in the order they are declared when attempting to authenticated a user. See <xref
|
||||||
|
linkend="ns-auth-manager"/> for more on information on how the Spring Security
|
||||||
<interfacename>AuthenticationManager</interfacename> is configured using the namespace. </para>
|
<interfacename>AuthenticationManager</interfacename> is configured using the namespace. </para>
|
||||||
<section xml:id="ns-password-encoder">
|
<section xml:id="ns-password-encoder">
|
||||||
<title>Adding a Password Encoder</title>
|
<title>Adding a Password Encoder</title>
|
||||||
@@ -516,7 +519,7 @@ List<OpenIDAttribute> attributes = token.getAttributes();</programlisting>The
|
|||||||
<classname>OpenIDAttribute</classname> contains the attribute type and the retrieved
|
<classname>OpenIDAttribute</classname> contains the attribute type and the retrieved
|
||||||
value (or values in the case of multi-valued attributes). We'll see more about how the
|
value (or values in the case of multi-valued attributes). We'll see more about how the
|
||||||
<classname>SecurityContextHolder</classname> class is used when we look at core Spring
|
<classname>SecurityContextHolder</classname> class is used when we look at core Spring
|
||||||
Security components in the <link xlink:href="core-components">technical overview</link>
|
Security components in the <link xlink:href="#core-components">technical overview</link>
|
||||||
chapter.</para>
|
chapter.</para>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
@@ -622,7 +625,7 @@ List<OpenIDAttribute> attributes = token.getAttributes();</programlisting>The
|
|||||||
<para>From version 2.0 onwards Spring Security has improved support substantially for adding
|
<para>From version 2.0 onwards Spring Security has improved support substantially for adding
|
||||||
security to your service layer methods. It provides support for JSR-250 annotation security as
|
security to your service layer methods. It provides support for JSR-250 annotation security as
|
||||||
well as the framework's original <literal>@Secured</literal> annotation. From 3.0 you can also
|
well as the framework's original <literal>@Secured</literal> annotation. From 3.0 you can also
|
||||||
make use of new <link xlink:href="el-access">expression-based annotations</link>. You can
|
make use of new <link xlink:href="#el-access">expression-based annotations</link>. You can
|
||||||
apply security to a single bean, using the <literal>intercept-methods</literal> element to
|
apply security to a single bean, using the <literal>intercept-methods</literal> element to
|
||||||
decorate the bean declaration, or you can secure multiple beans across the entire service
|
decorate the bean declaration, or you can secure multiple beans across the entire service
|
||||||
layer using the AspectJ style pointcuts. </para>
|
layer using the AspectJ style pointcuts. </para>
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class="org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
|||||||
configuration (hence the user of the <literal>custom-filter</literal>,
|
configuration (hence the user of the <literal>custom-filter</literal>,
|
||||||
<literal>authentication-manager</literal> and
|
<literal>authentication-manager</literal> and
|
||||||
<literal>custom-authentication-provider</literal> elements (you can read more about them
|
<literal>custom-authentication-provider</literal> elements (you can read more about them
|
||||||
in the <link xlink:href="ns-config">namespace chapter</link>). You would leave these out
|
in the <link xlink:href="#ns-config">namespace chapter</link>). You would leave these out
|
||||||
of a traditional bean configuration. It's also assumed that you have added a
|
of a traditional bean configuration. It's also assumed that you have added a
|
||||||
<interfacename>UserDetailsService</interfacename> (called
|
<interfacename>UserDetailsService</interfacename> (called
|
||||||
<quote>userDetailsService</quote>) to your configuration to load the user's roles.
|
<quote>userDetailsService</quote>) to your configuration to load the user's roles.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ Success! Your web filters appear to be properly configured!
|
|||||||
<title>CAS Sample</title>
|
<title>CAS Sample</title>
|
||||||
<para> The CAS sample requires that you run both a CAS server and CAS client. It isn't
|
<para> The CAS sample requires that you run both a CAS server and CAS client. It isn't
|
||||||
included in the distribution so you should check out the project code as described in
|
included in the distribution so you should check out the project code as described in
|
||||||
<link xlink:href="get-source">the introduction</link>. You'll find the relevant
|
<link xlink:href="#get-source">the introduction</link>. You'll find the relevant
|
||||||
files under the <filename>sample/cas</filename> directory. There's also a
|
files under the <filename>sample/cas</filename> directory. There's also a
|
||||||
<filename>Readme.txt</filename> file in there which explains how to run both the
|
<filename>Readme.txt</filename> file in there which explains how to run both the
|
||||||
server and the client directly from the source tree, complete with SSL support. You have
|
server and the client directly from the source tree, complete with SSL support. You have
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</author>
|
</author>
|
||||||
</authorgroup>
|
</authorgroup>
|
||||||
<productname>Spring Security</productname>
|
<productname>Spring Security</productname>
|
||||||
<releaseinfo>3.0.1.RELEASE</releaseinfo>
|
<releaseinfo>3.0.3.RELEASE</releaseinfo>
|
||||||
</info>
|
</info>
|
||||||
<toc/>
|
<toc/>
|
||||||
<preface xml:id="preface">
|
<preface xml:id="preface">
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
Spring Security 3.0, it can be used in two ways <footnote>
|
Spring Security 3.0, it can be used in two ways <footnote>
|
||||||
<para>The legacy options from Spring Security 2.0 are also supported, but
|
<para>The legacy options from Spring Security 2.0 are also supported, but
|
||||||
discouraged.</para>
|
discouraged.</para>
|
||||||
</footnote>. The first approach uses a <link xlink:href="el-access-we">web-security
|
</footnote>. The first approach uses a <link xlink:href="#el-access-web">web-security
|
||||||
expression</link>, specified in the <literal>access</literal> attribute of the tag.
|
expression</link>, specified in the <literal>access</literal> attribute of the tag.
|
||||||
The expression evaluation will be delegated to the
|
The expression evaluation will be delegated to the
|
||||||
<interfacename>WebSecurityExpressionHandler</interfacename> defined in the
|
<interfacename>WebSecurityExpressionHandler</interfacename> defined in the
|
||||||
|
|||||||
@@ -521,7 +521,7 @@ Successfully authenticated. Security context contains: \
|
|||||||
and should be consumed by Spring Security's <classname>RoleVoter</classname>. This is only
|
and should be consumed by Spring Security's <classname>RoleVoter</classname>. This is only
|
||||||
relevant when a voter-based <interfacename>AccessDecisionManager</interfacename> is in
|
relevant when a voter-based <interfacename>AccessDecisionManager</interfacename> is in
|
||||||
use. We'll see how the <interfacename>AccessDecisionManager</interfacename> is implemented
|
use. We'll see how the <interfacename>AccessDecisionManager</interfacename> is implemented
|
||||||
in the <link xlink:href="authz-arch">authorization chapter</link>.</para>
|
in the <link xlink:href="#authz-arch">authorization chapter</link>.</para>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<title>RunAsManager</title>
|
<title>RunAsManager</title>
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:xslthl="http://xslthl.sf.net"
|
||||||
|
exclude-result-prefixes="xslthl"
|
||||||
|
version='1.0'>
|
||||||
|
|
||||||
|
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
|
||||||
|
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/highlight.xsl"/>
|
||||||
|
|
||||||
|
<!-- Only use scaling in FO -->
|
||||||
|
<xsl:param name="ignore.image.scaling">1</xsl:param>
|
||||||
|
|
||||||
|
<!-- Use code syntax highlighting -->
|
||||||
|
<xsl:param name="highlight.source">1</xsl:param>
|
||||||
|
|
||||||
|
<!-- Extensions -->
|
||||||
|
<xsl:param name="use.extensions">1</xsl:param>
|
||||||
|
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||||
|
<xsl:param name="callout.extensions">1</xsl:param>
|
||||||
|
|
||||||
|
<!-- Activate Graphics -->
|
||||||
|
<xsl:param name="admon.graphics" select="1"/>
|
||||||
|
<xsl:param name="admon.graphics.path">images/</xsl:param>
|
||||||
|
<xsl:param name="admon.graphics.extension">.png</xsl:param>
|
||||||
|
<xsl:param name="callout.graphics" select="1" />
|
||||||
|
<xsl:param name="callout.defaultcolumn">120</xsl:param>
|
||||||
|
<xsl:param name="callout.graphics.path">images/callouts/</xsl:param>
|
||||||
|
<xsl:param name="callout.graphics.extension">.png</xsl:param>
|
||||||
|
|
||||||
|
<xsl:param name="table.borders.with.css" select="1"/>
|
||||||
|
<xsl:param name="html.stylesheet">css/manual.css</xsl:param>
|
||||||
|
<xsl:param name="html.stylesheet.type">text/css</xsl:param>
|
||||||
|
<xsl:param name="generate.toc">book toc,title</xsl:param>
|
||||||
|
|
||||||
|
<xsl:param name="admonition.title.properties">text-align: left</xsl:param>
|
||||||
|
|
||||||
|
<!-- Leave image paths as relative when navigating XInclude -->
|
||||||
|
<xsl:param name="keep.relative.image.uris" select="1"/>
|
||||||
|
|
||||||
|
<!-- Label Chapters and Sections (numbering) -->
|
||||||
|
<xsl:param name="chapter.autolabel" select="1"/>
|
||||||
|
<xsl:param name="section.autolabel" select="1"/>
|
||||||
|
<xsl:param name="section.autolabel.max.depth" select="2"/>
|
||||||
|
|
||||||
|
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||||
|
<xsl:param name="table.footnote.number.format" select="'1'"/>
|
||||||
|
|
||||||
|
<!-- Show only Sections up to level 2 in the TOCs -->
|
||||||
|
<xsl:param name="toc.section.depth">2</xsl:param>
|
||||||
|
|
||||||
|
<!-- Remove "Chapter" from the Chapter titles... -->
|
||||||
|
<xsl:param name="local.l10n.xml" select="document('')"/>
|
||||||
|
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
|
||||||
|
<l:l10n language="en">
|
||||||
|
<l:context name="title-numbered">
|
||||||
|
<l:template name="chapter" text="%n. %t"/>
|
||||||
|
<l:template name="section" text="%n %t"/>
|
||||||
|
</l:context>
|
||||||
|
</l:l10n>
|
||||||
|
</l:i18n>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:keyword' mode="xslthl">
|
||||||
|
<span class="hl-keyword"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:comment' mode="xslthl">
|
||||||
|
<span class="hl-comment"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:oneline-comment' mode="xslthl">
|
||||||
|
<span class="hl-comment"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:multiline-comment' mode="xslthl">
|
||||||
|
<span class="hl-multiline-comment"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:tag' mode="xslthl">
|
||||||
|
<span class="hl-tag"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:attribute' mode="xslthl">
|
||||||
|
<span class="hl-attribute"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:value' mode="xslthl">
|
||||||
|
<span class="hl-value"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match='xslthl:string' mode="xslthl">
|
||||||
|
<span class="hl-string"><xsl:apply-templates mode="xslthl"/></span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- Google Analytics -->
|
||||||
|
<xsl:template name="user.head.content">
|
||||||
|
<xsl:comment>Begin Google Analytics code</xsl:comment>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||||
|
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var pageTracker = _gat._getTracker("UA-2728886-3");
|
||||||
|
pageTracker._setDomainName("none");
|
||||||
|
pageTracker._setAllowLinker(true);
|
||||||
|
pageTracker._trackPageview();
|
||||||
|
</script>
|
||||||
|
<xsl:comment>End Google Analytics code</xsl:comment>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- Loopfuse -->
|
||||||
|
<xsl:template name="user.footer.content">
|
||||||
|
<xsl:comment>Begin LoopFuse code</xsl:comment>
|
||||||
|
<script src="http://loopfuse.net/webrecorder/js/listen.js" type="text/javascript">
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
_lf_cid = "LF_48be82fa";
|
||||||
|
_lf_remora();
|
||||||
|
</script>
|
||||||
|
<xsl:comment>End LoopFuse code</xsl:comment>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
apply plugin: 'java'
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
ajtools
|
||||||
|
aspectpath
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
ajtools "org.aspectj:aspectjtools:$aspectjVersion"
|
||||||
|
compile "org.aspectj:aspectjrt:$aspectjVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
task compileJava(overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
|
||||||
|
dependsOn processResources
|
||||||
|
sourceSet = sourceSets.main
|
||||||
|
aspectPath = configurations.aspectpath
|
||||||
|
}
|
||||||
|
|
||||||
|
task compileTestJava(overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
|
||||||
|
dependsOn processTestResources, compileJava, jar
|
||||||
|
sourceSet = sourceSets.test
|
||||||
|
aspectPath = files(configurations.aspectpath, jar.archivePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ajc extends DefaultTask {
|
||||||
|
@Input
|
||||||
|
SourceSet sourceSet
|
||||||
|
|
||||||
|
@Input
|
||||||
|
FileCollection aspectPath
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
def compile() {
|
||||||
|
println "Running ajc ..."
|
||||||
|
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: project.configurations.ajtools.asPath)
|
||||||
|
ant.iajc(classpath: sourceSet.compileClasspath.asPath, fork: 'true', destDir: sourceSet.classesDir.absolutePath,
|
||||||
|
source: project.convention.plugins.java.sourceCompatibility,
|
||||||
|
target: project.convention.plugins.java.targetCompatibility,
|
||||||
|
aspectPath: aspectPath.asPath, sourceRootCopyFilter: '**/*.java', showWeaveInfo: 'true') {
|
||||||
|
sourceroots {
|
||||||
|
sourceSet.java.srcDirs.each {
|
||||||
|
pathelement(location: it.absolutePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apply plugin: 'java'
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
bundlor
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
bundlor 'com.springsource.bundlor:com.springsource.bundlor.ant:1.0.0.RELEASE',
|
||||||
|
'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RELEASE',
|
||||||
|
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RELEASE'
|
||||||
|
}
|
||||||
|
|
||||||
|
task bundlor(dependsOn: compileJava) {
|
||||||
|
onlyIf {
|
||||||
|
dependsOnTaskDidWork()
|
||||||
|
}
|
||||||
|
doFirst {
|
||||||
|
ant.taskdef(resource: 'com/springsource/bundlor/ant/antlib.xml', classpath: configurations.bundlor.asPath)
|
||||||
|
File template = new File(projectDir, 'template.mf')
|
||||||
|
mkdir("$buildDir/bundlor")
|
||||||
|
if (template.exists()) {
|
||||||
|
ant.bundlor(inputPath: sourceSets.main.classesDir, outputPath: "$buildDir/bundlor", manifestTemplatePath: template) {
|
||||||
|
property(name: 'version', value: "$version")
|
||||||
|
property(name: 'spring.version', value: "$springVersion")
|
||||||
|
}
|
||||||
|
jar.manifest.from("$buildDir/bundlor/META-INF/MANIFEST.MF")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jar.dependsOn bundlor
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
apply plugin: 'java'
|
||||||
|
apply plugin: 'eclipse'
|
||||||
|
|
||||||
|
springVersion = '3.0.3.RELEASE'
|
||||||
|
springLdapVersion = '1.3.0.RELEASE'
|
||||||
|
ehcacheVersion = '1.6.2'
|
||||||
|
aspectjVersion = '1.6.8'
|
||||||
|
apacheDsVersion = '1.5.5'
|
||||||
|
jstlVersion = '1.1.2'
|
||||||
|
jettyVersion = '6.1.22'
|
||||||
|
hsqlVersion = '1.8.0.10'
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
provided
|
||||||
|
compile.extendsFrom provided
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile 'commons-logging:commons-logging:1.1.1'
|
||||||
|
|
||||||
|
compile ("org.springframework:spring-core:$springVersion") {
|
||||||
|
exclude(group: 'commons-logging', module: 'commons-logging')
|
||||||
|
}
|
||||||
|
|
||||||
|
testCompile 'junit:junit:4.7',
|
||||||
|
'org.mockito:mockito-core:1.8.3',
|
||||||
|
'org.jmock:jmock:2.5.1',
|
||||||
|
'org.jmock:jmock-junit4:2.5.1',
|
||||||
|
'org.hamcrest:hamcrest-core:1.1',
|
||||||
|
'org.hamcrest:hamcrest-library:1.1',
|
||||||
|
"org.springframework:spring-test:$springVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
onlyIf {
|
||||||
|
!project.hasProperty('skipTests')
|
||||||
|
}
|
||||||
|
jvmArgs = ['-ea', '-Xms128m', '-Xmx500m', '-XX:MaxPermSize=128m']
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
apply plugin: 'maven'
|
||||||
|
|
||||||
|
// Create a source jar for uploading
|
||||||
|
task sourceJar(type: Jar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from sourceSets.main.java
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
deployerJars
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives sourceJar
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:3.0.0.RELEASE"
|
||||||
|
}
|
||||||
|
|
||||||
|
gradle.taskGraph.whenReady {graph ->
|
||||||
|
if (graph.hasTask(uploadArchives)) {
|
||||||
|
// check properties defined and fail early
|
||||||
|
s3AccessKey
|
||||||
|
s3SecretAccessKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def deployer = null
|
||||||
|
|
||||||
|
uploadArchives {
|
||||||
|
deployer = repositories.mavenDeployer {
|
||||||
|
configuration = configurations.deployerJars
|
||||||
|
}
|
||||||
|
doFirst {
|
||||||
|
if (releaseBuild) {
|
||||||
|
// "mavenSyncRepoDir" should be set in properties
|
||||||
|
repository(url: mavenSyncRepoDir)
|
||||||
|
} else {
|
||||||
|
s3credentials = [userName: s3AccessKey, passphrase: s3SecretAccessKey]
|
||||||
|
repository(url: "s3://maven.springframework.org/milestone") {
|
||||||
|
authentication(s3credentials)
|
||||||
|
}
|
||||||
|
snapshotRepository(url: "s3://maven.springframework.org/snapshot") {
|
||||||
|
authentication(s3credentials)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pom Customization
|
||||||
|
|
||||||
|
installer = install.repositories.mavenInstaller
|
||||||
|
|
||||||
|
def optionalDeps = ['commons-logging', 'ehcache', 'log4j', 'apacheds-core', 'jsp-api', 'jsr250-api', 'ldapsdk']
|
||||||
|
|
||||||
|
[installer, deployer]*.pom.collect { pom ->
|
||||||
|
pom.scopeMappings.addMapping(10, configurations.provided, 'provided')
|
||||||
|
}
|
||||||
|
|
||||||
|
[installer, deployer]*.pom*.whenConfigured { pom ->
|
||||||
|
pom.dependencies.findAll { dep ->
|
||||||
|
optionalDeps.contains(dep.artifactId) ||
|
||||||
|
dep.groupId.startsWith('org.apache.directory') ||
|
||||||
|
dep.groupId.startsWith('org.slf4j')
|
||||||
|
}*.optional = true
|
||||||
|
|
||||||
|
if (pom.artifactId == 'spring-security-config') {
|
||||||
|
pom.dependencies.find { dep -> dep.artifactId == 'spring-security-web'}.optional = true
|
||||||
|
pom.dependencies.find { dep -> dep.artifactId == 'spring-web'}.optional = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-itest</artifactId>
|
<artifactId>spring-security-itest</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-security-itest-context</artifactId>
|
<artifactId>spring-security-itest-context</artifactId>
|
||||||
<name>Spring Security - Miscellaneous Application Context Integration Tests</name>
|
<name>Spring Security - Miscellaneous Application Context Integration Tests</name>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-itest</artifactId>
|
<artifactId>spring-security-itest</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-security-itest-misc</artifactId>
|
<artifactId>spring-security-itest-misc</artifactId>
|
||||||
<name>Spring Security - Miscellaneous Integration Tests</name>
|
<name>Spring Security - Miscellaneous Integration Tests</name>
|
||||||
|
|||||||
+5
-5
@@ -3,12 +3,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-security-itest</artifactId>
|
<artifactId>spring-security-itest</artifactId>
|
||||||
<name>Spring Security - Integration Tests</name>
|
<name>Spring Security - Integration Tests</name>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>web</module>
|
<module>web</module>
|
||||||
<!-- module>webflow</module-->
|
<!-- module>webflow</module-->
|
||||||
@@ -66,19 +66,19 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>1.5.10</version>
|
<version>1.6.0</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
<version>1.5.10</version>
|
<version>1.6.0</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>jcl-over-slf4j</artifactId>
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
<version>1.5.10</version>
|
<version>1.6.0</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "org.springframework:spring-context:$springVersion",
|
compile "org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-web:$springVersion",
|
"org.springframework:spring-web:$springVersion"
|
||||||
'javax.servlet:servlet-api:2.5'
|
|
||||||
|
provided 'javax.servlet:servlet-api:2.5'
|
||||||
|
|
||||||
testCompile project(':spring-security-core'),
|
testCompile project(':spring-security-core'),
|
||||||
project(':spring-security-web'),
|
project(':spring-security-web'),
|
||||||
"org.springframework:spring-core:$springVersion",
|
project(':spring-security-taglibs'),
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-webmvc:$springVersion",
|
"org.springframework:spring-webmvc:$springVersion",
|
||||||
"org.mortbay.jetty:jetty:$jettyVersion",
|
"org.mortbay.jetty:jetty:$jettyVersion",
|
||||||
|
|||||||
+6
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-itest</artifactId>
|
<artifactId>spring-security-itest</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-security-itest-web</artifactId>
|
<artifactId>spring-security-itest-web</artifactId>
|
||||||
<name>Spring Security - Web Integration Tests</name>
|
<name>Spring Security - Web Integration Tests</name>
|
||||||
@@ -28,6 +28,11 @@
|
|||||||
<groupId>javax.servlet</groupId>
|
<groupId>javax.servlet</groupId>
|
||||||
<artifactId>servlet-api</artifactId>
|
<artifactId>servlet-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-taglibs</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-webmvc</artifactId>
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<user name="miles" password="milespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_TRUMPETER"/>
|
<user name="miles" password="milespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_TRUMPETER"/>
|
||||||
<user name="johnc" password="johncspassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SAXOPHONIST"/>
|
<user name="johnc" password="johncspassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SAXOPHONIST"/>
|
||||||
<user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ROCK,ROLE_GUITARIST"/>
|
<user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ROCK,ROLE_GUITARIST"/>
|
||||||
|
<user name="theescapist<>&." password="theescapistspassword" authorities="ROLE_USER"/>
|
||||||
</user-service>
|
</user-service>
|
||||||
</authentication-provider>
|
</authentication-provider>
|
||||||
</authentication-manager>
|
</authentication-manager>
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||||
|
<!DOCTYPE taglib
|
||||||
|
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
|
||||||
|
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
|
||||||
|
<taglib>
|
||||||
|
<tlib-version>1.0</tlib-version>
|
||||||
|
<jsp-version>1.2</jsp-version>
|
||||||
|
<short-name>security</short-name>
|
||||||
|
<uri>http://www.springframework.org/security/tags</uri>
|
||||||
|
<description>
|
||||||
|
Spring Security Authorization Tag Library
|
||||||
|
$Id$
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<tag>
|
||||||
|
<name>authorize</name>
|
||||||
|
<tag-class>org.springframework.security.taglibs.authz.AuthorizeTag</tag-class>
|
||||||
|
<description>
|
||||||
|
A tag which outputs the body of the tag if the configured access expression
|
||||||
|
evaluates to true for the currently authenticated principal.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>access</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>false</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
A Spring-EL expression which is supported by the WebSecurityExpressionHandler
|
||||||
|
in the application context. The latter will be used to evaluate the expression.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>url</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>false</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
A URL within the application. If the user has access to this URL (as determined by
|
||||||
|
the AccessDecisionManager), the tag body will be evaluated. If not, it will
|
||||||
|
be skipped.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>method</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>false</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
Can optionally be used to narrow down the HTTP method (typically GET or POST) to which the URL
|
||||||
|
applies to. Only has any meaning when used in combination with the "url" attribute.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>ifNotGranted</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>true</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
A comma separated list of roles which the user must not have
|
||||||
|
for the body to be output. Deprecated in favour of the access expression.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>ifAllGranted</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>true</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
A comma separated list of roles which the user must all
|
||||||
|
possess for the body to be output. Deprecated in favour of the access expression.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>ifAnyGranted</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>true</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
A comma separated list of roles, one of which the user must
|
||||||
|
possess for the body to be output. Deprecated in favour of the access expression.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
</tag>
|
||||||
|
|
||||||
|
<tag>
|
||||||
|
<name>authentication</name>
|
||||||
|
<tag-class>org.springframework.security.taglibs.authz.AuthenticationTag</tag-class>
|
||||||
|
<description>
|
||||||
|
Allows access to the current Authentication object.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>property</name>
|
||||||
|
<required>true</required>
|
||||||
|
<rtexprvalue>true</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
Property of the Authentication object which should be output. Supports nested
|
||||||
|
properties. For example if the principal object is an instance of UserDetails,
|
||||||
|
the property "principal.username" will return the username. Alternatively, using
|
||||||
|
"name" will call getName method on the Authentication object directly.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
<attribute>
|
||||||
|
<name>var</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>false</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
Name of the exported scoped variable which will contain the
|
||||||
|
evaluated property of the Authentication object.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
<attribute>
|
||||||
|
<description>Set HTML escaping for this tag, as a boolean value.</description>
|
||||||
|
<name>htmlEscape</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>true</rtexprvalue>
|
||||||
|
</attribute>
|
||||||
|
<attribute>
|
||||||
|
<name>scope</name>
|
||||||
|
<required>false</required>
|
||||||
|
<rtexprvalue>false</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
Scope for var.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
</tag>
|
||||||
|
|
||||||
|
<tag>
|
||||||
|
<name>accesscontrollist</name>
|
||||||
|
<tag-class>org.springframework.security.taglibs.authz.AccessControlListTag</tag-class>
|
||||||
|
<description>
|
||||||
|
Allows inclusion of a tag body if the current Authentication
|
||||||
|
has one of the specified permissions to the presented
|
||||||
|
domain object instance.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<attribute>
|
||||||
|
<name>hasPermission</name>
|
||||||
|
<required>true</required>
|
||||||
|
<rtexprvalue>true</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
A comma separated list of permissions, which will be converted to
|
||||||
|
Permission instances by the configured PermissionFactory.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
<attribute>
|
||||||
|
<name>domainObject</name>
|
||||||
|
<required>true</required>
|
||||||
|
<rtexprvalue>true</rtexprvalue>
|
||||||
|
<description>
|
||||||
|
The actual domain object instance for which permissions
|
||||||
|
are being evaluated.
|
||||||
|
</description>
|
||||||
|
</attribute>
|
||||||
|
</tag>
|
||||||
|
|
||||||
|
</taglib>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Authentication Tag Test Page</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li>This is the authentication name: <sec:authentication property="name"/></li>
|
||||||
|
<li>This is the principal.username: <sec:authentication property="principal.username"/></li>
|
||||||
|
<li>This is the unescaped authentication name: <sec:authentication property="name" htmlEscape="false"/></li>
|
||||||
|
<li>This is the unescaped principal.username: <sec:authentication property="principal.username" htmlEscape="false"/></li>
|
||||||
|
|
||||||
|
</ul
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
+12
@@ -95,4 +95,16 @@ public class InMemoryProviderWebAppTests extends AbstractWebServerIntegrationTes
|
|||||||
tester.assertTextPresent("This session has been expired");
|
tester.assertTextPresent("This session has been expired");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void authenticationTagEscapingWorksCorrectly() {
|
||||||
|
beginAt("secure/authenticationTagTestPage.jsp");
|
||||||
|
login("theescapist<>&.", "theescapistspassword");
|
||||||
|
String response = tester.getServerResponse();
|
||||||
|
assertTrue(response.contains("This is the unescaped authentication name: theescapist<>&."));
|
||||||
|
assertTrue(response.contains("This is the unescaped principal.username: theescapist<>&."));
|
||||||
|
assertTrue(response.contains("This is the authentication name: theescapist<>&."));
|
||||||
|
assertTrue(response.contains("This is the principal.username: theescapist<>&."));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -4,11 +4,9 @@ test.exclude('**/OpenLDAPIntegrationTestSuite.class')
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':spring-security-core'),
|
compile project(':spring-security-core'),
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-tx:$springVersion",
|
"org.springframework:spring-tx:$springVersion",
|
||||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
|
||||||
"org.apache.directory.server:apacheds-core:$apacheDsVersion",
|
"org.apache.directory.server:apacheds-core:$apacheDsVersion",
|
||||||
"org.apache.directory.server:apacheds-core-entry:$apacheDsVersion",
|
"org.apache.directory.server:apacheds-core-entry:$apacheDsVersion",
|
||||||
"org.apache.directory.server:apacheds-protocol-shared:$apacheDsVersion",
|
"org.apache.directory.server:apacheds-protocol-shared:$apacheDsVersion",
|
||||||
@@ -16,6 +14,12 @@ dependencies {
|
|||||||
"org.apache.directory.server:apacheds-server-jndi:$apacheDsVersion",
|
"org.apache.directory.server:apacheds-server-jndi:$apacheDsVersion",
|
||||||
'org.apache.directory.shared:shared-ldap:0.9.15',
|
'org.apache.directory.shared:shared-ldap:0.9.15',
|
||||||
'ldapsdk:ldapsdk:4.1'
|
'ldapsdk:ldapsdk:4.1'
|
||||||
|
compile ("org.springframework.ldap:spring-ldap-core:$springLdapVersion") {
|
||||||
|
exclude(group: 'commons-logging', module: 'commons-logging')
|
||||||
|
exclude(group: 'org.springframework', module: 'spring-core')
|
||||||
|
exclude(group: 'org.springframework', module: 'spring-tx')
|
||||||
|
exclude(group: 'org.springframework', module: 'spring-beans')
|
||||||
|
}
|
||||||
|
|
||||||
runtime 'org.slf4j:slf4j-log4j12:1.4.3'
|
runtime 'org.slf4j:slf4j-log4j12:1.4.3'
|
||||||
}
|
}
|
||||||
+1
-5
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.3.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<artifactId>spring-security-ldap</artifactId>
|
<artifactId>spring-security-ldap</artifactId>
|
||||||
@@ -19,10 +19,6 @@
|
|||||||
<groupId>org.springframework.ldap</groupId>
|
<groupId>org.springframework.ldap</groupId>
|
||||||
<artifactId>spring-ldap-core</artifactId>
|
<artifactId>spring-ldap-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ldapsdk</groupId>
|
<groupId>ldapsdk</groupId>
|
||||||
<artifactId>ldapsdk</artifactId>
|
<artifactId>ldapsdk</artifactId>
|
||||||
|
|||||||
+11
-6
@@ -193,21 +193,26 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
|||||||
public Object executeWithContext(DirContext ctx) throws NamingException {
|
public Object executeWithContext(DirContext ctx) throws NamingException {
|
||||||
DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
|
DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
|
||||||
NamingEnumeration<SearchResult> resultsEnum = ctx.search(base, filter, params, searchControls);
|
NamingEnumeration<SearchResult> resultsEnum = ctx.search(base, filter, params, searchControls);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Searching for entry in under DN '" + ctxBaseDn
|
||||||
|
+ "', base = '" + base + "', filter = '" + filter + "'");
|
||||||
|
}
|
||||||
|
|
||||||
Set<DirContextOperations> results = new HashSet<DirContextOperations>();
|
Set<DirContextOperations> results = new HashSet<DirContextOperations>();
|
||||||
try {
|
try {
|
||||||
while (resultsEnum.hasMore()) {
|
while (resultsEnum.hasMore()) {
|
||||||
|
|
||||||
SearchResult searchResult = resultsEnum.next();
|
SearchResult searchResult = resultsEnum.next();
|
||||||
// Work out the DN of the matched entry
|
// Work out the DN of the matched entry
|
||||||
StringBuilder dn = new StringBuilder(searchResult.getName());
|
DistinguishedName dn = new DistinguishedName(searchResult.getName());
|
||||||
|
|
||||||
if (base.length() > 0) {
|
if (base.length() > 0) {
|
||||||
dn.append(",");
|
dn.prepend(new DistinguishedName(base));
|
||||||
dn.append(base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
results.add(new DirContextAdapter(searchResult.getAttributes(),
|
if (logger.isDebugEnabled()) {
|
||||||
new DistinguishedName(dn.toString()), ctxBaseDn));
|
logger.debug("Found DN: " + dn);
|
||||||
|
}
|
||||||
|
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
|
||||||
}
|
}
|
||||||
} catch (PartialResultException e) {
|
} catch (PartialResultException e) {
|
||||||
logger.info("Ignoring PartialResultException");
|
logger.info("Ignoring PartialResultException");
|
||||||
|
|||||||
+4
-4
@@ -99,8 +99,9 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DirContextOperations bindWithDn(String userDn, String username, String password) {
|
private DirContextOperations bindWithDn(String userDnStr, String username, String password) {
|
||||||
BaseLdapPathContextSource ctxSource = (BaseLdapPathContextSource) getContextSource();
|
BaseLdapPathContextSource ctxSource = (BaseLdapPathContextSource) getContextSource();
|
||||||
|
DistinguishedName userDn = new DistinguishedName(userDnStr);
|
||||||
DistinguishedName fullDn = new DistinguishedName(userDn);
|
DistinguishedName fullDn = new DistinguishedName(userDn);
|
||||||
fullDn.prepend(ctxSource.getBaseLdapPath());
|
fullDn.prepend(ctxSource.getBaseLdapPath());
|
||||||
|
|
||||||
@@ -114,8 +115,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
|||||||
|
|
||||||
Attributes attrs = ctx.getAttributes(userDn, getUserAttributes());
|
Attributes attrs = ctx.getAttributes(userDn, getUserAttributes());
|
||||||
|
|
||||||
DirContextAdapter result = new DirContextAdapter(attrs, new DistinguishedName(userDn),
|
DirContextAdapter result = new DirContextAdapter(attrs, userDn, ctxSource.getBaseLdapPath());
|
||||||
ctxSource.getBaseLdapPath());
|
|
||||||
|
|
||||||
if (ppolicy != null) {
|
if (ppolicy != null) {
|
||||||
result.setAttributeValue(ppolicy.getID(), ppolicy);
|
result.setAttributeValue(ppolicy.getID(), ppolicy);
|
||||||
@@ -128,7 +128,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
|||||||
// unless a subclass wishes to implement more specialized behaviour.
|
// unless a subclass wishes to implement more specialized behaviour.
|
||||||
if ((e instanceof org.springframework.ldap.AuthenticationException)
|
if ((e instanceof org.springframework.ldap.AuthenticationException)
|
||||||
|| (e instanceof org.springframework.ldap.OperationNotSupportedException)) {
|
|| (e instanceof org.springframework.ldap.OperationNotSupportedException)) {
|
||||||
handleBindException(userDn, username, e);
|
handleBindException(userDnStr, username, e);
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-3
@@ -34,11 +34,13 @@ import org.springframework.util.Assert;
|
|||||||
* distinguished name and a set of attributes that have been retrieved from the Ldap server.
|
* distinguished name and a set of attributes that have been retrieved from the Ldap server.
|
||||||
* <p>
|
* <p>
|
||||||
* An instance may be created as the result of a search, or when user information is retrieved during authentication.
|
* An instance may be created as the result of a search, or when user information is retrieved during authentication.
|
||||||
* </p>
|
|
||||||
* <p>
|
* <p>
|
||||||
* An instance of this class will be used by the <tt>LdapAuthenticationProvider</tt> to construct the final user details
|
* An instance of this class will be used by the <tt>LdapAuthenticationProvider</tt> to construct the final user details
|
||||||
* object that it returns.
|
* object that it returns.
|
||||||
* </p>
|
* <p>
|
||||||
|
* The {@code equals} and {@code hashcode} methods are implemented using the {@code Dn} property and do not consider
|
||||||
|
* additional state, so it is not possible two store two instances with the same DN in the same set, or use them as
|
||||||
|
* keys in a map.
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
@@ -104,14 +106,28 @@ public class LdapUserDetailsImpl implements LdapUserDetails, PasswordPolicyData
|
|||||||
return graceLoginsRemaining;
|
return graceLoginsRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof LdapUserDetailsImpl) {
|
||||||
|
return dn.equals(((LdapUserDetailsImpl)obj).dn);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return dn.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(super.toString()).append(": ");
|
sb.append(super.toString()).append(": ");
|
||||||
|
sb.append("Dn: ").append(dn).append("; ");
|
||||||
sb.append("Username: ").append(this.username).append("; ");
|
sb.append("Username: ").append(this.username).append("; ");
|
||||||
sb.append("Password: [PROTECTED]; ");
|
sb.append("Password: [PROTECTED]; ");
|
||||||
sb.append("Enabled: ").append(this.enabled).append("; ");
|
sb.append("Enabled: ").append(this.enabled).append("; ");
|
||||||
sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
|
sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
|
||||||
sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
|
sb.append("CredentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
|
||||||
sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
|
sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
|
||||||
|
|
||||||
if (this.getAuthorities() != null) {
|
if (this.getAuthorities() != null) {
|
||||||
|
|||||||
+12
-3
@@ -1,10 +1,13 @@
|
|||||||
package org.springframework.security.ldap.userdetails;
|
package org.springframework.security.ldap.userdetails;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.springframework.ldap.core.DirContextOperations;
|
import org.springframework.ldap.core.DirContextOperations;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.ldap.authentication.NullLdapAuthoritiesPopulator;
|
|
||||||
import org.springframework.security.ldap.search.LdapUserSearch;
|
import org.springframework.security.ldap.search.LdapUserSearch;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -16,8 +19,8 @@ import org.springframework.util.Assert;
|
|||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class LdapUserDetailsService implements UserDetailsService {
|
public class LdapUserDetailsService implements UserDetailsService {
|
||||||
private LdapUserSearch userSearch;
|
private final LdapUserSearch userSearch;
|
||||||
private LdapAuthoritiesPopulator authoritiesPopulator;
|
private final LdapAuthoritiesPopulator authoritiesPopulator;
|
||||||
private UserDetailsContextMapper userDetailsMapper = new LdapUserDetailsMapper();
|
private UserDetailsContextMapper userDetailsMapper = new LdapUserDetailsMapper();
|
||||||
|
|
||||||
public LdapUserDetailsService(LdapUserSearch userSearch) {
|
public LdapUserDetailsService(LdapUserSearch userSearch) {
|
||||||
@@ -42,4 +45,10 @@ public class LdapUserDetailsService implements UserDetailsService {
|
|||||||
Assert.notNull(userDetailsMapper, "userDetailsMapper must not be null");
|
Assert.notNull(userDetailsMapper, "userDetailsMapper must not be null");
|
||||||
this.userDetailsMapper = userDetailsMapper;
|
this.userDetailsMapper = userDetailsMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class NullLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
|
||||||
|
public Collection<GrantedAuthority> getGrantedAuthorities(DirContextOperations userDetails, String username) {
|
||||||
|
return AuthorityUtils.NO_AUTHORITIES;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -18,14 +18,13 @@ package org.springframework.security.ldap.authentication;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.ldap.core.DirContextAdapter;
|
|
||||||
import org.springframework.ldap.core.DirContextOperations;
|
import org.springframework.ldap.core.DirContextOperations;
|
||||||
import org.springframework.ldap.core.DistinguishedName;
|
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
||||||
|
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link BindAuthenticator}.
|
* Tests for {@link BindAuthenticator}.
|
||||||
@@ -37,7 +36,6 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
|
|||||||
|
|
||||||
private BindAuthenticator authenticator;
|
private BindAuthenticator authenticator;
|
||||||
private Authentication bob;
|
private Authentication bob;
|
||||||
// private Authentication ben;
|
|
||||||
|
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
@@ -46,7 +44,6 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
|
|||||||
authenticator = new BindAuthenticator(getContextSource());
|
authenticator = new BindAuthenticator(getContextSource());
|
||||||
authenticator.setMessageSource(new SpringSecurityMessageSource());
|
authenticator.setMessageSource(new SpringSecurityMessageSource());
|
||||||
bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
|
bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
|
||||||
// ben = new UsernamePasswordAuthenticationToken("ben", "benspassword");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,11 +72,14 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAuthenticationWithUserSearch() throws Exception {
|
public void testAuthenticationWithUserSearch() throws Exception {
|
||||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people"));
|
//DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people"));
|
||||||
|
authenticator.setUserSearch(new FilterBasedLdapUserSearch("ou=people", "(uid={0})", getContextSource()));
|
||||||
authenticator.setUserSearch(new MockUserSearch(ctx));
|
|
||||||
authenticator.afterPropertiesSet();
|
authenticator.afterPropertiesSet();
|
||||||
authenticator.authenticate(bob);
|
authenticator.authenticate(bob);
|
||||||
|
// SEC-1444
|
||||||
|
authenticator.setUserSearch(new FilterBasedLdapUserSearch("ou=people", "(cn={0})", getContextSource()));
|
||||||
|
authenticator.authenticate(new UsernamePasswordAuthenticationToken("mouse, jerry", "jerryspassword"));
|
||||||
|
authenticator.authenticate(new UsernamePasswordAuthenticationToken("slash/guy", "slashguyspassword"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+1
-3
@@ -70,13 +70,11 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests
|
|||||||
@Test
|
@Test
|
||||||
public void extraFilterPartToExcludeBob() throws Exception {
|
public void extraFilterPartToExcludeBob() throws Exception {
|
||||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people",
|
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people",
|
||||||
"(&(cn=*)(!(|(uid={0})(uid=rod)(uid=jerry))))", dirCtxFactory);
|
"(&(cn=*)(!(|(uid={0})(uid=rod)(uid=jerry)(uid=slashguy))))", dirCtxFactory);
|
||||||
|
|
||||||
// Search for bob, get back ben...
|
// Search for bob, get back ben...
|
||||||
DirContextOperations ben = locator.searchForUser("bob");
|
DirContextOperations ben = locator.searchForUser("bob");
|
||||||
assertEquals("Ben Alex", ben.getStringAttribute("cn"));
|
assertEquals("Ben Alex", ben.getStringAttribute("cn"));
|
||||||
|
|
||||||
// assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IncorrectResultSizeDataAccessException.class)
|
@Test(expected=IncorrectResultSizeDataAccessException.class)
|
||||||
|
|||||||
+27
-7
@@ -1,16 +1,20 @@
|
|||||||
package org.springframework.security.ldap.userdetails;
|
package org.springframework.security.ldap.userdetails;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
import org.springframework.ldap.core.DirContextAdapter;
|
import org.springframework.ldap.core.DirContextAdapter;
|
||||||
import org.springframework.ldap.core.DistinguishedName;
|
import org.springframework.ldap.core.DistinguishedName;
|
||||||
import org.springframework.security.ldap.userdetails.InetOrgPerson;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class InetOrgPersonTests extends TestCase {
|
public class InetOrgPersonTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testUsernameIsMappedFromContextUidIfNotSet() {
|
public void testUsernameIsMappedFromContextUidIfNotSet() {
|
||||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||||
@@ -18,7 +22,19 @@ public class InetOrgPersonTests extends TestCase {
|
|||||||
assertEquals("ghengis", p.getUsername());
|
assertEquals("ghengis", p.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUsernameIsDifferentFromContextUidIfSet() {
|
@Test
|
||||||
|
public void hashLookupViaEqualObjectRetrievesOriginal() throws Exception {
|
||||||
|
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||||
|
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||||
|
essence = new InetOrgPerson.Essence(createUserContext());
|
||||||
|
InetOrgPerson p2 = (InetOrgPerson) essence.createUserDetails();
|
||||||
|
Set<InetOrgPerson> set = new HashSet<InetOrgPerson>();
|
||||||
|
set.add(p);
|
||||||
|
assertTrue(set.contains(p2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void usernameIsDifferentFromContextUidIfSet() {
|
||||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||||
essence.setUsername("joe");
|
essence.setUsername("joe");
|
||||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||||
@@ -27,7 +43,8 @@ public class InetOrgPersonTests extends TestCase {
|
|||||||
assertEquals("ghengis", p.getUid());
|
assertEquals("ghengis", p.getUid());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAttributesMapCorrectlyFromContext() {
|
@Test
|
||||||
|
public void attributesMapCorrectlyFromContext() {
|
||||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||||
|
|
||||||
@@ -50,6 +67,7 @@ public class InetOrgPersonTests extends TestCase {
|
|||||||
assertEquals("G", p.getInitials());
|
assertEquals("G", p.getInitials());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testPasswordIsSetFromContextUserPassword() {
|
public void testPasswordIsSetFromContextUserPassword() {
|
||||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||||
@@ -57,7 +75,8 @@ public class InetOrgPersonTests extends TestCase {
|
|||||||
assertEquals("pillage", p.getPassword());
|
assertEquals("pillage", p.getPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMappingBackToContextMatchesOriginalData() {
|
@Test
|
||||||
|
public void mappingBackToContextMatchesOriginalData() {
|
||||||
DirContextAdapter ctx1 = createUserContext();
|
DirContextAdapter ctx1 = createUserContext();
|
||||||
DirContextAdapter ctx2 = new DirContextAdapter();
|
DirContextAdapter ctx2 = new DirContextAdapter();
|
||||||
ctx1.setAttributeValues("objectclass", new String[] {"top", "person", "organizationalPerson", "inetOrgPerson"});
|
ctx1.setAttributeValues("objectclass", new String[] {"top", "person", "organizationalPerson", "inetOrgPerson"});
|
||||||
@@ -68,7 +87,8 @@ public class InetOrgPersonTests extends TestCase {
|
|||||||
assertEquals(ctx1, ctx2);
|
assertEquals(ctx1, ctx2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCopyMatchesOriginalData() {
|
@Test
|
||||||
|
public void copyMatchesOriginalData() {
|
||||||
DirContextAdapter ctx1 = createUserContext();
|
DirContextAdapter ctx1 = createUserContext();
|
||||||
DirContextAdapter ctx2 = new DirContextAdapter();
|
DirContextAdapter ctx2 = new DirContextAdapter();
|
||||||
ctx2.setDn(new DistinguishedName("ignored=ignored"));
|
ctx2.setDn(new DistinguishedName("ignored=ignored"));
|
||||||
|
|||||||
@@ -58,6 +58,16 @@ sn: Mouse
|
|||||||
uid: jerry
|
uid: jerry
|
||||||
userPassword: jerryspassword
|
userPassword: jerryspassword
|
||||||
|
|
||||||
|
dn: cn=slash/guy,ou=people,dc=springframework,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: person
|
||||||
|
objectclass: organizationalPerson
|
||||||
|
objectclass: inetOrgPerson
|
||||||
|
cn: slash/guy
|
||||||
|
sn: Slash
|
||||||
|
uid: slashguy
|
||||||
|
userPassword: slashguyspassword
|
||||||
|
|
||||||
dn: cn=developers,ou=groups,dc=springframework,dc=org
|
dn: cn=developers,ou=groups,dc=springframework,dc=org
|
||||||
objectclass: top
|
objectclass: top
|
||||||
objectclass: groupOfNames
|
objectclass: groupOfNames
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user