Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82d140ffb1 | |||
| 1563491322 | |||
| b688bb69ee | |||
| 36f008643d | |||
| cbdf77e991 | |||
| 399e921d14 | |||
| c458311d2d | |||
| d6f408e8bf | |||
| 1739628e6a | |||
| 8e68fa1334 | |||
| 82cd72768d | |||
| 161710cc87 | |||
| dc1b652512 | |||
| ed9411c660 | |||
| e58f982351 | |||
| 072b73354f | |||
| 443231d1e8 | |||
| 45674a16ea | |||
| a1b124def5 | |||
| f6abc24ed6 | |||
| 1a9b7e1b6f | |||
| 8b5c70951d | |||
| c891ab45ec | |||
| 657a69b906 | |||
| 3b8fbe8bee | |||
| 4ad85cdfdf | |||
| 845c50a1c3 | |||
| 25d222208d | |||
| 9b0c21dfef | |||
| 8301bd6276 | |||
| 1872d94aa1 | |||
| 46611872db | |||
| b6cbdde0cb | |||
| 71e1702224 | |||
| 80ccd2b285 | |||
| 02c1f02f2a | |||
| 21a664b2eb | |||
| 9a2d0c2cb5 | |||
| 73b62497a3 | |||
| 09aba3906c | |||
| 57cfff6f5c | |||
| b7b6b2bac7 | |||
| 8602ae3863 | |||
| 8737fe3acb | |||
| 27faad3402 | |||
| aaa7bd90b2 | |||
| 295e0ded18 | |||
| 304f12fb63 | |||
| 8cbe232fbf | |||
| 5ac106808e | |||
| 8c605516b3 | |||
| e6e168f127 | |||
| 6d6c2d31ef | |||
| 8f6aecac9b | |||
| 0760bb947b | |||
| 9d2e2ca11d | |||
| 6354c7e052 | |||
| 42cdaa0ce2 | |||
| eda60b72b1 | |||
| 0d198d42ae | |||
| f000aaa7e8 | |||
| 634e340d80 | |||
| 4c8e9e2d7e | |||
| e518adbef1 | |||
| 59b69f6f48 | |||
| b8e50c0933 | |||
| 677576ea8b | |||
| 91153df78d | |||
| 1b0ac9c785 | |||
| 8c9159f273 | |||
| 4c8b0faa88 | |||
| 5a5b62e2cb | |||
| 6ac8588144 | |||
| 5690f1c581 | |||
| 87cf27ab7c | |||
| 41e06152b3 | |||
| a7e21318bf | |||
| bc6aae132b | |||
| b46ae6ac62 | |||
| 317da55cd0 | |||
| 9e751e22c8 | |||
| 4d65b35827 | |||
| 9831980bc2 |
@@ -3,6 +3,14 @@ target/
|
|||||||
.project
|
.project
|
||||||
.settings/
|
.settings/
|
||||||
build/
|
build/
|
||||||
|
out/
|
||||||
|
intellij/
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
*.log
|
*.log
|
||||||
|
*.log.1
|
||||||
|
.DS_Store
|
||||||
|
*.iml
|
||||||
.gradle/
|
.gradle/
|
||||||
gradle.properties
|
gradle.properties
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|||||||
@@ -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.4.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,5 @@
|
|||||||
|
Implementation-Title: org.springframework.security.acls
|
||||||
|
Implementation-Version: ${version}
|
||||||
Bundle-SymbolicName: org.springframework.security.acls
|
Bundle-SymbolicName: org.springframework.security.acls
|
||||||
Bundle-Name: Spring Security Acls
|
Bundle-Name: Spring Security Acls
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: SpringSource
|
||||||
@@ -18,4 +20,3 @@ Import-Template:
|
|||||||
org.springframework.util.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
|
org.springframework.util.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
|
||||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||||
javax.sql.*;version="0";resolution:=optional
|
javax.sql.*;version="0";resolution:=optional
|
||||||
|
|
||||||
@@ -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.4.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.4.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() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+111
-171
@@ -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.4.CI-SNAPSHOT'
|
||||||
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 {
|
configure(coreModuleProjects) {
|
||||||
compile 'commons-logging:commons-logging:1.1.1'
|
apply from: "$rootDir/gradle/bundlor.gradle"
|
||||||
|
|
||||||
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()) {
|
|
||||||
apply id: '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: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,57 +41,70 @@ 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'
|
||||||
task login << {
|
if (project.hasProperty('remoteSiteDir')) {
|
||||||
ant.input("Please enter the ssh username for host '$sshHost'", addproperty: "ssh.username")
|
remoteDir = project.property('remoteSiteDir')
|
||||||
ant.input("Please enter the ssh password '$sshHost'", addproperty: "ssh.password")
|
|
||||||
username = ant.properties['ssh.username']
|
|
||||||
password = ant.properties['ssh.password']
|
|
||||||
}
|
}
|
||||||
|
login = docSiteLogin
|
||||||
|
|
||||||
task uploadApidocs (dependsOn: login) << {
|
def faqDir = new File(project(':faq').buildDir, 'docs')
|
||||||
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}")
|
into('faq') {
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${apitar.archiveName}")
|
from faqDir
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
task dist(type: Zip) {
|
||||||
@@ -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 << {
|
|
||||||
def shaFile = file("${dist.archivePath}.sha1")
|
|
||||||
assert dist.archivePath.isFile()
|
|
||||||
assert shaFile.isFile()
|
|
||||||
ant.taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: configurations.antlibs.asPath)
|
|
||||||
ant.s3(accessKey: s3AccessKey, secretKey: s3SecretAccessKey) {
|
|
||||||
upload(bucketName: 'dist.springframework.org', file: dist.archivePath,
|
|
||||||
toFile: releaseType() + "/SEC/${dist.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: dist.archiveName)
|
|
||||||
}
|
|
||||||
upload(bucketName: 'dist.springframework.org', file: shaFile,
|
|
||||||
toFile: releaseType() + "/SEC/${dist.archiveName}.sha1", publicRead: 'true')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def javaProjects() {
|
task uploadDist(type: UploadDist) {
|
||||||
|
archiveFile = dist.archivePath
|
||||||
|
shaFile = "${dist.archivePath}.sha1" as File
|
||||||
|
archiveName = dist.archiveName
|
||||||
|
classpath = configurations.antlibs
|
||||||
|
}
|
||||||
|
|
||||||
|
def getJavaProjects() {
|
||||||
subprojects.findAll {project -> project.name != 'faq' && project.name != 'manual' }
|
subprojects.findAll {project -> project.name != 'faq' && project.name != 'manual' }
|
||||||
}
|
}
|
||||||
|
|
||||||
def sampleProjects() {
|
def getSampleProjects() {
|
||||||
subprojects.findAll {project -> project.name.startsWith('spring-security-samples') }
|
subprojects.findAll {project -> project.name.startsWith('spring-security-samples') }
|
||||||
}
|
}
|
||||||
|
|
||||||
def itestProjects() {
|
def getItestProjects() {
|
||||||
subprojects.findAll {project -> project.name.startsWith('itest') }
|
subprojects.findAll {project -> project.name.startsWith('itest') }
|
||||||
}
|
}
|
||||||
|
|
||||||
def coreModuleProjects() {
|
def getCoreModuleProjects() {
|
||||||
javaProjects() - sampleProjects() - itestProjects()
|
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() {
|
def releaseType() {
|
||||||
if (releaseBuild) {
|
if (project.releaseBuild) {
|
||||||
'release'
|
'release'
|
||||||
} else if (snapshotBuild) {
|
} else if (project.snapshotBuild) {
|
||||||
'snapshot'
|
'snapshot'
|
||||||
} else {
|
} else {
|
||||||
'milestone'
|
'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:ns-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.4.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)
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,5 @@
|
|||||||
|
Implementation-Title: org.springframework.security.cas
|
||||||
|
Implementation-Version: ${version}
|
||||||
Bundle-SymbolicName: org.springframework.security.cas
|
Bundle-SymbolicName: org.springframework.security.cas
|
||||||
Bundle-Name: Spring Security CAS
|
Bundle-Name: Spring Security CAS
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: SpringSource
|
||||||
@@ -18,4 +20,3 @@ Import-Template:
|
|||||||
org.springframework.util;version="[${spring.version}, 3.1.0)",
|
org.springframework.util;version="[${spring.version}, 3.1.0)",
|
||||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||||
javax.servlet.*;version="0"
|
javax.servlet.*;version="0"
|
||||||
|
|
||||||
@@ -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.4.rnc spring-security-3.0.4.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.4.xsd spring-security.xsl spring-security-3.0.4.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.4.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>
|
||||||
|
|||||||
@@ -50,4 +50,5 @@ public abstract class Elements {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||||
|
public static final String HTTP_FIREWALL = "http-firewall";
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-7
@@ -3,6 +3,8 @@ package org.springframework.security.config;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||||
@@ -15,12 +17,14 @@ import org.springframework.security.config.authentication.JdbcUserServiceBeanDef
|
|||||||
import org.springframework.security.config.authentication.UserServiceBeanDefinitionParser;
|
import org.springframework.security.config.authentication.UserServiceBeanDefinitionParser;
|
||||||
import org.springframework.security.config.http.FilterChainMapBeanDefinitionDecorator;
|
import org.springframework.security.config.http.FilterChainMapBeanDefinitionDecorator;
|
||||||
import org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser;
|
import org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser;
|
||||||
|
import org.springframework.security.config.http.HttpFirewallBeanDefinitionParser;
|
||||||
import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser;
|
import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
||||||
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
||||||
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
||||||
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
@@ -33,18 +37,44 @@ import org.w3c.dom.Node;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public final class SecurityNamespaceHandler implements NamespaceHandler {
|
public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||||
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
|
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
|
||||||
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
|
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
|
||||||
private BeanDefinitionDecorator filterChainMapBDD;
|
private BeanDefinitionDecorator filterChainMapBDD;
|
||||||
|
|
||||||
|
public SecurityNamespaceHandler() {
|
||||||
|
String coreVersion = SpringSecurityCoreVersion.getVersion();
|
||||||
|
|
||||||
|
Package pkg = SpringSecurityCoreVersion.class.getPackage();
|
||||||
|
|
||||||
|
if (pkg == null || coreVersion == null) {
|
||||||
|
logger.info("Couldn't determine package version information.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String version = pkg.getImplementationVersion();
|
||||||
|
logger.info("Spring Security 'config' module version is " + version);
|
||||||
|
|
||||||
|
if (version.compareTo(coreVersion) != 0) {
|
||||||
|
logger.error("You are running with different versions of the Spring Security 'core' and 'config' modules");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
if (!namespaceMatchesVersion(element)) {
|
if (!namespaceMatchesVersion(element)) {
|
||||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd schema with Spring Security 3.0." +
|
pc.getReaderContext().fatal("You must use a 3.0 schema with Spring Security 3.0." +
|
||||||
" Please update your schema declarations to the 3.0 schema.", element);
|
"(2.0 or 3.1 versions are not valid)" +
|
||||||
|
" Please update your schema declarations to the 3.0.3 schema (spring-security-3.0.3.xsd).", element);
|
||||||
}
|
}
|
||||||
String name = pc.getDelegate().getLocalName(element);
|
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 +97,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 +124,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,15 +139,14 @@ 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())) {
|
||||||
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
|
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
|
||||||
|
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
|
||||||
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
parsers.put(Elements.FILTER_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 +165,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);
|
||||||
|
|||||||
+18
-13
@@ -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);
|
|
||||||
|
String entryPointId;
|
||||||
|
|
||||||
|
if (basicAuthElt != null && StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
|
||||||
|
basicEntryPoint = new RuntimeBeanReference(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
|
||||||
|
} else {
|
||||||
|
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||||
entryPoint.setSource(pc.extractSource(httpElt));
|
entryPoint.setSource(pc.extractSource(httpElt));
|
||||||
|
|
||||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||||
|
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||||
String entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
|
||||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-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);
|
||||||
@@ -396,6 +396,11 @@ class HttpConfigurationBuilder {
|
|||||||
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
|
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
|
||||||
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
|
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
|
||||||
|
|
||||||
|
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
||||||
|
if(StringUtils.hasText(method)) {
|
||||||
|
requestKey.getConstructorArgumentValues().addGenericArgumentValue(method);
|
||||||
|
}
|
||||||
|
|
||||||
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
|
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
|
||||||
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
||||||
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
||||||
@@ -464,7 +469,7 @@ class HttpConfigurationBuilder {
|
|||||||
return allowSessionCreation;
|
return allowSessionCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManagedMap<BeanDefinition, List<BeanMetadataElement>> getFilterChainMap() {
|
public ManagedMap<Object, List<BeanMetadataElement>> getFilterChainMap() {
|
||||||
return filterChainMap;
|
return filterChainMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
package org.springframework.security.config.http;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeanMetadataElement;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.ManagedMap;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
|
import org.springframework.security.config.BeanIds;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects the supplied {@code HttpFirewall} bean reference into the {@code FilterChainProxy}.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
*/
|
||||||
|
public class HttpFirewallBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
|
String ref = element.getAttribute("ref");
|
||||||
|
|
||||||
|
if (!StringUtils.hasText(ref)) {
|
||||||
|
pc.getReaderContext().error("ref attribute is required", pc.extractSource(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
BeanDefinitionBuilder injector = BeanDefinitionBuilder.rootBeanDefinition(HttpFirewallInjectionBeanPostProcessor.class);
|
||||||
|
injector.addConstructorArgValue(ref);
|
||||||
|
|
||||||
|
pc.getReaderContext().registerWithGeneratedName(injector.getBeanDefinition());
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package org.springframework.security.config.http;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.security.config.BeanIds;
|
||||||
|
import org.springframework.security.web.FilterChainProxy;
|
||||||
|
import org.springframework.security.web.firewall.HttpFirewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luke Taylor
|
||||||
|
*/
|
||||||
|
public class HttpFirewallInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||||
|
private ConfigurableListableBeanFactory beanFactory;
|
||||||
|
private String ref;
|
||||||
|
|
||||||
|
public HttpFirewallInjectionBeanPostProcessor(String ref) {
|
||||||
|
this.ref = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
|
||||||
|
HttpFirewall fw = (HttpFirewall) beanFactory.getBean(ref);
|
||||||
|
((FilterChainProxy)bean).setFirewall(fw);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||||
|
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-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;
|
||||||
@@ -55,6 +56,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
static final String OPT_FILTERS_NONE = "none";
|
static final String OPT_FILTERS_NONE = "none";
|
||||||
|
|
||||||
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
|
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
|
||||||
|
static final String ATT_HTTP_METHOD = "method";
|
||||||
|
|
||||||
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
|
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
|
||||||
|
|
||||||
@@ -135,10 +137,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 +168,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 +251,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);
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-5
@@ -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);
|
||||||
|
|
||||||
|
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));
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.ManagedMap;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
@@ -64,16 +65,16 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
|
|||||||
interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||||
|
|
||||||
// Lookup parent bean information
|
// Lookup parent bean information
|
||||||
Element parent = (Element) node.getParentNode();
|
String parentBeanClass = ((Element) node.getParentNode()).getAttribute("class");
|
||||||
String parentBeanClass = parent.getAttribute("class");
|
|
||||||
parent = null;
|
|
||||||
|
|
||||||
// Parse the included methods
|
// Parse the included methods
|
||||||
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
|
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
|
||||||
Map<String, List<ConfigAttribute>> mappings = new LinkedHashMap<String, List<ConfigAttribute>>();
|
Map<String, BeanDefinition> mappings = new ManagedMap<String, BeanDefinition>();
|
||||||
|
|
||||||
for (Element protectmethodElt : methods) {
|
for (Element protectmethodElt : methods) {
|
||||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(protectmethodElt.getAttribute(ATT_ACCESS));
|
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
|
||||||
|
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
|
||||||
|
attributeBuilder.addConstructorArgValue(protectmethodElt.getAttribute(ATT_ACCESS));
|
||||||
|
|
||||||
// Support inference of class names
|
// Support inference of class names
|
||||||
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
|
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
|
||||||
@@ -84,7 +85,7 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mappings.put(methodName, SecurityConfig.createList(tokens));
|
mappings.put(methodName, attributeBuilder.getBeanDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinition metadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
BeanDefinition metadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
||||||
|
|||||||
+16
-13
@@ -1,11 +1,7 @@
|
|||||||
package org.springframework.security.config.method;
|
package org.springframework.security.config.method;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
@@ -44,15 +40,16 @@ 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 {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
|
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
|
||||||
|
|
||||||
private Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
private final Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
||||||
private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
private final MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
||||||
private PointcutParser parser;
|
private final Set<PointcutExpression> pointCutExpressions = new LinkedHashSet<PointcutExpression>();
|
||||||
|
private final PointcutParser parser;
|
||||||
|
private final Set<String> processedBeans = new HashSet<String>();
|
||||||
|
|
||||||
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
||||||
Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required");
|
Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required");
|
||||||
@@ -78,6 +75,11 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (processedBeans.contains(beanName)) {
|
||||||
|
// We already have the metadata for this bean
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
// Obtain methods for the present bean
|
// Obtain methods for the present bean
|
||||||
Method[] methods;
|
Method[] methods;
|
||||||
try {
|
try {
|
||||||
@@ -88,10 +90,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
|
||||||
@@ -100,6 +99,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processedBeans.add(beanName);
|
||||||
|
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +135,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,7 @@
|
|||||||
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.4.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.4.xsd=org/springframework/security/config/spring-security-3.0.4.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
|
||||||
|
|||||||
+1381
File diff suppressed because it is too large
Load Diff
+14
-4
@@ -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.
|
||||||
@@ -242,6 +245,9 @@ protect-pointcut.attlist &=
|
|||||||
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
||||||
attribute access {xsd:token}
|
attribute access {xsd:token}
|
||||||
|
|
||||||
|
http-firewall =
|
||||||
|
## Allows a custom instance of HttpFirewall to be injected into the FilterChainProxy created by the namespace.
|
||||||
|
element http-firewall {ref}
|
||||||
|
|
||||||
http =
|
http =
|
||||||
## Container element for HTTP security configuration
|
## Container element for HTTP security configuration
|
||||||
@@ -273,7 +279,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 +422,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 +547,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.
|
||||||
@@ -619,5 +631,3 @@ position =
|
|||||||
|
|
||||||
|
|
||||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||||
|
|
||||||
|
|
||||||
+1386
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -70,40 +70,40 @@ public class FilterChainProxyConfigTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperation() throws Exception {
|
public void normalOperation() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperationWithNewConfig() throws Exception {
|
public void normalOperationWithNewConfig() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
||||||
checkPathAndFilterOrder(filterChainProxy);
|
checkPathAndFilterOrder(filterChainProxy);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperationWithNewConfigRegex() throws Exception {
|
public void normalOperationWithNewConfigRegex() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
||||||
checkPathAndFilterOrder(filterChainProxy);
|
checkPathAndFilterOrder(filterChainProxy);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
||||||
checkPathAndFilterOrder(filterChainProxy);
|
checkPathAndFilterOrder(filterChainProxy);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pathWithNoMatchHasNoFilters() throws Exception {
|
public void pathWithNoMatchHasNoFilters() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||||
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void urlStrippingPropertyIsRespected() throws Exception {
|
public void urlStrippingPropertyIsRespected() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||||
|
|
||||||
// Should only match if we are stripping the query string
|
// Should only match if we are stripping the query string
|
||||||
String url = "/blah.bar?x=something";
|
String url = "/blah.bar?x=something";
|
||||||
@@ -116,7 +116,7 @@ public class FilterChainProxyConfigTests {
|
|||||||
// SEC-1235
|
// SEC-1235
|
||||||
@Test
|
@Test
|
||||||
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() throws Exception {
|
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
|
||||||
|
|
||||||
String[] paths = filterChainProxy.getFilterChainMap().keySet().toArray(new String[0]);
|
String[] paths = filterChainProxy.getFilterChainMap().keySet().toArray(new String[0]);
|
||||||
assertEquals("/login*", paths[0]);
|
assertEquals("/login*", paths[0]);
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ public class SecurityNamespacehandlerTests {
|
|||||||
);
|
);
|
||||||
fail("Expected BeanDefinitionParsingException");
|
fail("Expected BeanDefinitionParsingException");
|
||||||
} catch (BeanDefinitionParsingException expected) {
|
} catch (BeanDefinitionParsingException expected) {
|
||||||
assertTrue(expected.getMessage().contains("You cannot use a spring-security-2.0.xsd schema"));
|
assertTrue(expected.getMessage().contains("You must use a 3.0 schema with Spring Security 3.0."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+46
@@ -80,11 +80,13 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
|
|||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||||
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
|
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
|
||||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||||
|
import org.springframework.security.web.firewall.DefaultHttpFirewall;
|
||||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||||
import org.springframework.security.web.session.SessionManagementFilter;
|
import org.springframework.security.web.session.SessionManagementFilter;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -407,6 +409,23 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void httpMethodMatchIsSupportedForRequiresChannel() throws Exception {
|
||||||
|
setContext(
|
||||||
|
" <http auto-config='true'>" +
|
||||||
|
" <intercept-url pattern='/anyurl'/>" +
|
||||||
|
" <intercept-url pattern='/anyurl' method='GET' access='ROLE_ADMIN' requires-channel='https' />" +
|
||||||
|
" </http>" + AUTH_PROVIDER_XML);
|
||||||
|
|
||||||
|
ChannelProcessingFilter filter = getFilter(ChannelProcessingFilter.class);
|
||||||
|
FilterInvocationSecurityMetadataSource fids = (FilterInvocationSecurityMetadataSource)FieldUtils.getFieldValue(filter,"securityMetadataSource");
|
||||||
|
Collection<ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"));
|
||||||
|
assertEquals(1, attrs.size());
|
||||||
|
attrs = fids.getAttributes(createFilterinvocation("/anyurl", "POST"));
|
||||||
|
assertEquals(null, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void oncePerRequestAttributeIsSupported() throws Exception {
|
public void oncePerRequestAttributeIsSupported() throws Exception {
|
||||||
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||||
@@ -416,6 +435,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);
|
||||||
@@ -1218,6 +1252,18 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void httpFirewallInjectionIsSupported() throws Exception {
|
||||||
|
setContext(
|
||||||
|
"<http-firewall ref='fw'/>" +
|
||||||
|
"<http>" +
|
||||||
|
" <form-login />" +
|
||||||
|
"</http>" +
|
||||||
|
"<b:bean id='fw' class='" + DefaultHttpFirewall.class.getName() +"'/>" +
|
||||||
|
AUTH_PROVIDER_XML);
|
||||||
|
FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
||||||
|
assertSame(appContext.getBean("fw"), FieldUtils.getFieldValue(fcp, "firewall"));
|
||||||
|
}
|
||||||
|
|
||||||
private void setContext(String context) {
|
private void setContext(String context) {
|
||||||
appContext = new InMemoryXmlApplicationContext(context);
|
appContext = new InMemoryXmlApplicationContext(context);
|
||||||
|
|||||||
+46
-4
@@ -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
@@ -25,6 +25,8 @@ public class InterceptMethodsBeanDefinitionDecoratorTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void loadContext() {
|
public void loadContext() {
|
||||||
|
// Set value for placeholder
|
||||||
|
System.setProperty("admin.role", "ROLE_ADMIN");
|
||||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
|
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
|
||||||
target = (TestBusinessBean) appContext.getBean("target");
|
target = (TestBusinessBean) appContext.getBean("target");
|
||||||
}
|
}
|
||||||
|
|||||||
+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.4", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
||||||
this(xml, "3.0", parent);
|
this(xml, "3.0.4", parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
|
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
|
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
|
||||||
|
|
||||||
|
<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>
|
||||||
|
|
||||||
<b:bean id="target" class="org.springframework.security.config.TestBusinessBeanImpl">
|
<b:bean id="target" class="org.springframework.security.config.TestBusinessBeanImpl">
|
||||||
<!-- This will add a security interceptor to the bean -->
|
<!-- This will add a security interceptor to the bean -->
|
||||||
<intercept-methods>
|
<intercept-methods>
|
||||||
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="ROLE_ADMIN" />
|
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="${admin.role}" />
|
||||||
<protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
|
<protect method="get*" access="${admin.role},ROLE_USER" />
|
||||||
<protect method="doSomething" access="ROLE_USER" />
|
<protect method="doSomething" access="ROLE_USER" />
|
||||||
</intercept-methods>
|
</intercept-methods>
|
||||||
</b:bean>
|
</b:bean>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
Implementation-Title: org.springframework.security.config
|
||||||
|
Implementation-Version: ${version}
|
||||||
Bundle-SymbolicName: org.springframework.security.config
|
Bundle-SymbolicName: org.springframework.security.config
|
||||||
Bundle-Name: Spring Security Namespace Configuration
|
Bundle-Name: Spring Security Namespace Configuration
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: SpringSource
|
||||||
|
|||||||
@@ -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.4.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
@@ -36,6 +36,14 @@ public abstract class SecurityExpressionRoot {
|
|||||||
this.authentication = a;
|
this.authentication = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean hasAuthority(String authority) {
|
||||||
|
return hasRole(authority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean hasAnyAuthority(String... authorities) {
|
||||||
|
return hasAnyRole(authorities);
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean hasRole(String role) {
|
public final boolean hasRole(String role) {
|
||||||
return getAuthoritySet().contains(role);
|
return getAuthoritySet().contains(role);
|
||||||
}
|
}
|
||||||
|
|||||||
+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
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
|
|||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +107,7 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
|||||||
|
|
||||||
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
|
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
|
||||||
if (authorities == null || authorities.isEmpty()) {
|
if (authorities == null || authorities.isEmpty()) {
|
||||||
return null;
|
return AuthorityUtils.NO_AUTHORITIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>();
|
Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>();
|
||||||
|
|||||||
+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) {
|
||||||
|
|||||||
+7
-3
@@ -25,6 +25,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
@@ -42,7 +43,8 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource implements BeanClassLoaderAware {
|
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource
|
||||||
|
implements BeanClassLoaderAware {
|
||||||
|
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||||
@@ -103,7 +105,7 @@ public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethod
|
|||||||
* for matching multiple methods.
|
* for matching multiple methods.
|
||||||
*
|
*
|
||||||
* @param name type and method name, separated by a dot
|
* @param name type and method name, separated by a dot
|
||||||
* @param attr required authorities associated with the method
|
* @param attr the security attributes associated with the method
|
||||||
*/
|
*/
|
||||||
private void addSecureMethod(String name, List<ConfigAttribute> attr) {
|
private void addSecureMethod(String name, List<ConfigAttribute> attr) {
|
||||||
int lastDotIndex = name.lastIndexOf(".");
|
int lastDotIndex = name.lastIndexOf(".");
|
||||||
@@ -175,7 +177,9 @@ public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethod
|
|||||||
* Adds configuration attributes for a specific method, for example where the method has been
|
* Adds configuration attributes for a specific method, for example where the method has been
|
||||||
* matched using a pointcut expression. If a match already exists in the map for the method, then
|
* matched using a pointcut expression. If a match already exists in the map for the method, then
|
||||||
* the existing match will be retained, so that if this method is called for a more general pointcut
|
* the existing match will be retained, so that if this method is called for a more general pointcut
|
||||||
* it will not override a more specific one which has already been added. This
|
* it will not override a more specific one which has already been added.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called during initialization of the {@code BeanFactory}.
|
||||||
*/
|
*/
|
||||||
public void addSecureMethod(Class<?> javaType, Method method, List<ConfigAttribute> attr) {
|
public void addSecureMethod(Class<?> javaType, Method method, List<ConfigAttribute> attr) {
|
||||||
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
||||||
|
|||||||
+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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -16,6 +16,8 @@
|
|||||||
package org.springframework.security.authentication.dao;
|
package org.springframework.security.authentication.dao;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.security.authentication.AccountExpiredException;
|
import org.springframework.security.authentication.AccountExpiredException;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
@@ -71,6 +73,9 @@ import org.springframework.util.Assert;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean,
|
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean,
|
||||||
MessageSourceAware {
|
MessageSourceAware {
|
||||||
|
|
||||||
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||||
@@ -123,6 +128,8 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||||||
try {
|
try {
|
||||||
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
|
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
|
||||||
} catch (UsernameNotFoundException notFound) {
|
} catch (UsernameNotFoundException notFound) {
|
||||||
|
logger.debug("User '" + username + "' not found");
|
||||||
|
|
||||||
if (hideUserNotFoundExceptions) {
|
if (hideUserNotFoundExceptions) {
|
||||||
throw new BadCredentialsException(messages.getMessage(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||||
@@ -291,16 +298,22 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||||||
private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
|
private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
|
||||||
public void check(UserDetails user) {
|
public void check(UserDetails user) {
|
||||||
if (!user.isAccountNonLocked()) {
|
if (!user.isAccountNonLocked()) {
|
||||||
|
logger.debug("User account is locked");
|
||||||
|
|
||||||
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
|
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
|
||||||
"User account is locked"), user);
|
"User account is locked"), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.isEnabled()) {
|
if (!user.isEnabled()) {
|
||||||
|
logger.debug("User account is disabled");
|
||||||
|
|
||||||
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
|
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
|
||||||
"User is disabled"), user);
|
"User is disabled"), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.isAccountNonExpired()) {
|
if (!user.isAccountNonExpired()) {
|
||||||
|
logger.debug("User account is expired");
|
||||||
|
|
||||||
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
|
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
|
||||||
"User account has expired"), user);
|
"User account has expired"), user);
|
||||||
}
|
}
|
||||||
@@ -310,6 +323,8 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||||||
private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
|
private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
|
||||||
public void check(UserDetails user) {
|
public void check(UserDetails user) {
|
||||||
if (!user.isCredentialsNonExpired()) {
|
if (!user.isCredentialsNonExpired()) {
|
||||||
|
logger.debug("User account credentials have expired");
|
||||||
|
|
||||||
throw new CredentialsExpiredException(messages.getMessage(
|
throw new CredentialsExpiredException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
||||||
"User credentials have expired"), user);
|
"User credentials have expired"), user);
|
||||||
|
|||||||
+4
@@ -56,6 +56,8 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (authentication.getCredentials() == null) {
|
if (authentication.getCredentials() == null) {
|
||||||
|
logger.debug("Authentication failed: no credentials provided");
|
||||||
|
|
||||||
throw new BadCredentialsException(messages.getMessage(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||||
includeDetailsObject ? userDetails : null);
|
includeDetailsObject ? userDetails : null);
|
||||||
@@ -64,6 +66,8 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
String presentedPassword = authentication.getCredentials().toString();
|
String presentedPassword = authentication.getCredentials().toString();
|
||||||
|
|
||||||
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
|
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
|
||||||
|
logger.debug("Authentication failed: password does not match stored value");
|
||||||
|
|
||||||
throw new BadCredentialsException(messages.getMessage(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||||
includeDetailsObject ? userDetails : null);
|
includeDetailsObject ? userDetails : 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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.springframework.security.core;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.core.SpringVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class used for checking version compatibility in a deployed application.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
*/
|
||||||
|
public class SpringSecurityCoreVersion {
|
||||||
|
private static final Log logger = LogFactory.getLog(SpringSecurityCoreVersion.class);
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Check Spring Compatibility
|
||||||
|
String springVersion = SpringVersion.getVersion();
|
||||||
|
String version = getVersion();
|
||||||
|
|
||||||
|
if (springVersion != null) {
|
||||||
|
// TODO: Generate version class and information dynamically from a template in the build file
|
||||||
|
logger.info("You are running with Spring Security Core " + springVersion);
|
||||||
|
if (!springVersion.startsWith("3")) {
|
||||||
|
logger.error("Spring Major version '3' expected, but you are running with version: " + springVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (springVersion.compareTo("3.0.3") < 0) {
|
||||||
|
logger.warn("You are advised to use Spring 3.0.3 or later with this version. You are running: " +
|
||||||
|
springVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getVersion() {
|
||||||
|
Package pkg = SpringSecurityCoreVersion.class.getPackage();
|
||||||
|
return (pkg != null ? pkg.getImplementationVersion() : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -35,7 +35,7 @@ final class InheritableThreadLocalSecurityContextHolderStrategy implements Secur
|
|||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public void clearContext() {
|
public void clearContext() {
|
||||||
contextHolder.set(null);
|
contextHolder.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecurityContext getContext() {
|
public SecurityContext getContext() {
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextH
|
|||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public void clearContext() {
|
public void clearContext() {
|
||||||
contextHolder.set(null);
|
contextHolder.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecurityContext getContext() {
|
public SecurityContext getContext() {
|
||||||
|
|||||||
@@ -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(": ");
|
||||||
|
|||||||
@@ -152,6 +152,8 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService {
|
|||||||
List<UserDetails> users = loadUsersByUsername(username);
|
List<UserDetails> users = loadUsersByUsername(username);
|
||||||
|
|
||||||
if (users.size() == 0) {
|
if (users.size() == 0) {
|
||||||
|
logger.debug("Query returned no results for user '" + username + "'");
|
||||||
|
|
||||||
throw new UsernameNotFoundException(
|
throw new UsernameNotFoundException(
|
||||||
messages.getMessage("JdbcDaoImpl.notFound", new Object[]{username}, "Username {0} not found"), username);
|
messages.getMessage("JdbcDaoImpl.notFound", new Object[]{username}, "Username {0} not found"), username);
|
||||||
}
|
}
|
||||||
@@ -173,6 +175,8 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService {
|
|||||||
addCustomAuthorities(user.getUsername(), dbAuths);
|
addCustomAuthorities(user.getUsername(), dbAuths);
|
||||||
|
|
||||||
if (dbAuths.size() == 0) {
|
if (dbAuths.size() == 0) {
|
||||||
|
logger.debug("User '" + username + "' has no authorities and will be treated as 'not found'");
|
||||||
|
|
||||||
throw new UsernameNotFoundException(
|
throw new UsernameNotFoundException(
|
||||||
messages.getMessage("JdbcDaoImpl.noAuthority",
|
messages.getMessage("JdbcDaoImpl.noAuthority",
|
||||||
new Object[] {username}, "User {0} has no GrantedAuthority"), username);
|
new Object[] {username}, "User {0} has no GrantedAuthority"), username);
|
||||||
|
|||||||
+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")));
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
-2
@@ -1,12 +1,16 @@
|
|||||||
package org.springframework.security.access.expression;
|
package org.springframework.security.access.expression;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
|
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
|
||||||
@@ -16,11 +20,30 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
|||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class SecurityExpressionRootTests {
|
public class SecurityExpressionRootTests {
|
||||||
|
private final Authentication JOE = new TestingAuthenticationToken("joe", "pass", "A", "B");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void denyAllIsFalsePermitAllTrue() throws Exception {
|
||||||
|
SecurityExpressionRoot root = new SecurityExpressionRoot(JOE) {};
|
||||||
|
assertFalse(root.denyAll());
|
||||||
|
assertFalse(root.denyAll);
|
||||||
|
assertTrue(root.permitAll());
|
||||||
|
assertTrue(root.permitAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rememberMeIsCorrectlyDetected() throws Exception {
|
||||||
|
SecurityExpressionRoot root = new SecurityExpressionRoot(JOE) {};
|
||||||
|
AuthenticationTrustResolver atr = mock(AuthenticationTrustResolver.class);
|
||||||
|
root.setTrustResolver(atr);
|
||||||
|
when(atr.isRememberMe(JOE)).thenReturn(true);
|
||||||
|
assertTrue(root.isRememberMe());
|
||||||
|
assertFalse(root.isFullyAuthenticated());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void roleHierarchySupportIsCorrectlyUsedInEvaluatingRoles() throws Exception {
|
public void roleHierarchySupportIsCorrectlyUsedInEvaluatingRoles() throws Exception {
|
||||||
SecurityExpressionRoot root =
|
SecurityExpressionRoot root = new SecurityExpressionRoot(JOE) {};
|
||||||
new SecurityExpressionRoot(new TestingAuthenticationToken("joe", "pass", "A", "B")) {};
|
|
||||||
|
|
||||||
root.setRoleHierarchy(new RoleHierarchy() {
|
root.setRoleHierarchy(new RoleHierarchy() {
|
||||||
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
|
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
|
||||||
@@ -29,9 +52,11 @@ public class SecurityExpressionRootTests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(root.hasRole("C"));
|
assertTrue(root.hasRole("C"));
|
||||||
|
assertTrue(root.hasAuthority("C"));
|
||||||
assertFalse(root.hasRole("A"));
|
assertFalse(root.hasRole("A"));
|
||||||
assertFalse(root.hasRole("B"));
|
assertFalse(root.hasRole("B"));
|
||||||
assertTrue(root.hasAnyRole("C", "A", "B"));
|
assertTrue(root.hasAnyRole("C", "A", "B"));
|
||||||
|
assertTrue(root.hasAnyAuthority("C", "A", "B"));
|
||||||
assertFalse(root.hasAnyRole("A", "B"));
|
assertFalse(root.hasAnyRole("A", "B"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package org.springframework.security.access.hierarchicalroles;
|
package org.springframework.security.access.hierarchicalroles;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
@@ -30,6 +31,19 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
|||||||
*/
|
*/
|
||||||
public class RoleHierarchyImplTests extends TestCase {
|
public class RoleHierarchyImplTests extends TestCase {
|
||||||
|
|
||||||
|
public void testRoleHierarchyWithNullOrEmptyAuthorities() {
|
||||||
|
List<GrantedAuthority> authorities0 = null;
|
||||||
|
List<GrantedAuthority> authorities1 = new ArrayList<GrantedAuthority>();
|
||||||
|
|
||||||
|
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
|
||||||
|
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B");
|
||||||
|
|
||||||
|
assertNotNull(roleHierarchyImpl.getReachableGrantedAuthorities(authorities0));
|
||||||
|
assertEquals(0, roleHierarchyImpl.getReachableGrantedAuthorities(authorities0).size());
|
||||||
|
assertNotNull(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1));
|
||||||
|
assertEquals(0, roleHierarchyImpl.getReachableGrantedAuthorities(authorities1).size());
|
||||||
|
}
|
||||||
|
|
||||||
public void testSimpleRoleHierarchy() {
|
public void testSimpleRoleHierarchy() {
|
||||||
|
|
||||||
List<GrantedAuthority> authorities0 = AuthorityUtils.createAuthorityList("ROLE_0");
|
List<GrantedAuthority> authorities0 = AuthorityUtils.createAuthorityList("ROLE_0");
|
||||||
|
|||||||
+25
-33
@@ -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);
|
||||||
|
try {
|
||||||
interceptor.invoke(joinPoint, aspectJCallback);
|
interceptor.invoke(joinPoint, aspectJCallback);
|
||||||
jmock.assertIsSatisfied();
|
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();
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,5 @@
|
|||||||
|
Implementation-Title: org.springframework.security.core
|
||||||
|
Implementation-Version: ${version}
|
||||||
Bundle-SymbolicName: org.springframework.security.core
|
Bundle-SymbolicName: org.springframework.security.core
|
||||||
Bundle-Name: Spring Security Core
|
Bundle-Name: Spring Security Core
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: SpringSource
|
||||||
@@ -25,4 +27,3 @@ Import-Template:
|
|||||||
javax.crypto.*;version="0";resolution:=optional,
|
javax.crypto.*;version="0";resolution:=optional,
|
||||||
javax.security.auth.*;version="0";resolution:=optional,
|
javax.security.auth.*;version="0";resolution:=optional,
|
||||||
javax.naming.*;version="0";resolution:=optional
|
javax.naming.*;version="0";resolution:=optional
|
||||||
|
|
||||||
+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')
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
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-ns/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-ns/current/html/highlight.xsl"/>
|
||||||
|
|
||||||
<!--xsl:param name="use.id.as.filename">'1'</xsl:param-->
|
<!--xsl:param name="use.id.as.filename">'1'</xsl:param-->
|
||||||
|
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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).
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
<bean id="daoAuthenticationProvider"
|
<bean id="daoAuthenticationProvider"
|
||||||
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||||
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
|
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
|
||||||
<property name="saltSource" ref bean="saltSource"/>
|
<property name="saltSource" ref="saltSource"/>
|
||||||
<property name="passwordEncoder" ref="passwordEncoder"/>
|
<property name="passwordEncoder" ref="passwordEncoder"/>
|
||||||
</bean>]]></programlisting> The <interfacename>PasswordEncoder</interfacename> and
|
</bean>]]></programlisting> The <interfacename>PasswordEncoder</interfacename> and
|
||||||
<interfacename>SaltSource</interfacename> are optional. A
|
<interfacename>SaltSource</interfacename> are optional. A
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -154,14 +154,16 @@
|
|||||||
within the expression, so you can also access properties on the arguments. For
|
within the expression, so you can also access properties on the arguments. For
|
||||||
example, if you wanted a particular method to only allow access to a user whose
|
example, if you wanted a particular method to only allow access to a user whose
|
||||||
username matched that of the contact, you could write</para>
|
username matched that of the contact, you could write</para>
|
||||||
<programlisting> @PreAuthorize("#contact.name == principal.name)")
|
<programlisting>
|
||||||
|
@PreAuthorize("#contact.name == authentication.name")
|
||||||
public void doSomething(Contact contact);</programlisting>
|
public void doSomething(Contact contact);</programlisting>
|
||||||
<para>Here we are accessing another built–in expression, which is the
|
<para>Here we are accessing another built–in expression, <literal>authentication</literal>,
|
||||||
<literal>principal</literal> of the current Spring Security
|
which is the <interfacename>Authentication</interfacename> stored in the
|
||||||
<interfacename>Authentication</interfacename> object obtained from the
|
security context. You can also access its <quote>principal</quote> property
|
||||||
security context. You can also access the
|
directly, using the expression <literal>principal</literal>. The value will
|
||||||
<interfacename>Authentication</interfacename> object itself directly using
|
often be a <interfacename>UserDetails</interfacename> instance, so you might use an
|
||||||
the expression name <literal>authentication</literal>.</para>
|
expression like <literal>principal.username</literal> or
|
||||||
|
<literal>principal.enabled</literal>.</para>
|
||||||
<para>Less commonly, you may wish to perform an access-control check after the
|
<para>Less commonly, you may wish to perform an access-control check after the
|
||||||
method has been invoked. This can be achieved using the
|
method has been invoked. This can be achieved using the
|
||||||
<literal>@PostAuthorize</literal> annotation. To access the return value
|
<literal>@PostAuthorize</literal> annotation. To access the return value
|
||||||
|
|||||||
@@ -364,16 +364,18 @@ public interface UserDetailsContextMapper {
|
|||||||
|
|
||||||
void mapUserToContext(UserDetails user, DirContextAdapter ctx);
|
void mapUserToContext(UserDetails user, DirContextAdapter ctx);
|
||||||
}]]>
|
}]]>
|
||||||
</programlisting> Only the first method is relevant for
|
</programlisting> Only the first method is relevant for authentication. If you
|
||||||
authentication. If you provide an implementation of this interface, you can control
|
provide an implementation of this interface and inject it into the
|
||||||
exactly how the UserDetails object is created. The first parameter is an instance of
|
<classname>LdapAuthenticationProvider</classname>, you have control over exactly how
|
||||||
Spring LDAP's <interfacename>DirContextOperations</interfacename> which gives you
|
the UserDetails object is created. The first parameter is an instance of Spring
|
||||||
access to the LDAP attributes which were loaded. The <literal>username</literal>
|
LDAP's <interfacename>DirContextOperations</interfacename> which gives you access to
|
||||||
parameter is the name used to authenticate and the final parameter is the collection
|
the LDAP attributes which were loaded during authentication. The
|
||||||
of authorities loaded for the user. </para>
|
<literal>username</literal> parameter is the name used to authenticate and the final
|
||||||
|
parameter is the collection of authorities loaded for the user by the configured
|
||||||
|
<interfacename>LdapAuthoritiesPopulator</interfacename>. </para>
|
||||||
<para> The way the context data is loaded varies slightly depending on the type of
|
<para> The way the context data is loaded varies slightly depending on the type of
|
||||||
authentication you are using. With the <classname>BindAuthenticator</classname>,
|
authentication you are using. With the <classname>BindAuthenticator</classname>, the
|
||||||
the context returned from the bind operation will be used to read the attributes,
|
context returned from the bind operation will be used to read the attributes,
|
||||||
otherwise the data will be read using the standard context obtained from the
|
otherwise the data will be read using the standard context obtained from the
|
||||||
configured <interfacename>ContextSource</interfacename> (when a search is configured
|
configured <interfacename>ContextSource</interfacename> (when a search is configured
|
||||||
to locate the user, this will be the data returned by the search object). </para>
|
to locate the user, this will be the data returned by the search object). </para>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<para> Namespace configuration has been available since version 2.0 of the Spring framework. It
|
<para> Namespace configuration has been available since version 2.0 of the Spring framework. It
|
||||||
allows you to supplement the traditional Spring beans application context syntax with elements
|
allows you to supplement the traditional Spring beans application context syntax with elements
|
||||||
from additional XML schema. You can find more information in the Spring <link
|
from additional XML schema. You can find more information in the Spring <link
|
||||||
xlink:href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/apc.html"
|
xlink:href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.htm"
|
||||||
> Reference Documentation</link>. A namespace element can be used simply to allow a more
|
> Reference Documentation</link>. A namespace element can be used simply to allow a more
|
||||||
concise way of configuring an individual bean or, more powerfully, to define an alternative
|
concise way of configuring an individual bean or, more powerfully, to define an alternative
|
||||||
configuration syntax which more closely matches the problem domain and hides the underlying
|
configuration syntax which more closely matches the problem domain and hides the underlying
|
||||||
@@ -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>
|
||||||
@@ -128,7 +129,11 @@
|
|||||||
<literal><http></literal> element is the parent for all web-related namespace
|
<literal><http></literal> element is the parent for all web-related namespace
|
||||||
functionality. The <literal><intercept-url></literal> element defines a
|
functionality. The <literal><intercept-url></literal> element defines a
|
||||||
<literal>pattern</literal> which is matched against the URLs of incoming requests using an
|
<literal>pattern</literal> which is matched against the URLs of incoming requests using an
|
||||||
ant path style syntax. The <literal>access</literal> attribute defines the access
|
ant path style syntax<footnote>
|
||||||
|
<para>See the section on <link xlink:href="#request-matching">Request
|
||||||
|
Matching</link> in the Web Application Infrastructure chapter for more details
|
||||||
|
on how matches are actually performed.</para>
|
||||||
|
</footnote>. The <literal>access</literal> attribute defines the access
|
||||||
requirements for requests matching the given pattern. With the default configuration, this
|
requirements for requests matching the given pattern. With the default configuration, this
|
||||||
is typically a comma-separated list of roles, one of which a user must have to be allowed to
|
is typically a comma-separated list of roles, one of which a user must have to be allowed to
|
||||||
make the request. The prefix <quote>ROLE_</quote> is a marker which indicates that a simple
|
make the request. The prefix <quote>ROLE_</quote> is a marker which indicates that a simple
|
||||||
@@ -329,8 +334,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 +523,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 +629,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.
|
||||||
|
|||||||
@@ -143,7 +143,7 @@
|
|||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="rememberMeAuthenticationProvider" class=
|
<bean id="rememberMeAuthenticationProvider" class=
|
||||||
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationProvider">
|
"org.springframework.security.authentication.rememberme.RememberMeAuthenticationProvider">
|
||||||
<property name="key" value="springRocks"/>
|
<property name="key" value="springRocks"/>
|
||||||
</bean>
|
</bean>
|
||||||
]]>
|
]]>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user