Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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
|
.project
|
||||||
.settings/
|
.settings/
|
||||||
build/
|
build/
|
||||||
|
out/
|
||||||
|
intellij/
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
*.log
|
*.log
|
||||||
|
*.log.1
|
||||||
|
.DS_Store
|
||||||
|
*.iml
|
||||||
.gradle/
|
.gradle/
|
||||||
gradle.properties
|
gradle.properties
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ dependencies {
|
|||||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||||
"org.springframework:spring-aop:$springVersion",
|
"org.springframework:spring-aop:$springVersion",
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-tx:$springVersion",
|
"org.springframework:spring-tx:$springVersion",
|
||||||
"org.springframework:spring-jdbc:$springVersion"
|
"org.springframework:spring-jdbc:$springVersion"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.6.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
|
|||||||
+1
-1
@@ -108,7 +108,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
|||||||
|
|
||||||
logger.debug("Denying access");
|
logger.debug("Denying access");
|
||||||
|
|
||||||
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
|
throw new AccessDeniedException(messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
|
||||||
new Object[] {authentication.getName(), returnedObject},
|
new Object[] {authentication.getName(), returnedObject},
|
||||||
"Authentication {0} has NO permissions to the domain object {1}"));
|
"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) {
|
if (obj instanceof AclImpl) {
|
||||||
AclImpl rhs = (AclImpl) obj;
|
AclImpl rhs = (AclImpl) obj;
|
||||||
if (this.aces.equals(rhs.aces)) {
|
if (this.aces.equals(rhs.aces)) {
|
||||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
|
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl !=null && this.parentAcl.equals(rhs.parentAcl))) {
|
||||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
|
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity != null && this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||||
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
|
if ((this.id == null && rhs.id == null) || (this.id != null && this.id.equals(rhs.id))) {
|
||||||
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
|
if ((this.owner == null && rhs.owner == null) || (this.owner != null && this.owner.equals(rhs.owner))) {
|
||||||
if (this.entriesInheriting == rhs.entriesInheriting) {
|
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||||
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||||
return true;
|
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++) {
|
for (int i = 0; i < this.loadedSids.size(); i++) {
|
||||||
if (!this.loadedSids.get(i).equals(rhs.loadedSids.get(i))) {
|
if (!this.loadedSids.get(i).equals(rhs.loadedSids.get(i))) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -504,6 +504,16 @@ public class AclImplTests {
|
|||||||
acl.deleteAce(1);
|
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 ==================================================================================================
|
//~ Inner Classes ==================================================================================================
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,5 @@
|
|||||||
|
Implementation-Title: org.springframework.security.acls
|
||||||
|
Implementation-Version: ${version}
|
||||||
Bundle-SymbolicName: org.springframework.security.acls
|
Bundle-SymbolicName: org.springframework.security.acls
|
||||||
Bundle-Name: Spring Security Acls
|
Bundle-Name: Spring Security Acls
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: SpringSource
|
||||||
@@ -18,4 +20,3 @@ Import-Template:
|
|||||||
org.springframework.util.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
|
org.springframework.util.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
|
||||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||||
javax.sql.*;version="0";resolution:=optional
|
javax.sql.*;version="0";resolution:=optional
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':spring-security-core'),
|
||||||
|
"org.springframework:spring-beans:$springVersion",
|
||||||
|
"org.springframework:spring-context:$springVersion"
|
||||||
|
}
|
||||||
+4
-8
@@ -5,16 +5,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.6.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<artifactId>spring-security-aspects</artifactId>
|
<artifactId>spring-security-aspects</artifactId>
|
||||||
<name>Spring Security - Aspects</name>
|
<name>Spring Security - Aspects</name>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.aspectj</groupId>
|
<groupId>org.aspectj</groupId>
|
||||||
<artifactId>aspectjweaver</artifactId>
|
<artifactId>aspectjweaver</artifactId>
|
||||||
@@ -22,7 +18,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-core</artifactId>
|
<artifactId>spring-security-core</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.6.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
@@ -39,12 +35,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.aspectj</groupId>
|
<groupId>org.aspectj</groupId>
|
||||||
<artifactId>aspectjrt</artifactId>
|
<artifactId>aspectjrt</artifactId>
|
||||||
<version>1.6.5</version>
|
<version>1.6.8</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.aspectj</groupId>
|
<groupId>org.aspectj</groupId>
|
||||||
<artifactId>aspectjtools</artifactId>
|
<artifactId>aspectjtools</artifactId>
|
||||||
<version>1.6.5</version>
|
<version>1.6.8</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<executions>
|
<executions>
|
||||||
|
|||||||
+18
-8
@@ -2,11 +2,12 @@ package org.springframework.security.access.intercept.aspectj.aspect;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.security.access.annotation.Secured;
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.security.access.prepost.*;
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
|
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
|
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concrete AspectJ transaction aspect using Spring Security @Secured annotation
|
* Concrete AspectJ aspect using Spring Security @Secured annotation
|
||||||
* for JDK 1.5+.
|
* for JDK 1.5+.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
@@ -16,8 +17,8 @@ import org.springframework.security.access.intercept.aspectj.AspectJSecurityInte
|
|||||||
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
|
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
|
||||||
*
|
*
|
||||||
* @author Mike Wiesner
|
* @author Mike Wiesner
|
||||||
* @since 1.0
|
* @author Luke Taylor
|
||||||
* @version $Id$
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public aspect AnnotationSecurityAspect implements InitializingBean {
|
public aspect AnnotationSecurityAspect implements InitializingBean {
|
||||||
|
|
||||||
@@ -34,11 +35,19 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
|
|||||||
private pointcut executionOfSecuredMethod() :
|
private pointcut executionOfSecuredMethod() :
|
||||||
execution(* *(..)) && @annotation(Secured);
|
execution(* *(..)) && @annotation(Secured);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches the execution of any method with Pre/Post annotations.
|
||||||
|
*/
|
||||||
|
private pointcut executionOfPrePostAnnotatedMethod() :
|
||||||
|
execution(* *(..)) && (@annotation(PreAuthorize) || @annotation(PreFilter)
|
||||||
|
|| @annotation(PostAuthorize) || @annotation(PostFilter));
|
||||||
|
|
||||||
private pointcut securedMethodExecution() :
|
private pointcut securedMethodExecution() :
|
||||||
executionOfAnyPublicMethodInAtSecuredType() ||
|
executionOfAnyPublicMethodInAtSecuredType() ||
|
||||||
executionOfSecuredMethod();
|
executionOfSecuredMethod() ||
|
||||||
|
executionOfPrePostAnnotatedMethod();
|
||||||
|
|
||||||
private AspectJSecurityInterceptor securityInterceptor;
|
private AspectJMethodSecurityInterceptor securityInterceptor;
|
||||||
|
|
||||||
Object around(): securedMethodExecution() {
|
Object around(): securedMethodExecution() {
|
||||||
if (this.securityInterceptor == null) {
|
if (this.securityInterceptor == null) {
|
||||||
@@ -54,13 +63,14 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
|
|||||||
return this.securityInterceptor.invoke(thisJoinPoint, callback);
|
return this.securityInterceptor.invoke(thisJoinPoint, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
|
public void setSecurityInterceptor(AspectJMethodSecurityInterceptor securityInterceptor) {
|
||||||
this.securityInterceptor = securityInterceptor;
|
this.securityInterceptor = securityInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (this.securityInterceptor == null)
|
if (this.securityInterceptor == null) {
|
||||||
throw new IllegalArgumentException("securityInterceptor required");
|
throw new IllegalArgumentException("securityInterceptor required");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
package org.springframework.security.access.intercept.aspectj.aspect;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.springframework.security.access.AccessDecisionManager;
|
||||||
|
import org.springframework.security.access.AccessDecisionVoter;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
|
||||||
|
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||||
|
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
|
||||||
|
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
|
||||||
|
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
||||||
|
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
|
||||||
|
import org.springframework.security.access.vote.AffirmativeBased;
|
||||||
|
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @since 3.0.3
|
||||||
|
*/
|
||||||
|
public class AnnotationSecurityAspectTests {
|
||||||
|
private @Mock AccessDecisionManager adm;
|
||||||
|
private @Mock AuthenticationManager authman;
|
||||||
|
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
|
||||||
|
// private TestingAuthenticationToken bob = new TestingAuthenticationToken("bob", "", "ROLE_B");
|
||||||
|
private AspectJMethodSecurityInterceptor interceptor;
|
||||||
|
private SecuredImpl secured = new SecuredImpl();
|
||||||
|
private PrePostSecured prePostSecured = new PrePostSecured();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public final void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
interceptor = new AspectJMethodSecurityInterceptor();
|
||||||
|
interceptor.setAccessDecisionManager(adm);
|
||||||
|
interceptor.setAuthenticationManager(authman);
|
||||||
|
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
|
||||||
|
AnnotationSecurityAspect secAspect = AnnotationSecurityAspect.aspectOf();
|
||||||
|
secAspect.setSecurityInterceptor(interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void clearContext() {
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void securedInterfaceMethodAllowsAllAccess() throws Exception {
|
||||||
|
secured.securedMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||||
|
public void securedClassMethodDeniesUnauthenticatedAccess() throws Exception {
|
||||||
|
secured.securedClassMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void securedClassMethodAllowsAccessToRoleA() throws Exception {
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||||
|
secured.securedClassMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEC-1262
|
||||||
|
@Test(expected=AccessDeniedException.class)
|
||||||
|
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(anne);
|
||||||
|
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
|
||||||
|
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
|
||||||
|
AffirmativeBased adm = new AffirmativeBased();
|
||||||
|
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
|
||||||
|
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
|
||||||
|
adm.setDecisionVoters(Arrays.asList(voters));
|
||||||
|
interceptor.setAccessDecisionManager(adm);
|
||||||
|
prePostSecured.denyAllMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecuredInterface {
|
||||||
|
@Secured("ROLE_X")
|
||||||
|
void securedMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SecuredImpl implements SecuredInterface {
|
||||||
|
|
||||||
|
// Not really secured because AspectJ doesn't inherit annotations from interfaces
|
||||||
|
public void securedMethod() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Secured("ROLE_A")
|
||||||
|
public void securedClassMethod() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrePostSecured {
|
||||||
|
|
||||||
|
@PreAuthorize("denyAll")
|
||||||
|
public void denyAllMethod() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+111
-171
@@ -1,137 +1,35 @@
|
|||||||
import java.util.jar.Manifest
|
apply plugin: 'base'
|
||||||
import org.gradle.api.tasks.bundling.GradleManifest
|
|
||||||
|
|
||||||
apply id: 'base'
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
version = '3.0.2.RELEASE'
|
version = '3.0.6.RELEASE'
|
||||||
releaseBuild = version.endsWith('RELEASE')
|
releaseBuild = version.endsWith('RELEASE')
|
||||||
snapshotBuild = version.endsWith('SNAPSHOT')
|
snapshotBuild = version.endsWith('SNAPSHOT')
|
||||||
|
|
||||||
group = 'org.springframework.security'
|
group = 'org.springframework.security'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenRepo name:'Local', urls:'file:///Users/luke/.m2/repository'
|
mavenRepo name:'Local', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
// mavenRepo name:'SpringSource Milestone Repo', urls:'http://repository.springsource.com/maven/bundles/milestone'
|
mavenRepo name: 'SpringSource Milestone Repo', urls: 'http://repository.springsource.com/maven/bundles/milestone'
|
||||||
|
mavenRepo name: 'SpringSource Maven Snapshot Repo', urls: 'http://maven.springframework.org/snapshot/'
|
||||||
|
mavenRepo name: 'SpringSource Enterprise Release', urls: 'http://repository.springsource.com/maven/bundles/release'
|
||||||
|
mavenRepo name: 'SpringSource Enterprise External', urls: 'http://repository.springsource.com/maven/bundles/external'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(javaProjects()) {
|
configure(javaProjects) {
|
||||||
apply id: 'java'
|
apply from: "$rootDir/gradle/javaprojects.gradle"
|
||||||
|
apply from: "$rootDir/gradle/maven.gradle"
|
||||||
springVersion = '3.0.1.RELEASE'
|
|
||||||
springLdapVersion = '1.3.0.RELEASE'
|
|
||||||
ehcacheVersion = '1.6.2'
|
|
||||||
aspectjVersion = '1.6.8'
|
|
||||||
apacheDsVersion = '1.5.5'
|
|
||||||
jstlVersion = '1.1.2'
|
|
||||||
jettyVersion = '6.1.22'
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
bundlor
|
|
||||||
provided
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
configure(coreModuleProjects) {
|
||||||
compile 'commons-logging:commons-logging:1.1.1'
|
apply from: "$rootDir/gradle/bundlor.gradle"
|
||||||
|
|
||||||
testCompile 'junit:junit:4.7',
|
|
||||||
'org.mockito:mockito-core:1.7',
|
|
||||||
'org.jmock:jmock:2.5.1',
|
|
||||||
'org.jmock:jmock-junit4:2.5.1',
|
|
||||||
'org.hamcrest:hamcrest-core:1.1',
|
|
||||||
'org.hamcrest:hamcrest-library:1.1',
|
|
||||||
"org.springframework:spring-test:$springVersion"
|
|
||||||
bundlor 'com.springsource.bundlor:com.springsource.bundlor.ant:1.0.0.RC1',
|
|
||||||
'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RC1',
|
|
||||||
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RC1'
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
compileClasspath = compileClasspath + configurations.provided
|
|
||||||
}
|
|
||||||
test {
|
|
||||||
compileClasspath = compileClasspath + configurations.provided
|
|
||||||
runtimeClasspath = runtimeClasspath + configurations.provided
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea", '-Xms128m', '-Xmx500m', '-XX:MaxPermSize=128m', '-XX:+HeapDumpOnOutOfMemoryError'])
|
|
||||||
}
|
|
||||||
|
|
||||||
task bundlor (dependsOn: compileJava) << {
|
|
||||||
if (!dependsOnTaskDidWork()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ant.taskdef(resource: 'com/springsource/bundlor/ant/antlib.xml', classpath: configurations.bundlor.asPath)
|
|
||||||
File template = new File(projectDir, 'template.mf')
|
|
||||||
mkdir(buildDir, 'bundlor')
|
|
||||||
if (template.exists()) {
|
|
||||||
ant.bundlor(inputPath: sourceSets.main.classesDir, outputPath: "$buildDir/bundlor", manifestTemplatePath: template) {
|
|
||||||
property(name: 'version', value: "$version")
|
|
||||||
property(name: 'spring.version', value: "$springVersion")
|
|
||||||
}
|
|
||||||
// See GRADLE-395 for support for using an existing manifest
|
|
||||||
jar.manifest = new GradleManifest(new Manifest(new File("$buildDir/bundlor/META-INF/MANIFEST.MF").newInputStream()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jar.dependsOn bundlor
|
|
||||||
}
|
|
||||||
|
|
||||||
configure(javaProjects()) {
|
|
||||||
apply id: 'maven'
|
|
||||||
|
|
||||||
// Create a source jar for uploading
|
|
||||||
task sourceJar(type: Jar) {
|
|
||||||
classifier = 'sources'
|
|
||||||
from sourceSets.main.java
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
deployerJars
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
archives sourceJar
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:2.0.1.BUILD-SNAPSHOT"
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadArchives {
|
|
||||||
repositories.mavenDeployer {
|
|
||||||
configuration = configurations.deployerJars
|
|
||||||
if (releaseBuild) {
|
|
||||||
// "mavenSyncRepoDir" should be set in properties
|
|
||||||
repository(url: mavenSyncRepoDir)
|
|
||||||
} else {
|
|
||||||
s3credentials = [userName: s3AccessKey, passphrase: s3SecretAccessKey]
|
|
||||||
repository(url: "s3://maven.springframework.org/milestone") {
|
|
||||||
authentication(s3credentials)
|
|
||||||
}
|
|
||||||
snapshotRepository(url: "s3://maven.springframework.org/snapshot") {
|
|
||||||
authentication(s3credentials)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conf2ScopeMappings.addMapping(1, configurations.provided, "provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
configure(coreModuleProjects()) {
|
|
||||||
// Gives better names in structure101 jar diagram
|
// Gives better names in structure101 jar diagram
|
||||||
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
|
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
configure (aspectjProjects) {
|
||||||
// Required for ant s3 task
|
apply from: "$rootDir/gradle/aspectj.gradle"
|
||||||
mavenRepo name: "s2.com release", urls: "http://repository.springsource.com/maven/bundles/release"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
@@ -143,57 +41,70 @@ dependencies {
|
|||||||
"net.java.dev.jets3t:jets3t:0.6.1"
|
"net.java.dev.jets3t:jets3t:0.6.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
def docsDir = new File(project(':manual').buildDir, 'docs')
|
|
||||||
|
|
||||||
task apidocs(type: Javadoc) {
|
task apidocs(type: Javadoc) {
|
||||||
destinationDir = new File(buildDir, 'apidocs')
|
destinationDir = new File(buildDir, 'apidocs')
|
||||||
title = "Spring Security $version API"
|
title = "Spring Security $version API"
|
||||||
optionsFile = file("$buildDir/tmp/javadoc.options")
|
optionsFile = file("$buildDir/tmp/javadoc.options")
|
||||||
|
|
||||||
source coreModuleProjects().collect { project ->
|
source coreModuleProjects.collect {project ->
|
||||||
project.sourceSets.main.allJava
|
project.sourceSets.main.allJava
|
||||||
}
|
}
|
||||||
|
|
||||||
classpath = files(coreModuleProjects().collect { project ->
|
classpath = files(coreModuleProjects.collect {project ->
|
||||||
project.sourceSets.main.compileClasspath })
|
project.sourceSets.main.compileClasspath
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
task apitar(type: Tar, dependsOn: apidocs) {
|
task docSiteLogin(type: Login) {
|
||||||
compression = Compression.BZIP2
|
if (project.hasProperty('sshHost')) {
|
||||||
|
host = project.property('sshHost')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define remoteSiteDir and sshHost in gradle.properties
|
||||||
|
def remoteDocsDir = null
|
||||||
|
|
||||||
|
if (hasProperty('remoteSiteDir')) {
|
||||||
|
remoteDocsDir="$remoteSiteDir/docs/3.0.x"
|
||||||
|
}
|
||||||
|
|
||||||
|
task uploadApidocs(type: TarUpload) {
|
||||||
|
dependsOn apidocs
|
||||||
classifier = 'apidocs'
|
classifier = 'apidocs'
|
||||||
|
remoteDir = remoteDocsDir
|
||||||
|
login = docSiteLogin
|
||||||
|
|
||||||
into('apidocs') {
|
into('apidocs') {
|
||||||
from apidocs.destinationDir
|
from apidocs.destinationDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task doctar(type: Tar, dependsOn: ':manual:doc') {
|
def docsDir = new File(project(':manual').buildDir, 'docs')
|
||||||
compression = Compression.BZIP2
|
|
||||||
|
task uploadDoc(type: TarUpload) {
|
||||||
|
dependsOn ':manual:doc'
|
||||||
classifier = 'doc'
|
classifier = 'doc'
|
||||||
|
remoteDir = remoteDocsDir
|
||||||
|
login = docSiteLogin
|
||||||
|
|
||||||
into('reference') {
|
into('reference') {
|
||||||
from docsDir
|
from docsDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def username;
|
task uploadFaq(type: TarUpload) {
|
||||||
def password;
|
dependsOn ':faq:docbookHtmlSingle'
|
||||||
|
classifier = 'faq'
|
||||||
task login << {
|
if (project.hasProperty('remoteSiteDir')) {
|
||||||
ant.input("Please enter the ssh username for host '$sshHost'", addproperty: "ssh.username")
|
remoteDir = project.property('remoteSiteDir')
|
||||||
ant.input("Please enter the ssh password '$sshHost'", addproperty: "ssh.password")
|
|
||||||
username = ant.properties['ssh.username']
|
|
||||||
password = ant.properties['ssh.password']
|
|
||||||
}
|
}
|
||||||
|
login = docSiteLogin
|
||||||
|
|
||||||
task uploadApidocs (dependsOn: login) << {
|
def faqDir = new File(project(':faq').buildDir, 'docs')
|
||||||
ant.scp(file: apitar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
|
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${apitar.archiveName}")
|
into('faq') {
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${apitar.archiveName}")
|
from faqDir
|
||||||
}
|
}
|
||||||
|
|
||||||
task uploadManual (dependsOn: login) << {
|
|
||||||
ant.scp(file: doctar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
|
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${doctar.archiveName}")
|
|
||||||
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${doctar.archiveName}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task dist(type: Zip) {
|
task dist(type: Zip) {
|
||||||
@@ -206,61 +117,90 @@ task dist (type: Zip) {
|
|||||||
from docsDir
|
from docsDir
|
||||||
}
|
}
|
||||||
into('dist') {
|
into('dist') {
|
||||||
from coreModuleProjects().collect { project -> project.libsDir }
|
from coreModuleProjects.collect {project -> project.libsDir }
|
||||||
from project(':spring-security-samples-tutorial').libsDir
|
from project(':spring-security-samples-tutorial').libsDir
|
||||||
from project(':spring-security-samples-contacts').libsDir
|
from project(':spring-security-samples-contacts').libsDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dist.dependsOn apidocs, ':manual:doc'
|
dist {
|
||||||
dist.dependsOn subprojects.collect { "$it.path:assemble" }
|
dependsOn apidocs, ':manual:doc', subprojects.collect { "$it.path:assemble" }
|
||||||
|
doLast {
|
||||||
dist.doLast {
|
|
||||||
ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
|
ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
|
||||||
}
|
}
|
||||||
|
|
||||||
task uploadDist << {
|
|
||||||
def shaFile = file("${dist.archivePath}.sha1")
|
|
||||||
assert dist.archivePath.isFile()
|
|
||||||
assert shaFile.isFile()
|
|
||||||
ant.taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: configurations.antlibs.asPath)
|
|
||||||
ant.s3(accessKey: s3AccessKey, secretKey: s3SecretAccessKey) {
|
|
||||||
upload(bucketName: 'dist.springframework.org', file: dist.archivePath,
|
|
||||||
toFile: releaseType() + "/SEC/${dist.archiveName}", publicRead: 'true') {
|
|
||||||
metadata(name: 'project.name', value: 'Spring Security')
|
|
||||||
metadata(name: 'release.type', value: releaseType())
|
|
||||||
metadata(name: 'bundle.version', value: version)
|
|
||||||
metadata(name: 'package.file.name', value: dist.archiveName)
|
|
||||||
}
|
|
||||||
upload(bucketName: 'dist.springframework.org', file: shaFile,
|
|
||||||
toFile: releaseType() + "/SEC/${dist.archiveName}.sha1", publicRead: 'true')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def javaProjects() {
|
task uploadDist(type: UploadDist) {
|
||||||
|
archiveFile = dist.archivePath
|
||||||
|
shaFile = "${dist.archivePath}.sha1" as File
|
||||||
|
archiveName = dist.archiveName
|
||||||
|
classpath = configurations.antlibs
|
||||||
|
}
|
||||||
|
|
||||||
|
def getJavaProjects() {
|
||||||
subprojects.findAll {project -> project.name != 'faq' && project.name != 'manual' }
|
subprojects.findAll {project -> project.name != 'faq' && project.name != 'manual' }
|
||||||
}
|
}
|
||||||
|
|
||||||
def sampleProjects() {
|
def getSampleProjects() {
|
||||||
subprojects.findAll {project -> project.name.startsWith('spring-security-samples') }
|
subprojects.findAll {project -> project.name.startsWith('spring-security-samples') }
|
||||||
}
|
}
|
||||||
|
|
||||||
def itestProjects() {
|
def getItestProjects() {
|
||||||
subprojects.findAll {project -> project.name.startsWith('itest') }
|
subprojects.findAll {project -> project.name.startsWith('itest') }
|
||||||
}
|
}
|
||||||
|
|
||||||
def coreModuleProjects() {
|
def getCoreModuleProjects() {
|
||||||
javaProjects() - sampleProjects() - itestProjects()
|
javaProjects - sampleProjects - itestProjects - aspectjProjects
|
||||||
|
}
|
||||||
|
|
||||||
|
def getAspectjProjects() {
|
||||||
|
subprojects.findAll {project -> project.name == 'spring-security-aspects' || project.name == 'spring-security-samples-aspectj'}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UploadDist extends DefaultTask {
|
||||||
|
@InputFile
|
||||||
|
File shaFile
|
||||||
|
|
||||||
|
@InputFile
|
||||||
|
File archiveFile
|
||||||
|
|
||||||
|
@Input
|
||||||
|
String archiveName
|
||||||
|
|
||||||
|
@InputFiles
|
||||||
|
def classpath
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
def upload() {
|
||||||
|
def accessKey = project.s3AccessKey
|
||||||
|
def secretKey = project.s3SecretAccessKey
|
||||||
|
def version = project.version
|
||||||
|
|
||||||
|
project.ant {
|
||||||
|
taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: classpath.asPath)
|
||||||
|
s3(accessKey: accessKey, secretKey: secretKey) {
|
||||||
|
upload(bucketName: 'dist.springframework.org', file: archiveFile,
|
||||||
|
toFile: releaseType() + "/SEC/${archiveName}", publicRead: 'true') {
|
||||||
|
metadata(name: 'project.name', value: 'Spring Security')
|
||||||
|
metadata(name: 'release.type', value: releaseType())
|
||||||
|
metadata(name: 'bundle.version', value: version)
|
||||||
|
metadata(name: 'package.file.name', value: archiveName)
|
||||||
|
}
|
||||||
|
upload(bucketName: 'dist.springframework.org', file: shaFile,
|
||||||
|
toFile: releaseType() + "/SEC/${archiveName}.sha1", publicRead: 'true')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def releaseType() {
|
def releaseType() {
|
||||||
if (releaseBuild) {
|
if (project.releaseBuild) {
|
||||||
'release'
|
'release'
|
||||||
} else if (snapshotBuild) {
|
} else if (project.snapshotBuild) {
|
||||||
'snapshot'
|
'snapshot'
|
||||||
} else {
|
} else {
|
||||||
'milestone'
|
'milestone'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apply plugin: 'groovy'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||||
|
mavenCentral()
|
||||||
|
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
def fopDeps = [ 'org.apache.xmlgraphics:fop:0.95-1@jar',
|
||||||
|
'org.apache.xmlgraphics:xmlgraphics-commons:1.3',
|
||||||
|
'org.apache.xmlgraphics:batik-bridge:1.7@jar',
|
||||||
|
'org.apache.xmlgraphics:batik-util:1.7@jar',
|
||||||
|
'org.apache.xmlgraphics:batik-css:1.7@jar',
|
||||||
|
'org.apache.xmlgraphics:batik-dom:1.7',
|
||||||
|
'org.apache.xmlgraphics:batik-svg-dom:1.7@jar',
|
||||||
|
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
|
||||||
|
groovy localGroovy()
|
||||||
|
compile gradleApi(),
|
||||||
|
'org.apache.xerces:resolver:2.9.1',
|
||||||
|
'saxon:saxon:6.5.3',
|
||||||
|
'org.apache.xerces:xercesImpl:2.9.1',
|
||||||
|
fopDeps
|
||||||
|
|
||||||
|
runtime 'net.sf.xslthl:xslthl:2.0.1',
|
||||||
|
'net.sf.docbook:docbook-xsl:1.75.2:ns-resources@zip'
|
||||||
|
}
|
||||||
|
|
||||||
|
task ide(type: Copy) {
|
||||||
|
from configurations.runtime
|
||||||
|
into 'ide'
|
||||||
|
}
|
||||||
@@ -0,0 +1,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
|
||||||
+2
-2
@@ -2,12 +2,12 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile project(':spring-security-core'),
|
compile project(':spring-security-core'),
|
||||||
project(':spring-security-web'),
|
project(':spring-security-web'),
|
||||||
"javax.servlet:servlet-api:2.5",
|
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-tx:$springVersion",
|
"org.springframework:spring-tx:$springVersion",
|
||||||
"org.springframework:spring-web:$springVersion",
|
"org.springframework:spring-web:$springVersion",
|
||||||
"org.jasig.cas:cas-client-core:3.1.9",
|
"org.jasig.cas:cas-client-core:3.1.9",
|
||||||
"net.sf.ehcache:ehcache:$ehcacheVersion"
|
"net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||||
|
|
||||||
|
provided 'javax.servlet:servlet-api:2.5'
|
||||||
}
|
}
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.6.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-security-cas-client</artifactId>
|
<artifactId>spring-security-cas-client</artifactId>
|
||||||
<name>Spring Security - CAS support</name>
|
<name>Spring Security - CAS support</name>
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
|||||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||||
*/
|
*/
|
||||||
public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
|
public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
|
||||||
final Collection<GrantedAuthority> authorities, final UserDetails userDetails, final Assertion assertion) {
|
final Collection<? extends GrantedAuthority> authorities, final UserDetails userDetails, final Assertion assertion) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
|
|
||||||
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (credentials == null)
|
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (credentials == null)
|
||||||
|
|||||||
+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>.
|
* By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Rob Winch
|
||||||
*/
|
*/
|
||||||
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||||
//~ Static fields/initializers =====================================================================================
|
//~ Static fields/initializers =====================================================================================
|
||||||
@@ -89,7 +90,13 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
|||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
|
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;
|
final String username = CAS_STATEFUL_IDENTIFIER;
|
||||||
String password = request.getParameter(this.artifactParameter);
|
String password = request.getParameter(this.artifactParameter);
|
||||||
|
|
||||||
@@ -108,18 +115,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
|||||||
* Overridden to provide proxying capabilities.
|
* Overridden to provide proxying capabilities.
|
||||||
*/
|
*/
|
||||||
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
|
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
|
||||||
final String requestUri = request.getRequestURI();
|
return isProxyRequest(request) || super.requiresAuthentication(request, response);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
|
||||||
@@ -134,4 +130,14 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
|||||||
public final void setServiceProperties(final ServiceProperties serviceProperties) {
|
public final void setServiceProperties(final ServiceProperties serviceProperties) {
|
||||||
this.artifactParameter = serviceProperties.getArtifactParameter();
|
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;
|
package org.springframework.security.cas.web;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
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.junit.Test;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
@@ -30,6 +34,7 @@ import org.springframework.security.core.AuthenticationException;
|
|||||||
* Tests {@link CasAuthenticationFilter}.
|
* Tests {@link CasAuthenticationFilter}.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Rob Winch
|
||||||
*/
|
*/
|
||||||
public class CasAuthenticationFilterTests {
|
public class CasAuthenticationFilterTests {
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
@@ -67,4 +72,58 @@ public class CasAuthenticationFilterTests {
|
|||||||
|
|
||||||
filter.attemptAuthentication(new MockHttpServletRequest(), new MockHttpServletResponse());
|
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-SymbolicName: org.springframework.security.cas
|
||||||
Bundle-Name: Spring Security CAS
|
Bundle-Name: Spring Security CAS
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: SpringSource
|
||||||
@@ -18,4 +20,3 @@ Import-Template:
|
|||||||
org.springframework.util;version="[${spring.version}, 3.1.0)",
|
org.springframework.util;version="[${spring.version}, 3.1.0)",
|
||||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||||
javax.servlet.*;version="0"
|
javax.servlet.*;version="0"
|
||||||
|
|
||||||
@@ -5,24 +5,20 @@ compileTestJava.dependsOn(':spring-security-core:compileTestJava')
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile project(':spring-security-core'),
|
compile project(':spring-security-core'),
|
||||||
project(':spring-security-web'),
|
project(':spring-security-web'),
|
||||||
"javax.servlet:servlet-api:2.5",
|
'aopalliance:aopalliance:1.0',
|
||||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||||
"org.springframework:spring-aop:$springVersion",
|
"org.springframework:spring-aop:$springVersion",
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-web:$springVersion",
|
"org.springframework:spring-web:$springVersion",
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-tx:$springVersion"
|
"org.springframework:spring-tx:$springVersion"
|
||||||
|
|
||||||
|
provided "javax.servlet:servlet-api:2.5"
|
||||||
|
|
||||||
testCompile project(':spring-security-ldap'),
|
testCompile project(':spring-security-ldap'),
|
||||||
project(':spring-security-openid'),
|
project(':spring-security-openid'),
|
||||||
files(this.project(':spring-security-core').sourceSets.test.classesDir),
|
files(this.project(':spring-security-core').sourceSets.test.classesDir),
|
||||||
'javax.annotation:jsr250-api:1.0',
|
'javax.annotation:jsr250-api:1.0',
|
||||||
'aopalliance:aopalliance:1.0',
|
|
||||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
||||||
"org.springframework:spring-jdbc:$springVersion"
|
"org.springframework:spring-jdbc:$springVersion"
|
||||||
}
|
}
|
||||||
|
|
||||||
task show << {
|
|
||||||
println dependencies
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
pushd src/main/resources/org/springframework/security/config/
|
pushd src/main/resources/org/springframework/security/config/
|
||||||
|
|
||||||
echo "Converting rnc file to xsd ..."
|
echo "Converting rnc file to xsd ..."
|
||||||
java -jar ~/bin/trang.jar spring-security-3.0.rnc spring-security-3.0.xsd
|
java -jar ~/bin/trang.jar spring-security-3.0.4.rnc spring-security-3.0.4.xsd
|
||||||
|
|
||||||
echo "Applying XSL transformation to xsd ..."
|
echo "Applying XSL transformation to xsd ..."
|
||||||
xsltproc --output spring-security-3.0.xsd spring-security.xsl spring-security-3.0.xsd
|
xsltproc --output spring-security-3.0.4.xsd spring-security.xsl spring-security-3.0.4.xsd
|
||||||
|
|
||||||
popd
|
popd
|
||||||
+2
-6
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.6.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<artifactId>spring-security-config</artifactId>
|
<artifactId>spring-security-config</artifactId>
|
||||||
@@ -41,10 +41,6 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-ldap</artifactId>
|
<artifactId>spring-security-ldap</artifactId>
|
||||||
@@ -76,7 +72,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
<version>1.5.10</version>
|
<version>1.6.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -50,4 +50,5 @@ public abstract class Elements {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||||
|
public static final String HTTP_FIREWALL = "http-firewall";
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-7
@@ -3,6 +3,8 @@ package org.springframework.security.config;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||||
@@ -15,12 +17,14 @@ import org.springframework.security.config.authentication.JdbcUserServiceBeanDef
|
|||||||
import org.springframework.security.config.authentication.UserServiceBeanDefinitionParser;
|
import org.springframework.security.config.authentication.UserServiceBeanDefinitionParser;
|
||||||
import org.springframework.security.config.http.FilterChainMapBeanDefinitionDecorator;
|
import org.springframework.security.config.http.FilterChainMapBeanDefinitionDecorator;
|
||||||
import org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser;
|
import org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser;
|
||||||
|
import org.springframework.security.config.http.HttpFirewallBeanDefinitionParser;
|
||||||
import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser;
|
import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
|
||||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
||||||
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
|
||||||
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
|
||||||
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
@@ -33,18 +37,44 @@ import org.w3c.dom.Node;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public final class SecurityNamespaceHandler implements NamespaceHandler {
|
public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||||
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
|
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
|
||||||
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
|
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
|
||||||
private BeanDefinitionDecorator filterChainMapBDD;
|
private BeanDefinitionDecorator filterChainMapBDD;
|
||||||
|
|
||||||
|
public SecurityNamespaceHandler() {
|
||||||
|
String coreVersion = SpringSecurityCoreVersion.getVersion();
|
||||||
|
|
||||||
|
Package pkg = SpringSecurityCoreVersion.class.getPackage();
|
||||||
|
|
||||||
|
if (pkg == null || coreVersion == null) {
|
||||||
|
logger.info("Couldn't determine package version information.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String version = pkg.getImplementationVersion();
|
||||||
|
logger.info("Spring Security 'config' module version is " + version);
|
||||||
|
|
||||||
|
if (version.compareTo(coreVersion) != 0) {
|
||||||
|
logger.error("You are running with different versions of the Spring Security 'core' and 'config' modules");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
if (!namespaceMatchesVersion(element)) {
|
if (!namespaceMatchesVersion(element)) {
|
||||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd schema with Spring Security 3.0." +
|
pc.getReaderContext().fatal("You must use a 3.0 schema with Spring Security 3.0." +
|
||||||
" Please update your schema declarations to the 3.0 schema.", element);
|
"(2.0 or 3.1 versions are not valid)" +
|
||||||
|
" Please update your schema declarations to the 3.0.3 schema (spring-security-3.0.3.xsd).", element);
|
||||||
}
|
}
|
||||||
String name = pc.getDelegate().getLocalName(element);
|
String name = pc.getDelegate().getLocalName(element);
|
||||||
BeanDefinitionParser parser = parsers.get(name);
|
BeanDefinitionParser parser = parsers.get(name);
|
||||||
|
|
||||||
|
if (parser == null) {
|
||||||
|
// SEC-1455. Load parsers when required, not just on init().
|
||||||
|
loadParsers();
|
||||||
|
}
|
||||||
|
|
||||||
if (parser == null) {
|
if (parser == null) {
|
||||||
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
|
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
|
||||||
reportMissingWebClasses(name, pc, element);
|
reportMissingWebClasses(name, pc, element);
|
||||||
@@ -67,6 +97,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Elements.FILTER_CHAIN_MAP.equals(name)) {
|
if (Elements.FILTER_CHAIN_MAP.equals(name)) {
|
||||||
|
if (filterChainMapBDD == null) {
|
||||||
|
loadParsers();
|
||||||
|
}
|
||||||
if (filterChainMapBDD == null) {
|
if (filterChainMapBDD == null) {
|
||||||
reportMissingWebClasses(name, pc, node);
|
reportMissingWebClasses(name, pc, node);
|
||||||
}
|
}
|
||||||
@@ -91,8 +124,12 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
|
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void init() {
|
public void init() {
|
||||||
|
loadParsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void loadParsers() {
|
||||||
// Parsers
|
// Parsers
|
||||||
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
|
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
|
||||||
parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
|
parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
|
||||||
@@ -102,15 +139,14 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
|
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
|
||||||
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
||||||
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
|
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
|
||||||
// registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
|
|
||||||
|
|
||||||
// Only load the web-namespace parsers if the web classes are available
|
// Only load the web-namespace parsers if the web classes are available
|
||||||
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
|
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
|
||||||
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
|
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
|
||||||
|
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
|
||||||
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||||
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
|
||||||
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
|
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
|
||||||
//registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,8 +165,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
|||||||
|
|
||||||
private boolean matchesVersionInternal(Element element) {
|
private boolean matchesVersionInternal(Element element) {
|
||||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||||
return schemaLocation.matches("(?m).*spring-security-3.0.xsd.*")
|
return schemaLocation.matches("(?m).*spring-security-3\\.0.*xsd.*")
|
||||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
|| schemaLocation.matches("(?m).*spring-security\\.xsd.*")
|
||||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-20
@@ -1,18 +1,16 @@
|
|||||||
package org.springframework.security.config.authentication;
|
package org.springframework.security.config.authentication;
|
||||||
|
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
import org.springframework.security.config.Elements;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,9 +20,6 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
|
|||||||
static final String CACHE_REF = "cache-ref";
|
static final String CACHE_REF = "cache-ref";
|
||||||
public static final String CACHING_SUFFIX = ".caching";
|
public static final String CACHING_SUFFIX = ".caching";
|
||||||
|
|
||||||
/** UserDetailsService bean Id. For use in a stateful context (i.e. in AuthenticationProviderBDP) */
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
protected abstract String getBeanClassName(Element element);
|
protected abstract String getBeanClassName(Element element);
|
||||||
|
|
||||||
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
||||||
@@ -51,34 +46,33 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
|
|||||||
parserContext.registerBeanComponent(new BeanComponentDefinition(cachingUserService, beanId + CACHING_SUFFIX));
|
parserContext.registerBeanComponent(new BeanComponentDefinition(cachingUserService, beanId + CACHING_SUFFIX));
|
||||||
}
|
}
|
||||||
|
|
||||||
id = beanId;
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext pc)
|
||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
|
|
||||||
String id = element.getAttribute("id");
|
String id = element.getAttribute("id");
|
||||||
|
|
||||||
|
if (pc.isNested()) {
|
||||||
|
// We're inside an <authentication-provider> element
|
||||||
|
if (!StringUtils.hasText(id)) {
|
||||||
|
id = pc.getReaderContext().generateBeanName(definition);
|
||||||
|
}
|
||||||
|
BeanDefinition container = pc.getContainingBeanDefinition();
|
||||||
|
container.getPropertyValues().add("userDetailsService", new RuntimeBeanReference(id));
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.hasText(id)) {
|
if (StringUtils.hasText(id)) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Elements.AUTHENTICATION_PROVIDER.equals(element.getParentNode().getNodeName())) {
|
|
||||||
return parserContext.getReaderContext().generateBeanName(definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If top level, use the default name or throw an exception if already used
|
// If top level, use the default name or throw an exception if already used
|
||||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
|
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
|
||||||
throw new BeanDefinitionStoreException("No id supplied and another " +
|
throw new BeanDefinitionStoreException("No id supplied and another " +
|
||||||
"bean is already registered as " + BeanIds.USER_DETAILS_SERVICE);
|
"bean is already registered as " + BeanIds.USER_DETAILS_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BeanIds.USER_DETAILS_SERVICE;
|
return BeanIds.USER_DETAILS_SERVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -35,6 +35,7 @@ import org.w3c.dom.NodeList;
|
|||||||
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
|
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
private static final String ATT_ALIAS = "alias";
|
private static final String ATT_ALIAS = "alias";
|
||||||
private static final String ATT_REF = "ref";
|
private static final String ATT_REF = "ref";
|
||||||
|
private static final String ATT_ERASE_CREDENTIALS = "erase-credentials";
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
|
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
|
||||||
@@ -72,6 +73,11 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
|||||||
}
|
}
|
||||||
|
|
||||||
providerManagerBldr.addPropertyValue("providers", providers);
|
providerManagerBldr.addPropertyValue("providers", providers);
|
||||||
|
|
||||||
|
if ("true".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
|
||||||
|
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", true);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the default event publisher
|
// Add the default event publisher
|
||||||
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
|
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
|
||||||
String id = pc.getReaderContext().generateBeanName(publisher);
|
String id = pc.getReaderContext().generateBeanName(publisher);
|
||||||
|
|||||||
+16
-76
@@ -7,7 +7,6 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
|||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.Elements;
|
import org.springframework.security.config.Elements;
|
||||||
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.util.xml.DomUtils;
|
import org.springframework.util.xml.DomUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
@@ -21,14 +20,14 @@ import org.w3c.dom.Element;
|
|||||||
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
|
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
private static String ATT_USER_DETAILS_REF = "user-service-ref";
|
private static String ATT_USER_DETAILS_REF = "user-service-ref";
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
|
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
|
||||||
authProvider.setSource(parserContext.extractSource(element));
|
authProvider.setSource(pc.extractSource(element));
|
||||||
|
|
||||||
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
|
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
|
||||||
|
|
||||||
if (passwordEncoderElt != null) {
|
if (passwordEncoderElt != null) {
|
||||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, parserContext);
|
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, pc);
|
||||||
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||||
|
|
||||||
if (pep.getSaltSource() != null) {
|
if (pep.getSaltSource() != null) {
|
||||||
@@ -37,98 +36,39 @@ public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitio
|
|||||||
}
|
}
|
||||||
|
|
||||||
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
|
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
|
||||||
Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
|
if (userServiceElt == null) {
|
||||||
Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
|
userServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
|
||||||
|
}
|
||||||
|
if (userServiceElt == null) {
|
||||||
|
userServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
String ref = element.getAttribute(ATT_USER_DETAILS_REF);
|
String ref = element.getAttribute(ATT_USER_DETAILS_REF);
|
||||||
|
|
||||||
if (StringUtils.hasText(ref)) {
|
if (StringUtils.hasText(ref)) {
|
||||||
if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) {
|
if (userServiceElt != null) {
|
||||||
parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
|
pc.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
|
||||||
"elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" +
|
"elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" +
|
||||||
Elements.LDAP_USER_SERVICE + "'", element);
|
Elements.LDAP_USER_SERVICE + "'", element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authProvider.getPropertyValues().add("userDetailsService", new RuntimeBeanReference(ref));
|
||||||
} else {
|
} else {
|
||||||
// Use the child elements to create the UserDetailsService
|
// Use the child elements to create the UserDetailsService
|
||||||
AbstractUserDetailsServiceBeanDefinitionParser parser = null;
|
|
||||||
Element elt = null;
|
|
||||||
|
|
||||||
if (userServiceElt != null) {
|
if (userServiceElt != null) {
|
||||||
elt = userServiceElt;
|
pc.getDelegate().parseCustomElement(userServiceElt, authProvider);
|
||||||
parser = new UserServiceBeanDefinitionParser();
|
|
||||||
} else if (jdbcUserServiceElt != null) {
|
|
||||||
elt = jdbcUserServiceElt;
|
|
||||||
parser = new JdbcUserServiceBeanDefinitionParser();
|
|
||||||
} else if (ldapUserServiceElt != null) {
|
|
||||||
elt = ldapUserServiceElt;
|
|
||||||
parser = new LdapUserServiceBeanDefinitionParser();
|
|
||||||
} else {
|
} else {
|
||||||
parserContext.getReaderContext().error("A user-service is required", element);
|
pc.getReaderContext().error("A user-service is required", element);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.parse(elt, parserContext);
|
|
||||||
ref = parser.getId();
|
|
||||||
|
|
||||||
// Pinch the cache-ref from the UserDetailService element, if set.
|
// Pinch the cache-ref from the UserDetailService element, if set.
|
||||||
String cacheRef = elt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
|
String cacheRef = userServiceElt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
|
||||||
|
|
||||||
if (StringUtils.hasText(cacheRef)) {
|
if (StringUtils.hasText(cacheRef)) {
|
||||||
authProvider.getPropertyValues().addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
|
authProvider.getPropertyValues().addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref));
|
|
||||||
|
|
||||||
// We need to register the provider to access it in the post processor to check if it has a cache
|
|
||||||
// final String id = parserContext.getReaderContext().generateBeanName(authProvider);
|
|
||||||
// parserContext.getRegistry().registerBeanDefinition(id, authProvider);
|
|
||||||
// parserContext.registerComponent(new BeanComponentDefinition(authProvider, id));
|
|
||||||
|
|
||||||
|
|
||||||
// BeanDefinitionBuilder cacheResolverBldr = BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProviderCacheResolver.class);
|
|
||||||
// cacheResolverBldr.addConstructorArgValue(id);
|
|
||||||
// cacheResolverBldr.addConstructorArgValue(ref);
|
|
||||||
// cacheResolverBldr.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
|
||||||
// BeanDefinition cacheResolver = cacheResolverBldr.getBeanDefinition();
|
|
||||||
//
|
|
||||||
// String name = parserContext.getReaderContext().generateBeanName(cacheResolver);
|
|
||||||
// parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
|
|
||||||
// parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
|
|
||||||
|
|
||||||
// ConfigUtils.addAuthenticationProvider(parserContext, id, element);
|
|
||||||
|
|
||||||
return authProvider;
|
return authProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the registered user service bean has an associated cache and, if so, sets it on the
|
|
||||||
* authentication provider.
|
|
||||||
*/
|
|
||||||
// static class AuthenticationProviderCacheResolver implements BeanFactoryPostProcessor, Ordered {
|
|
||||||
// private String providerId;
|
|
||||||
// private String userServiceId;
|
|
||||||
//
|
|
||||||
// public AuthenticationProviderCacheResolver(String providerId, String userServiceId) {
|
|
||||||
// this.providerId = providerId;
|
|
||||||
// this.userServiceId = userServiceId;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
|
||||||
// RootBeanDefinition provider = (RootBeanDefinition) beanFactory.getBeanDefinition(providerId);
|
|
||||||
//
|
|
||||||
// String cachingId = userServiceId + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
|
||||||
//
|
|
||||||
// if (beanFactory.containsBeanDefinition(cachingId)) {
|
|
||||||
// RootBeanDefinition cachingUserService = (RootBeanDefinition) beanFactory.getBeanDefinition(cachingId);
|
|
||||||
//
|
|
||||||
// PropertyValue userCacheProperty = cachingUserService.getPropertyValues().getPropertyValue("userCache");
|
|
||||||
//
|
|
||||||
// provider.getPropertyValues().addPropertyValue(userCacheProperty);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public int getOrder() {
|
|
||||||
// return HIGHEST_PRECEDENCE;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -24,6 +24,7 @@ import org.w3c.dom.Element;
|
|||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||||
|
|
||||||
static final String ATT_PASSWORD = "password";
|
static final String ATT_PASSWORD = "password";
|
||||||
@@ -90,7 +91,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
|
|||||||
user.addConstructorArgValue(!locked);
|
user.addConstructorArgValue(!locked);
|
||||||
user.addConstructorArgValue(authorities.getBeanDefinition());
|
user.addConstructorArgValue(authorities.getBeanDefinition());
|
||||||
|
|
||||||
users.put(userName, user.getBeanDefinition());
|
users.put(userName.toLowerCase(), user.getBeanDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap.getPropertyValues().addPropertyValue("users", users);
|
userMap.getPropertyValues().addPropertyValue("users", users);
|
||||||
|
|||||||
+44
-45
@@ -2,11 +2,6 @@ package org.springframework.security.config.http;
|
|||||||
|
|
||||||
import static org.springframework.security.config.http.SecurityFilters.*;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.BeanMetadataElement;
|
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.SubjectDnX509PrincipalExtractor;
|
||||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
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.BasicAuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.util.xml.DomUtils;
|
import org.springframework.util.xml.DomUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles creation of authentication mechanism filters and related beans for <http> parsing.
|
* 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_REF = "ref";
|
||||||
|
|
||||||
|
private static final String ATT_KEY = "key";
|
||||||
|
|
||||||
private Element httpElt;
|
private Element httpElt;
|
||||||
private ParserContext pc;
|
private ParserContext pc;
|
||||||
|
|
||||||
@@ -81,10 +81,8 @@ final class AuthenticationConfigBuilder {
|
|||||||
private String rememberMeServicesId;
|
private String rememberMeServicesId;
|
||||||
private BeanReference rememberMeProviderRef;
|
private BeanReference rememberMeProviderRef;
|
||||||
private BeanDefinition basicFilter;
|
private BeanDefinition basicFilter;
|
||||||
private BeanDefinition basicEntryPoint;
|
private RuntimeBeanReference basicEntryPoint;
|
||||||
private RootBeanDefinition formFilter;
|
|
||||||
private BeanDefinition formEntryPoint;
|
private BeanDefinition formEntryPoint;
|
||||||
private RootBeanDefinition openIDFilter;
|
|
||||||
private BeanDefinition openIDEntryPoint;
|
private BeanDefinition openIDEntryPoint;
|
||||||
private BeanReference openIDProviderRef;
|
private BeanReference openIDProviderRef;
|
||||||
private String openIDProviderId;
|
private String openIDProviderId;
|
||||||
@@ -99,8 +97,6 @@ final class AuthenticationConfigBuilder {
|
|||||||
private BeanDefinition etf;
|
private BeanDefinition etf;
|
||||||
private BeanReference requestCache;
|
private BeanReference requestCache;
|
||||||
|
|
||||||
final SecureRandom random;
|
|
||||||
|
|
||||||
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
|
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
|
||||||
String portMapperName) {
|
String portMapperName) {
|
||||||
this.httpElt = element;
|
this.httpElt = element;
|
||||||
@@ -108,18 +104,9 @@ final class AuthenticationConfigBuilder {
|
|||||||
this.portMapperName = portMapperName;
|
this.portMapperName = portMapperName;
|
||||||
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||||
this.allowSessionCreation = allowSessionCreation;
|
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) {
|
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.
|
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||||
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
|
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
|
||||||
|
|
||||||
@@ -127,10 +114,10 @@ final class AuthenticationConfigBuilder {
|
|||||||
String key = rememberMeElt.getAttribute(ATT_KEY);
|
String key = rememberMeElt.getAttribute(ATT_KEY);
|
||||||
|
|
||||||
if (!StringUtils.hasText(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);
|
rememberMeFilter.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
|
||||||
rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
|
rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
|
||||||
createRememberMeProvider(key);
|
createRememberMeProvider(key);
|
||||||
@@ -152,10 +139,11 @@ final class AuthenticationConfigBuilder {
|
|||||||
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||||
|
|
||||||
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
|
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
|
||||||
|
RootBeanDefinition formFilter = null;
|
||||||
|
|
||||||
if (formLoginElt != null || autoConfig) {
|
if (formLoginElt != null || autoConfig) {
|
||||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||||
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
|
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
|
||||||
|
|
||||||
parser.parse(formLoginElt, pc);
|
parser.parse(formLoginElt, pc);
|
||||||
formFilter = parser.getFilterBean();
|
formFilter = parser.getFilterBean();
|
||||||
@@ -163,7 +151,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (formFilter != null) {
|
if (formFilter != null) {
|
||||||
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||||
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||||
|
|
||||||
|
|
||||||
@@ -176,10 +164,11 @@ final class AuthenticationConfigBuilder {
|
|||||||
|
|
||||||
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
||||||
|
RootBeanDefinition openIDFilter = null;
|
||||||
|
|
||||||
if (openIDLoginElt != null) {
|
if (openIDLoginElt != null) {
|
||||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||||
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
|
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
|
||||||
|
|
||||||
parser.parse(openIDLoginElt, pc);
|
parser.parse(openIDLoginElt, pc);
|
||||||
openIDFilter = parser.getFilterBean();
|
openIDFilter = parser.getFilterBean();
|
||||||
@@ -214,7 +203,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (openIDFilter != null) {
|
if (openIDFilter != null) {
|
||||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||||
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||||
// Required by login page filter
|
// Required by login page filter
|
||||||
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
|
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
|
||||||
@@ -256,25 +245,29 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RootBeanDefinition filter = null;
|
RootBeanDefinition filter = null;
|
||||||
RootBeanDefinition entryPoint = null;
|
|
||||||
|
|
||||||
if (basicAuthElt != null || autoConfig) {
|
if (basicAuthElt != null || autoConfig) {
|
||||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
|
||||||
entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
|
||||||
|
String entryPointId;
|
||||||
|
|
||||||
|
if (basicAuthElt != null && StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
|
||||||
|
basicEntryPoint = new RuntimeBeanReference(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
|
||||||
|
} else {
|
||||||
|
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
|
||||||
entryPoint.setSource(pc.extractSource(httpElt));
|
entryPoint.setSource(pc.extractSource(httpElt));
|
||||||
|
|
||||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||||
|
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
||||||
String entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
|
|
||||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||||
|
basicEntryPoint = new RuntimeBeanReference(entryPointId);
|
||||||
|
}
|
||||||
|
|
||||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||||
filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(entryPointId));
|
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
|
||||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
basicFilter = filter;
|
basicFilter = filter;
|
||||||
basicEntryPoint = entryPoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void createX509Filter(BeanReference authManager) {
|
void createX509Filter(BeanReference authManager) {
|
||||||
@@ -325,7 +318,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
|
|
||||||
|
|
||||||
void createLoginPageFilterIfNeeded() {
|
void createLoginPageFilterIfNeeded() {
|
||||||
boolean needLoginPage = formFilter != null || openIDFilter != null;
|
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
|
||||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||||
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
|
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
|
||||||
|
|
||||||
@@ -336,11 +329,11 @@ final class AuthenticationConfigBuilder {
|
|||||||
BeanDefinitionBuilder loginPageFilter =
|
BeanDefinitionBuilder loginPageFilter =
|
||||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||||
|
|
||||||
if (formFilter != null) {
|
if (formFilterId != null) {
|
||||||
loginPageFilter.addConstructorArgReference(formFilterId);
|
loginPageFilter.addConstructorArgReference(formFilterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openIDFilter != null) {
|
if (openIDFilterId != null) {
|
||||||
loginPageFilter.addConstructorArgReference(openIDFilterId);
|
loginPageFilter.addConstructorArgReference(openIDFilterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +363,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
if (anonymousElt != null) {
|
if (anonymousElt != null) {
|
||||||
grantedAuthority = anonymousElt.getAttribute("granted-authority");
|
grantedAuthority = anonymousElt.getAttribute("granted-authority");
|
||||||
username = anonymousElt.getAttribute("username");
|
username = anonymousElt.getAttribute("username");
|
||||||
key = anonymousElt.getAttribute("key");
|
key = anonymousElt.getAttribute(ATT_KEY);
|
||||||
source = pc.extractSource(anonymousElt);
|
source = pc.extractSource(anonymousElt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +377,7 @@ final class AuthenticationConfigBuilder {
|
|||||||
|
|
||||||
if (!StringUtils.hasText(key)) {
|
if (!StringUtils.hasText(key)) {
|
||||||
// Generate a random key for the Anonymous provider
|
// Generate a random key for the Anonymous provider
|
||||||
key = Long.toString(random.nextLong());
|
key = createKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
anonymousFilter = new RootBeanDefinition(AnonymousAuthenticationFilter.class);
|
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() {
|
void createExceptionTranslationFilter() {
|
||||||
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||||
etfBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(httpElt, pc));
|
etfBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(httpElt, pc));
|
||||||
@@ -499,12 +497,12 @@ final class AuthenticationConfigBuilder {
|
|||||||
"but not both.", pc.extractSource(openIDLoginElt));
|
"but not both.", pc.extractSource(openIDLoginElt));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formFilter != null && openIDLoginPage == null) {
|
if (formFilterId != null && openIDLoginPage == null) {
|
||||||
return formEntryPoint;
|
return formEntryPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise use OpenID if enabled
|
// Otherwise use OpenID if enabled
|
||||||
if (openIDFilter != null) {
|
if (openIDFilterId != null) {
|
||||||
return openIDEntryPoint;
|
return openIDEntryPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +538,8 @@ final class AuthenticationConfigBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void createUserServiceInjector() {
|
void createUserServiceInjector() {
|
||||||
BeanDefinitionBuilder userServiceInjector = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
BeanDefinitionBuilder userServiceInjector =
|
||||||
|
BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||||
userServiceInjector.addConstructorArgValue(x509ProviderId);
|
userServiceInjector.addConstructorArgValue(x509ProviderId);
|
||||||
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
|
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
|
||||||
userServiceInjector.addConstructorArgValue(openIDProviderId);
|
userServiceInjector.addConstructorArgValue(openIDProviderId);
|
||||||
@@ -567,12 +566,12 @@ final class AuthenticationConfigBuilder {
|
|||||||
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
|
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formFilter != null) {
|
if (formFilterId != null) {
|
||||||
filters.add(new OrderDecorator(formFilter, FORM_LOGIN_FILTER));
|
filters.add(new OrderDecorator(new RuntimeBeanReference(formFilterId), FORM_LOGIN_FILTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openIDFilter != null) {
|
if (openIDFilterId != null) {
|
||||||
filters.add(new OrderDecorator(openIDFilter, OPENID_FILTER));
|
filters.add(new OrderDecorator(new RuntimeBeanReference(openIDFilterId), OPENID_FILTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loginPageGenerationFilter != null) {
|
if (loginPageGenerationFilter != null) {
|
||||||
|
|||||||
+10
@@ -1,5 +1,8 @@
|
|||||||
package org.springframework.security.config.http;
|
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 java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
@@ -112,6 +115,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||||||
if (!StringUtils.hasText(access)) {
|
if (!StringUtils.hasText(access)) {
|
||||||
continue;
|
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);
|
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 DEF_FORM_LOGIN_TARGET_URL = "/";
|
||||||
|
|
||||||
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
|
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
|
||||||
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
|
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL =
|
||||||
|
DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
|
||||||
|
|
||||||
private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
|
private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
|
||||||
private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
|
private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
|
||||||
@@ -40,17 +41,19 @@ public class FormLoginBeanDefinitionParser {
|
|||||||
private final String filterClassName;
|
private final String filterClassName;
|
||||||
private final BeanReference requestCache;
|
private final BeanReference requestCache;
|
||||||
private final BeanReference sessionStrategy;
|
private final BeanReference sessionStrategy;
|
||||||
|
private final boolean allowSessionCreation;
|
||||||
|
|
||||||
private RootBeanDefinition filterBean;
|
private RootBeanDefinition filterBean;
|
||||||
private RootBeanDefinition entryPointBean;
|
private RootBeanDefinition entryPointBean;
|
||||||
private String loginPage;
|
private String loginPage;
|
||||||
|
|
||||||
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
|
||||||
BeanReference requestCache, BeanReference sessionStrategy) {
|
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation) {
|
||||||
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
||||||
this.filterClassName = filterClassName;
|
this.filterClassName = filterClassName;
|
||||||
this.requestCache = requestCache;
|
this.requestCache = requestCache;
|
||||||
this.sessionStrategy = sessionStrategy;
|
this.sessionStrategy = sessionStrategy;
|
||||||
|
this.allowSessionCreation = allowSessionCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeanDefinition parse(Element elt, ParserContext pc) {
|
public BeanDefinition parse(Element elt, ParserContext pc) {
|
||||||
@@ -135,6 +138,7 @@ public class FormLoginBeanDefinitionParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
|
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
|
||||||
|
failureHandler.addPropertyValue("allowSessionCreation", allowSessionCreation);
|
||||||
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
|
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+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.SecurityFilters.*;
|
||||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||||
|
import static org.springframework.security.config.Elements.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -83,7 +84,7 @@ class HttpConfigurationBuilder {
|
|||||||
private final List<Element> interceptUrls;
|
private final List<Element> interceptUrls;
|
||||||
|
|
||||||
// Use ManagedMap to allow placeholder resolution
|
// Use ManagedMap to allow placeholder resolution
|
||||||
private ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap;
|
private ManagedMap<Object, List<BeanMetadataElement>> filterChainMap;
|
||||||
|
|
||||||
private BeanDefinition cpf;
|
private BeanDefinition cpf;
|
||||||
private BeanDefinition securityContextPersistenceFilter;
|
private BeanDefinition securityContextPersistenceFilter;
|
||||||
@@ -109,7 +110,7 @@ class HttpConfigurationBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void parseInterceptUrlsForEmptyFilterChains() {
|
void parseInterceptUrlsForEmptyFilterChains() {
|
||||||
filterChainMap = new ManagedMap<BeanDefinition, List<BeanMetadataElement>>();
|
filterChainMap = new ManagedMap<Object, List<BeanMetadataElement>>();
|
||||||
|
|
||||||
for (Element urlElt : interceptUrls) {
|
for (Element urlElt : interceptUrls) {
|
||||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||||
@@ -393,9 +394,21 @@ class HttpConfigurationBuilder {
|
|||||||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||||
|
|
||||||
if (StringUtils.hasText(requiredChannel)) {
|
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);
|
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
|
||||||
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
|
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
|
||||||
|
|
||||||
|
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
||||||
|
if(StringUtils.hasText(method)) {
|
||||||
|
requestKey.getConstructorArgumentValues().addGenericArgumentValue(method);
|
||||||
|
}
|
||||||
|
|
||||||
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
|
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
|
||||||
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
||||||
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
||||||
@@ -464,7 +477,7 @@ class HttpConfigurationBuilder {
|
|||||||
return allowSessionCreation;
|
return allowSessionCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManagedMap<BeanDefinition, List<BeanMetadataElement>> getFilterChainMap() {
|
public ManagedMap<Object, List<BeanMetadataElement>> getFilterChainMap() {
|
||||||
return filterChainMap;
|
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.BeanMetadataElement;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanReference;
|
import org.springframework.beans.factory.config.BeanReference;
|
||||||
|
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||||
@@ -55,6 +56,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
static final String OPT_FILTERS_NONE = "none";
|
static final String OPT_FILTERS_NONE = "none";
|
||||||
|
|
||||||
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
|
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
|
||||||
|
static final String ATT_HTTP_METHOD = "method";
|
||||||
|
|
||||||
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
|
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
|
||||||
|
|
||||||
@@ -135,10 +137,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
filterChain.add(od.bean);
|
filterChain.add(od.bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
|
ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
|
||||||
BeanDefinition universalMatch = new RootBeanDefinition(String.class);
|
filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
|
||||||
universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());
|
|
||||||
filterChainMap.put(universalMatch, filterChain);
|
|
||||||
|
|
||||||
registerFilterChainProxy(pc, filterChainMap, matcher, source);
|
registerFilterChainProxy(pc, filterChainMap, matcher, source);
|
||||||
|
|
||||||
@@ -168,6 +168,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
|
||||||
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||||
authManager.addPropertyValue("providers", authenticationProviders);
|
authManager.addPropertyValue("providers", authenticationProviders);
|
||||||
|
RootBeanDefinition clearCredentials = new RootBeanDefinition(MethodInvokingFactoryBean.class);
|
||||||
|
clearCredentials.getPropertyValues().addPropertyValue("targetObject", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
|
||||||
|
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
|
||||||
|
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
|
||||||
|
|
||||||
if (concurrencyController != null) {
|
if (concurrencyController != null) {
|
||||||
authManager.addPropertyValue("sessionController", concurrencyController);
|
authManager.addPropertyValue("sessionController", concurrencyController);
|
||||||
@@ -247,7 +251,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
return customFilters;
|
return customFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
|
private void registerFilterChainProxy(ParserContext pc, Map<Object, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
|
||||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -36,12 +36,12 @@ class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ord
|
|||||||
"jar file in your application", e);
|
"jar file in your application", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] sources = bf.getBeanNamesForType(contextSourceClass);
|
String[] sources = bf.getBeanNamesForType(contextSourceClass, false, false);
|
||||||
|
|
||||||
|
|
||||||
if (sources.length == 0) {
|
if (sources.length == 0) {
|
||||||
throw new ApplicationContextException("No BaseLdapPathContextSource instances found. Have you " +
|
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) {
|
if (!bf.containsBean(BeanIds.CONTEXT_SOURCE) && defaultNameRequired) {
|
||||||
|
|||||||
+25
-5
@@ -37,6 +37,7 @@ import org.springframework.security.access.expression.method.ExpressionBasedPreI
|
|||||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||||
|
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||||
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
||||||
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
|
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
|
||||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
||||||
@@ -76,6 +77,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
private static final String ATT_USE_SECURED = "secured-annotations";
|
private static final String ATT_USE_SECURED = "secured-annotations";
|
||||||
private static final String ATT_USE_PREPOST = "pre-post-annotations";
|
private static final String ATT_USE_PREPOST = "pre-post-annotations";
|
||||||
private static final String ATT_REF = "ref";
|
private static final String ATT_REF = "ref";
|
||||||
|
private static final String ATT_MODE = "mode";
|
||||||
private static final String ATT_ADVICE_ORDER = "order";
|
private static final String ATT_ADVICE_ORDER = "order";
|
||||||
|
|
||||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||||
@@ -90,6 +92,8 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||||
boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
|
boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
|
||||||
|
boolean useAspectJ = "aspectj".equals(element.getAttribute(ATT_MODE));
|
||||||
|
|
||||||
BeanDefinition preInvocationVoter = null;
|
BeanDefinition preInvocationVoter = null;
|
||||||
ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>();
|
ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>();
|
||||||
|
|
||||||
@@ -165,6 +169,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
|
DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
|
||||||
|
|
||||||
if (pointcutMap.size() > 0) {
|
if (pointcutMap.size() > 0) {
|
||||||
|
if (useAspectJ) {
|
||||||
|
pc.getReaderContext().error("You can't use AspectJ mode with protect-pointcut definitions", source);
|
||||||
|
}
|
||||||
// Only add it if there are actually any pointcuts defined.
|
// Only add it if there are actually any pointcuts defined.
|
||||||
BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
||||||
BeanReference ref = new RuntimeBeanReference(pc.getReaderContext().generateBeanName(mapBasedMetadataSource));
|
BeanReference ref = new RuntimeBeanReference(pc.getReaderContext().generateBeanName(mapBasedMetadataSource));
|
||||||
@@ -190,13 +197,22 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
}
|
}
|
||||||
|
|
||||||
String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
|
String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
|
||||||
|
|
||||||
BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId,
|
BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId,
|
||||||
metadataSource, afterInvocationProviders, source);
|
metadataSource, afterInvocationProviders, source, useAspectJ);
|
||||||
|
|
||||||
|
if (useAspectJ) {
|
||||||
|
BeanDefinitionBuilder aspect =
|
||||||
|
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
|
||||||
|
aspect.setFactoryMethod("aspectOf");
|
||||||
|
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
aspect.addPropertyValue("securityInterceptor", interceptor);
|
||||||
|
String id = pc.getReaderContext().registerWithGeneratedName(aspect.getBeanDefinition());
|
||||||
|
pc.registerBeanComponent(new BeanComponentDefinition(aspect.getBeanDefinition(), id));
|
||||||
|
} else {
|
||||||
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
|
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
|
||||||
|
|
||||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
|
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
|
||||||
|
}
|
||||||
|
|
||||||
pc.popAndRegisterContainingComponent();
|
pc.popAndRegisterContainingComponent();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -284,12 +300,16 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId,
|
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId,
|
||||||
String runAsManagerId, BeanReference metadataSource, List<BeanMetadataElement> afterInvocationProviders, Object source) {
|
String runAsManagerId, BeanReference metadataSource,
|
||||||
BeanDefinitionBuilder bldr = BeanDefinitionBuilder.rootBeanDefinition(MethodSecurityInterceptor.class);
|
List<BeanMetadataElement> afterInvocationProviders, Object source, boolean useAspectJ) {
|
||||||
|
BeanDefinitionBuilder bldr =
|
||||||
|
BeanDefinitionBuilder.rootBeanDefinition(useAspectJ ?
|
||||||
|
AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class);
|
||||||
bldr.getRawBeanDefinition().setSource(source);
|
bldr.getRawBeanDefinition().setSource(source);
|
||||||
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
|
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||||
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
|
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
|
||||||
bldr.addPropertyValue("securityMetadataSource", metadataSource);
|
bldr.addPropertyValue("securityMetadataSource", metadataSource);
|
||||||
|
|
||||||
if (StringUtils.hasText(runAsManagerId)) {
|
if (StringUtils.hasText(runAsManagerId)) {
|
||||||
bldr.addPropertyReference("runAsManager", runAsManagerId);
|
bldr.addPropertyReference("runAsManager", runAsManagerId);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.ManagedMap;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
@@ -64,16 +65,16 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
|
|||||||
interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||||
|
|
||||||
// Lookup parent bean information
|
// Lookup parent bean information
|
||||||
Element parent = (Element) node.getParentNode();
|
String parentBeanClass = ((Element) node.getParentNode()).getAttribute("class");
|
||||||
String parentBeanClass = parent.getAttribute("class");
|
|
||||||
parent = null;
|
|
||||||
|
|
||||||
// Parse the included methods
|
// Parse the included methods
|
||||||
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
|
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
|
||||||
Map<String, List<ConfigAttribute>> mappings = new LinkedHashMap<String, List<ConfigAttribute>>();
|
Map<String, BeanDefinition> mappings = new ManagedMap<String, BeanDefinition>();
|
||||||
|
|
||||||
for (Element protectmethodElt : methods) {
|
for (Element protectmethodElt : methods) {
|
||||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(protectmethodElt.getAttribute(ATT_ACCESS));
|
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
|
||||||
|
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
|
||||||
|
attributeBuilder.addConstructorArgValue(protectmethodElt.getAttribute(ATT_ACCESS));
|
||||||
|
|
||||||
// Support inference of class names
|
// Support inference of class names
|
||||||
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
|
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
|
||||||
@@ -84,7 +85,7 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mappings.put(methodName, SecurityConfig.createList(tokens));
|
mappings.put(methodName, attributeBuilder.getBeanDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinition metadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
BeanDefinition metadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
|
||||||
|
|||||||
+16
-13
@@ -1,11 +1,7 @@
|
|||||||
package org.springframework.security.config.method;
|
package org.springframework.security.config.method;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
@@ -44,15 +40,16 @@ import org.springframework.util.StringUtils;
|
|||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
|
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
|
||||||
|
|
||||||
private Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
private final Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
|
||||||
private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
private final MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
|
||||||
private PointcutParser parser;
|
private final Set<PointcutExpression> pointCutExpressions = new LinkedHashSet<PointcutExpression>();
|
||||||
|
private final PointcutParser parser;
|
||||||
|
private final Set<String> processedBeans = new HashSet<String>();
|
||||||
|
|
||||||
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
|
||||||
Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required");
|
Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required");
|
||||||
@@ -78,6 +75,11 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (processedBeans.contains(beanName)) {
|
||||||
|
// We already have the metadata for this bean
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
// Obtain methods for the present bean
|
// Obtain methods for the present bean
|
||||||
Method[] methods;
|
Method[] methods;
|
||||||
try {
|
try {
|
||||||
@@ -88,10 +90,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
|
|
||||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||||
for (int i = 0; i < methods.length; i++) {
|
for (int i = 0; i < methods.length; i++) {
|
||||||
for (String ex : pointcutMap.keySet()) {
|
for (PointcutExpression expression : pointCutExpressions) {
|
||||||
// Parse the presented AspectJ pointcut expression
|
|
||||||
PointcutExpression expression = parser.parsePointcutExpression(ex);
|
|
||||||
|
|
||||||
// Try for the bean class directly
|
// Try for the bean class directly
|
||||||
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
||||||
// We've found the first expression that matches this method, so move onto the next method now
|
// We've found the first expression that matches this method, so move onto the next method now
|
||||||
@@ -100,6 +99,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processedBeans.add(beanName);
|
||||||
|
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +135,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
|||||||
Assert.notNull(definition, "A List of ConfigAttributes is required");
|
Assert.notNull(definition, "A List of ConfigAttributes is required");
|
||||||
pointcutExpression = replaceBooleanOperators(pointcutExpression);
|
pointcutExpression = replaceBooleanOperators(pointcutExpression);
|
||||||
pointcutMap.put(pointcutExpression, definition);
|
pointcutMap.put(pointcutExpression, definition);
|
||||||
|
// Parse the presented AspectJ pointcut expression and add it to the cache
|
||||||
|
pointCutExpressions.add(parser.parsePointcutExpression(pointcutExpression));
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.0.4.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-3.0.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
http\://www.springframework.org/schema/security/spring-security-3.0.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
||||||
|
http\://www.springframework.org/schema/security/spring-security-3.0.4.xsd=org/springframework/security/config/spring-security-3.0.4.xsd
|
||||||
|
http\://www.springframework.org/schema/security/spring-security-3.0.3.xsd=org/springframework/security/config/spring-security-3.0.3.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
|
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||||
|
|||||||
+1381
File diff suppressed because it is too large
Load Diff
+14
-4
@@ -208,6 +208,9 @@ global-method-security.attlist &=
|
|||||||
attribute order {xsd:token}?
|
attribute order {xsd:token}?
|
||||||
global-method-security.attlist &=
|
global-method-security.attlist &=
|
||||||
attribute proxy-target-class {boolean}?
|
attribute proxy-target-class {boolean}?
|
||||||
|
global-method-security.attlist &=
|
||||||
|
## Can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module.
|
||||||
|
attribute mode {"aspectj"}?
|
||||||
|
|
||||||
after-invocation-provider =
|
after-invocation-provider =
|
||||||
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
|
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
|
||||||
@@ -242,6 +245,9 @@ protect-pointcut.attlist &=
|
|||||||
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
||||||
attribute access {xsd:token}
|
attribute access {xsd:token}
|
||||||
|
|
||||||
|
http-firewall =
|
||||||
|
## Allows a custom instance of HttpFirewall to be injected into the FilterChainProxy created by the namespace.
|
||||||
|
element http-firewall {ref}
|
||||||
|
|
||||||
http =
|
http =
|
||||||
## Container element for HTTP security configuration
|
## Container element for HTTP security configuration
|
||||||
@@ -273,7 +279,7 @@ http.attlist &=
|
|||||||
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
|
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
|
||||||
attribute realm {xsd:token}?
|
attribute realm {xsd:token}?
|
||||||
http.attlist &=
|
http.attlist &=
|
||||||
## Allows a customized AuthenticationEntryPoint to be used.
|
## Allows a customized AuthenticationEntryPoint to be set on the ExceptionTranslationFilter.
|
||||||
attribute entry-point-ref {xsd:token}?
|
attribute entry-point-ref {xsd:token}?
|
||||||
http.attlist &=
|
http.attlist &=
|
||||||
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
||||||
@@ -416,7 +422,10 @@ filter-invocation-definition-source =
|
|||||||
|
|
||||||
http-basic =
|
http-basic =
|
||||||
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
|
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
|
||||||
element http-basic {empty}
|
element http-basic {http-basic.attlist, empty}
|
||||||
|
http-basic.attlist &=
|
||||||
|
## Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter.
|
||||||
|
attribute entry-point-ref {xsd:token}?
|
||||||
|
|
||||||
session-management =
|
session-management =
|
||||||
element session-management {session-management.attlist, concurrency-control?}
|
element session-management {session-management.attlist, concurrency-control?}
|
||||||
@@ -538,6 +547,9 @@ authentication-manager =
|
|||||||
authman.attlist &=
|
authman.attlist &=
|
||||||
## The alias you wish to use for the AuthenticationManager bean
|
## The alias you wish to use for the AuthenticationManager bean
|
||||||
attribute alias {xsd:ID}?
|
attribute alias {xsd:ID}?
|
||||||
|
authman.attlist &=
|
||||||
|
## If set to true, the AuthenticationManger will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated. Defaults to false.
|
||||||
|
attribute erase-credentials {boolean}?
|
||||||
|
|
||||||
authentication-provider =
|
authentication-provider =
|
||||||
## Indicates that the contained user-service should be used as an authentication source.
|
## Indicates that the contained user-service should be used as an authentication source.
|
||||||
@@ -619,5 +631,3 @@ position =
|
|||||||
|
|
||||||
|
|
||||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||||
|
|
||||||
|
|
||||||
+1386
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -70,40 +70,40 @@ public class FilterChainProxyConfigTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperation() throws Exception {
|
public void normalOperation() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperationWithNewConfig() throws Exception {
|
public void normalOperationWithNewConfig() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
||||||
checkPathAndFilterOrder(filterChainProxy);
|
checkPathAndFilterOrder(filterChainProxy);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperationWithNewConfigRegex() throws Exception {
|
public void normalOperationWithNewConfigRegex() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
||||||
checkPathAndFilterOrder(filterChainProxy);
|
checkPathAndFilterOrder(filterChainProxy);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
||||||
checkPathAndFilterOrder(filterChainProxy);
|
checkPathAndFilterOrder(filterChainProxy);
|
||||||
doNormalOperation(filterChainProxy);
|
doNormalOperation(filterChainProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pathWithNoMatchHasNoFilters() throws Exception {
|
public void pathWithNoMatchHasNoFilters() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||||
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void urlStrippingPropertyIsRespected() throws Exception {
|
public void urlStrippingPropertyIsRespected() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||||
|
|
||||||
// Should only match if we are stripping the query string
|
// Should only match if we are stripping the query string
|
||||||
String url = "/blah.bar?x=something";
|
String url = "/blah.bar?x=something";
|
||||||
@@ -116,7 +116,7 @@ public class FilterChainProxyConfigTests {
|
|||||||
// SEC-1235
|
// SEC-1235
|
||||||
@Test
|
@Test
|
||||||
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() throws Exception {
|
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() throws Exception {
|
||||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
|
FilterChainProxy filterChainProxy = appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
|
||||||
|
|
||||||
String[] paths = filterChainProxy.getFilterChainMap().keySet().toArray(new String[0]);
|
String[] paths = filterChainProxy.getFilterChainMap().keySet().toArray(new String[0]);
|
||||||
assertEquals("/login*", paths[0]);
|
assertEquals("/login*", paths[0]);
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ public class SecurityNamespacehandlerTests {
|
|||||||
);
|
);
|
||||||
fail("Expected BeanDefinitionParsingException");
|
fail("Expected BeanDefinitionParsingException");
|
||||||
} catch (BeanDefinitionParsingException expected) {
|
} catch (BeanDefinitionParsingException expected) {
|
||||||
assertTrue(expected.getMessage().contains("You cannot use a spring-security-2.0.xsd schema"));
|
assertTrue(expected.getMessage().contains("You must use a 3.0 schema with Spring Security 3.0."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -53,6 +53,20 @@ public class AuthenticationManagerBeanDefinitionParserTests {
|
|||||||
assertEquals(1, listener.events.size());
|
assertEquals(1, listener.events.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void credentialsAreNotClearedByDefault() throws Exception {
|
||||||
|
setContext(CONTEXT, "3.0");
|
||||||
|
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||||
|
assertFalse(pm.isEraseCredentialsAfterAuthentication());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearCredentialsPropertyIsRespected() throws Exception {
|
||||||
|
setContext("<authentication-manager erase-credentials='true'/>", "3.0.3");
|
||||||
|
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||||
|
assertTrue(pm.isEraseCredentialsAfterAuthentication());
|
||||||
|
}
|
||||||
|
|
||||||
private void setContext(String context, String version) {
|
private void setContext(String context, String version) {
|
||||||
appContext = new InMemoryXmlApplicationContext(context, version, null);
|
appContext = new InMemoryXmlApplicationContext(context, version, null);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -77,12 +77,12 @@ public class UserServiceBeanDefinitionParserTests {
|
|||||||
setContext(
|
setContext(
|
||||||
"<user-service id='service'>" +
|
"<user-service id='service'>" +
|
||||||
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
|
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
|
||||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
|
" <user name='Bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
|
||||||
"</user-service>");
|
"</user-service>");
|
||||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||||
UserDetails joe = userService.loadUserByUsername("joe");
|
UserDetails joe = userService.loadUserByUsername("joe");
|
||||||
assertFalse(joe.isAccountNonLocked());
|
assertFalse(joe.isAccountNonLocked());
|
||||||
UserDetails bob = userService.loadUserByUsername("bob");
|
UserDetails bob = userService.loadUserByUsername("bOb");
|
||||||
assertFalse(bob.isEnabled());
|
assertFalse(bob.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+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.HttpSessionSecurityContextRepository;
|
||||||
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
|
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
|
||||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||||
|
import org.springframework.security.web.firewall.DefaultHttpFirewall;
|
||||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||||
import org.springframework.security.web.session.SessionManagementFilter;
|
import org.springframework.security.web.session.SessionManagementFilter;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -183,6 +185,29 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
assertTrue(filters.size() == 0);
|
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
|
@Test
|
||||||
public void regexPathsWorkCorrectly() throws Exception {
|
public void regexPathsWorkCorrectly() throws Exception {
|
||||||
@@ -407,6 +432,23 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void httpMethodMatchIsSupportedForRequiresChannel() throws Exception {
|
||||||
|
setContext(
|
||||||
|
" <http auto-config='true'>" +
|
||||||
|
" <intercept-url pattern='/anyurl'/>" +
|
||||||
|
" <intercept-url pattern='/anyurl' method='GET' access='ROLE_ADMIN' requires-channel='https' />" +
|
||||||
|
" </http>" + AUTH_PROVIDER_XML);
|
||||||
|
|
||||||
|
ChannelProcessingFilter filter = getFilter(ChannelProcessingFilter.class);
|
||||||
|
FilterInvocationSecurityMetadataSource fids = (FilterInvocationSecurityMetadataSource)FieldUtils.getFieldValue(filter,"securityMetadataSource");
|
||||||
|
Collection<ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"));
|
||||||
|
assertEquals(1, attrs.size());
|
||||||
|
attrs = fids.getAttributes(createFilterinvocation("/anyurl", "POST"));
|
||||||
|
assertEquals(null, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void oncePerRequestAttributeIsSupported() throws Exception {
|
public void oncePerRequestAttributeIsSupported() throws Exception {
|
||||||
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||||
@@ -416,6 +458,21 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
assertFalse(fsi.isObserveOncePerRequest());
|
assertFalse(fsi.isObserveOncePerRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void httpBasicSupportsSeparateEntryPoint() throws Exception {
|
||||||
|
setContext("<http><http-basic entry-point-ref='ep' /></http>" +
|
||||||
|
"<b:bean id='ep' class='org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint'>" +
|
||||||
|
" <b:property name='realmName' value='whocares'/>" +
|
||||||
|
"</b:bean>" + AUTH_PROVIDER_XML);
|
||||||
|
|
||||||
|
BasicAuthenticationFilter baf = getFilter(BasicAuthenticationFilter.class);
|
||||||
|
assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(baf, "authenticationEntryPoint"));
|
||||||
|
// Since no other authentication system is in use, this should also end up on the ETF
|
||||||
|
ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
||||||
|
assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(etf, "authenticationEntryPoint"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void accessDeniedPageAttributeIsSupported() throws Exception {
|
public void accessDeniedPageAttributeIsSupported() throws Exception {
|
||||||
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||||
@@ -1218,6 +1275,18 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||||||
fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void httpFirewallInjectionIsSupported() throws Exception {
|
||||||
|
setContext(
|
||||||
|
"<http-firewall ref='fw'/>" +
|
||||||
|
"<http>" +
|
||||||
|
" <form-login />" +
|
||||||
|
"</http>" +
|
||||||
|
"<b:bean id='fw' class='" + DefaultHttpFirewall.class.getName() +"'/>" +
|
||||||
|
AUTH_PROVIDER_XML);
|
||||||
|
FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
||||||
|
assertSame(appContext.getBean("fw"), FieldUtils.getFieldValue(fcp, "firewall"));
|
||||||
|
}
|
||||||
|
|
||||||
private void setContext(String context) {
|
private void setContext(String context) {
|
||||||
appContext = new InMemoryXmlApplicationContext(context);
|
appContext = new InMemoryXmlApplicationContext(context);
|
||||||
|
|||||||
+46
-4
@@ -16,12 +16,15 @@ import org.springframework.context.ApplicationContext;
|
|||||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||||
import org.springframework.context.support.StaticApplicationContext;
|
import org.springframework.context.support.StaticApplicationContext;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
|
import org.springframework.security.access.SecurityConfig;
|
||||||
import org.springframework.security.access.annotation.BusinessService;
|
import org.springframework.security.access.annotation.BusinessService;
|
||||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||||
import org.springframework.security.access.intercept.RunAsManagerImpl;
|
import org.springframework.security.access.intercept.RunAsManagerImpl;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
|
||||||
import org.springframework.security.access.vote.AffirmativeBased;
|
import org.springframework.security.access.vote.AffirmativeBased;
|
||||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||||
@@ -30,6 +33,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
|||||||
import org.springframework.security.config.ConfigTestUtils;
|
import org.springframework.security.config.ConfigTestUtils;
|
||||||
import org.springframework.security.config.PostProcessedMockUserDetailsService;
|
import org.springframework.security.config.PostProcessedMockUserDetailsService;
|
||||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
@@ -40,6 +44,8 @@ import org.springframework.security.util.FieldUtils;
|
|||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||||
|
private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob","bobspassword");
|
||||||
|
|
||||||
private AbstractXmlApplicationContext appContext;
|
private AbstractXmlApplicationContext appContext;
|
||||||
|
|
||||||
private BusinessService target;
|
private BusinessService target;
|
||||||
@@ -166,7 +172,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
" 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) " +
|
" 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) " +
|
||||||
" and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' " +
|
" and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' " +
|
||||||
" access='ROLE_USER'/>" +
|
" access='ROLE_USER'/>" +
|
||||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
"</global-method-security>" + AUTH_PROVIDER_XML
|
||||||
);
|
);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
// String method should not be protected
|
// String method should not be protected
|
||||||
@@ -231,7 +237,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
target.someAdminMethod();
|
target.someAdminMethod();
|
||||||
}
|
}
|
||||||
@@ -242,7 +248,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
List<String> arg = new ArrayList<String>();
|
List<String> arg = new ArrayList<String>();
|
||||||
arg.add("joe");
|
arg.add("joe");
|
||||||
@@ -261,7 +267,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
target = (BusinessService) appContext.getBean("target");
|
target = (BusinessService) appContext.getBean("target");
|
||||||
Object[] arg = new String[] {"joe", "bob", "sam"};
|
Object[] arg = new String[] {"joe", "bob", "sam"};
|
||||||
Object[] result = target.methodReturningAnArray(arg);
|
Object[] result = target.methodReturningAnArray(arg);
|
||||||
@@ -283,6 +289,33 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
AUTH_PROVIDER_XML);
|
AUTH_PROVIDER_XML);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SEC-1450
|
||||||
|
@Test(expected=AuthenticationException.class)
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void genericsAreMatchedByProtectPointcut() throws Exception {
|
||||||
|
setContext(
|
||||||
|
"<b:bean id='target' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$ConcreteFoo'/>" +
|
||||||
|
"<global-method-security>" +
|
||||||
|
" <protect-pointcut expression='execution(* org..*Foo.foo(..))' access='ROLE_USER'/>" +
|
||||||
|
"</global-method-security>" + AUTH_PROVIDER_XML
|
||||||
|
);
|
||||||
|
Foo foo = (Foo) appContext.getBean("target");
|
||||||
|
foo.foo(new SecurityConfig("A"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEC-1448
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void genericsMethodArgumentNamesAreResolved() throws Exception {
|
||||||
|
setContext(
|
||||||
|
"<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>" +
|
||||||
|
"<global-method-security pre-post-annotations='enabled'/>" + AUTH_PROVIDER_XML
|
||||||
|
);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||||
|
Foo foo = (Foo) appContext.getBean("target");
|
||||||
|
foo.foo(new SecurityConfig("A"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runAsManagerIsSetCorrectly() throws Exception {
|
public void runAsManagerIsSetCorrectly() throws Exception {
|
||||||
StaticApplicationContext parent = new StaticApplicationContext();
|
StaticApplicationContext parent = new StaticApplicationContext();
|
||||||
@@ -305,6 +338,15 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||||||
private void setContext(String context, ApplicationContext parent) {
|
private void setContext(String context, ApplicationContext parent) {
|
||||||
appContext = new InMemoryXmlApplicationContext(context, parent);
|
appContext = new InMemoryXmlApplicationContext(context, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Foo<T extends ConfigAttribute> {
|
||||||
|
void foo(T action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ConcreteFoo implements Foo<SecurityConfig> {
|
||||||
|
@PreAuthorize("#action.attribute == 'A'")
|
||||||
|
public void foo(SecurityConfig action) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
+2
@@ -25,6 +25,8 @@ public class InterceptMethodsBeanDefinitionDecoratorTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void loadContext() {
|
public void loadContext() {
|
||||||
|
// Set value for placeholder
|
||||||
|
System.setProperty("admin.role", "ROLE_ADMIN");
|
||||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
|
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
|
||||||
target = (TestBusinessBean) appContext.getBean("target");
|
target = (TestBusinessBean) appContext.getBean("target");
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -22,11 +22,11 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
|
|||||||
Resource inMemoryXml;
|
Resource inMemoryXml;
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml) {
|
public InMemoryXmlApplicationContext(String xml) {
|
||||||
this(xml, "3.0", null);
|
this(xml, "3.0.4", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
||||||
this(xml, "3.0", parent);
|
this(xml, "3.0.4", parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
|
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
|
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
|
||||||
|
|
||||||
|
<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>
|
||||||
|
|
||||||
<b:bean id="target" class="org.springframework.security.config.TestBusinessBeanImpl">
|
<b:bean id="target" class="org.springframework.security.config.TestBusinessBeanImpl">
|
||||||
<!-- This will add a security interceptor to the bean -->
|
<!-- This will add a security interceptor to the bean -->
|
||||||
<intercept-methods>
|
<intercept-methods>
|
||||||
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="ROLE_ADMIN" />
|
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="${admin.role}" />
|
||||||
<protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
|
<protect method="get*" access="${admin.role},ROLE_USER" />
|
||||||
<protect method="doSomething" access="ROLE_USER" />
|
<protect method="doSomething" access="ROLE_USER" />
|
||||||
</intercept-methods>
|
</intercept-methods>
|
||||||
</b:bean>
|
</b:bean>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
Implementation-Title: org.springframework.security.config
|
||||||
|
Implementation-Version: ${version}
|
||||||
Bundle-SymbolicName: org.springframework.security.config
|
Bundle-SymbolicName: org.springframework.security.config
|
||||||
Bundle-Name: Spring Security Namespace Configuration
|
Bundle-Name: Spring Security Namespace Configuration
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: SpringSource
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ dependencies {
|
|||||||
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||||
"org.springframework:spring-aop:$springVersion",
|
"org.springframework:spring-aop:$springVersion",
|
||||||
"org.springframework:spring-beans:$springVersion",
|
"org.springframework:spring-beans:$springVersion",
|
||||||
"org.springframework:spring-core:$springVersion",
|
|
||||||
"org.springframework:spring-context:$springVersion",
|
"org.springframework:spring-context:$springVersion",
|
||||||
"org.springframework:spring-expression:$springVersion",
|
"org.springframework:spring-expression:$springVersion",
|
||||||
"org.springframework:spring-jdbc:$springVersion",
|
"org.springframework:spring-jdbc:$springVersion",
|
||||||
|
|||||||
+1
-5
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-parent</artifactId>
|
<artifactId>spring-security-parent</artifactId>
|
||||||
<version>3.0.2.RELEASE</version>
|
<version>3.0.6.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<artifactId>spring-security-core</artifactId>
|
<artifactId>spring-security-core</artifactId>
|
||||||
@@ -65,10 +65,6 @@
|
|||||||
<artifactId>ehcache</artifactId>
|
<artifactId>ehcache</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-collections</groupId>
|
<groupId>commons-collections</groupId>
|
||||||
<artifactId>commons-collections</artifactId>
|
<artifactId>commons-collections</artifactId>
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Votes according to JSR 250.
|
* Votes according to JSR 250.
|
||||||
|
* <p>
|
||||||
|
* If no JSR-250 attributes are found, it will abstain, otherwise it will grant or deny access
|
||||||
|
* based on the attributes that are found.
|
||||||
*
|
*
|
||||||
* @param authentication The authentication object.
|
* @param authentication The authentication object.
|
||||||
* @param object The access object.
|
* @param object The access object.
|
||||||
@@ -44,6 +47,8 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
|||||||
* @return The vote.
|
* @return The vote.
|
||||||
*/
|
*/
|
||||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> definition) {
|
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> definition) {
|
||||||
|
boolean jsr250AttributeFound = false;
|
||||||
|
|
||||||
for (ConfigAttribute attribute : definition) {
|
for (ConfigAttribute attribute : definition) {
|
||||||
if (Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE.equals(attribute)) {
|
if (Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE.equals(attribute)) {
|
||||||
return ACCESS_GRANTED;
|
return ACCESS_GRANTED;
|
||||||
@@ -54,18 +59,17 @@ public class Jsr250Voter implements AccessDecisionVoter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (supports(attribute)) {
|
if (supports(attribute)) {
|
||||||
|
jsr250AttributeFound = true;
|
||||||
// Attempt to find a matching granted authority
|
// Attempt to find a matching granted authority
|
||||||
for (GrantedAuthority authority : authentication.getAuthorities()) {
|
for (GrantedAuthority authority : authentication.getAuthorities()) {
|
||||||
if (attribute.getAttribute().equals(authority.getAuthority())) {
|
if (attribute.getAttribute().equals(authority.getAuthority())) {
|
||||||
return ACCESS_GRANTED;
|
return ACCESS_GRANTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No match - deny access
|
|
||||||
return ACCESS_DENIED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ACCESS_ABSTAIN;
|
return jsr250AttributeFound ? ACCESS_DENIED : ACCESS_ABSTAIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ import org.springframework.security.access.method.AbstractFallbackMethodSecurity
|
|||||||
public class SecuredAnnotationSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
|
public class SecuredAnnotationSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
|
||||||
|
|
||||||
protected Collection<ConfigAttribute> findAttributes(Class<?> clazz) {
|
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) {
|
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
|
||||||
|
|||||||
+8
@@ -36,6 +36,14 @@ public abstract class SecurityExpressionRoot {
|
|||||||
this.authentication = a;
|
this.authentication = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean hasAuthority(String authority) {
|
||||||
|
return hasRole(authority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean hasAnyAuthority(String... authorities) {
|
||||||
|
return hasAnyRole(authorities);
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean hasRole(String role) {
|
public final boolean hasRole(String role) {
|
||||||
return getAuthoritySet().contains(role);
|
return getAuthoritySet().contains(role);
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-2
@@ -3,11 +3,13 @@ package org.springframework.security.access.expression.method;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal security-specific EvaluationContext implementation which lazily adds the
|
* Internal security-specific EvaluationContext implementation which lazily adds the
|
||||||
@@ -18,6 +20,8 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||||
|
private static Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class);
|
||||||
|
|
||||||
private ParameterNameDiscoverer parameterNameDiscoverer;
|
private ParameterNameDiscoverer parameterNameDiscoverer;
|
||||||
private boolean argumentsAdded;
|
private boolean argumentsAdded;
|
||||||
private MethodInvocation mi;
|
private MethodInvocation mi;
|
||||||
@@ -58,10 +62,21 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
|||||||
|
|
||||||
private void addArgumentsAsVariables() {
|
private void addArgumentsAsVariables() {
|
||||||
Object[] args = mi.getArguments();
|
Object[] args = mi.getArguments();
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Object targetObject = mi.getThis();
|
Object targetObject = mi.getThis();
|
||||||
Method method = ClassUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
|
Method method = AopUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
|
||||||
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
|
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
|
||||||
|
|
||||||
|
if (paramNames == null) {
|
||||||
|
logger.warn("Unable to resolve method parameter names for method: " + method
|
||||||
|
+ ". Debug symbol information is required if you are using parameter names in expressions.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0; i < args.length; i++) {
|
for(int i=0; i < args.length; i++) {
|
||||||
super.setVariable(paramNames[i], args[i]);
|
super.setVariable(paramNames[i], args[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
|
|||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +107,7 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
|||||||
|
|
||||||
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
|
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
|
||||||
if (authorities == null || authorities.isEmpty()) {
|
if (authorities == null || authorities.isEmpty()) {
|
||||||
return null;
|
return AuthorityUtils.NO_AUTHORITIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>();
|
Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>();
|
||||||
|
|||||||
+10
-6
@@ -40,6 +40,7 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF
|
|||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -224,16 +225,18 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no further work post-invocation
|
// no further work post-invocation
|
||||||
return new InterceptorStatusToken(authenticated, false, attributes, object);
|
return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);
|
||||||
} else {
|
} else {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
logger.debug("Switching to RunAs Authentication: " + runAs);
|
logger.debug("Switching to RunAs Authentication: " + runAs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SecurityContext origCtx = SecurityContextHolder.getContext();
|
||||||
|
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
|
||||||
SecurityContextHolder.getContext().setAuthentication(runAs);
|
SecurityContextHolder.getContext().setAuthentication(runAs);
|
||||||
|
|
||||||
// need to revert to token.Authenticated post-invocation
|
// 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 (token.isContextHolderRefreshRequired()) {
|
||||||
if (logger.isDebugEnabled()) {
|
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) {
|
if (afterInvocationManager != null) {
|
||||||
// Attempt after invocation handling
|
// Attempt after invocation handling
|
||||||
try {
|
try {
|
||||||
returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
|
returnedObject = afterInvocationManager.decide(token.getSecurityContext().getAuthentication(),
|
||||||
|
token.getSecureObject(),
|
||||||
token.getAttributes(), returnedObject);
|
token.getAttributes(), returnedObject);
|
||||||
}
|
}
|
||||||
catch (AccessDeniedException accessDeniedException) {
|
catch (AccessDeniedException accessDeniedException) {
|
||||||
AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
|
AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
|
||||||
.getAttributes(), token.getAuthentication(), accessDeniedException);
|
.getAttributes(), token.getSecurityContext().getAuthentication(), accessDeniedException);
|
||||||
publishEvent(event);
|
publishEvent(event);
|
||||||
|
|
||||||
throw accessDeniedException;
|
throw accessDeniedException;
|
||||||
|
|||||||
+6
-5
@@ -19,6 +19,7 @@ import java.util.Collection;
|
|||||||
|
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.security.core.Authentication;
|
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 {
|
public class InterceptorStatusToken {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private Authentication authentication;
|
private SecurityContext securityContext;
|
||||||
private Collection<ConfigAttribute> attr;
|
private Collection<ConfigAttribute> attr;
|
||||||
private Object secureObject;
|
private Object secureObject;
|
||||||
private boolean contextHolderRefreshRequired;
|
private boolean contextHolderRefreshRequired;
|
||||||
|
|
||||||
//~ Constructors ===================================================================================================
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public InterceptorStatusToken(Authentication authentication, boolean contextHolderRefreshRequired,
|
public InterceptorStatusToken(SecurityContext securityContext, boolean contextHolderRefreshRequired,
|
||||||
Collection<ConfigAttribute> attributes, Object secureObject) {
|
Collection<ConfigAttribute> attributes, Object secureObject) {
|
||||||
this.authentication = authentication;
|
this.securityContext = securityContext;
|
||||||
this.contextHolderRefreshRequired = contextHolderRefreshRequired;
|
this.contextHolderRefreshRequired = contextHolderRefreshRequired;
|
||||||
this.attr = attributes;
|
this.attr = attributes;
|
||||||
this.secureObject = secureObject;
|
this.secureObject = secureObject;
|
||||||
@@ -54,8 +55,8 @@ public class InterceptorStatusToken {
|
|||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Authentication getAuthentication() {
|
public SecurityContext getSecurityContext() {
|
||||||
return authentication;
|
return securityContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getSecureObject() {
|
public Object getSecureObject() {
|
||||||
|
|||||||
+2
-1
@@ -73,7 +73,8 @@ public class RunAsUserToken extends AbstractAuthenticationToken {
|
|||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder(super.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();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -6,8 +6,9 @@ package org.springframework.security.access.intercept.aspectj;
|
|||||||
* AspectJ processing to continue.
|
* AspectJ processing to continue.
|
||||||
*
|
*
|
||||||
* @author Mike Wiesner
|
* @author Mike Wiesner
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface AspectJAnnotationCallback {
|
public interface AspectJAnnotationCallback {
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
|||||||
+2
@@ -11,7 +11,9 @@ import org.aspectj.lang.JoinPoint;
|
|||||||
* AspectJ interceptor that supports @Aspect notation.
|
* AspectJ interceptor that supports @Aspect notation.
|
||||||
*
|
*
|
||||||
* @author Mike Wiesner
|
* @author Mike Wiesner
|
||||||
|
* @deprecated Use AspectJMethodSecurityInterceptor instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AspectJAnnotationSecurityInterceptor extends AbstractSecurityInterceptor {
|
public class AspectJAnnotationSecurityInterceptor extends AbstractSecurityInterceptor {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
package org.springframework.security.access.intercept.aspectj;
|
||||||
|
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.springframework.security.access.intercept.InterceptorStatusToken;
|
||||||
|
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AspectJ {@code JoinPoint} security interceptor which wraps the {@code JoinPoint} in a {@code MethodInvocation}
|
||||||
|
* adapter to make it compatible with security infrastructure classes which only support {@code MethodInvocation}s.
|
||||||
|
* <p>
|
||||||
|
* One of the {@code invoke} methods should be called from the {@code around()} advice in your aspect.
|
||||||
|
* Alternatively you can use one of the pre-defined aspects from the aspects module.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @since 3.0.3
|
||||||
|
*/
|
||||||
|
public final class AspectJMethodSecurityInterceptor extends MethodSecurityInterceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that is suitable for user with @Aspect notation.
|
||||||
|
*
|
||||||
|
* @param jp The AspectJ joint point being invoked which requires a security decision
|
||||||
|
* @return The returned value from the method invocation
|
||||||
|
* @throws Throwable if the invocation throws one
|
||||||
|
*/
|
||||||
|
public Object invoke(JoinPoint jp) throws Throwable {
|
||||||
|
return super.invoke(new MethodInvocationAdapter(jp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that is suitable for user with traditional AspectJ-code aspects.
|
||||||
|
*
|
||||||
|
* @param jp The AspectJ joint point being invoked which requires a security decision
|
||||||
|
* @param advisorProceed the advice-defined anonymous class that implements {@code AspectJCallback} containing
|
||||||
|
* a simple {@code return proceed();} statement
|
||||||
|
*
|
||||||
|
* @return The returned value from the method invocation
|
||||||
|
*/
|
||||||
|
public Object invoke(JoinPoint jp, AspectJCallback advisorProceed) {
|
||||||
|
Object result = null;
|
||||||
|
InterceptorStatusToken token = super.beforeInvocation(new MethodInvocationAdapter(jp));
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = advisorProceed.proceedWithObject();
|
||||||
|
} finally {
|
||||||
|
result = super.afterInvocation(token, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -37,7 +37,9 @@ import org.aspectj.lang.JoinPoint;
|
|||||||
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
|
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @deprecated Use AspectJMethodSecurityInterceptor instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {
|
public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
|
|||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package org.springframework.security.access.intercept.aspectj;
|
||||||
|
|
||||||
|
import java.lang.reflect.AccessibleObject;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.reflect.CodeSignature;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorates a JoinPoint to allow it to be used with method-security infrastructure
|
||||||
|
* classes which support {@code MethodInvocation} instances.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
* @since 3.0.3
|
||||||
|
*/
|
||||||
|
public final class MethodInvocationAdapter implements MethodInvocation {
|
||||||
|
private final ProceedingJoinPoint jp;
|
||||||
|
private final Method method;
|
||||||
|
private final Object target;
|
||||||
|
|
||||||
|
MethodInvocationAdapter(JoinPoint jp) {
|
||||||
|
this.jp = (ProceedingJoinPoint)jp;
|
||||||
|
if (jp.getTarget() != null) {
|
||||||
|
target = jp.getTarget();
|
||||||
|
} else {
|
||||||
|
// SEC-1295: target may be null if an ITD is in use
|
||||||
|
target = jp.getSignature().getDeclaringType();
|
||||||
|
}
|
||||||
|
String targetMethodName = jp.getStaticPart().getSignature().getName();
|
||||||
|
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
|
||||||
|
Class<?> declaringType = ((CodeSignature) jp.getStaticPart().getSignature()).getDeclaringType();
|
||||||
|
|
||||||
|
method = ClassUtils.getMethodIfAvailable(declaringType, targetMethodName, types);
|
||||||
|
Assert.notNull(method, "Could not obtain target method from JoinPoint: '"+ jp + "'");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Method getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getArguments() {
|
||||||
|
return jp.getArgs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessibleObject getStaticPart() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getThis() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object proceed() throws Throwable {
|
||||||
|
return jp.proceed();
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -3,8 +3,8 @@ package org.springframework.security.access.method;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract implementation of {@link MethodSecurityMetadataSource} that supports both Spring AOP and AspectJ and
|
* Abstract implementation of {@link MethodSecurityMetadataSource} that supports both Spring AOP and AspectJ and
|
||||||
@@ -29,7 +29,7 @@ public abstract class AbstractFallbackMethodSecurityMetadataSource extends Abstr
|
|||||||
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
|
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
|
||||||
// The method may be on an interface, but we need attributes from the target class.
|
// The method may be on an interface, but we need attributes from the target class.
|
||||||
// If the target class is null, the method will be unchanged.
|
// If the target class is null, the method will be unchanged.
|
||||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||||
// First try is the method in the target class.
|
// First try is the method in the target class.
|
||||||
Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
|
Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
|
|||||||
+13
-1
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
package org.springframework.security.access.method;
|
package org.springframework.security.access.method;
|
||||||
|
|
||||||
|
import org.springframework.aop.framework.AopProxyUtils;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
@@ -49,7 +50,18 @@ public abstract class AbstractMethodSecurityMetadataSource implements MethodSecu
|
|||||||
if (object instanceof MethodInvocation) {
|
if (object instanceof MethodInvocation) {
|
||||||
MethodInvocation mi = (MethodInvocation) object;
|
MethodInvocation mi = (MethodInvocation) object;
|
||||||
Object target = mi.getThis();
|
Object target = mi.getThis();
|
||||||
return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
|
Class<?> targetClass = null;
|
||||||
|
|
||||||
|
if (target != null) {
|
||||||
|
targetClass = target instanceof Class<?> ? (Class<?>)target : 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) {
|
if (object instanceof JoinPoint) {
|
||||||
|
|||||||
+4
@@ -88,6 +88,10 @@ public final class DelegatingMethodSecurityMetadataSource extends AbstractMethod
|
|||||||
this.methodSecurityMetadataSources = methodSecurityMetadataSources;
|
this.methodSecurityMetadataSources = methodSecurityMetadataSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MethodSecurityMetadataSource> getMethodSecurityMetadataSources() {
|
||||||
|
return methodSecurityMetadataSources;
|
||||||
|
}
|
||||||
|
|
||||||
//~ Inner Classes ==================================================================================================
|
//~ Inner Classes ==================================================================================================
|
||||||
|
|
||||||
private static class DefaultCacheKey {
|
private static class DefaultCacheKey {
|
||||||
|
|||||||
+7
-3
@@ -25,6 +25,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
@@ -42,7 +43,8 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource implements BeanClassLoaderAware {
|
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource
|
||||||
|
implements BeanClassLoaderAware {
|
||||||
|
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||||
@@ -103,7 +105,7 @@ public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethod
|
|||||||
* for matching multiple methods.
|
* for matching multiple methods.
|
||||||
*
|
*
|
||||||
* @param name type and method name, separated by a dot
|
* @param name type and method name, separated by a dot
|
||||||
* @param attr required authorities associated with the method
|
* @param attr the security attributes associated with the method
|
||||||
*/
|
*/
|
||||||
private void addSecureMethod(String name, List<ConfigAttribute> attr) {
|
private void addSecureMethod(String name, List<ConfigAttribute> attr) {
|
||||||
int lastDotIndex = name.lastIndexOf(".");
|
int lastDotIndex = name.lastIndexOf(".");
|
||||||
@@ -175,7 +177,9 @@ public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethod
|
|||||||
* Adds configuration attributes for a specific method, for example where the method has been
|
* Adds configuration attributes for a specific method, for example where the method has been
|
||||||
* matched using a pointcut expression. If a match already exists in the map for the method, then
|
* matched using a pointcut expression. If a match already exists in the map for the method, then
|
||||||
* the existing match will be retained, so that if this method is called for a more general pointcut
|
* the existing match will be retained, so that if this method is called for a more general pointcut
|
||||||
* it will not override a more specific one which has already been added. This
|
* it will not override a more specific one which has already been added.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called during initialization of the {@code BeanFactory}.
|
||||||
*/
|
*/
|
||||||
public void addSecureMethod(Class<?> javaType, Method method, List<ConfigAttribute> attr) {
|
public void addSecureMethod(Class<?> javaType, Method method, List<ConfigAttribute> attr) {
|
||||||
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
||||||
|
|||||||
+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)
|
// 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) {
|
if (annotation != null) {
|
||||||
logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
|
logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
|
||||||
return annotation;
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -77,7 +77,9 @@ public abstract class AbstractAuthenticationManager implements AuthenticationMan
|
|||||||
* be serialized to the client. Defaults to 'false'.
|
* be serialized to the client. Defaults to 'false'.
|
||||||
*
|
*
|
||||||
* @see org.springframework.security.core.AuthenticationException#getExtraInformation()
|
* @see org.springframework.security.core.AuthenticationException#getExtraInformation()
|
||||||
|
* @deprecated the {@code extraInformation} property is deprecated
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setClearExtraInformation(boolean clearExtraInformation) {
|
public void setClearExtraInformation(boolean clearExtraInformation) {
|
||||||
this.clearExtraInformation = 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.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ import org.springframework.security.core.userdetails.UserDetails;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAuthenticationToken implements Authentication {
|
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private Object details;
|
private Object details;
|
||||||
@@ -49,7 +50,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the
|
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the
|
||||||
* principal represented by this authentication object.
|
* principal represented by this authentication object.
|
||||||
*/
|
*/
|
||||||
public AbstractAuthenticationToken(Collection<GrantedAuthority> authorities) {
|
public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
|
||||||
if (authorities == null) {
|
if (authorities == null) {
|
||||||
this.authorities = AuthorityUtils.NO_AUTHORITIES;
|
this.authorities = AuthorityUtils.NO_AUTHORITIES;
|
||||||
return;
|
return;
|
||||||
@@ -67,6 +68,55 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
public Collection<GrantedAuthority> getAuthorities() {
|
||||||
|
return authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
if (this.getPrincipal() instanceof UserDetails) {
|
||||||
|
return ((UserDetails) this.getPrincipal()).getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getPrincipal() instanceof Principal) {
|
||||||
|
return ((Principal)getPrincipal()).getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.getPrincipal() == null) ? "" : this.getPrincipal().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAuthenticated() {
|
||||||
|
return authenticated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthenticated(boolean authenticated) {
|
||||||
|
this.authenticated = authenticated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getDetails() {
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetails(Object details) {
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the {@code credentials}, {@code principal} and {@code details} objects, invoking the
|
||||||
|
* {@code eraseCredentials} method on any which implement {@link CredentialsContainer}.
|
||||||
|
*/
|
||||||
|
public void eraseCredentials() {
|
||||||
|
eraseSecret(getCredentials());
|
||||||
|
eraseSecret(getPrincipal());
|
||||||
|
eraseSecret(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void eraseSecret(Object secret) {
|
||||||
|
if (secret instanceof CredentialsContainer) {
|
||||||
|
((CredentialsContainer)secret).eraseCredentials();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof AbstractAuthenticationToken)) {
|
if (!(obj instanceof AbstractAuthenticationToken)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -109,26 +159,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
return this.isAuthenticated() == test.isAuthenticated();
|
return this.isAuthenticated() == test.isAuthenticated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<GrantedAuthority> getAuthorities() {
|
@Override
|
||||||
return authorities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getDetails() {
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
if (this.getPrincipal() instanceof UserDetails) {
|
|
||||||
return ((UserDetails) this.getPrincipal()).getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getPrincipal() instanceof Principal) {
|
|
||||||
return ((Principal)getPrincipal()).getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (this.getPrincipal() == null) ? "" : this.getPrincipal().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int code = 31;
|
int code = 31;
|
||||||
|
|
||||||
@@ -155,23 +186,12 @@ public abstract class AbstractAuthenticationToken implements Authentication {
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAuthenticated() {
|
@Override
|
||||||
return authenticated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthenticated(boolean authenticated) {
|
|
||||||
this.authenticated = authenticated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDetails(Object details) {
|
|
||||||
this.details = details;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(super.toString()).append(": ");
|
sb.append(super.toString()).append(": ");
|
||||||
sb.append("Principal: ").append(this.getPrincipal()).append("; ");
|
sb.append("Principal: ").append(this.getPrincipal()).append("; ");
|
||||||
sb.append("Password: [PROTECTED]; ");
|
sb.append("Credentials: [PROTECTED]; ");
|
||||||
sb.append("Authenticated: ").append(this.isAuthenticated()).append("; ");
|
sb.append("Authenticated: ").append(this.isAuthenticated()).append("; ");
|
||||||
sb.append("Details: ").append(this.getDetails()).append("; ");
|
sb.append("Details: ").append(this.getDetails()).append("; ");
|
||||||
|
|
||||||
|
|||||||
+1
@@ -17,6 +17,7 @@ public abstract class AccountStatusException extends AuthenticationException {
|
|||||||
super(msg, t);
|
super(msg, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
protected AccountStatusException(String msg, Object extraInformation) {
|
protected AccountStatusException(String msg, Object extraInformation) {
|
||||||
super(msg, extraInformation);
|
super(msg, extraInformation);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -14,20 +14,20 @@ public class AccountStatusUserDetailsChecker implements UserDetailsChecker {
|
|||||||
|
|
||||||
public void check(UserDetails user) {
|
public void check(UserDetails user) {
|
||||||
if (!user.isAccountNonLocked()) {
|
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()) {
|
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()) {
|
if (!user.isAccountNonExpired()) {
|
||||||
throw new AccountExpiredException(messages.getMessage("UserDetailsService.expired",
|
throw new AccountExpiredException(messages.getMessage("AccountStatusUserDetailsChecker.expired",
|
||||||
"User account has expired"), user);
|
"User account has expired"), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.isCredentialsNonExpired()) {
|
if (!user.isCredentialsNonExpired()) {
|
||||||
throw new CredentialsExpiredException(messages.getMessage("UserDetailsService.credentialsExpired",
|
throw new CredentialsExpiredException(messages.getMessage("AccountStatusUserDetailsChecker.credentialsExpired",
|
||||||
"User credentials have expired"), user);
|
"User credentials have expired"), user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -36,6 +36,7 @@ public class BadCredentialsException extends AuthenticationException {
|
|||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public BadCredentialsException(String msg, Object extraInformation) {
|
public BadCredentialsException(String msg, Object extraInformation) {
|
||||||
super(msg, extraInformation);
|
super(msg, extraInformation);
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-1
@@ -26,6 +26,7 @@ import org.springframework.context.MessageSourceAware;
|
|||||||
import org.springframework.context.support.MessageSourceAccessor;
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -42,10 +43,17 @@ import org.springframework.util.Assert;
|
|||||||
* <code>AuthenticationException</code>, the last <code>AuthenticationException</code> received will be used.
|
* <code>AuthenticationException</code>, the last <code>AuthenticationException</code> received will be used.
|
||||||
* If no provider returns a non-null response, or indicates it can even process an <code>Authentication</code>,
|
* If no provider returns a non-null response, or indicates it can even process an <code>Authentication</code>,
|
||||||
* the <code>ProviderManager</code> will throw a <code>ProviderNotFoundException</code>.
|
* the <code>ProviderManager</code> will throw a <code>ProviderNotFoundException</code>.
|
||||||
|
* A parent {@code AuthenticationManager} can also be set, and this will also be tried if none of the configured
|
||||||
|
* providers can perform the authentication. This is intended to support namespace configuration options though and
|
||||||
|
* is not a feature that should normally be required.
|
||||||
* <p>
|
* <p>
|
||||||
* The exception to this process is when a provider throws an {@link AccountStatusException}, in which case no
|
* The exception to this process is when a provider throws an {@link AccountStatusException}, in which case no
|
||||||
* further providers in the list will be queried.
|
* further providers in the list will be queried.
|
||||||
*
|
*
|
||||||
|
* Post-authentication, the credentials will be cleared from the returned {@code Authentication} object, if it
|
||||||
|
* implements the {@link CredentialsContainer} interface. This behaviour can be controlled by modifying the
|
||||||
|
* {@link #setEraseCredentialsAfterAuthentication(boolean) eraseCredentialsAfterAuthentication} property.
|
||||||
|
*
|
||||||
* <h2>Event Publishing</h2>
|
* <h2>Event Publishing</h2>
|
||||||
* <p>
|
* <p>
|
||||||
* Authentication event publishing is delegated to the configured {@link AuthenticationEventPublisher} which defaults
|
* Authentication event publishing is delegated to the configured {@link AuthenticationEventPublisher} which defaults
|
||||||
@@ -57,9 +65,10 @@ import org.springframework.util.Assert;
|
|||||||
* the <tt><http></tt> configuration, so you will receive events from the web part of your application automatically.
|
* the <tt><http></tt> configuration, so you will receive events from the web part of your application automatically.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that the implementation also publishes authentication failure events when it obtains an authentication result
|
* Note that the implementation also publishes authentication failure events when it obtains an authentication result
|
||||||
* (or an exception) from the "parent" <tt>AuthenticationManager</tt> if one has been set. So in this situation, the
|
* (or an exception) from the "parent" {@code AuthenticationManager} if one has been set. So in this situation, the
|
||||||
* parent should not generally be configured to publish events or there will be duplicates.
|
* parent should not generally be configured to publish events or there will be duplicates.
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
*
|
*
|
||||||
@@ -76,6 +85,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
|||||||
private List<AuthenticationProvider> providers = Collections.emptyList();
|
private List<AuthenticationProvider> providers = Collections.emptyList();
|
||||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||||
private AuthenticationManager parent;
|
private AuthenticationManager parent;
|
||||||
|
private boolean eraseCredentialsAfterAuthentication = false;
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@@ -145,6 +155,11 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
|
||||||
|
// Authentication is complete. Remove credentials and other secret data from authentication
|
||||||
|
((CredentialsContainer)result).eraseCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
eventPublisher.publishAuthenticationSuccess(result);
|
eventPublisher.publishAuthenticationSuccess(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -193,6 +208,22 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
|
|||||||
this.eventPublisher = eventPublisher;
|
this.eventPublisher = eventPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to, a resulting {@code Authentication} which implements the {@code CredentialsContainer} interface
|
||||||
|
* will have its {@link CredentialsContainer#eraseCredentials() eraseCredentials} method called before it is returned
|
||||||
|
* from the {@code authenticate()} method.
|
||||||
|
*
|
||||||
|
* @param eraseSecretData set to {@literal false} to retain the credentials data in memory.
|
||||||
|
* Defaults to {@literal true}.
|
||||||
|
*/
|
||||||
|
public void setEraseCredentialsAfterAuthentication(boolean eraseSecretData) {
|
||||||
|
this.eraseCredentialsAfterAuthentication = eraseSecretData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEraseCredentialsAfterAuthentication() {
|
||||||
|
return eraseCredentialsAfterAuthentication;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link AuthenticationProvider} objects to be used for authentication.
|
* Sets the {@link AuthenticationProvider} objects to be used for authentication.
|
||||||
*
|
*
|
||||||
|
|||||||
+20
-19
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
package org.springframework.security.authentication;
|
package org.springframework.security.authentication;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
@@ -28,8 +27,9 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
* <code>GrantedAuthority</code>s that apply.
|
* <code>GrantedAuthority</code>s that apply.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
|
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final Object principal;
|
private final Object principal;
|
||||||
@@ -46,7 +46,7 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
|||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||||
*/
|
*/
|
||||||
public RememberMeAuthenticationToken(String key, Object principal, Collection<GrantedAuthority> authorities) {
|
public RememberMeAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
|
|
||||||
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
|
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
|
||||||
@@ -60,6 +60,23 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
|||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always returns an empty <code>String</code>
|
||||||
|
*
|
||||||
|
* @return an empty String
|
||||||
|
*/
|
||||||
|
public Object getCredentials() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyHash() {
|
||||||
|
return this.keyHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return this.principal;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!super.equals(obj)) {
|
if (!super.equals(obj)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -78,20 +95,4 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Always returns an empty <code>String</code>
|
|
||||||
*
|
|
||||||
* @return an empty String
|
|
||||||
*/
|
|
||||||
public Object getCredentials() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getKeyHash() {
|
|
||||||
return this.keyHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getPrincipal() {
|
|
||||||
return this.principal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -22,8 +22,8 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link org.springframework.security.core.Authentication} implementation that is designed for simple presentation of a
|
* An {@link org.springframework.security.core.Authentication} implementation that is designed for simple presentation
|
||||||
* username and password.
|
* of a username and password.
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>principal</code> and <code>credentials</code> should be set with an <code>Object</code> that provides
|
* The <code>principal</code> and <code>credentials</code> should be set with an <code>Object</code> that provides
|
||||||
* the respective property via its <code>Object.toString()</code> method. The simplest such <code>Object</code> to use
|
* the respective property via its <code>Object.toString()</code> method. The simplest such <code>Object</code> to use
|
||||||
@@ -34,8 +34,8 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final Object credentials;
|
|
||||||
private final Object principal;
|
private final Object principal;
|
||||||
|
private Object credentials;
|
||||||
|
|
||||||
//~ Constructors ===================================================================================================
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
|||||||
* @param credentials
|
* @param credentials
|
||||||
* @param authorities
|
* @param authorities
|
||||||
*/
|
*/
|
||||||
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<GrantedAuthority> authorities) {
|
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
this.principal = principal;
|
this.principal = principal;
|
||||||
this.credentials = credentials;
|
this.credentials = credentials;
|
||||||
@@ -94,4 +94,10 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
|||||||
|
|
||||||
super.setAuthenticated(false);
|
super.setAuthenticated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eraseCredentials() {
|
||||||
|
super.eraseCredentials();
|
||||||
|
credentials = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -16,6 +16,8 @@
|
|||||||
package org.springframework.security.authentication.dao;
|
package org.springframework.security.authentication.dao;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.security.authentication.AccountExpiredException;
|
import org.springframework.security.authentication.AccountExpiredException;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
@@ -71,6 +73,9 @@ import org.springframework.util.Assert;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean,
|
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean,
|
||||||
MessageSourceAware {
|
MessageSourceAware {
|
||||||
|
|
||||||
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||||
@@ -123,6 +128,8 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||||||
try {
|
try {
|
||||||
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
|
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
|
||||||
} catch (UsernameNotFoundException notFound) {
|
} catch (UsernameNotFoundException notFound) {
|
||||||
|
logger.debug("User '" + username + "' not found");
|
||||||
|
|
||||||
if (hideUserNotFoundExceptions) {
|
if (hideUserNotFoundExceptions) {
|
||||||
throw new BadCredentialsException(messages.getMessage(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||||
@@ -291,16 +298,22 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||||||
private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
|
private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
|
||||||
public void check(UserDetails user) {
|
public void check(UserDetails user) {
|
||||||
if (!user.isAccountNonLocked()) {
|
if (!user.isAccountNonLocked()) {
|
||||||
|
logger.debug("User account is locked");
|
||||||
|
|
||||||
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
|
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
|
||||||
"User account is locked"), user);
|
"User account is locked"), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.isEnabled()) {
|
if (!user.isEnabled()) {
|
||||||
|
logger.debug("User account is disabled");
|
||||||
|
|
||||||
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
|
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
|
||||||
"User is disabled"), user);
|
"User is disabled"), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.isAccountNonExpired()) {
|
if (!user.isAccountNonExpired()) {
|
||||||
|
logger.debug("User account is expired");
|
||||||
|
|
||||||
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
|
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
|
||||||
"User account has expired"), user);
|
"User account has expired"), user);
|
||||||
}
|
}
|
||||||
@@ -310,6 +323,8 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||||||
private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
|
private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
|
||||||
public void check(UserDetails user) {
|
public void check(UserDetails user) {
|
||||||
if (!user.isCredentialsNonExpired()) {
|
if (!user.isCredentialsNonExpired()) {
|
||||||
|
logger.debug("User account credentials have expired");
|
||||||
|
|
||||||
throw new CredentialsExpiredException(messages.getMessage(
|
throw new CredentialsExpiredException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
||||||
"User credentials have expired"), user);
|
"User credentials have expired"), user);
|
||||||
|
|||||||
+4
@@ -56,6 +56,8 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (authentication.getCredentials() == null) {
|
if (authentication.getCredentials() == null) {
|
||||||
|
logger.debug("Authentication failed: no credentials provided");
|
||||||
|
|
||||||
throw new BadCredentialsException(messages.getMessage(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||||
includeDetailsObject ? userDetails : null);
|
includeDetailsObject ? userDetails : null);
|
||||||
@@ -64,6 +66,8 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
String presentedPassword = authentication.getCredentials().toString();
|
String presentedPassword = authentication.getCredentials().toString();
|
||||||
|
|
||||||
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
|
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
|
||||||
|
logger.debug("Authentication failed: password does not match stored value");
|
||||||
|
|
||||||
throw new BadCredentialsException(messages.getMessage(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
|
||||||
includeDetailsObject ? userDetails : null);
|
includeDetailsObject ? userDetails : null);
|
||||||
|
|||||||
+5
-5
@@ -16,12 +16,12 @@
|
|||||||
package org.springframework.security.authentication.encoding;
|
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.Base64;
|
||||||
|
import org.springframework.security.core.codec.Utf8;
|
||||||
import org.springframework.util.Assert;
|
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
|
* 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;
|
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) {
|
private byte[] extractSalt(String encPass) {
|
||||||
@@ -145,7 +145,7 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
|
|||||||
|
|
||||||
String encodedRawPass = encodePassword(rawPass, salt).substring(startOfHash);
|
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;
|
package org.springframework.security.authentication.encoding;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
|
|
||||||
import org.springframework.security.core.codec.Base64;
|
import org.springframework.security.core.codec.Base64;
|
||||||
import org.springframework.security.core.codec.Hex;
|
import org.springframework.security.core.codec.Hex;
|
||||||
|
import org.springframework.security.core.codec.Utf8;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MD4 implementation of PasswordEncoder.
|
* MD4 implementation of PasswordEncoder.
|
||||||
@@ -60,7 +61,7 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
|
|||||||
byte[] resBuf = md4.digest();
|
byte[] resBuf = md4.digest();
|
||||||
|
|
||||||
if (getEncodeHashAsBase64()) {
|
if (getEncodeHashAsBase64()) {
|
||||||
return new String(Base64.encode(resBuf));
|
return Utf8.decode(Base64.encode(resBuf));
|
||||||
} else {
|
} else {
|
||||||
return new String(Hex.encode(resBuf));
|
return new String(Hex.encode(resBuf));
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,7 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
|
|||||||
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
|
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
|
||||||
String pass1 = "" + encPass;
|
String pass1 = "" + encPass;
|
||||||
String pass2 = encodePassword(rawPass, salt);
|
String pass2 = encodePassword(rawPass, salt);
|
||||||
return pass1.equals(pass2);
|
return PasswordEncoderUtils.equals(pass1,pass2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlgorithm() {
|
public String getAlgorithm() {
|
||||||
|
|||||||
+7
-6
@@ -1,13 +1,14 @@
|
|||||||
package org.springframework.security.authentication.encoding;
|
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.io.UnsupportedEncodingException;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
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.
|
* Base for digest password encoders.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -92,7 +93,7 @@ public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getEncodeHashAsBase64()) {
|
if (getEncodeHashAsBase64()) {
|
||||||
return new String(Base64.encode(digest));
|
return Utf8.decode(Base64.encode(digest));
|
||||||
} else {
|
} else {
|
||||||
return new String(Hex.encode(digest));
|
return new String(Hex.encode(digest));
|
||||||
}
|
}
|
||||||
@@ -126,7 +127,7 @@ public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
|
|||||||
String pass1 = "" + encPass;
|
String pass1 = "" + encPass;
|
||||||
String pass2 = encodePassword(rawPass, salt);
|
String pass2 = encodePassword(rawPass, salt);
|
||||||
|
|
||||||
return pass1.equals(pass2);
|
return PasswordEncoderUtils.equals(pass1,pass2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlgorithm() {
|
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;
|
package org.springframework.security.authentication.encoding;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Plaintext implementation of PasswordEncoder.</p>
|
* <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
|
* <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)
|
// authentication will fail as the encodePassword never allows them)
|
||||||
String pass2 = mergePasswordAndSalt(rawPass, salt, false);
|
String pass2 = mergePasswordAndSalt(rawPass, salt, false);
|
||||||
|
|
||||||
if (!ignorePasswordCase) {
|
if (ignorePasswordCase) {
|
||||||
return pass1.equals(pass2);
|
// Note: per String javadoc to get correct results for Locale insensitive, use English
|
||||||
} else {
|
pass1 = pass1.toLowerCase(Locale.ENGLISH);
|
||||||
return pass1.equalsIgnoreCase(pass2);
|
pass2 = pass2.toLowerCase(Locale.ENGLISH);
|
||||||
}
|
}
|
||||||
|
return PasswordEncoderUtils.equals(pass1,pass2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+22
-20
@@ -15,22 +15,6 @@
|
|||||||
|
|
||||||
package org.springframework.security.authentication.jaas;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
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.security.core.session.SessionDestroyedEvent;
|
||||||
import org.springframework.util.Assert;
|
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.
|
* 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.
|
// Create a set to hold the authorities, and add any that have already been applied.
|
||||||
authorities = new HashSet<GrantedAuthority>();
|
authorities = new HashSet<GrantedAuthority>();
|
||||||
authorities.addAll(request.getAuthorities());
|
|
||||||
|
|
||||||
// Get the subject principals and pass them to each of the AuthorityGranters
|
// Get the subject principals and pass them to each of the AuthorityGranters
|
||||||
Set<Principal> principals = loginContext.getSubject().getPrincipals();
|
Set<Principal> principals = loginContext.getSubject().getPrincipals();
|
||||||
@@ -269,14 +265,20 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String convertLoginConfigToUrl() throws IOException {
|
private String convertLoginConfigToUrl() throws IOException {
|
||||||
String loginConfigPath = loginConfig.getFile().getAbsolutePath();
|
String loginConfigPath;
|
||||||
loginConfigPath.replace(File.separatorChar, '/');
|
|
||||||
|
try {
|
||||||
|
loginConfigPath = loginConfig.getFile().getAbsolutePath().replace(File.separatorChar, '/');
|
||||||
|
|
||||||
if (!loginConfigPath.startsWith("/")) {
|
if (!loginConfigPath.startsWith("/")) {
|
||||||
loginConfigPath = "/" + loginConfigPath;
|
loginConfigPath = "/" + loginConfigPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new URL("file", "", loginConfigPath).toString();
|
return new URL("file", "", loginConfigPath).toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// SEC-1700: May be inside a jar
|
||||||
|
return loginConfig.getURL().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) }
|
* If set, a call to {@code Configuration#refresh()} will be made by {@code #configureJaas(Resource) }
|
||||||
* method. Defaults to {@code true}.
|
* 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.
|
* @param refresh set to {@code false} to disable reloading of the configuration.
|
||||||
* May be useful in some environments.
|
* May be useful in some environments.
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ public abstract class AuthenticationException extends RuntimeException {
|
|||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private Authentication authentication;
|
private Authentication authentication;
|
||||||
private Object extraInformation;
|
private transient Object extraInformation;
|
||||||
|
|
||||||
//~ Constructors ===================================================================================================
|
//~ 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 msg the detail message
|
||||||
* @param t the root cause
|
* @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
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
@@ -48,15 +48,22 @@ public abstract class AuthenticationException extends RuntimeException {
|
|||||||
super(msg);
|
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) {
|
public AuthenticationException(String msg, Object extraInformation) {
|
||||||
super(msg);
|
super(msg);
|
||||||
|
if (extraInformation instanceof CredentialsContainer) {
|
||||||
|
((CredentialsContainer) extraInformation).eraseCredentials();
|
||||||
|
}
|
||||||
this.extraInformation = extraInformation;
|
this.extraInformation = extraInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ 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() {
|
public Authentication getAuthentication() {
|
||||||
return authentication;
|
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() {
|
public Object getExtraInformation() {
|
||||||
return extraInformation;
|
return extraInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void clearExtraInformation() {
|
public void clearExtraInformation() {
|
||||||
this.extraInformation = null;
|
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.
|
* See <a href="http://iharder.net/base64">http://iharder.net/base64</a> for more information.
|
||||||
* <p>
|
* <p>
|
||||||
* For internal use only.
|
* For internal use only.
|
||||||
@@ -101,8 +101,8 @@ public final class Base64 {
|
|||||||
-9,-9,-9,-9,-9,-9, // Decimal 91 - 96
|
-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'
|
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'
|
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 // Decimal 123 - 127
|
||||||
/*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
|
,-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 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 153 - 165
|
||||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
|
-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 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 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,-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
|
-9, // Decimal 96
|
||||||
26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
|
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'
|
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 // Decimal 123 - 127
|
||||||
/*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
|
,-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 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 153 - 165
|
||||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
|
-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 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 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,-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
|
-9, // Decimal 96
|
||||||
38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm'
|
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'
|
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 // Decimal 123 - 127
|
||||||
/*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
|
,-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 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 153 - 165
|
||||||
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
|
-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 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 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,-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 source The data to convert
|
||||||
* @param off Offset in array where conversion should begin
|
* @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.
|
// 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];
|
byte[] finalOut = new byte[e];
|
||||||
System.arraycopy(outBuff,0, finalOut,0,e);
|
System.arraycopy(outBuff,0, finalOut,0,e);
|
||||||
//System.err.println("Having to resize array from " + outBuff.length + " to " + 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
|
byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space
|
||||||
int b4Posn = 0; // Keep track of four byte input buffer
|
int b4Posn = 0; // Keep track of four byte input buffer
|
||||||
int i = 0; // Source array counter
|
int i = 0; // Source array counter
|
||||||
byte sbiCrop = 0; // Low seven bits (ASCII) of input
|
|
||||||
byte sbiDecode = 0; // Special value from DECODABET
|
byte sbiDecode = 0; // Special value from DECODABET
|
||||||
|
|
||||||
for( i = off; i < off+len; i++ ) { // Loop through source
|
for( i = off; i < off+len; i++ ) { // Loop through source
|
||||||
|
|
||||||
sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
|
sbiDecode = DECODABET[ source[i]&0xFF ];
|
||||||
sbiDecode = DECODABET[ sbiCrop ]; // Special value
|
|
||||||
|
|
||||||
// White space, Equals sign, or legit Base64 character
|
// White space, Equals sign, or legit Base64 character
|
||||||
// Note the values such as -5 and -9 in the
|
// Note the values such as -5 and -9 in the
|
||||||
// DECODABETs at the top of the file.
|
// DECODABETs at the top of the file.
|
||||||
if( sbiDecode >= WHITE_SPACE_ENC ) {
|
if( sbiDecode >= WHITE_SPACE_ENC ) {
|
||||||
if( sbiDecode >= EQUALS_SIGN_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?
|
if( b4Posn > 3 ) { // Time to decode?
|
||||||
outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
|
outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
|
||||||
b4Posn = 0;
|
b4Posn = 0;
|
||||||
|
|
||||||
// If that was the equals sign, break out of 'for' loop
|
// If that was the equals sign, break out of 'for' loop
|
||||||
if( sbiCrop == EQUALS_SIGN ) {
|
if( source[i] == EQUALS_SIGN ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -629,7 +623,7 @@ public final class Base64 {
|
|||||||
else {
|
else {
|
||||||
// There's a bad input character in the Base64 stream.
|
// There's a bad input character in the Base64 stream.
|
||||||
throw new InvalidBase64CharacterException( String.format(
|
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 ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public void clearContext() {
|
public void clearContext() {
|
||||||
contextHolder.set(null);
|
contextHolder.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecurityContext getContext() {
|
public SecurityContext getContext() {
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextH
|
|||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public void clearContext() {
|
public void clearContext() {
|
||||||
contextHolder.set(null);
|
contextHolder.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecurityContext getContext() {
|
public SecurityContext getContext() {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.SortedSet;
|
|||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,12 +34,18 @@ import org.springframework.util.Assert;
|
|||||||
* Implemented with value object semantics (immutable after construction, like a <code>String</code>).
|
* Implemented with value object semantics (immutable after construction, like a <code>String</code>).
|
||||||
* Developers may use this class directly, subclass it, or write their own {@link UserDetails} implementation from
|
* Developers may use this class directly, subclass it, or write their own {@link UserDetails} implementation from
|
||||||
* scratch.
|
* scratch.
|
||||||
|
* <p>
|
||||||
|
* {@code equals} and {@code hashcode} implementations are based on the {@code username} property only, as the
|
||||||
|
* intention is that lookups of the same user principal object (in a user registry, for example) will match
|
||||||
|
* where the objects represent the same user, not just when all the properties (authorities, password for
|
||||||
|
* example) are the same.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
* @author Luke Taylor
|
||||||
*/
|
*/
|
||||||
public class User implements UserDetails {
|
public class User implements UserDetails, CredentialsContainer {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
private final String password;
|
private String password;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final Set<GrantedAuthority> authorities;
|
private final Set<GrantedAuthority> authorities;
|
||||||
private final boolean accountNonExpired;
|
private final boolean accountNonExpired;
|
||||||
@@ -81,7 +88,7 @@ public class User implements UserDetails {
|
|||||||
* <code>GrantedAuthority</code> collection
|
* <code>GrantedAuthority</code> collection
|
||||||
*/
|
*/
|
||||||
public User(String username, String password, boolean enabled, boolean accountNonExpired,
|
public User(String username, String password, boolean enabled, boolean accountNonExpired,
|
||||||
boolean credentialsNonExpired, boolean accountNonLocked, Collection<GrantedAuthority> authorities) {
|
boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
|
||||||
if (((username == null) || "".equals(username)) || (password == null)) {
|
if (((username == null) || "".equals(username)) || (password == null)) {
|
||||||
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
||||||
@@ -98,27 +105,6 @@ public class User implements UserDetails {
|
|||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public boolean equals(Object rhs) {
|
|
||||||
if (!(rhs instanceof User) || (rhs == null)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
User user = (User) rhs;
|
|
||||||
|
|
||||||
// We rely on constructor to guarantee any User has non-null
|
|
||||||
// authorities
|
|
||||||
if (!authorities.equals(user.authorities)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We rely on constructor to guarantee non-null username and password
|
|
||||||
return (this.getPassword().equals(user.getPassword()) && this.getUsername().equals(user.getUsername())
|
|
||||||
&& (this.isAccountNonExpired() == user.isAccountNonExpired())
|
|
||||||
&& (this.isAccountNonLocked() == user.isAccountNonLocked())
|
|
||||||
&& (this.isCredentialsNonExpired() == user.isCredentialsNonExpired())
|
|
||||||
&& (this.isEnabled() == user.isEnabled()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<GrantedAuthority> getAuthorities() {
|
public Collection<GrantedAuthority> getAuthorities() {
|
||||||
return authorities;
|
return authorities;
|
||||||
}
|
}
|
||||||
@@ -131,38 +117,8 @@ public class User implements UserDetails {
|
|||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public boolean isEnabled() {
|
||||||
int code = 9792;
|
return enabled;
|
||||||
|
|
||||||
for (GrantedAuthority authority : getAuthorities()) {
|
|
||||||
code = code * (authority.hashCode() % 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getPassword() != null) {
|
|
||||||
code = code * (this.getPassword().hashCode() % 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getUsername() != null) {
|
|
||||||
code = code * (this.getUsername().hashCode() % 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isAccountNonExpired()) {
|
|
||||||
code = code * -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isAccountNonLocked()) {
|
|
||||||
code = code * -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isCredentialsNonExpired()) {
|
|
||||||
code = code * -5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isEnabled()) {
|
|
||||||
code = code * -7;
|
|
||||||
}
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAccountNonExpired() {
|
public boolean isAccountNonExpired() {
|
||||||
@@ -170,18 +126,18 @@ public class User implements UserDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAccountNonLocked() {
|
public boolean isAccountNonLocked() {
|
||||||
return this.accountNonLocked;
|
return accountNonLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCredentialsNonExpired() {
|
public boolean isCredentialsNonExpired() {
|
||||||
return credentialsNonExpired;
|
return credentialsNonExpired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public void eraseCredentials() {
|
||||||
return enabled;
|
password = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<GrantedAuthority> authorities) {
|
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||||
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
|
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
|
||||||
// Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-717)
|
// Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-717)
|
||||||
SortedSet<GrantedAuthority> sortedAuthorities =
|
SortedSet<GrantedAuthority> sortedAuthorities =
|
||||||
@@ -211,7 +167,30 @@ public class User implements UserDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the supplied object is a {@code User} instance with the
|
||||||
|
* same {@code username} value.
|
||||||
|
* <p>
|
||||||
|
* In other words, the objects are equal if they have the same username, representing the
|
||||||
|
* same principal.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object rhs) {
|
||||||
|
if (rhs instanceof User) {
|
||||||
|
return username.equals(((User) rhs).username);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hashcode of the {@code username}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return username.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(super.toString()).append(": ");
|
sb.append(super.toString()).append(": ");
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user