Compare commits
157 Commits
6.2.8
...
3.0.7.RELEASE
| Author | SHA1 | Date | |
|---|---|---|---|
| 714ee3e960 | |||
| ee74c4ced2 | |||
| 102027a44c | |||
| 799a43d72e | |||
| 3dc4158f7d | |||
| 62f70f17ff | |||
| 4b0fbe1606 | |||
| a8bce41876 | |||
| cea1f4499f | |||
| c19a5ffd73 | |||
| 594ee9515e | |||
| a087e828a6 | |||
| 5238ba0e26 | |||
| 887e3361d2 | |||
| a24570ae06 | |||
| ba719dc0e1 | |||
| 28e70db8f2 | |||
| 84031c6001 | |||
| ca2af8bc59 | |||
| 6f59805ef3 | |||
| f359bed596 | |||
| 0f1ae574ab | |||
| cb7a94af88 | |||
| 9b8d2719a6 | |||
| 73b67da3a8 | |||
| b5546d1d29 | |||
| 70ca0d1a39 | |||
| 7a5a062cd0 | |||
| 977da0da1f | |||
| dfbc938e99 | |||
| d5f1f6cbff | |||
| a2cdbab50c | |||
| 1833b234a5 | |||
| 6c97fccc91 | |||
| 2888f2b86f | |||
| 04d42211b1 | |||
| 6a87a5f1a1 | |||
| f6b21880a2 | |||
| 198d5d0482 | |||
| acee3e2593 | |||
| b87dabe1ac | |||
| f509193604 | |||
| 11a091f051 | |||
| 8e48658efb | |||
| afd556412e | |||
| 187a530760 | |||
| 1b6587a5d4 | |||
| ece824fca2 | |||
| e3644e2d27 | |||
| b3943ac268 | |||
| 537d8f108a | |||
| d0bada2bad | |||
| 952af853ac | |||
| 4dea140331 | |||
| bb3a973fcb | |||
| 522e8db5da | |||
| 8f71f6febf | |||
| 69a1fb76d3 | |||
| 156a6924fa | |||
| d53db3ba13 | |||
| 90304f64c6 | |||
| 6349359b77 | |||
| e80853b698 | |||
| 82d105cbc3 | |||
| e88f47a96a | |||
| 979ea63980 | |||
| 0bdc9c176b | |||
| 80fd238c3a | |||
| 5c597c8cde | |||
| ec7b9703a6 | |||
| 71b2af31ee | |||
| fc75b69ab8 | |||
| 6141ef79b3 | |||
| 3cfe23f60d | |||
| 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
|
||||
.settings/
|
||||
build/
|
||||
out/
|
||||
intellij/
|
||||
*.ipr
|
||||
*.iws
|
||||
*.log
|
||||
*.log.1
|
||||
.DS_Store
|
||||
*.iml
|
||||
.gradle/
|
||||
gradle.properties
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
@@ -5,7 +5,6 @@ dependencies {
|
||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-core:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion"
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.7.RELEASE</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
||||
|
||||
logger.debug("Denying access");
|
||||
|
||||
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
|
||||
throw new AccessDeniedException(messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
|
||||
new Object[] {authentication.getName(), returnedObject},
|
||||
"Authentication {0} has NO permissions to the domain object {1}"));
|
||||
}
|
||||
|
||||
@@ -379,15 +379,15 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
if (obj instanceof AclImpl) {
|
||||
AclImpl rhs = (AclImpl) obj;
|
||||
if (this.aces.equals(rhs.aces)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl !=null && this.parentAcl.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity != null && this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null) || (this.id != null && this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null) || (this.owner != null && this.owner.equals(rhs.owner))) {
|
||||
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||
return true;
|
||||
}
|
||||
if (this.loadedSids.size() == rhs.loadedSids.size()) {
|
||||
if (this.loadedSids != null && (this.loadedSids.size() == rhs.loadedSids.size())) {
|
||||
for (int i = 0; i < this.loadedSids.size(); i++) {
|
||||
if (!this.loadedSids.get(i).equals(rhs.loadedSids.get(i))) {
|
||||
return false;
|
||||
|
||||
@@ -504,6 +504,16 @@ public class AclImplTests {
|
||||
acl.deleteAce(1);
|
||||
}
|
||||
|
||||
// SEC-1795
|
||||
@Test
|
||||
public void changingParentIsSuccessful() throws Exception {
|
||||
AclImpl parentAcl = new AclImpl(objectIdentity, 1L, mockAuthzStrategy, mockAuditLogger);
|
||||
AclImpl childAcl = new AclImpl(objectIdentity, 2L, mockAuthzStrategy, mockAuditLogger);
|
||||
AclImpl changeParentAcl = new AclImpl(objectIdentity, 3L, mockAuthzStrategy, mockAuditLogger);
|
||||
|
||||
childAcl.setParent(parentAcl);
|
||||
childAcl.setParent(changeParentAcl);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
|
||||
+3
-2
@@ -1,3 +1,5 @@
|
||||
Implementation-Title: org.springframework.security.acls
|
||||
Implementation-Version: ${version}
|
||||
Bundle-SymbolicName: org.springframework.security.acls
|
||||
Bundle-Name: Spring Security Acls
|
||||
Bundle-Vendor: SpringSource
|
||||
@@ -17,5 +19,4 @@ Import-Template:
|
||||
org.springframework.transaction.support.*;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,
|
||||
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>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.7.RELEASE</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<name>Spring Security - Aspects</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
@@ -22,7 +18,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.7.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
@@ -39,12 +35,12 @@
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.5</version>
|
||||
<version>1.6.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
<version>1.6.5</version>
|
||||
<version>1.6.8</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
|
||||
+18
-8
@@ -2,11 +2,12 @@ package org.springframework.security.access.intercept.aspectj.aspect;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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.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+.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @since 1.0
|
||||
* @version $Id$
|
||||
* @author Luke Taylor
|
||||
* @since 3.1
|
||||
*/
|
||||
public aspect AnnotationSecurityAspect implements InitializingBean {
|
||||
|
||||
@@ -34,11 +35,19 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
|
||||
private pointcut executionOfSecuredMethod() :
|
||||
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() :
|
||||
executionOfAnyPublicMethodInAtSecuredType() ||
|
||||
executionOfSecuredMethod();
|
||||
executionOfSecuredMethod() ||
|
||||
executionOfPrePostAnnotatedMethod();
|
||||
|
||||
private AspectJSecurityInterceptor securityInterceptor;
|
||||
private AspectJMethodSecurityInterceptor securityInterceptor;
|
||||
|
||||
Object around(): securedMethodExecution() {
|
||||
if (this.securityInterceptor == null) {
|
||||
@@ -54,13 +63,14 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
|
||||
return this.securityInterceptor.invoke(thisJoinPoint, callback);
|
||||
}
|
||||
|
||||
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
|
||||
public void setSecurityInterceptor(AspectJMethodSecurityInterceptor securityInterceptor) {
|
||||
this.securityInterceptor = securityInterceptor;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.securityInterceptor == null)
|
||||
if (this.securityInterceptor == null) {
|
||||
throw new IllegalArgumentException("securityInterceptor required");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package org.springframework.security.access.intercept.aspectj.aspect;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
|
||||
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
||||
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0.3
|
||||
*/
|
||||
public class AnnotationSecurityAspectTests {
|
||||
private @Mock AccessDecisionManager adm;
|
||||
private @Mock AuthenticationManager authman;
|
||||
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
|
||||
// private TestingAuthenticationToken bob = new TestingAuthenticationToken("bob", "", "ROLE_B");
|
||||
private AspectJMethodSecurityInterceptor interceptor;
|
||||
private SecuredImpl secured = new SecuredImpl();
|
||||
private PrePostSecured prePostSecured = new PrePostSecured();
|
||||
|
||||
@Before
|
||||
public final void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
interceptor = new AspectJMethodSecurityInterceptor();
|
||||
interceptor.setAccessDecisionManager(adm);
|
||||
interceptor.setAuthenticationManager(authman);
|
||||
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
|
||||
AnnotationSecurityAspect secAspect = AnnotationSecurityAspect.aspectOf();
|
||||
secAspect.setSecurityInterceptor(interceptor);
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void securedInterfaceMethodAllowsAllAccess() throws Exception {
|
||||
secured.securedMethod();
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void securedClassMethodDeniesUnauthenticatedAccess() throws Exception {
|
||||
secured.securedClassMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void securedClassMethodAllowsAccessToRoleA() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||
secured.securedClassMethod();
|
||||
}
|
||||
|
||||
// SEC-1262
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
|
||||
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
|
||||
AffirmativeBased adm = new AffirmativeBased();
|
||||
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
|
||||
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
|
||||
adm.setDecisionVoters(Arrays.asList(voters));
|
||||
interceptor.setAccessDecisionManager(adm);
|
||||
prePostSecured.denyAllMethod();
|
||||
}
|
||||
}
|
||||
|
||||
interface SecuredInterface {
|
||||
@Secured("ROLE_X")
|
||||
void securedMethod();
|
||||
}
|
||||
|
||||
class SecuredImpl implements SecuredInterface {
|
||||
|
||||
// Not really secured because AspectJ doesn't inherit annotations from interfaces
|
||||
public void securedMethod() {
|
||||
}
|
||||
|
||||
@Secured("ROLE_A")
|
||||
public void securedClassMethod() {
|
||||
}
|
||||
}
|
||||
|
||||
class PrePostSecured {
|
||||
|
||||
@PreAuthorize("denyAll")
|
||||
public void denyAllMethod() {
|
||||
}
|
||||
}
|
||||
+132
-192
@@ -1,137 +1,35 @@
|
||||
import java.util.jar.Manifest
|
||||
import org.gradle.api.tasks.bundling.GradleManifest
|
||||
|
||||
apply id: 'base'
|
||||
apply plugin: 'base'
|
||||
|
||||
allprojects {
|
||||
version = '3.0.2.RELEASE'
|
||||
version = '3.0.7.RELEASE'
|
||||
releaseBuild = version.endsWith('RELEASE')
|
||||
snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
|
||||
group = 'org.springframework.security'
|
||||
|
||||
repositories {
|
||||
mavenRepo name:'Local', urls:'file:///Users/luke/.m2/repository'
|
||||
mavenRepo name:'Local', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||
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()) {
|
||||
apply id: 'java'
|
||||
|
||||
springVersion = '3.0.1.RELEASE'
|
||||
springLdapVersion = '1.3.0.RELEASE'
|
||||
ehcacheVersion = '1.6.2'
|
||||
aspectjVersion = '1.6.8'
|
||||
apacheDsVersion = '1.5.5'
|
||||
jstlVersion = '1.1.2'
|
||||
jettyVersion = '6.1.22'
|
||||
|
||||
configurations {
|
||||
bundlor
|
||||
provided
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'commons-logging:commons-logging:1.1.1'
|
||||
|
||||
testCompile 'junit:junit:4.7',
|
||||
'org.mockito:mockito-core:1.7',
|
||||
'org.jmock:jmock:2.5.1',
|
||||
'org.jmock:jmock-junit4:2.5.1',
|
||||
'org.hamcrest:hamcrest-core:1.1',
|
||||
'org.hamcrest:hamcrest-library:1.1',
|
||||
"org.springframework:spring-test:$springVersion"
|
||||
bundlor 'com.springsource.bundlor:com.springsource.bundlor.ant:1.0.0.RC1',
|
||||
'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RC1',
|
||||
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RC1'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
compileClasspath = compileClasspath + configurations.provided
|
||||
}
|
||||
test {
|
||||
compileClasspath = compileClasspath + configurations.provided
|
||||
runtimeClasspath = runtimeClasspath + configurations.provided
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea", '-Xms128m', '-Xmx500m', '-XX:MaxPermSize=128m', '-XX:+HeapDumpOnOutOfMemoryError'])
|
||||
}
|
||||
|
||||
task bundlor (dependsOn: compileJava) << {
|
||||
if (!dependsOnTaskDidWork()) {
|
||||
return
|
||||
}
|
||||
ant.taskdef(resource: 'com/springsource/bundlor/ant/antlib.xml', classpath: configurations.bundlor.asPath)
|
||||
File template = new File(projectDir, 'template.mf')
|
||||
mkdir(buildDir, 'bundlor')
|
||||
if (template.exists()) {
|
||||
ant.bundlor(inputPath: sourceSets.main.classesDir, outputPath: "$buildDir/bundlor", manifestTemplatePath: template) {
|
||||
property(name: 'version', value: "$version")
|
||||
property(name: 'spring.version', value: "$springVersion")
|
||||
}
|
||||
// See GRADLE-395 for support for using an existing manifest
|
||||
jar.manifest = new GradleManifest(new Manifest(new File("$buildDir/bundlor/META-INF/MANIFEST.MF").newInputStream()))
|
||||
}
|
||||
}
|
||||
|
||||
jar.dependsOn bundlor
|
||||
configure(javaProjects) {
|
||||
apply from: "$rootDir/gradle/javaprojects.gradle"
|
||||
apply from: "$rootDir/gradle/maven.gradle"
|
||||
}
|
||||
|
||||
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()) {
|
||||
configure(coreModuleProjects) {
|
||||
apply from: "$rootDir/gradle/bundlor.gradle"
|
||||
// Gives better names in structure101 jar diagram
|
||||
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
|
||||
}
|
||||
|
||||
repositories {
|
||||
// Required for ant s3 task
|
||||
mavenRepo name: "s2.com release", urls: "http://repository.springsource.com/maven/bundles/release"
|
||||
configure (aspectjProjects) {
|
||||
apply from: "$rootDir/gradle/aspectj.gradle"
|
||||
}
|
||||
|
||||
configurations {
|
||||
@@ -143,62 +41,75 @@ dependencies {
|
||||
"net.java.dev.jets3t:jets3t:0.6.1"
|
||||
}
|
||||
|
||||
def docsDir = new File(project(':manual').buildDir, 'docs')
|
||||
|
||||
task apidocs(type: Javadoc) {
|
||||
destinationDir = new File(buildDir, 'apidocs')
|
||||
title = "Spring Security $version API"
|
||||
optionsFile = file("$buildDir/tmp/javadoc.options")
|
||||
|
||||
source coreModuleProjects().collect { project ->
|
||||
source coreModuleProjects.collect {project ->
|
||||
project.sourceSets.main.allJava
|
||||
}
|
||||
|
||||
classpath = files(coreModuleProjects().collect { project ->
|
||||
project.sourceSets.main.compileClasspath })
|
||||
classpath = files(coreModuleProjects.collect {project ->
|
||||
project.sourceSets.main.compileClasspath
|
||||
})
|
||||
}
|
||||
|
||||
task apitar(type: Tar, dependsOn: apidocs) {
|
||||
compression = Compression.BZIP2
|
||||
task docSiteLogin(type: Login) {
|
||||
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'
|
||||
remoteDir = remoteDocsDir
|
||||
login = docSiteLogin
|
||||
|
||||
into('apidocs') {
|
||||
from apidocs.destinationDir
|
||||
}
|
||||
}
|
||||
|
||||
task doctar(type: Tar, dependsOn: ':manual:doc') {
|
||||
compression = Compression.BZIP2
|
||||
def docsDir = new File(project(':manual').buildDir, 'docs')
|
||||
|
||||
task uploadDoc(type: TarUpload) {
|
||||
dependsOn ':manual:doc'
|
||||
classifier = 'doc'
|
||||
remoteDir = remoteDocsDir
|
||||
login = docSiteLogin
|
||||
|
||||
into('reference') {
|
||||
from docsDir
|
||||
}
|
||||
}
|
||||
|
||||
def username;
|
||||
def password;
|
||||
task uploadFaq(type: TarUpload) {
|
||||
dependsOn ':faq:docbookHtmlSingle'
|
||||
classifier = 'faq'
|
||||
if (project.hasProperty('remoteSiteDir')) {
|
||||
remoteDir = project.property('remoteSiteDir')
|
||||
}
|
||||
login = docSiteLogin
|
||||
|
||||
task login << {
|
||||
ant.input("Please enter the ssh username for host '$sshHost'", addproperty: "ssh.username")
|
||||
ant.input("Please enter the ssh password '$sshHost'", addproperty: "ssh.password")
|
||||
username = ant.properties['ssh.username']
|
||||
password = ant.properties['ssh.password']
|
||||
def faqDir = new File(project(':faq').buildDir, 'docs')
|
||||
|
||||
into('faq') {
|
||||
from faqDir
|
||||
}
|
||||
}
|
||||
|
||||
task uploadApidocs (dependsOn: login) << {
|
||||
ant.scp(file: apitar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
|
||||
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${apitar.archiveName}")
|
||||
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${apitar.archiveName}")
|
||||
}
|
||||
|
||||
task uploadManual (dependsOn: login) << {
|
||||
ant.scp(file: doctar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
|
||||
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${doctar.archiveName}")
|
||||
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${doctar.archiveName}")
|
||||
}
|
||||
|
||||
task dist (type: Zip) {
|
||||
task dist(type: Zip) {
|
||||
def zipRootDir = "${project.name}-$version"
|
||||
into (zipRootDir) {
|
||||
into(zipRootDir) {
|
||||
into('docs/apidocs') {
|
||||
from apidocs.destinationDir
|
||||
}
|
||||
@@ -206,61 +117,90 @@ task dist (type: Zip) {
|
||||
from docsDir
|
||||
}
|
||||
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-contacts').libsDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dist.dependsOn apidocs, ':manual:doc'
|
||||
dist.dependsOn subprojects.collect { "$it.path:assemble" }
|
||||
|
||||
dist.doLast {
|
||||
ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
|
||||
dist {
|
||||
dependsOn apidocs, ':manual:doc', subprojects.collect { "$it.path:assemble" }
|
||||
doLast {
|
||||
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)
|
||||
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' }
|
||||
}
|
||||
|
||||
def getSampleProjects() {
|
||||
subprojects.findAll {project -> project.name.startsWith('spring-security-samples') }
|
||||
}
|
||||
|
||||
def getItestProjects() {
|
||||
subprojects.findAll {project -> project.name.startsWith('itest') }
|
||||
}
|
||||
|
||||
def getCoreModuleProjects() {
|
||||
javaProjects - sampleProjects - itestProjects - aspectjProjects
|
||||
}
|
||||
|
||||
def getAspectjProjects() {
|
||||
subprojects.findAll {project -> project.name == 'spring-security-aspects' || project.name == 'spring-security-samples-aspectj'}
|
||||
}
|
||||
|
||||
class UploadDist extends DefaultTask {
|
||||
@InputFile
|
||||
File shaFile
|
||||
|
||||
@InputFile
|
||||
File archiveFile
|
||||
|
||||
@Input
|
||||
String archiveName
|
||||
|
||||
@InputFiles
|
||||
def classpath
|
||||
|
||||
@TaskAction
|
||||
def upload() {
|
||||
def accessKey = project.s3AccessKey
|
||||
def secretKey = project.s3SecretAccessKey
|
||||
def version = project.version
|
||||
|
||||
project.ant {
|
||||
taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: classpath.asPath)
|
||||
s3(accessKey: accessKey, secretKey: secretKey) {
|
||||
upload(bucketName: 'dist.springframework.org', file: archiveFile,
|
||||
toFile: releaseType() + "/SEC/${archiveName}", publicRead: 'true') {
|
||||
metadata(name: 'project.name', value: 'Spring Security')
|
||||
metadata(name: 'release.type', value: releaseType())
|
||||
metadata(name: 'bundle.version', value: version)
|
||||
metadata(name: 'package.file.name', value: archiveName)
|
||||
}
|
||||
upload(bucketName: 'dist.springframework.org', file: shaFile,
|
||||
toFile: releaseType() + "/SEC/${archiveName}.sha1", publicRead: 'true')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def releaseType() {
|
||||
if (project.releaseBuild) {
|
||||
'release'
|
||||
} else if (project.snapshotBuild) {
|
||||
'snapshot'
|
||||
} else {
|
||||
'milestone'
|
||||
}
|
||||
upload(bucketName: 'dist.springframework.org', file: shaFile,
|
||||
toFile: releaseType() + "/SEC/${dist.archiveName}.sha1", publicRead: 'true')
|
||||
}
|
||||
}
|
||||
|
||||
def javaProjects() {
|
||||
subprojects.findAll { project -> project.name != 'faq' && project.name != 'manual' }
|
||||
}
|
||||
|
||||
def sampleProjects() {
|
||||
subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
|
||||
}
|
||||
|
||||
def itestProjects() {
|
||||
subprojects.findAll { project -> project.name.startsWith('itest') }
|
||||
}
|
||||
|
||||
def coreModuleProjects() {
|
||||
javaProjects() - sampleProjects() - itestProjects()
|
||||
}
|
||||
|
||||
def releaseType() {
|
||||
if (releaseBuild) {
|
||||
'release'
|
||||
} else if (snapshotBuild) {
|
||||
'snapshot'
|
||||
} else {
|
||||
'milestone'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
apply plugin: 'groovy'
|
||||
|
||||
repositories {
|
||||
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||
mavenCentral()
|
||||
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
def fopDeps = [ 'org.apache.xmlgraphics:fop:0.95-1@jar',
|
||||
'org.apache.xmlgraphics:xmlgraphics-commons:1.3',
|
||||
'org.apache.xmlgraphics:batik-bridge:1.7@jar',
|
||||
'org.apache.xmlgraphics:batik-util:1.7@jar',
|
||||
'org.apache.xmlgraphics:batik-css:1.7@jar',
|
||||
'org.apache.xmlgraphics:batik-dom:1.7',
|
||||
'org.apache.xmlgraphics:batik-svg-dom:1.7@jar',
|
||||
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
|
||||
groovy localGroovy()
|
||||
compile gradleApi(),
|
||||
'org.apache.xerces:resolver:2.9.1',
|
||||
'saxon:saxon:6.5.3',
|
||||
'org.apache.xerces:xercesImpl:2.9.1',
|
||||
fopDeps
|
||||
|
||||
runtime 'net.sf.xslthl:xslthl:2.0.1',
|
||||
'net.sf.docbook:docbook-xsl:1.75.2:ns-resources@zip'
|
||||
}
|
||||
|
||||
task ide(type: Copy) {
|
||||
from configurations.runtime
|
||||
into 'ide'
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
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
|
||||
Login login
|
||||
@Input
|
||||
String host
|
||||
|
||||
TarUpload() {
|
||||
compression = Compression.BZIP2
|
||||
if (project.configurations.findByName('antjsch') == null) {
|
||||
project.configurations.add('antjsch')
|
||||
project.dependencies {
|
||||
antjsch 'org.apache.ant:ant-jsch:1.8.1'
|
||||
}
|
||||
def classpath = project.configurations.antjsch.asPath
|
||||
project.ant {
|
||||
taskdef(name: 'scp', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', classpath: classpath)
|
||||
taskdef(name: 'sshexec', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', classpath: classpath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
this.host = login.host
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores login information for a remote host.
|
||||
*/
|
||||
class Login extends DefaultTask {
|
||||
@Input
|
||||
String host
|
||||
String username
|
||||
String password
|
||||
|
||||
@TaskAction
|
||||
login() {
|
||||
def console = System.console()
|
||||
if (console) {
|
||||
username = console.readLine("\nPlease enter the ssh username for host '$host': ")
|
||||
password = new String(console.readPassword("Please enter the ssh password for '$host': "))
|
||||
} else {
|
||||
logger.error "Unable to access System.console()."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
+4
-4
@@ -2,12 +2,12 @@
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
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-tx:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.jasig.cas:cas-client-core:3.1.9",
|
||||
"net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||
|
||||
provided 'javax.servlet:servlet-api:2.5'
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.7.RELEASE</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-cas-client</artifactId>
|
||||
<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
|
||||
*/
|
||||
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);
|
||||
|
||||
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (credentials == null)
|
||||
|
||||
+19
-13
@@ -54,6 +54,7 @@ import org.springframework.security.web.authentication.AbstractAuthenticationPro
|
||||
* By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
@@ -89,7 +90,13 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
|
||||
throws AuthenticationException {
|
||||
throws AuthenticationException, IOException {
|
||||
// if the request is a proxy request process it and return null to indicate the request has been processed
|
||||
if(isProxyRequest(request)) {
|
||||
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
|
||||
return null;
|
||||
}
|
||||
|
||||
final String username = CAS_STATEFUL_IDENTIFIER;
|
||||
String password = request.getParameter(this.artifactParameter);
|
||||
|
||||
@@ -108,18 +115,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
* Overridden to provide proxying capabilities.
|
||||
*/
|
||||
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
final String requestUri = request.getRequestURI();
|
||||
|
||||
if (CommonUtils.isEmpty(this.proxyReceptorUrl) || !requestUri.endsWith(this.proxyReceptorUrl) || this.proxyGrantingTicketStorage == null) {
|
||||
return super.requiresAuthentication(request, response);
|
||||
}
|
||||
|
||||
try {
|
||||
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
|
||||
return false;
|
||||
} catch (final IOException e) {
|
||||
return super.requiresAuthentication(request, response);
|
||||
}
|
||||
return isProxyRequest(request) || super.requiresAuthentication(request, response);
|
||||
}
|
||||
|
||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||
@@ -134,4 +130,14 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
public final void setServiceProperties(final ServiceProperties serviceProperties) {
|
||||
this.artifactParameter = serviceProperties.getArtifactParameter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is eligible to be processed as a proxy request.
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private boolean isProxyRequest(final HttpServletRequest request) {
|
||||
final String requestUri = request.getRequestURI();
|
||||
return this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl) && requestUri.endsWith(this.proxyReceptorUrl);
|
||||
}
|
||||
}
|
||||
|
||||
+59
@@ -16,7 +16,11 @@
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -30,6 +34,7 @@ import org.springframework.security.core.AuthenticationException;
|
||||
* Tests {@link CasAuthenticationFilter}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class CasAuthenticationFilterTests {
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -67,4 +72,58 @@ public class CasAuthenticationFilterTests {
|
||||
|
||||
filter.attemptAuthentication(new MockHttpServletRequest(), new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationFilterProcessUrl() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI(filter.getFilterProcessesUrl());
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthenticationProxyRequest() {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
assertTrue(filter.requiresAuthentication(request, response));
|
||||
request.setRequestURI("/other");
|
||||
assertFalse(filter.requiresAuthentication(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateProxyUrl() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
assertNull(filter.attemptAuthentication(request, response));
|
||||
}
|
||||
|
||||
// SEC-1592
|
||||
@Test
|
||||
public void testChainNotInvokedForProxy() throws Exception {
|
||||
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
|
||||
request.setRequestURI("/pgtCallback");
|
||||
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
|
||||
filter.setProxyReceptorUrl(request.getRequestURI());
|
||||
|
||||
filter.doFilter(request,response,chain);
|
||||
verifyZeroInteractions(chain);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,3 +1,5 @@
|
||||
Implementation-Title: org.springframework.security.cas
|
||||
Implementation-Version: ${version}
|
||||
Bundle-SymbolicName: org.springframework.security.cas
|
||||
Bundle-Name: Spring Security CAS
|
||||
Bundle-Vendor: SpringSource
|
||||
@@ -18,4 +20,3 @@ Import-Template:
|
||||
org.springframework.util;version="[${spring.version}, 3.1.0)",
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
javax.servlet.*;version="0"
|
||||
|
||||
@@ -5,24 +5,20 @@ compileTestJava.dependsOn(':spring-security-core:compileTestJava')
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
project(':spring-security-web'),
|
||||
"javax.servlet:servlet-api:2.5",
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-core:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion"
|
||||
|
||||
provided "javax.servlet:servlet-api:2.5"
|
||||
|
||||
testCompile project(':spring-security-ldap'),
|
||||
project(':spring-security-openid'),
|
||||
files(this.project(':spring-security-core').sourceSets.test.classesDir),
|
||||
'javax.annotation:jsr250-api:1.0',
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion"
|
||||
}
|
||||
|
||||
task show << {
|
||||
println dependencies
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
pushd src/main/resources/org/springframework/security/config/
|
||||
|
||||
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 ..."
|
||||
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
|
||||
+2
-6
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.7.RELEASE</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
@@ -41,10 +41,6 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
@@ -76,7 +72,7 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.5.10</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -50,4 +50,5 @@ public abstract class Elements {
|
||||
@Deprecated
|
||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||
public static final String HTTP_FIREWALL = "http-firewall";
|
||||
}
|
||||
|
||||
+43
-7
@@ -3,6 +3,8 @@ package org.springframework.security.config;
|
||||
import java.util.HashMap;
|
||||
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.BeanDefinitionHolder;
|
||||
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.http.FilterChainMapBeanDefinitionDecorator;
|
||||
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.ldap.LdapProviderBeanDefinitionParser;
|
||||
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
||||
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
@@ -33,18 +37,44 @@ import org.w3c.dom.Node;
|
||||
* @since 2.0
|
||||
*/
|
||||
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 BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
|
||||
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) {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd schema with Spring Security 3.0." +
|
||||
" Please update your schema declarations to the 3.0 schema.", element);
|
||||
pc.getReaderContext().fatal("You must use a 3.0 schema with Spring Security 3.0." +
|
||||
"(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);
|
||||
BeanDefinitionParser parser = parsers.get(name);
|
||||
|
||||
if (parser == null) {
|
||||
// SEC-1455. Load parsers when required, not just on init().
|
||||
loadParsers();
|
||||
}
|
||||
|
||||
if (parser == null) {
|
||||
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
|
||||
reportMissingWebClasses(name, pc, element);
|
||||
@@ -67,6 +97,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
}
|
||||
|
||||
if (Elements.FILTER_CHAIN_MAP.equals(name)) {
|
||||
if (filterChainMapBDD == null) {
|
||||
loadParsers();
|
||||
}
|
||||
if (filterChainMapBDD == null) {
|
||||
reportMissingWebClasses(name, pc, node);
|
||||
}
|
||||
@@ -91,8 +124,12 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void init() {
|
||||
loadParsers();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void loadParsers() {
|
||||
// Parsers
|
||||
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
|
||||
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.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
||||
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
|
||||
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
|
||||
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
|
||||
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
|
||||
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||
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) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-3.0.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-3\\.0.*xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security\\.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
|
||||
+14
-20
@@ -1,18 +1,16 @@
|
||||
package org.springframework.security.config.authentication;
|
||||
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
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.Elements;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
@@ -22,9 +20,6 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
|
||||
static final String CACHE_REF = "cache-ref";
|
||||
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 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));
|
||||
}
|
||||
|
||||
id = beanId;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext pc)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
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)) {
|
||||
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 (parserContext.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
|
||||
throw new BeanDefinitionStoreException("No id supplied and another " +
|
||||
"bean is already registered as " + 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 {
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
private static final String ATT_REF = "ref";
|
||||
private static final String ATT_ERASE_CREDENTIALS = "erase-credentials";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
|
||||
@@ -72,6 +73,11 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
}
|
||||
|
||||
providerManagerBldr.addPropertyValue("providers", providers);
|
||||
|
||||
if ("true".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
|
||||
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", true);
|
||||
}
|
||||
|
||||
// Add the default event publisher
|
||||
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
|
||||
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.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -21,14 +20,14 @@ import org.w3c.dom.Element;
|
||||
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
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);
|
||||
authProvider.setSource(parserContext.extractSource(element));
|
||||
authProvider.setSource(pc.extractSource(element));
|
||||
|
||||
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
|
||||
|
||||
if (passwordEncoderElt != null) {
|
||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, parserContext);
|
||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, pc);
|
||||
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||
|
||||
if (pep.getSaltSource() != null) {
|
||||
@@ -37,98 +36,39 @@ public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitio
|
||||
}
|
||||
|
||||
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
|
||||
Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
|
||||
Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
|
||||
if (userServiceElt == null) {
|
||||
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);
|
||||
|
||||
if (StringUtils.hasText(ref)) {
|
||||
if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) {
|
||||
parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
|
||||
if (userServiceElt != null) {
|
||||
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.LDAP_USER_SERVICE + "'", element);
|
||||
}
|
||||
|
||||
authProvider.getPropertyValues().add("userDetailsService", new RuntimeBeanReference(ref));
|
||||
} else {
|
||||
// Use the child elements to create the UserDetailsService
|
||||
AbstractUserDetailsServiceBeanDefinitionParser parser = null;
|
||||
Element elt = null;
|
||||
|
||||
if (userServiceElt != null) {
|
||||
elt = userServiceElt;
|
||||
parser = new UserServiceBeanDefinitionParser();
|
||||
} else if (jdbcUserServiceElt != null) {
|
||||
elt = jdbcUserServiceElt;
|
||||
parser = new JdbcUserServiceBeanDefinitionParser();
|
||||
} else if (ldapUserServiceElt != null) {
|
||||
elt = ldapUserServiceElt;
|
||||
parser = new LdapUserServiceBeanDefinitionParser();
|
||||
pc.getDelegate().parseCustomElement(userServiceElt, authProvider);
|
||||
} 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.
|
||||
String cacheRef = elt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
|
||||
String cacheRef = userServiceElt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
|
||||
|
||||
if (StringUtils.hasText(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Ben Alex
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
|
||||
static final String ATT_PASSWORD = "password";
|
||||
@@ -90,7 +91,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
||||
user.addConstructorArgValue(!locked);
|
||||
user.addConstructorArgValue(authorities.getBeanDefinition());
|
||||
|
||||
users.put(userName, user.getBeanDefinition());
|
||||
users.put(userName.toLowerCase(), user.getBeanDefinition());
|
||||
}
|
||||
|
||||
userMap.getPropertyValues().addPropertyValue("users", users);
|
||||
|
||||
+45
-46
@@ -2,11 +2,6 @@ package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.SecurityFilters.*;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
@@ -33,13 +28,16 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
||||
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Handles creation of authentication mechanism filters and related beans for <http> parsing.
|
||||
*
|
||||
@@ -68,6 +66,8 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
private static final String ATT_REF = "ref";
|
||||
|
||||
private static final String ATT_KEY = "key";
|
||||
|
||||
private Element httpElt;
|
||||
private ParserContext pc;
|
||||
|
||||
@@ -81,10 +81,8 @@ final class AuthenticationConfigBuilder {
|
||||
private String rememberMeServicesId;
|
||||
private BeanReference rememberMeProviderRef;
|
||||
private BeanDefinition basicFilter;
|
||||
private BeanDefinition basicEntryPoint;
|
||||
private RootBeanDefinition formFilter;
|
||||
private RuntimeBeanReference basicEntryPoint;
|
||||
private BeanDefinition formEntryPoint;
|
||||
private RootBeanDefinition openIDFilter;
|
||||
private BeanDefinition openIDEntryPoint;
|
||||
private BeanReference openIDProviderRef;
|
||||
private String openIDProviderId;
|
||||
@@ -99,8 +97,6 @@ final class AuthenticationConfigBuilder {
|
||||
private BeanDefinition etf;
|
||||
private BeanReference requestCache;
|
||||
|
||||
final SecureRandom random;
|
||||
|
||||
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
|
||||
String portMapperName) {
|
||||
this.httpElt = element;
|
||||
@@ -108,18 +104,9 @@ final class AuthenticationConfigBuilder {
|
||||
this.portMapperName = portMapperName;
|
||||
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||
this.allowSessionCreation = allowSessionCreation;
|
||||
try {
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Shouldn't happen...
|
||||
throw new RuntimeException("Failed find SHA1PRNG algorithm!");
|
||||
}
|
||||
}
|
||||
|
||||
void createRememberMeFilter(BeanReference authenticationManager) {
|
||||
final String ATT_KEY = "key";
|
||||
final String DEF_KEY = "SpringSecured";
|
||||
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
|
||||
|
||||
@@ -127,10 +114,10 @@ final class AuthenticationConfigBuilder {
|
||||
String key = rememberMeElt.getAttribute(ATT_KEY);
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
key = DEF_KEY;
|
||||
key = createKey();
|
||||
}
|
||||
|
||||
rememberMeFilter = (RootBeanDefinition) new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
|
||||
rememberMeFilter = new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
|
||||
rememberMeFilter.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
|
||||
rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
|
||||
createRememberMeProvider(key);
|
||||
@@ -152,10 +139,11 @@ final class AuthenticationConfigBuilder {
|
||||
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
|
||||
RootBeanDefinition formFilter = null;
|
||||
|
||||
if (formLoginElt != null || autoConfig) {
|
||||
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);
|
||||
formFilter = parser.getFilterBean();
|
||||
@@ -163,7 +151,7 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
|
||||
if (formFilter != null) {
|
||||
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
|
||||
|
||||
@@ -176,10 +164,11 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
||||
RootBeanDefinition openIDFilter = null;
|
||||
|
||||
if (openIDLoginElt != null) {
|
||||
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);
|
||||
openIDFilter = parser.getFilterBean();
|
||||
@@ -214,7 +203,7 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
// Required by login page filter
|
||||
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
|
||||
@@ -256,25 +245,29 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
|
||||
RootBeanDefinition filter = null;
|
||||
RootBeanDefinition entryPoint = null;
|
||||
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
||||
entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(httpElt));
|
||||
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||
String entryPointId;
|
||||
|
||||
String entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, 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.getPropertyValues().addPropertyValue("realmName", realm);
|
||||
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||
basicEntryPoint = new RuntimeBeanReference(entryPointId);
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(entryPointId));
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
basicFilter = filter;
|
||||
basicEntryPoint = entryPoint;
|
||||
}
|
||||
|
||||
void createX509Filter(BeanReference authManager) {
|
||||
@@ -325,7 +318,7 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
|
||||
void createLoginPageFilterIfNeeded() {
|
||||
boolean needLoginPage = formFilter != null || openIDFilter != null;
|
||||
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
|
||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
|
||||
|
||||
@@ -336,11 +329,11 @@ final class AuthenticationConfigBuilder {
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||
|
||||
if (formFilter != null) {
|
||||
if (formFilterId != null) {
|
||||
loginPageFilter.addConstructorArgReference(formFilterId);
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
if (openIDFilterId != null) {
|
||||
loginPageFilter.addConstructorArgReference(openIDFilterId);
|
||||
}
|
||||
|
||||
@@ -370,7 +363,7 @@ final class AuthenticationConfigBuilder {
|
||||
if (anonymousElt != null) {
|
||||
grantedAuthority = anonymousElt.getAttribute("granted-authority");
|
||||
username = anonymousElt.getAttribute("username");
|
||||
key = anonymousElt.getAttribute("key");
|
||||
key = anonymousElt.getAttribute(ATT_KEY);
|
||||
source = pc.extractSource(anonymousElt);
|
||||
}
|
||||
|
||||
@@ -384,7 +377,7 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
// Generate a random key for the Anonymous provider
|
||||
key = Long.toString(random.nextLong());
|
||||
key = createKey();
|
||||
}
|
||||
|
||||
anonymousFilter = new RootBeanDefinition(AnonymousAuthenticationFilter.class);
|
||||
@@ -404,6 +397,11 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
}
|
||||
|
||||
private String createKey() {
|
||||
SecureRandom random = new SecureRandom();
|
||||
return Long.toString(random.nextLong());
|
||||
}
|
||||
|
||||
void createExceptionTranslationFilter() {
|
||||
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
etfBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(httpElt, pc));
|
||||
@@ -499,12 +497,12 @@ final class AuthenticationConfigBuilder {
|
||||
"but not both.", pc.extractSource(openIDLoginElt));
|
||||
}
|
||||
|
||||
if (formFilter != null && openIDLoginPage == null) {
|
||||
if (formFilterId != null && openIDLoginPage == null) {
|
||||
return formEntryPoint;
|
||||
}
|
||||
|
||||
// Otherwise use OpenID if enabled
|
||||
if (openIDFilter != null) {
|
||||
if (openIDFilterId != null) {
|
||||
return openIDEntryPoint;
|
||||
}
|
||||
|
||||
@@ -540,7 +538,8 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
|
||||
void createUserServiceInjector() {
|
||||
BeanDefinitionBuilder userServiceInjector = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
BeanDefinitionBuilder userServiceInjector =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
userServiceInjector.addConstructorArgValue(x509ProviderId);
|
||||
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
|
||||
userServiceInjector.addConstructorArgValue(openIDProviderId);
|
||||
@@ -567,12 +566,12 @@ final class AuthenticationConfigBuilder {
|
||||
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
|
||||
}
|
||||
|
||||
if (formFilter != null) {
|
||||
filters.add(new OrderDecorator(formFilter, FORM_LOGIN_FILTER));
|
||||
if (formFilterId != null) {
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(formFilterId), FORM_LOGIN_FILTER));
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
filters.add(new OrderDecorator(openIDFilter, OPENID_FILTER));
|
||||
if (openIDFilterId != null) {
|
||||
filters.add(new OrderDecorator(new RuntimeBeanReference(openIDFilterId), OPENID_FILTER));
|
||||
}
|
||||
|
||||
if (loginPageGenerationFilter != null) {
|
||||
|
||||
+10
@@ -1,5 +1,8 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||
import static org.springframework.security.config.Elements.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -112,6 +115,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
if (!StringUtils.hasText(access)) {
|
||||
continue;
|
||||
}
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
if(OPT_FILTERS_NONE.equals(filters)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Ambiguous configuration. Cannot contain " + INTERCEPT_URL+"@" + ATT_FILTERS +
|
||||
"=\"" + OPT_FILTERS_NONE + "\" and " + INTERCEPT_URL + "@" + ATT_ACCESS,
|
||||
parserContext.extractSource(urlElt));
|
||||
}
|
||||
|
||||
String path = urlElt.getAttribute(ATT_PATTERN);
|
||||
|
||||
|
||||
+6
-2
@@ -31,7 +31,8 @@ public class FormLoginBeanDefinitionParser {
|
||||
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 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_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
|
||||
@@ -40,17 +41,19 @@ public class FormLoginBeanDefinitionParser {
|
||||
private final String filterClassName;
|
||||
private final BeanReference requestCache;
|
||||
private final BeanReference sessionStrategy;
|
||||
private final boolean allowSessionCreation;
|
||||
|
||||
private RootBeanDefinition filterBean;
|
||||
private RootBeanDefinition entryPointBean;
|
||||
private String loginPage;
|
||||
|
||||
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
||||
BeanReference requestCache, BeanReference sessionStrategy) {
|
||||
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation) {
|
||||
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
||||
this.filterClassName = filterClassName;
|
||||
this.requestCache = requestCache;
|
||||
this.sessionStrategy = sessionStrategy;
|
||||
this.allowSessionCreation = allowSessionCreation;
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext pc) {
|
||||
@@ -135,6 +138,7 @@ public class FormLoginBeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
|
||||
failureHandler.addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
|
||||
}
|
||||
|
||||
|
||||
+16
-3
@@ -2,6 +2,7 @@ package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.SecurityFilters.*;
|
||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||
import static org.springframework.security.config.Elements.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -83,7 +84,7 @@ class HttpConfigurationBuilder {
|
||||
private final List<Element> interceptUrls;
|
||||
|
||||
// Use ManagedMap to allow placeholder resolution
|
||||
private ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap;
|
||||
private ManagedMap<Object, List<BeanMetadataElement>> filterChainMap;
|
||||
|
||||
private BeanDefinition cpf;
|
||||
private BeanDefinition securityContextPersistenceFilter;
|
||||
@@ -109,7 +110,7 @@ class HttpConfigurationBuilder {
|
||||
}
|
||||
|
||||
void parseInterceptUrlsForEmptyFilterChains() {
|
||||
filterChainMap = new ManagedMap<BeanDefinition, List<BeanMetadataElement>>();
|
||||
filterChainMap = new ManagedMap<Object, List<BeanMetadataElement>>();
|
||||
|
||||
for (Element urlElt : interceptUrls) {
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
@@ -393,9 +394,21 @@ class HttpConfigurationBuilder {
|
||||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||
|
||||
if (StringUtils.hasText(requiredChannel)) {
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
if(OPT_FILTERS_NONE.equals(filters)) {
|
||||
pc.getReaderContext().error(
|
||||
"Ambiguous configuration. Cannot contain " + INTERCEPT_URL+"@" + ATT_FILTERS +
|
||||
"=\"" + OPT_FILTERS_NONE + "\" and " + INTERCEPT_URL + "@" + ATT_REQUIRES_CHANNEL,
|
||||
pc.extractSource(urlElt));
|
||||
}
|
||||
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
|
||||
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);
|
||||
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
||||
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
||||
@@ -464,7 +477,7 @@ class HttpConfigurationBuilder {
|
||||
return allowSessionCreation;
|
||||
}
|
||||
|
||||
public ManagedMap<BeanDefinition, List<BeanMetadataElement>> getFilterChainMap() {
|
||||
public ManagedMap<Object, List<BeanMetadataElement>> getFilterChainMap() {
|
||||
return filterChainMap;
|
||||
}
|
||||
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
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 {
|
||||
|
||||
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.factory.config.BeanDefinition;
|
||||
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.parsing.BeanComponentDefinition;
|
||||
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 ATT_REQUIRES_CHANNEL = "requires-channel";
|
||||
static final String ATT_HTTP_METHOD = "method";
|
||||
|
||||
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
|
||||
|
||||
@@ -135,10 +137,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
filterChain.add(od.bean);
|
||||
}
|
||||
|
||||
ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
|
||||
BeanDefinition universalMatch = new RootBeanDefinition(String.class);
|
||||
universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());
|
||||
filterChainMap.put(universalMatch, filterChain);
|
||||
ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
|
||||
filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
|
||||
|
||||
registerFilterChainProxy(pc, filterChainMap, matcher, source);
|
||||
|
||||
@@ -168,6 +168,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
||||
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||
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) {
|
||||
authManager.addPropertyValue("sessionController", concurrencyController);
|
||||
@@ -247,7 +251,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
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)) {
|
||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||
}
|
||||
|
||||
+3
-3
@@ -36,12 +36,12 @@ class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ord
|
||||
"jar file in your application", e);
|
||||
}
|
||||
|
||||
String[] sources = bf.getBeanNamesForType(contextSourceClass);
|
||||
|
||||
String[] sources = bf.getBeanNamesForType(contextSourceClass, false, false);
|
||||
|
||||
if (sources.length == 0) {
|
||||
throw new ApplicationContextException("No BaseLdapPathContextSource instances found. Have you " +
|
||||
"added an <" + Elements.LDAP_SERVER + " /> element to your application context?");
|
||||
"added an <" + Elements.LDAP_SERVER + " /> element to your application context? If you have " +
|
||||
"declared an explicit bean, do not use lazy-init");
|
||||
}
|
||||
|
||||
if (!bf.containsBean(BeanIds.CONTEXT_SOURCE) && defaultNameRequired) {
|
||||
|
||||
+26
-6
@@ -37,6 +37,7 @@ import org.springframework.security.access.expression.method.ExpressionBasedPreI
|
||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
|
||||
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_PREPOST = "pre-post-annotations";
|
||||
private static final String ATT_REF = "ref";
|
||||
private static final String ATT_MODE = "mode";
|
||||
private static final String ATT_ADVICE_ORDER = "order";
|
||||
|
||||
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 useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
|
||||
boolean useAspectJ = "aspectj".equals(element.getAttribute(ATT_MODE));
|
||||
|
||||
BeanDefinition preInvocationVoter = null;
|
||||
ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>();
|
||||
|
||||
@@ -165,6 +169,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
|
||||
|
||||
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.
|
||||
BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
||||
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);
|
||||
|
||||
BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId,
|
||||
metadataSource, afterInvocationProviders, source);
|
||||
metadataSource, afterInvocationProviders, source, useAspectJ);
|
||||
|
||||
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
|
||||
if (useAspectJ) {
|
||||
BeanDefinitionBuilder aspect =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
|
||||
aspect.setFactoryMethod("aspectOf");
|
||||
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
aspect.addPropertyValue("securityInterceptor", interceptor);
|
||||
String id = pc.getReaderContext().registerWithGeneratedName(aspect.getBeanDefinition());
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(aspect.getBeanDefinition(), id));
|
||||
} else {
|
||||
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
|
||||
}
|
||||
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
|
||||
pc.popAndRegisterContainingComponent();
|
||||
|
||||
return null;
|
||||
@@ -284,12 +300,16 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
||||
}
|
||||
|
||||
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId,
|
||||
String runAsManagerId, BeanReference metadataSource, List<BeanMetadataElement> afterInvocationProviders, Object source) {
|
||||
BeanDefinitionBuilder bldr = BeanDefinitionBuilder.rootBeanDefinition(MethodSecurityInterceptor.class);
|
||||
String runAsManagerId, BeanReference metadataSource,
|
||||
List<BeanMetadataElement> afterInvocationProviders, Object source, boolean useAspectJ) {
|
||||
BeanDefinitionBuilder bldr =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(useAspectJ ?
|
||||
AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class);
|
||||
bldr.getRawBeanDefinition().setSource(source);
|
||||
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
|
||||
bldr.addPropertyValue("securityMetadataSource", metadataSource);
|
||||
|
||||
if (StringUtils.hasText(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.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.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
@@ -64,16 +65,16 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
|
||||
interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
// Lookup parent bean information
|
||||
Element parent = (Element) node.getParentNode();
|
||||
String parentBeanClass = parent.getAttribute("class");
|
||||
parent = null;
|
||||
String parentBeanClass = ((Element) node.getParentNode()).getAttribute("class");
|
||||
|
||||
// Parse the included methods
|
||||
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) {
|
||||
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
|
||||
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);
|
||||
|
||||
+16
-13
@@ -1,11 +1,7 @@
|
||||
package org.springframework.security.config.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -44,15 +40,16 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
|
||||
|
||||
private Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
||||
private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
||||
private PointcutParser parser;
|
||||
private final Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
||||
private final MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
||||
private final Set<PointcutExpression> pointCutExpressions = new LinkedHashSet<PointcutExpression>();
|
||||
private final PointcutParser parser;
|
||||
private final Set<String> processedBeans = new HashSet<String>();
|
||||
|
||||
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
||||
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 {
|
||||
if (processedBeans.contains(beanName)) {
|
||||
// We already have the metadata for this bean
|
||||
return bean;
|
||||
}
|
||||
|
||||
// Obtain methods for the present bean
|
||||
Method[] methods;
|
||||
try {
|
||||
@@ -88,10 +90,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
|
||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
for (String ex : pointcutMap.keySet()) {
|
||||
// Parse the presented AspectJ pointcut expression
|
||||
PointcutExpression expression = parser.parsePointcutExpression(ex);
|
||||
|
||||
for (PointcutExpression expression : pointCutExpressions) {
|
||||
// Try for the bean class directly
|
||||
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
|
||||
@@ -100,6 +99,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
processedBeans.add(beanName);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
@@ -134,6 +135,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
Assert.notNull(definition, "A List of ConfigAttributes is required");
|
||||
pointcutExpression = replaceBooleanOperators(pointcutExpression);
|
||||
pointcutMap.put(pointcutExpression, definition);
|
||||
// Parse the presented AspectJ pointcut expression and add it to the cache
|
||||
pointCutExpressions.add(parser.parsePointcutExpression(pointcutExpression));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
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.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.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
|
||||
|
||||
+1381
File diff suppressed because it is too large
Load Diff
+107
-97
@@ -8,7 +8,7 @@ start = http | ldap-server | authentication-provider | ldap-authentication-provi
|
||||
hash =
|
||||
## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.
|
||||
attribute hash {"plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
|
||||
base64 =
|
||||
base64 =
|
||||
## Whether a string should be base64 encoded
|
||||
attribute base64 {"true" | "false"}
|
||||
path-type =
|
||||
@@ -20,9 +20,9 @@ port =
|
||||
url =
|
||||
## Specifies a URL.
|
||||
attribute url { xsd:token }
|
||||
id =
|
||||
id =
|
||||
## A bean identifier, used for referring to the bean elsewhere in the context.
|
||||
attribute id {xsd:ID}
|
||||
attribute id {xsd:ID}
|
||||
ref =
|
||||
## Defines a reference to a Spring bean Id.
|
||||
attribute ref {xsd:token}
|
||||
@@ -35,47 +35,47 @@ user-service-ref =
|
||||
## A reference to a user-service (or UserDetailsService bean) Id
|
||||
attribute user-service-ref {xsd:token}
|
||||
|
||||
data-source-ref =
|
||||
data-source-ref =
|
||||
## A reference to a DataSource bean
|
||||
attribute data-source-ref {xsd:token}
|
||||
|
||||
password-encoder =
|
||||
attribute data-source-ref {xsd:token}
|
||||
|
||||
password-encoder =
|
||||
## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.
|
||||
element password-encoder {password-encoder.attlist, salt-source?}
|
||||
element password-encoder {password-encoder.attlist, salt-source?}
|
||||
password-encoder.attlist &=
|
||||
ref | (hash? & base64?)
|
||||
|
||||
|
||||
salt-source =
|
||||
## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.
|
||||
element salt-source {user-property | system-wide | ref}
|
||||
user-property =
|
||||
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
|
||||
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
|
||||
attribute user-property {xsd:token}
|
||||
system-wide =
|
||||
## A single value that will be used as the salt for a password encoder.
|
||||
## A single value that will be used as the salt for a password encoder.
|
||||
attribute system-wide {xsd:token}
|
||||
|
||||
|
||||
boolean = "true" | "false"
|
||||
|
||||
role-prefix =
|
||||
## A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.
|
||||
attribute role-prefix {xsd:token}
|
||||
|
||||
|
||||
use-expressions =
|
||||
## Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted.
|
||||
## Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted.
|
||||
attribute use-expressions {boolean}
|
||||
|
||||
ldap-server =
|
||||
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
|
||||
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
|
||||
element ldap-server {ldap-server.attlist}
|
||||
ldap-server.attlist &= id?
|
||||
ldap-server.attlist &= (url | port)?
|
||||
ldap-server.attlist &=
|
||||
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
|
||||
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
|
||||
attribute manager-dn {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## The password for the manager DN.
|
||||
attribute manager-password {xsd:string}?
|
||||
attribute manager-password {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## Explicitly specifies an ldif file resource to load into an embedded LDAP server
|
||||
attribute ldif { xsd:string }?
|
||||
@@ -84,14 +84,14 @@ ldap-server.attlist &=
|
||||
attribute root { xsd:string }?
|
||||
|
||||
ldap-server-ref-attribute =
|
||||
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
|
||||
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
|
||||
attribute server-ref {xsd:token}
|
||||
|
||||
|
||||
group-search-filter-attribute =
|
||||
group-search-filter-attribute =
|
||||
## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
|
||||
attribute group-search-filter {xsd:token}
|
||||
group-search-base-attribute =
|
||||
group-search-base-attribute =
|
||||
## Search base for group membership searches. Defaults to "" (searching from the root).
|
||||
attribute group-search-base {xsd:token}
|
||||
user-search-filter-attribute =
|
||||
@@ -103,7 +103,7 @@ user-search-base-attribute =
|
||||
group-role-attribute-attribute =
|
||||
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".
|
||||
attribute group-role-attribute {xsd:token}
|
||||
user-details-class-attribute =
|
||||
user-details-class-attribute =
|
||||
## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object
|
||||
attribute user-details-class {"person" | "inetOrgPerson"}
|
||||
user-context-mapper-attribute =
|
||||
@@ -113,7 +113,7 @@ user-context-mapper-attribute =
|
||||
|
||||
ldap-user-service =
|
||||
element ldap-user-service {ldap-us.attlist}
|
||||
ldap-us.attlist &= id?
|
||||
ldap-us.attlist &= id?
|
||||
ldap-us.attlist &=
|
||||
ldap-server-ref-attribute?
|
||||
ldap-us.attlist &=
|
||||
@@ -144,7 +144,7 @@ ldap-ap.attlist &=
|
||||
user-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-search-base-attribute?
|
||||
ldap-ap.attlist &=
|
||||
ldap-ap.attlist &=
|
||||
group-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-role-attribute-attribute?
|
||||
@@ -159,7 +159,7 @@ ldap-ap.attlist &=
|
||||
password-compare-element =
|
||||
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user
|
||||
element password-compare {password-compare.attlist, password-encoder?}
|
||||
|
||||
|
||||
password-compare.attlist &=
|
||||
## The attribute in the directory which contains the user password. Defaults to "userPassword".
|
||||
attribute password-attribute {xsd:token}?
|
||||
@@ -187,7 +187,7 @@ protect.attlist &=
|
||||
|
||||
global-method-security =
|
||||
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250.
|
||||
element global-method-security {global-method-security.attlist, (pre-post-annotation-handling | expression-handler)?, protect-pointcut*, after-invocation-provider*}
|
||||
element global-method-security {global-method-security.attlist, (pre-post-annotation-handling | expression-handler)?, protect-pointcut*, after-invocation-provider*}
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled".
|
||||
attribute pre-post-annotations {"disabled" | "enabled" }?
|
||||
@@ -208,26 +208,29 @@ global-method-security.attlist &=
|
||||
attribute order {xsd:token}?
|
||||
global-method-security.attlist &=
|
||||
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 =
|
||||
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
|
||||
element after-invocation-provider {ref}
|
||||
element after-invocation-provider {ref}
|
||||
|
||||
pre-post-annotation-handling =
|
||||
## Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled.
|
||||
element pre-post-annotation-handling {invocation-attribute-factory, pre-invocation-advice, post-invocation-advice}
|
||||
|
||||
## Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled.
|
||||
element pre-post-annotation-handling {invocation-attribute-factory, pre-invocation-advice, post-invocation-advice}
|
||||
|
||||
invocation-attribute-factory =
|
||||
## Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods.
|
||||
## Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods.
|
||||
element invocation-attribute-factory {ref}
|
||||
|
||||
|
||||
pre-invocation-advice =
|
||||
element pre-invocation-advice {ref}
|
||||
|
||||
post-invocation-advice =
|
||||
element post-invocation-advice {ref}
|
||||
|
||||
|
||||
|
||||
expression-handler =
|
||||
## Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied.
|
||||
element expression-handler {ref}
|
||||
@@ -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"
|
||||
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 =
|
||||
## Container element for HTTP security configuration
|
||||
@@ -254,9 +260,9 @@ http.attlist &=
|
||||
http.attlist &=
|
||||
## Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set using security-context-repository-ref, then the only value which can be set is "always". Otherwise the session creation behaviour will be determined by the repository bean implementation.
|
||||
attribute create-session {"ifRequired" | "always" | "never" }?
|
||||
http.attlist &=
|
||||
http.attlist &=
|
||||
## A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests.
|
||||
attribute security-context-repository-ref {xsd:token}?
|
||||
attribute security-context-repository-ref {xsd:token}?
|
||||
http.attlist &=
|
||||
## The path format used to define the paths in child elements.
|
||||
path-type?
|
||||
@@ -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".
|
||||
attribute realm {xsd:token}?
|
||||
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}?
|
||||
http.attlist &=
|
||||
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
||||
@@ -282,17 +288,17 @@ http.attlist &=
|
||||
## Deprecated in favour of the access-denied-handler element.
|
||||
attribute access-denied-page {xsd:token}?
|
||||
http.attlist &=
|
||||
##
|
||||
attribute disable-url-rewriting {boolean}?
|
||||
##
|
||||
attribute disable-url-rewriting {boolean}?
|
||||
|
||||
|
||||
access-denied-handler =
|
||||
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
|
||||
|
||||
access-denied-handler =
|
||||
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
|
||||
element access-denied-handler {access-denied-handler.attlist, empty}
|
||||
access-denied-handler.attlist &= (ref | access-denied-handler-page)
|
||||
|
||||
access-denied-handler-page =
|
||||
## The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access.
|
||||
## The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access.
|
||||
attribute error-page {xsd:token}
|
||||
|
||||
intercept-url =
|
||||
@@ -316,16 +322,16 @@ intercept-url.attlist &=
|
||||
attribute requires-channel {xsd:token}?
|
||||
|
||||
logout =
|
||||
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
|
||||
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
|
||||
element logout {logout.attlist, empty}
|
||||
logout.attlist &=
|
||||
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
|
||||
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
|
||||
attribute logout-url {xsd:token}?
|
||||
logout.attlist &=
|
||||
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
|
||||
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
|
||||
attribute logout-success-url {xsd:token}?
|
||||
logout.attlist &=
|
||||
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
|
||||
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
|
||||
attribute invalidate-session {boolean}?
|
||||
logout.attlist &=
|
||||
## A reference to a LogoutSuccessHandler implementation which will be used to determine the destination to which the user is taken after logging out.
|
||||
@@ -346,8 +352,8 @@ form-login.attlist &=
|
||||
## The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application.
|
||||
attribute default-target-url {xsd:token}?
|
||||
form-login.attlist &=
|
||||
## Whether the user should always be redirected to the default-target-url after login.
|
||||
attribute always-use-default-target {boolean}?
|
||||
## Whether the user should always be redirected to the default-target-url after login.
|
||||
attribute always-use-default-target {boolean}?
|
||||
form-login.attlist &=
|
||||
## The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested.
|
||||
attribute login-page {xsd:token}?
|
||||
@@ -362,7 +368,7 @@ form-login.attlist &=
|
||||
attribute authentication-failure-handler-ref {xsd:token}?
|
||||
|
||||
|
||||
openid-login =
|
||||
openid-login =
|
||||
## Sets up form login for authentication with an Open ID identity
|
||||
element openid-login {form-login.attlist, user-service-ref?, attribute-exchange?}
|
||||
|
||||
@@ -380,7 +386,7 @@ openid-attribute.attlist &=
|
||||
attribute required {boolean}?
|
||||
openid-attribute.attlist &=
|
||||
attribute count {xsd:int}?
|
||||
|
||||
|
||||
|
||||
filter-chain-map =
|
||||
## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
|
||||
@@ -397,7 +403,7 @@ filter-chain.attlist &=
|
||||
attribute filters {xsd:token}
|
||||
|
||||
filter-security-metadata-source =
|
||||
## Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
|
||||
## Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
|
||||
element filter-security-metadata-source {fsmds.attlist, intercept-url+}
|
||||
fsmds.attlist &=
|
||||
use-expressions?
|
||||
@@ -410,15 +416,18 @@ fsmds.attlist &=
|
||||
## as for http element
|
||||
path-type?
|
||||
|
||||
filter-invocation-definition-source =
|
||||
filter-invocation-definition-source =
|
||||
## Deprecated synonym for filter-security-metadata-source
|
||||
element filter-invocation-definition-source {fsmds.attlist, intercept-url+}
|
||||
|
||||
http-basic =
|
||||
## 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?}
|
||||
|
||||
session-management.attlist &=
|
||||
@@ -431,18 +440,18 @@ session-management.attlist &=
|
||||
## Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter
|
||||
attribute session-authentication-strategy-ref {xsd:token}?
|
||||
session-management.attlist &=
|
||||
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
|
||||
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
|
||||
attribute session-authentication-error-url {xsd:token}?
|
||||
|
||||
|
||||
concurrency-control =
|
||||
|
||||
|
||||
concurrency-control =
|
||||
## Enables concurrent session control, limiting the number of authenticated sessions a user may have at the same time.
|
||||
element concurrency-control {concurrency-control.attlist, empty}
|
||||
|
||||
|
||||
concurrency-control.attlist &=
|
||||
## The maximum number of sessions a single authenticated user can have open at the same time. Defaults to "1".
|
||||
attribute max-sessions {xsd:positiveInteger}?
|
||||
concurrency-control.attlist &=
|
||||
concurrency-control.attlist &=
|
||||
## The URL a user will be redirected to if they attempt to use a session which has been "expired" because they have logged in again.
|
||||
attribute expired-url {xsd:token}?
|
||||
concurrency-control.attlist &=
|
||||
@@ -457,21 +466,21 @@ concurrency-control.attlist &=
|
||||
|
||||
|
||||
remember-me =
|
||||
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
|
||||
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
|
||||
element remember-me {remember-me.attlist}
|
||||
remember-me.attlist &=
|
||||
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.
|
||||
attribute key {xsd:token}?
|
||||
|
||||
|
||||
remember-me.attlist &=
|
||||
(token-repository-ref | remember-me-data-source-ref | remember-me-services-ref)
|
||||
|
||||
remember-me.attlist &=
|
||||
user-service-ref?
|
||||
|
||||
|
||||
remember-me.attlist &=
|
||||
## Exports the internally defined RememberMeServices as a bean alias, allowing it to be used by other beans in the application context.
|
||||
attribute services-alias {xsd:token}?
|
||||
attribute services-alias {xsd:token}?
|
||||
|
||||
remember-me.attlist &=
|
||||
## Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS. Defaults to false.
|
||||
@@ -480,15 +489,15 @@ remember-me.attlist &=
|
||||
remember-me.attlist &=
|
||||
## The period (in seconds) for which the remember-me cookie should be valid.
|
||||
attribute token-validity-seconds {xsd:integer}?
|
||||
|
||||
|
||||
token-repository-ref =
|
||||
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
|
||||
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
|
||||
attribute token-repository-ref {xsd:token}
|
||||
remember-me-services-ref =
|
||||
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
|
||||
remember-me-services-ref =
|
||||
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
|
||||
attribute services-ref {xsd:token}?
|
||||
remember-me-data-source-ref =
|
||||
## DataSource bean for the database that contains the token repository schema.
|
||||
## DataSource bean for the database that contains the token repository schema.
|
||||
data-source-ref
|
||||
|
||||
anonymous =
|
||||
@@ -497,56 +506,59 @@ anonymous =
|
||||
anonymous.attlist &=
|
||||
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".
|
||||
attribute key {xsd:token}?
|
||||
anonymous.attlist &=
|
||||
anonymous.attlist &=
|
||||
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
|
||||
attribute username {xsd:token}?
|
||||
anonymous.attlist &=
|
||||
## The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS".
|
||||
attribute granted-authority {xsd:token}?
|
||||
anonymous.attlist &=
|
||||
## With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property.
|
||||
## With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property.
|
||||
attribute enabled {boolean}?
|
||||
|
||||
|
||||
port-mappings =
|
||||
port-mappings =
|
||||
## Defines the list of mappings between http and https ports for use in redirects
|
||||
element port-mappings {port-mappings.attlist, port-mapping+}
|
||||
|
||||
port-mappings.attlist &= empty
|
||||
|
||||
port-mapping =
|
||||
port-mapping =
|
||||
element port-mapping {http-port, https-port}
|
||||
|
||||
|
||||
http-port = attribute http {xsd:token}
|
||||
|
||||
https-port = attribute https {xsd:token}
|
||||
|
||||
|
||||
x509 =
|
||||
x509 =
|
||||
## Adds support for X.509 client authentication.
|
||||
element x509 {x509.attlist}
|
||||
x509.attlist &=
|
||||
x509.attlist &=
|
||||
## The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),".
|
||||
attribute subject-principal-regex {xsd:token}?
|
||||
x509.attlist &=
|
||||
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
|
||||
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
|
||||
user-service-ref?
|
||||
|
||||
authentication-manager =
|
||||
## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans.
|
||||
## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans.
|
||||
element authentication-manager {authman.attlist & authentication-provider* & ldap-authentication-provider*}
|
||||
authman.attlist &=
|
||||
## The alias you wish to use for the AuthenticationManager bean
|
||||
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 =
|
||||
## 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.
|
||||
element authentication-provider {ap.attlist & any-user-service & password-encoder?}
|
||||
ap.attlist &=
|
||||
## Specifies a reference to a separately configured AuthenticationProvider instance which should be registered within the AuthenticationManager.
|
||||
ref?
|
||||
## Specifies a reference to a separately configured AuthenticationProvider instance which should be registered within the AuthenticationManager.
|
||||
ref?
|
||||
ap.attlist &=
|
||||
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
|
||||
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
|
||||
user-service-ref?
|
||||
|
||||
user-service =
|
||||
@@ -554,31 +566,31 @@ user-service =
|
||||
element user-service {id? & (properties-file | (user*))}
|
||||
properties-file =
|
||||
attribute properties {xsd:token}?
|
||||
|
||||
|
||||
user =
|
||||
## Represents a user in the application.
|
||||
## Represents a user in the application.
|
||||
element user {user.attlist, empty}
|
||||
user.attlist &=
|
||||
## The username assigned to the user.
|
||||
## The username assigned to the user.
|
||||
attribute name {xsd:token}
|
||||
user.attlist &=
|
||||
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty.
|
||||
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty.
|
||||
attribute password {xsd:string}?
|
||||
user.attlist &=
|
||||
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
|
||||
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
|
||||
attribute authorities {xsd:token}
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as locked and unusable.
|
||||
## Can be set to "true" to mark an account as locked and unusable.
|
||||
attribute locked {boolean}?
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as disabled and unusable.
|
||||
## Can be set to "true" to mark an account as disabled and unusable.
|
||||
attribute disabled {boolean}?
|
||||
|
||||
jdbc-user-service =
|
||||
## Causes creation of a JDBC-based UserDetailsService.
|
||||
element jdbc-user-service {id? & jdbc-user-service.attlist}
|
||||
## Causes creation of a JDBC-based UserDetailsService.
|
||||
element jdbc-user-service {id? & jdbc-user-service.attlist}
|
||||
jdbc-user-service.attlist &=
|
||||
## The bean ID of the DataSource which provides the required tables.
|
||||
## The bean ID of the DataSource which provides the required tables.
|
||||
attribute data-source-ref {xsd:token}
|
||||
jdbc-user-service.attlist &=
|
||||
cache-ref?
|
||||
@@ -593,12 +605,12 @@ jdbc-user-service.attlist &=
|
||||
attribute group-authorities-by-username-query {xsd:token}?
|
||||
jdbc-user-service.attlist &=
|
||||
role-prefix?
|
||||
|
||||
|
||||
|
||||
any-user-service = user-service | jdbc-user-service | ldap-user-service
|
||||
|
||||
|
||||
custom-filter =
|
||||
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain.
|
||||
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain.
|
||||
element custom-filter {custom-filter.attlist}
|
||||
|
||||
custom-filter.attlist &=
|
||||
@@ -608,7 +620,7 @@ custom-filter.attlist &=
|
||||
(after | before | position)
|
||||
|
||||
after =
|
||||
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
|
||||
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
|
||||
attribute after {named-security-filter}
|
||||
before =
|
||||
## The filter immediately before which the custom-filter should be placed in the chain
|
||||
@@ -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"
|
||||
|
||||
|
||||
+1386
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -70,40 +70,40 @@ public class FilterChainProxyConfigTests {
|
||||
|
||||
@Test
|
||||
public void normalOperation() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfig() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfigRegex() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
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"));
|
||||
}
|
||||
|
||||
@Test
|
||||
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
|
||||
String url = "/blah.bar?x=something";
|
||||
@@ -116,7 +116,7 @@ public class FilterChainProxyConfigTests {
|
||||
// SEC-1235
|
||||
@Test
|
||||
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]);
|
||||
assertEquals("/login*", paths[0]);
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ public class SecurityNamespacehandlerTests {
|
||||
);
|
||||
fail("Expected BeanDefinitionParsingException");
|
||||
} 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());
|
||||
}
|
||||
|
||||
@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) {
|
||||
appContext = new InMemoryXmlApplicationContext(context, version, null);
|
||||
}
|
||||
|
||||
+2
-2
@@ -77,12 +77,12 @@ public class UserServiceBeanDefinitionParserTests {
|
||||
setContext(
|
||||
"<user-service id='service'>" +
|
||||
" <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>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertFalse(joe.isAccountNonLocked());
|
||||
UserDetails bob = userService.loadUserByUsername("bob");
|
||||
UserDetails bob = userService.loadUserByUsername("bOb");
|
||||
assertFalse(bob.isEnabled());
|
||||
}
|
||||
|
||||
|
||||
+69
@@ -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.SaveContextOnUpdateOrErrorResponseWrapper;
|
||||
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.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -183,6 +185,29 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
assertTrue(filters.size() == 0);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void filtersEqualsNoneErrorsWithRequiresChannel() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <intercept-url pattern='/ambiguousConfig' requires-channel='https' filters='none' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void filtersEqualsNoneErrorsWithAccess() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <intercept-url pattern='/ambiguousConfig' access='ROLE_USER' filters='none' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void filtersEqualsNoneErrorsWithRequiresChannelAndAccess() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <intercept-url pattern='/ambiguousConfig' requires-channel='https' filters='none' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regexPathsWorkCorrectly() throws Exception {
|
||||
@@ -407,6 +432,23 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
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
|
||||
public void oncePerRequestAttributeIsSupported() throws Exception {
|
||||
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
@@ -416,6 +458,21 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
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
|
||||
public void accessDeniedPageAttributeIsSupported() throws Exception {
|
||||
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
@@ -1218,6 +1275,18 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||
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) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
|
||||
+48
-6
@@ -16,12 +16,15 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
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.intercept.AfterInvocationProviderManager;
|
||||
import org.springframework.security.access.intercept.RunAsManagerImpl;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
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.vote.AffirmativeBased;
|
||||
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.PostProcessedMockUserDetailsService;
|
||||
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.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
@@ -40,6 +44,8 @@ import org.springframework.security.util.FieldUtils;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob","bobspassword");
|
||||
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
@@ -166,7 +172,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
" 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) " +
|
||||
" and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' " +
|
||||
" access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
"</global-method-security>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// String method should not be protected
|
||||
@@ -231,7 +237,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
target.someAdminMethod();
|
||||
}
|
||||
@@ -242,7 +248,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
List<String> arg = new ArrayList<String>();
|
||||
arg.add("joe");
|
||||
@@ -261,7 +267,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
Object[] arg = new String[] {"joe", "bob", "sam"};
|
||||
Object[] result = target.methodReturningAnArray(arg);
|
||||
@@ -283,6 +289,33 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
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
|
||||
public void runAsManagerIsSetCorrectly() throws Exception {
|
||||
StaticApplicationContext parent = new StaticApplicationContext();
|
||||
@@ -305,6 +338,15 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private void setContext(String context, ApplicationContext 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
|
||||
public void loadContext() {
|
||||
// Set value for placeholder
|
||||
System.setProperty("admin.role", "ROLE_ADMIN");
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
|
||||
target = (TestBusinessBean) appContext.getBean("target");
|
||||
}
|
||||
|
||||
+2
-2
@@ -22,11 +22,11 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
|
||||
Resource inMemoryXml;
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml) {
|
||||
this(xml, "3.0", null);
|
||||
this(xml, "3.0.4", null);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
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">
|
||||
|
||||
<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>
|
||||
|
||||
<b:bean id="target" class="org.springframework.security.config.TestBusinessBeanImpl">
|
||||
<!-- This will add a security interceptor to the bean -->
|
||||
<intercept-methods>
|
||||
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="ROLE_ADMIN" />
|
||||
<protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
|
||||
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="${admin.role}" />
|
||||
<protect method="get*" access="${admin.role},ROLE_USER" />
|
||||
<protect method="doSomething" access="ROLE_USER" />
|
||||
</intercept-methods>
|
||||
</b:bean>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
Implementation-Title: org.springframework.security.config
|
||||
Implementation-Version: ${version}
|
||||
Bundle-SymbolicName: org.springframework.security.config
|
||||
Bundle-Name: Spring Security Namespace Configuration
|
||||
Bundle-Vendor: SpringSource
|
||||
|
||||
@@ -5,7 +5,6 @@ dependencies {
|
||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-core:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-expression:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
|
||||
+1
-5
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.7.RELEASE</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
@@ -65,10 +65,6 @@
|
||||
<artifactId>ehcache</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
|
||||
@@ -37,6 +37,9 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
||||
|
||||
/**
|
||||
* 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 object The access object.
|
||||
@@ -44,6 +47,8 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
||||
* @return The vote.
|
||||
*/
|
||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> definition) {
|
||||
boolean jsr250AttributeFound = false;
|
||||
|
||||
for (ConfigAttribute attribute : definition) {
|
||||
if (Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE.equals(attribute)) {
|
||||
return ACCESS_GRANTED;
|
||||
@@ -54,18 +59,17 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
||||
}
|
||||
|
||||
if (supports(attribute)) {
|
||||
jsr250AttributeFound = true;
|
||||
// Attempt to find a matching granted authority
|
||||
for (GrantedAuthority authority : authentication.getAuthorities()) {
|
||||
if (attribute.getAttribute().equals(authority.getAuthority())) {
|
||||
return ACCESS_GRANTED;
|
||||
}
|
||||
}
|
||||
// No match - deny access
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
return ACCESS_ABSTAIN;
|
||||
return jsr250AttributeFound ? ACCESS_DENIED : ACCESS_ABSTAIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ import org.springframework.security.access.method.AbstractFallbackMethodSecurity
|
||||
public class SecuredAnnotationSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
|
||||
|
||||
protected Collection<ConfigAttribute> findAttributes(Class<?> clazz) {
|
||||
return processAnnotation(clazz.getAnnotation(Secured.class));
|
||||
return processAnnotation(AnnotationUtils.findAnnotation(clazz, Secured.class));
|
||||
}
|
||||
|
||||
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
|
||||
|
||||
+8
@@ -36,6 +36,14 @@ public abstract class SecurityExpressionRoot {
|
||||
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) {
|
||||
return getAuthoritySet().contains(role);
|
||||
}
|
||||
|
||||
+17
-2
@@ -3,11 +3,13 @@ package org.springframework.security.access.expression.method;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
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.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Internal security-specific EvaluationContext implementation which lazily adds the
|
||||
@@ -18,6 +20,8 @@ import org.springframework.util.ClassUtils;
|
||||
* @since 3.0
|
||||
*/
|
||||
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||
private static Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class);
|
||||
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer;
|
||||
private boolean argumentsAdded;
|
||||
private MethodInvocation mi;
|
||||
@@ -58,10 +62,21 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||
|
||||
private void addArgumentsAsVariables() {
|
||||
Object[] args = mi.getArguments();
|
||||
|
||||
if (args.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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++) {
|
||||
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.LogFactory;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
|
||||
/**
|
||||
@@ -106,7 +107,7 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
|
||||
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
|
||||
if (authorities == null || authorities.isEmpty()) {
|
||||
return null;
|
||||
return AuthorityUtils.NO_AUTHORITIES;
|
||||
}
|
||||
|
||||
Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>();
|
||||
|
||||
+10
-6
@@ -40,6 +40,7 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -224,16 +225,18 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||
}
|
||||
|
||||
// no further work post-invocation
|
||||
return new InterceptorStatusToken(authenticated, false, attributes, object);
|
||||
return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);
|
||||
} else {
|
||||
if (debug) {
|
||||
logger.debug("Switching to RunAs Authentication: " + runAs);
|
||||
}
|
||||
|
||||
SecurityContext origCtx = SecurityContextHolder.getContext();
|
||||
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
|
||||
SecurityContextHolder.getContext().setAuthentication(runAs);
|
||||
|
||||
// need to revert to token.Authenticated post-invocation
|
||||
return new InterceptorStatusToken(authenticated, true, attributes, object);
|
||||
return new InterceptorStatusToken(origCtx, true, attributes, object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,21 +256,22 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||
|
||||
if (token.isContextHolderRefreshRequired()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reverting to original Authentication: " + token.getAuthentication().toString());
|
||||
logger.debug("Reverting to original Authentication: " + token.getSecurityContext().getAuthentication());
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(token.getAuthentication());
|
||||
SecurityContextHolder.setContext(token.getSecurityContext());
|
||||
}
|
||||
|
||||
if (afterInvocationManager != null) {
|
||||
// Attempt after invocation handling
|
||||
try {
|
||||
returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
|
||||
returnedObject = afterInvocationManager.decide(token.getSecurityContext().getAuthentication(),
|
||||
token.getSecureObject(),
|
||||
token.getAttributes(), returnedObject);
|
||||
}
|
||||
catch (AccessDeniedException accessDeniedException) {
|
||||
AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
|
||||
.getAttributes(), token.getAuthentication(), accessDeniedException);
|
||||
.getAttributes(), token.getSecurityContext().getAuthentication(), accessDeniedException);
|
||||
publishEvent(event);
|
||||
|
||||
throw accessDeniedException;
|
||||
|
||||
+6
-5
@@ -19,6 +19,7 @@ import java.util.Collection;
|
||||
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,16 +34,16 @@ import org.springframework.security.core.Authentication;
|
||||
public class InterceptorStatusToken {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Authentication authentication;
|
||||
private SecurityContext securityContext;
|
||||
private Collection<ConfigAttribute> attr;
|
||||
private Object secureObject;
|
||||
private boolean contextHolderRefreshRequired;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public InterceptorStatusToken(Authentication authentication, boolean contextHolderRefreshRequired,
|
||||
public InterceptorStatusToken(SecurityContext securityContext, boolean contextHolderRefreshRequired,
|
||||
Collection<ConfigAttribute> attributes, Object secureObject) {
|
||||
this.authentication = authentication;
|
||||
this.securityContext = securityContext;
|
||||
this.contextHolderRefreshRequired = contextHolderRefreshRequired;
|
||||
this.attr = attributes;
|
||||
this.secureObject = secureObject;
|
||||
@@ -54,8 +55,8 @@ public class InterceptorStatusToken {
|
||||
return attr;
|
||||
}
|
||||
|
||||
public Authentication getAuthentication() {
|
||||
return authentication;
|
||||
public SecurityContext getSecurityContext() {
|
||||
return securityContext;
|
||||
}
|
||||
|
||||
public Object getSecureObject() {
|
||||
|
||||
+2
-1
@@ -73,7 +73,8 @@ public class RunAsUserToken extends AbstractAuthenticationToken {
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.append("; Original Class: ").append(this.originalAuthentication.getName());
|
||||
String className = this.originalAuthentication == null ? null : this.originalAuthentication.getName();
|
||||
sb.append("; Original Class: ").append(className);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
+2
-1
@@ -6,8 +6,9 @@ package org.springframework.security.access.intercept.aspectj;
|
||||
* AspectJ processing to continue.
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @deprecated
|
||||
*/
|
||||
|
||||
@Deprecated
|
||||
public interface AspectJAnnotationCallback {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
||||
+2
@@ -11,7 +11,9 @@ import org.aspectj.lang.JoinPoint;
|
||||
* AspectJ interceptor that supports @Aspect notation.
|
||||
*
|
||||
* @author Mike Wiesner
|
||||
* @deprecated Use AspectJMethodSecurityInterceptor instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class AspectJAnnotationSecurityInterceptor extends AbstractSecurityInterceptor {
|
||||
//~ 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.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @deprecated Use AspectJMethodSecurityInterceptor instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {
|
||||
//~ 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.util.Collection;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
// 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.
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
// First try is the method in the target class.
|
||||
Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
|
||||
if (attr != null) {
|
||||
|
||||
+13
-1
@@ -15,6 +15,7 @@
|
||||
|
||||
package org.springframework.security.access.method;
|
||||
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
@@ -49,7 +50,18 @@ public abstract class AbstractMethodSecurityMetadataSource implements MethodSecu
|
||||
if (object instanceof MethodInvocation) {
|
||||
MethodInvocation mi = (MethodInvocation) object;
|
||||
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 : AopProxyUtils.ultimateTargetClass(target);
|
||||
|
||||
if (targetClass == null) {
|
||||
// See SPR-7447. TODO: Only required for Spring < 3.0.4
|
||||
targetClass = target.getClass();
|
||||
}
|
||||
}
|
||||
|
||||
return getAttributes(mi.getMethod(), targetClass);
|
||||
}
|
||||
|
||||
if (object instanceof JoinPoint) {
|
||||
|
||||
+4
@@ -88,6 +88,10 @@ public final class DelegatingMethodSecurityMetadataSource extends AbstractMethod
|
||||
this.methodSecurityMetadataSources = methodSecurityMetadataSources;
|
||||
}
|
||||
|
||||
public List<MethodSecurityMetadataSource> getMethodSecurityMetadataSources() {
|
||||
return methodSecurityMetadataSources;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
+7
-3
@@ -25,6 +25,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -42,7 +43,8 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Ben Alex
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource implements BeanClassLoaderAware {
|
||||
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource
|
||||
implements BeanClassLoaderAware {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
@@ -103,7 +105,7 @@ public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethod
|
||||
* for matching multiple methods.
|
||||
*
|
||||
* @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) {
|
||||
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
|
||||
* 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
|
||||
* 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) {
|
||||
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
||||
|
||||
+1
-11
@@ -105,23 +105,13 @@ public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecur
|
||||
}
|
||||
|
||||
// Check the class-level (note declaringClass, not targetClass, which may not actually implement the method)
|
||||
annotation = specificMethod.getDeclaringClass().getAnnotation(annotationClass);
|
||||
annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);
|
||||
|
||||
if (annotation != null) {
|
||||
logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
|
||||
return annotation;
|
||||
}
|
||||
|
||||
// Check for a possible interface annotation which would not be inherited by the declaring class
|
||||
if (specificMethod != method) {
|
||||
annotation = method.getDeclaringClass().getAnnotation(annotationClass);
|
||||
|
||||
if (annotation != null) {
|
||||
logger.debug(annotation + " found on: " + method.getDeclaringClass().getName());
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -77,7 +77,9 @@ public abstract class AbstractAuthenticationManager implements AuthenticationMan
|
||||
* be serialized to the client. Defaults to 'false'.
|
||||
*
|
||||
* @see org.springframework.security.core.AuthenticationException#getExtraInformation()
|
||||
* @deprecated the {@code extraInformation} property is deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setClearExtraInformation(boolean clearExtraInformation) {
|
||||
this.clearExtraInformation = clearExtraInformation;
|
||||
}
|
||||
|
||||
+55
-35
@@ -22,6 +22,7 @@ import java.util.Collections;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.CredentialsContainer;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
@@ -34,7 +35,7 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public abstract class AbstractAuthenticationToken implements Authentication {
|
||||
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Object details;
|
||||
@@ -49,7 +50,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
||||
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the
|
||||
* principal represented by this authentication object.
|
||||
*/
|
||||
public AbstractAuthenticationToken(Collection<GrantedAuthority> authorities) {
|
||||
public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
|
||||
if (authorities == null) {
|
||||
this.authorities = AuthorityUtils.NO_AUTHORITIES;
|
||||
return;
|
||||
@@ -67,6 +68,55 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
||||
|
||||
//~ 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) {
|
||||
if (!(obj instanceof AbstractAuthenticationToken)) {
|
||||
return false;
|
||||
@@ -109,26 +159,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
||||
return this.isAuthenticated() == test.isAuthenticated();
|
||||
}
|
||||
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 31;
|
||||
|
||||
@@ -155,23 +186,12 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
||||
return code;
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
public void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
|
||||
public void setDetails(Object details) {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(super.toString()).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("Details: ").append(this.getDetails()).append("; ");
|
||||
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ public abstract class AccountStatusException extends AuthenticationException {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected AccountStatusException(String msg, Object extraInformation) {
|
||||
super(msg, extraInformation);
|
||||
}
|
||||
|
||||
+4
-4
@@ -14,20 +14,20 @@ public class AccountStatusUserDetailsChecker implements UserDetailsChecker {
|
||||
|
||||
public void check(UserDetails user) {
|
||||
if (!user.isAccountNonLocked()) {
|
||||
throw new LockedException(messages.getMessage("UserDetailsService.locked", "User account is locked"), user);
|
||||
throw new LockedException(messages.getMessage("AccountStatusUserDetailsChecker.locked", "User account is locked"), user);
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
throw new DisabledException(messages.getMessage("UserDetailsService.disabled", "User is disabled"), user);
|
||||
throw new DisabledException(messages.getMessage("AccountStatusUserDetailsChecker.disabled", "User is disabled"), user);
|
||||
}
|
||||
|
||||
if (!user.isAccountNonExpired()) {
|
||||
throw new AccountExpiredException(messages.getMessage("UserDetailsService.expired",
|
||||
throw new AccountExpiredException(messages.getMessage("AccountStatusUserDetailsChecker.expired",
|
||||
"User account has expired"), user);
|
||||
}
|
||||
|
||||
if (!user.isCredentialsNonExpired()) {
|
||||
throw new CredentialsExpiredException(messages.getMessage("UserDetailsService.credentialsExpired",
|
||||
throw new CredentialsExpiredException(messages.getMessage("AccountStatusUserDetailsChecker.credentialsExpired",
|
||||
"User credentials have expired"), user);
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ public class BadCredentialsException extends AuthenticationException {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public BadCredentialsException(String msg, Object extraInformation) {
|
||||
super(msg, extraInformation);
|
||||
}
|
||||
|
||||
+32
-1
@@ -26,6 +26,7 @@ import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.CredentialsContainer;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
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.
|
||||
* 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>.
|
||||
* 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>
|
||||
* 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.
|
||||
*
|
||||
* 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>
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*
|
||||
@@ -76,6 +85,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
||||
private List<AuthenticationProvider> providers = Collections.emptyList();
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
private AuthenticationManager parent;
|
||||
private boolean eraseCredentialsAfterAuthentication = false;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -145,6 +155,11 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
||||
}
|
||||
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
@@ -193,6 +208,22 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
||||
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.
|
||||
*
|
||||
|
||||
+20
-19
@@ -15,7 +15,6 @@
|
||||
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@@ -28,8 +27,9 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
* <code>GrantedAuthority</code>s that apply.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
|
||||
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Object principal;
|
||||
@@ -46,7 +46,7 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
||||
*
|
||||
* @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);
|
||||
|
||||
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
|
||||
@@ -60,6 +60,23 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
||||
|
||||
//~ 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) {
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
@@ -78,20 +95,4 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
||||
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
|
||||
* username and password.
|
||||
* An {@link org.springframework.security.core.Authentication} implementation that is designed for simple presentation
|
||||
* of a username and password.
|
||||
* <p>
|
||||
* 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
|
||||
@@ -34,8 +34,8 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final Object credentials;
|
||||
private final Object principal;
|
||||
private Object credentials;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -68,7 +68,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
||||
* @param credentials
|
||||
* @param authorities
|
||||
*/
|
||||
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<GrantedAuthority> authorities) {
|
||||
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(authorities);
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
@@ -94,4 +94,10 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
||||
|
||||
super.setAuthenticated(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eraseCredentials() {
|
||||
super.eraseCredentials();
|
||||
credentials = null;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -16,6 +16,8 @@
|
||||
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.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
@@ -71,6 +73,9 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean,
|
||||
MessageSourceAware {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
@@ -123,6 +128,8 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
||||
try {
|
||||
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
|
||||
} catch (UsernameNotFoundException notFound) {
|
||||
logger.debug("User '" + username + "' not found");
|
||||
|
||||
if (hideUserNotFoundExceptions) {
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||
@@ -178,7 +185,7 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
||||
* @return the successful authentication token
|
||||
*/
|
||||
protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
|
||||
UserDetails user) {
|
||||
UserDetails user) {
|
||||
// Ensure we return the original credentials the user supplied,
|
||||
// so subsequent attempts are successful even with encoded passwords.
|
||||
// Also ensure we return the original getDetails(), so that future
|
||||
@@ -291,16 +298,22 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
||||
private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
|
||||
public void check(UserDetails user) {
|
||||
if (!user.isAccountNonLocked()) {
|
||||
logger.debug("User account is locked");
|
||||
|
||||
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
|
||||
"User account is locked"), user);
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
logger.debug("User account is disabled");
|
||||
|
||||
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
|
||||
"User is disabled"), user);
|
||||
}
|
||||
|
||||
if (!user.isAccountNonExpired()) {
|
||||
logger.debug("User account is expired");
|
||||
|
||||
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
|
||||
"User account has expired"), user);
|
||||
}
|
||||
@@ -310,6 +323,8 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
||||
private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
|
||||
public void check(UserDetails user) {
|
||||
if (!user.isCredentialsNonExpired()) {
|
||||
logger.debug("User account credentials have expired");
|
||||
|
||||
throw new CredentialsExpiredException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
||||
"User credentials have expired"), user);
|
||||
|
||||
+4
@@ -56,6 +56,8 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
||||
}
|
||||
|
||||
if (authentication.getCredentials() == null) {
|
||||
logger.debug("Authentication failed: no credentials provided");
|
||||
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||
includeDetailsObject ? userDetails : null);
|
||||
@@ -64,6 +66,8 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
||||
String presentedPassword = authentication.getCredentials().toString();
|
||||
|
||||
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
|
||||
logger.debug("Authentication failed: password does not match stored value");
|
||||
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||
includeDetailsObject ? userDetails : null);
|
||||
|
||||
+5
-5
@@ -16,12 +16,12 @@
|
||||
package org.springframework.security.authentication.encoding;
|
||||
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import org.springframework.security.core.codec.Base64;
|
||||
import org.springframework.security.core.codec.Utf8;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* A version of {@link ShaPasswordEncoder} which supports Ldap SHA and SSHA (salted-SHA) encodings. The values are
|
||||
@@ -101,7 +101,7 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
|
||||
prefix = forceLowerCasePrefix ? SSHA_PREFIX_LC : SSHA_PREFIX;
|
||||
}
|
||||
|
||||
return prefix + new String(Base64.encode(hash));
|
||||
return prefix + Utf8.decode(Base64.encode(hash));
|
||||
}
|
||||
|
||||
private byte[] extractSalt(String encPass) {
|
||||
@@ -145,7 +145,7 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
|
||||
|
||||
String encodedRawPass = encodePassword(rawPass, salt).substring(startOfHash);
|
||||
|
||||
return encodedRawPass.equals(encPass.substring(startOfHash));
|
||||
return PasswordEncoderUtils.equals(encodedRawPass,encPass.substring(startOfHash));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+5
-4
@@ -14,10 +14,11 @@
|
||||
*/
|
||||
package org.springframework.security.authentication.encoding;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.springframework.security.core.codec.Base64;
|
||||
import org.springframework.security.core.codec.Hex;
|
||||
import org.springframework.security.core.codec.Utf8;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* MD4 implementation of PasswordEncoder.
|
||||
@@ -60,7 +61,7 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
|
||||
byte[] resBuf = md4.digest();
|
||||
|
||||
if (getEncodeHashAsBase64()) {
|
||||
return new String(Base64.encode(resBuf));
|
||||
return Utf8.decode(Base64.encode(resBuf));
|
||||
} else {
|
||||
return new String(Hex.encode(resBuf));
|
||||
}
|
||||
@@ -78,7 +79,7 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
|
||||
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
|
||||
String pass1 = "" + encPass;
|
||||
String pass2 = encodePassword(rawPass, salt);
|
||||
return pass1.equals(pass2);
|
||||
return PasswordEncoderUtils.equals(pass1,pass2);
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
|
||||
+7
-6
@@ -1,13 +1,14 @@
|
||||
package org.springframework.security.authentication.encoding;
|
||||
|
||||
import org.springframework.security.core.codec.Base64;
|
||||
import org.springframework.security.core.codec.Hex;
|
||||
import org.springframework.security.core.codec.Utf8;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.springframework.security.core.codec.Base64;
|
||||
import org.springframework.security.core.codec.Hex;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base for digest password encoders.
|
||||
* <p>
|
||||
@@ -92,7 +93,7 @@ public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
|
||||
}
|
||||
|
||||
if (getEncodeHashAsBase64()) {
|
||||
return new String(Base64.encode(digest));
|
||||
return Utf8.decode(Base64.encode(digest));
|
||||
} else {
|
||||
return new String(Hex.encode(digest));
|
||||
}
|
||||
@@ -126,7 +127,7 @@ public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
|
||||
String pass1 = "" + encPass;
|
||||
String pass2 = encodePassword(rawPass, salt);
|
||||
|
||||
return pass1.equals(pass2);
|
||||
return PasswordEncoderUtils.equals(pass1,pass2);
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package org.springframework.security.authentication.encoding;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* Utility for constant time comparison to prevent against timing attacks.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class PasswordEncoderUtils {
|
||||
|
||||
/**
|
||||
* Constant time comparison to prevent against timing attacks.
|
||||
* @param expected
|
||||
* @param actual
|
||||
* @return
|
||||
*/
|
||||
static boolean equals(String expected, String actual) {
|
||||
byte[] expectedBytes = bytesUtf8(expected);
|
||||
byte[] actualBytes = bytesUtf8(actual);
|
||||
int expectedLength = expectedBytes == null ? -1 : expectedBytes.length;
|
||||
int actualLength = actualBytes == null ? -1 : actualBytes.length;
|
||||
if (expectedLength != actualLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < expectedLength; i++) {
|
||||
result |= expectedBytes[i] ^ actualBytes[i];
|
||||
}
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
private static byte[] bytesUtf8(String s) {
|
||||
if(s == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return s.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("Could not get bytes in UTF-8 format",e);
|
||||
}
|
||||
}
|
||||
private PasswordEncoderUtils() {}
|
||||
}
|
||||
+7
-4
@@ -15,6 +15,8 @@
|
||||
|
||||
package org.springframework.security.authentication.encoding;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* <p>Plaintext implementation of PasswordEncoder.</p>
|
||||
* <P>As callers may wish to extract the password and salts separately from the encoded password, the salt must
|
||||
@@ -46,11 +48,12 @@ public class PlaintextPasswordEncoder extends BasePasswordEncoder {
|
||||
// authentication will fail as the encodePassword never allows them)
|
||||
String pass2 = mergePasswordAndSalt(rawPass, salt, false);
|
||||
|
||||
if (!ignorePasswordCase) {
|
||||
return pass1.equals(pass2);
|
||||
} else {
|
||||
return pass1.equalsIgnoreCase(pass2);
|
||||
if (ignorePasswordCase) {
|
||||
// Note: per String javadoc to get correct results for Locale insensitive, use English
|
||||
pass1 = pass1.toLowerCase(Locale.ENGLISH);
|
||||
pass2 = pass2.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
return PasswordEncoderUtils.equals(pass1,pass2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
-24
@@ -15,22 +15,6 @@
|
||||
|
||||
package org.springframework.security.authentication.jaas;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.Principal;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -49,6 +33,19 @@ import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.session.SessionDestroyedEvent;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.Principal;
|
||||
import java.security.Security;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation that retrieves user details from a JAAS login configuration.
|
||||
@@ -185,7 +182,6 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
|
||||
// Create a set to hold the authorities, and add any that have already been applied.
|
||||
authorities = new HashSet<GrantedAuthority>();
|
||||
authorities.addAll(request.getAuthorities());
|
||||
|
||||
// Get the subject principals and pass them to each of the AuthorityGranters
|
||||
Set<Principal> principals = loginContext.getSubject().getPrincipals();
|
||||
@@ -269,14 +265,20 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
}
|
||||
|
||||
private String convertLoginConfigToUrl() throws IOException {
|
||||
String loginConfigPath = loginConfig.getFile().getAbsolutePath();
|
||||
loginConfigPath.replace(File.separatorChar, '/');
|
||||
String loginConfigPath;
|
||||
|
||||
if (!loginConfigPath.startsWith("/")) {
|
||||
loginConfigPath = "/" + loginConfigPath;
|
||||
try {
|
||||
loginConfigPath = loginConfig.getFile().getAbsolutePath().replace(File.separatorChar, '/');
|
||||
|
||||
if (!loginConfigPath.startsWith("/")) {
|
||||
loginConfigPath = "/" + loginConfigPath;
|
||||
}
|
||||
|
||||
return new URL("file", "", loginConfigPath).toString();
|
||||
} catch (IOException e) {
|
||||
// SEC-1700: May be inside a jar
|
||||
return loginConfig.getURL().toString();
|
||||
}
|
||||
|
||||
return new URL("file", "", loginConfigPath).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,7 +429,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
* If set, a call to {@code Configuration#refresh()} will be made by {@code #configureJaas(Resource) }
|
||||
* method. Defaults to {@code true}.
|
||||
*
|
||||
* @see <a href="https://jira.springsource.org/browse/SEC-1320">SEC-1230</a>
|
||||
* @see <a href="https://jira.springsource.org/browse/SEC-1320">SEC-1320</a>
|
||||
*
|
||||
* @param refresh set to {@code false} to disable reloading of the configuration.
|
||||
* May be useful in some environments.
|
||||
|
||||
@@ -25,12 +25,12 @@ public abstract class AuthenticationException extends RuntimeException {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Authentication authentication;
|
||||
private Object extraInformation;
|
||||
private transient Object extraInformation;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>AuthenticationException</code> with the specified message and root cause.
|
||||
* Constructs an {@code AuthenticationException} with the specified message and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t the root cause
|
||||
@@ -40,7 +40,7 @@ public abstract class AuthenticationException extends RuntimeException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>AuthenticationException</code> with the specified message and no root cause.
|
||||
* Constructs an {@code AuthenticationException} with the specified message and no root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
@@ -48,15 +48,22 @@ public abstract class AuthenticationException extends RuntimeException {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the exception message or use a custom exception if you really need additional information.
|
||||
*/
|
||||
@Deprecated
|
||||
public AuthenticationException(String msg, Object extraInformation) {
|
||||
super(msg);
|
||||
if (extraInformation instanceof CredentialsContainer) {
|
||||
((CredentialsContainer) extraInformation).eraseCredentials();
|
||||
}
|
||||
this.extraInformation = extraInformation;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* The authentication request which this exception corresponds to (may be <code>null</code>)
|
||||
* The authentication request which this exception corresponds to (may be {@code null})
|
||||
*/
|
||||
public Authentication getAuthentication() {
|
||||
return authentication;
|
||||
@@ -67,14 +74,17 @@ public abstract class AuthenticationException extends RuntimeException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Any additional information about the exception. Generally a <code>UserDetails</code> object.
|
||||
* Any additional information about the exception. Generally a {@code UserDetails} object.
|
||||
*
|
||||
* @return extra information or <code>null</code>
|
||||
* @return extra information or {@code null}
|
||||
* @deprecated Use the exception message or use a custom exception if you really need additional information.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getExtraInformation() {
|
||||
return extraInformation;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void clearExtraInformation() {
|
||||
this.extraInformation = 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,39 @@
|
||||
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 " + version);
|
||||
if (!springVersion.startsWith("3")) {
|
||||
logger.error("Spring Major version '3' expected, but you are running with version: "
|
||||
+ springVersion + ". Please check your classpath for unwanted jar files.");
|
||||
}
|
||||
|
||||
if (springVersion.compareTo("3.0.6") < 0) {
|
||||
logger.warn("You are advised to use Spring 3.0.6 or later with this version. You are running: " +
|
||||
springVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
Package pkg = SpringSecurityCoreVersion.class.getPackage();
|
||||
return (pkg != null ? pkg.getImplementationVersion() : null);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package org.springframework.security.core.codec;
|
||||
|
||||
|
||||
/**
|
||||
* Base64 encoder which is a reduced version of Robert Harder's public domain implementation.
|
||||
* Base64 encoder which is a reduced version of Robert Harder's public domain implementation (version 2.3.7).
|
||||
* See <a href="http://iharder.net/base64">http://iharder.net/base64</a> for more information.
|
||||
* <p>
|
||||
* For internal use only.
|
||||
@@ -101,8 +101,8 @@ public final class Base64 {
|
||||
-9,-9,-9,-9,-9,-9, // Decimal 91 - 96
|
||||
26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
|
||||
39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
|
||||
-9,-9,-9,-9 // Decimal 123 - 126
|
||||
/*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
|
||||
-9,-9,-9,-9,-9 // Decimal 123 - 127
|
||||
,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
|
||||
@@ -111,7 +111,7 @@ public final class Base64 {
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
|
||||
};
|
||||
|
||||
|
||||
@@ -163,8 +163,8 @@ public final class Base64 {
|
||||
-9, // Decimal 96
|
||||
26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
|
||||
39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
|
||||
-9,-9,-9,-9 // Decimal 123 - 126
|
||||
/*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
|
||||
-9,-9,-9,-9,-9 // Decimal 123 - 127
|
||||
,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
|
||||
@@ -173,7 +173,7 @@ public final class Base64 {
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
|
||||
};
|
||||
|
||||
|
||||
@@ -228,8 +228,8 @@ public final class Base64 {
|
||||
-9, // Decimal 96
|
||||
38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm'
|
||||
51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z'
|
||||
-9,-9,-9,-9 // Decimal 123 - 126
|
||||
/*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
|
||||
-9,-9,-9,-9,-9 // Decimal 123 - 127
|
||||
,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
|
||||
@@ -238,7 +238,7 @@ public final class Base64 {
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
|
||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
|
||||
};
|
||||
|
||||
|
||||
@@ -370,10 +370,6 @@ public final class Base64 {
|
||||
|
||||
|
||||
/**
|
||||
* Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
|
||||
* a byte array instead of instantiating a String. This is more efficient
|
||||
* if you're working with I/O streams and have large data sets to encode.
|
||||
*
|
||||
*
|
||||
* @param source The data to convert
|
||||
* @param off Offset in array where conversion should begin
|
||||
@@ -444,7 +440,7 @@ public final class Base64 {
|
||||
|
||||
|
||||
// Only resize array if we didn't guess it right.
|
||||
if( e < outBuff.length - 1 ){
|
||||
if( e <= outBuff.length - 1 ){
|
||||
byte[] finalOut = new byte[e];
|
||||
System.arraycopy(outBuff,0, finalOut,0,e);
|
||||
//System.err.println("Having to resize array from " + outBuff.length + " to " + e );
|
||||
@@ -601,26 +597,24 @@ public final class Base64 {
|
||||
byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space
|
||||
int b4Posn = 0; // Keep track of four byte input buffer
|
||||
int i = 0; // Source array counter
|
||||
byte sbiCrop = 0; // Low seven bits (ASCII) of input
|
||||
byte sbiDecode = 0; // Special value from DECODABET
|
||||
|
||||
for( i = off; i < off+len; i++ ) { // Loop through source
|
||||
|
||||
sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
|
||||
sbiDecode = DECODABET[ sbiCrop ]; // Special value
|
||||
sbiDecode = DECODABET[ source[i]&0xFF ];
|
||||
|
||||
// White space, Equals sign, or legit Base64 character
|
||||
// Note the values such as -5 and -9 in the
|
||||
// DECODABETs at the top of the file.
|
||||
if( sbiDecode >= WHITE_SPACE_ENC ) {
|
||||
if( sbiDecode >= EQUALS_SIGN_ENC ) {
|
||||
b4[ b4Posn++ ] = sbiCrop; // Save non-whitespace
|
||||
b4[ b4Posn++ ] = source[i]; // Save non-whitespace
|
||||
if( b4Posn > 3 ) { // Time to decode?
|
||||
outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
|
||||
b4Posn = 0;
|
||||
|
||||
// If that was the equals sign, break out of 'for' loop
|
||||
if( sbiCrop == EQUALS_SIGN ) {
|
||||
if( source[i] == EQUALS_SIGN ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -629,7 +623,7 @@ public final class Base64 {
|
||||
else {
|
||||
// There's a bad input character in the Base64 stream.
|
||||
throw new InvalidBase64CharacterException( String.format(
|
||||
"Bad Base64 input character '%c' in array position %d", source[i], i ) );
|
||||
"Bad Base64 input character decimal %d in array position %d", ((int)source[i])&0xFF, i ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.springframework.security.core.codec;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* UTF-8 Charset encoder/decoder.
|
||||
* <p>
|
||||
* For internal use only.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public final class Utf8 {
|
||||
private static final Charset CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
/**
|
||||
* Get the bytes of the String in UTF-8 encoded form.
|
||||
*/
|
||||
public static byte[] encode(CharSequence string) {
|
||||
try {
|
||||
ByteBuffer bytes = CHARSET.newEncoder().encode(CharBuffer.wrap(string));
|
||||
|
||||
byte[] copy = new byte[bytes.limit()];
|
||||
System.arraycopy(bytes.array(), 0, copy, 0, bytes.limit());
|
||||
return copy;
|
||||
} catch (CharacterCodingException e) {
|
||||
throw new IllegalArgumentException("Encoding failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the bytes in UTF-8 form into a String.
|
||||
*/
|
||||
public static String decode(byte[] bytes) {
|
||||
try {
|
||||
return CHARSET.newDecoder().decode(ByteBuffer.wrap(bytes)).toString();
|
||||
} catch (CharacterCodingException e) {
|
||||
throw new IllegalArgumentException("Decoding failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ final class InheritableThreadLocalSecurityContextHolderStrategy implements Secur
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void clearContext() {
|
||||
contextHolder.set(null);
|
||||
contextHolder.remove();
|
||||
}
|
||||
|
||||
public SecurityContext getContext() {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextH
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void clearContext() {
|
||||
contextHolder.set(null);
|
||||
contextHolder.remove();
|
||||
}
|
||||
|
||||
public SecurityContext getContext() {
|
||||
|
||||
@@ -25,20 +25,31 @@ import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.CredentialsContainer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Models core user information retrieved by a {@link UserDetailsService}.
|
||||
* <p>
|
||||
* 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
|
||||
* 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.
|
||||
* <p>
|
||||
* Note that this implementation is not immutable. It implements the {@code CredentialsContainer} interface, in order
|
||||
* to allow the password to be erased after authentication. This may cause side-effects if you are storing instances
|
||||
* in-memory and reusing them. If so, make sure you return a copy from your {@code UserDetailsService} each time it is
|
||||
* invoked.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class User implements UserDetails {
|
||||
public class User implements UserDetails, CredentialsContainer {
|
||||
//~ Instance fields ================================================================================================
|
||||
private final String password;
|
||||
private String password;
|
||||
private final String username;
|
||||
private final Set<GrantedAuthority> authorities;
|
||||
private final boolean accountNonExpired;
|
||||
@@ -81,7 +92,7 @@ public class User implements UserDetails {
|
||||
* <code>GrantedAuthority</code> collection
|
||||
*/
|
||||
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)) {
|
||||
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
||||
@@ -98,27 +109,6 @@ public class User implements UserDetails {
|
||||
|
||||
//~ 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() {
|
||||
return authorities;
|
||||
}
|
||||
@@ -131,38 +121,8 @@ public class User implements UserDetails {
|
||||
return username;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int code = 9792;
|
||||
|
||||
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 isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public boolean isAccountNonExpired() {
|
||||
@@ -170,18 +130,18 @@ public class User implements UserDetails {
|
||||
}
|
||||
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.accountNonLocked;
|
||||
return accountNonLocked;
|
||||
}
|
||||
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return credentialsNonExpired;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
public void eraseCredentials() {
|
||||
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");
|
||||
// Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-717)
|
||||
SortedSet<GrantedAuthority> sortedAuthorities =
|
||||
@@ -211,7 +171,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() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(super.toString()).append(": ");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user