Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d6d9bc9d6b |
-15
@@ -1,15 +0,0 @@
|
||||
target
|
||||
.gradle
|
||||
build/
|
||||
.idea
|
||||
out/
|
||||
*.ipr
|
||||
*.iml
|
||||
*.iws
|
||||
*.log
|
||||
intellij/
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
.DS_Store
|
||||
atlassian-ide-plugin.xml
|
||||
+28
-19
@@ -3,13 +3,14 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>2.0.9.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<name>Spring Security - ACL module</name>
|
||||
<packaging>jar</packaging>
|
||||
<version>2.0.3</version>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -24,13 +25,6 @@
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
@@ -51,14 +45,29 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<!--
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
-->
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version.osgi}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
javax.sql.*
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.acls</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides an abstract base for standard {@link Permission} instances that wish to offer static convenience
|
||||
* methods to callers via delegation to {@link DefaultPermissionFactory}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractRegisteredPermission extends AbstractPermission {
|
||||
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
protected AbstractRegisteredPermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
|
||||
protected final static void registerPermissionsFor(Class subClass) {
|
||||
defaultPermissionFactory.registerPublicPermissions(subClass);
|
||||
}
|
||||
|
||||
public final static Permission buildFromMask(int mask) {
|
||||
return defaultPermissionFactory.buildFromMask(mask);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromMask(int[] masks) {
|
||||
return defaultPermissionFactory.buildFromMask(masks);
|
||||
}
|
||||
|
||||
public final static Permission buildFromName(String name) {
|
||||
return defaultPermissionFactory.buildFromName(name);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromName(String[] names) {
|
||||
return defaultPermissionFactory.buildFromName(names);
|
||||
}
|
||||
}
|
||||
@@ -28,16 +28,14 @@ import org.springframework.security.acls.Permission;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class BasePermission extends AbstractPermission {
|
||||
public class BasePermission extends AbstractRegisteredPermission {
|
||||
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
|
||||
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
|
||||
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
|
||||
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
|
||||
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
|
||||
|
||||
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
/**
|
||||
/**
|
||||
* Registers the public static permissions defined on this class. This is mandatory so
|
||||
* that the static methods will operate correctly.
|
||||
*/
|
||||
@@ -48,25 +46,4 @@ public class BasePermission extends AbstractPermission {
|
||||
protected BasePermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
|
||||
protected final static void registerPermissionsFor(Class subClass) {
|
||||
defaultPermissionFactory.registerPublicPermissions(subClass);
|
||||
}
|
||||
|
||||
public final static Permission buildFromMask(int mask) {
|
||||
return defaultPermissionFactory.buildFromMask(mask);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromMask(int[] masks) {
|
||||
return defaultPermissionFactory.buildFromMask(masks);
|
||||
}
|
||||
|
||||
public final static Permission buildFromName(String name) {
|
||||
return defaultPermissionFactory.buildFromName(name);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromName(String[] names) {
|
||||
return defaultPermissionFactory.buildFromName(names);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,12 @@ import java.lang.reflect.Field;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -175,33 +173,14 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
|
||||
Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
|
||||
|
||||
Field field = FieldUtils.getField(AclImpl.class, "aces");
|
||||
|
||||
try {
|
||||
fieldAces.setAccessible(true);
|
||||
fieldAcl.setAccessible(true);
|
||||
|
||||
// Obtain the "aces" from the input ACL
|
||||
Iterator i = ((List) fieldAces.get(inputAcl)).iterator();
|
||||
|
||||
// Create a list in which to store the "aces" for the "result" AclImpl instance
|
||||
List acesNew = new ArrayList();
|
||||
|
||||
// Iterate over the "aces" input and replace each nested AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
|
||||
// This ensures StubAclParent instances are removed, as per SEC-951
|
||||
while(i.hasNext()) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) i.next();
|
||||
fieldAcl.set(ace, result);
|
||||
acesNew.add(ace);
|
||||
}
|
||||
|
||||
// Finally, now that the "aces" have been converted to have the "result" AclImpl instance, modify the "result" AclImpl instance
|
||||
fieldAces.set(result, acesNew);
|
||||
field.setAccessible(true);
|
||||
field.set(result, field.get(inputAcl));
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not obtain or set AclImpl or AccessControlEntryImpl fields");
|
||||
throw new IllegalStateException("Could not obtain or set AclImpl.ace field");
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,6 @@ public class PermissionTests {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void basePermissionTest() {
|
||||
Permission p = BasePermission.buildFromName("WRITE");
|
||||
assertNotNull(p);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expectedIntegerValues() {
|
||||
assertEquals(1, BasePermission.READ.getMask());
|
||||
|
||||
@@ -53,7 +53,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken(null, "password");
|
||||
Authentication authentication = new TestingAuthenticationToken(null, "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
@@ -128,15 +128,15 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testPrincipalSidEquals() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
|
||||
Assert.assertFalse(principalSid.equals(null));
|
||||
Assert.assertFalse(principalSid.equals("DIFFERENT_TYPE_OBJECT"));
|
||||
Assert.assertTrue(principalSid.equals(principalSid));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(authentication)));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null))));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null))));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null, null))));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null, null))));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid("johndoe")));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid("scott")));
|
||||
}
|
||||
@@ -156,13 +156,14 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testPrincipalSidHashCode() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
|
||||
Assert.assertTrue(principalSid.hashCode() == new String("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() == new PrincipalSid("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid("scott").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password",
|
||||
null)).hashCode());
|
||||
}
|
||||
|
||||
public void testGrantedAuthoritySidHashCode() throws Exception {
|
||||
@@ -176,7 +177,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testGetters() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
PrincipalSid principalSid = new PrincipalSid(authentication);
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
Bundle-SymbolicName: org.springframework.security.acls
|
||||
Bundle-Name: Spring Security Acls
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-Version: ${version}
|
||||
Bundle-ManifestVersion: 2
|
||||
Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
|
||||
org.springframework.security.*;version="[${version}, ${version}]",
|
||||
org.springframework.context.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.dao.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.jdbc.core.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.util.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
javax.sql.*;version="0";resolution:=optional
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.5.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-catalina</artifactId>
|
||||
<name>Spring Security - Catalina adapter</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.5.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jboss</artifactId>
|
||||
<name>Spring Security - JBoss adapter</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.5.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jetty</artifactId>
|
||||
<name>Spring Security - Jetty adapter</name>
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.5.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<name>Spring Security - Adapters</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.5.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-resin</artifactId>
|
||||
<name>Spring Security - Resin adapter</name>
|
||||
|
||||
+27
-18
@@ -3,11 +3,11 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.9.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-cas-client</artifactId>
|
||||
<name>Spring Security - CAS support</name>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -15,13 +15,6 @@
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-dao</artifactId>
|
||||
@@ -38,7 +31,7 @@
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>3.1.5</version>
|
||||
<version>3.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
@@ -47,12 +40,28 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version.osgi}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.beans.*;version="${spring.version.osgi}",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.jasig.cas.client.*;version="[3.1.3, 4.0.0)"
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.cas</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+16
-25
@@ -76,7 +76,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.userDetailsService, "A userDetailsService must be set");
|
||||
Assert.notNull(this.ticketValidator, "A ticketValidator must be set");
|
||||
Assert.notNull(this.statelessTicketCache, "A statelessTicketCache must be set");
|
||||
@@ -140,38 +140,29 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
return result;
|
||||
}
|
||||
|
||||
private final CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException {
|
||||
try {
|
||||
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
|
||||
final UserDetails userDetails = loadUserByAssertion(assertion);
|
||||
private CasAuthenticationToken authenticateNow(Authentication authentication) throws AuthenticationException {
|
||||
try {
|
||||
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
|
||||
final UserDetails userDetails = userDetailsService.loadUserByUsername(assertion.getPrincipal().getName());
|
||||
userDetailsChecker.check(userDetails);
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(), userDetails.getAuthorities(), userDetails, assertion);
|
||||
} catch (final TicketValidationException e) {
|
||||
throw new BadCredentialsException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for retrieving the UserDetails based on the assertion. Default is to call configured userDetailsService and pass the username. Deployers
|
||||
* can override this method and retrieve the user based on any criteria they desire.
|
||||
*
|
||||
* @param assertion The CAS Assertion.
|
||||
* @returns the UserDetails.
|
||||
*/
|
||||
protected UserDetails loadUserByAssertion(final Assertion assertion) {
|
||||
return this.userDetailsService.loadUserByUsername(assertion.getPrincipal().getName());
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
|
||||
userDetails.getAuthorities(), userDetails, assertion);
|
||||
} catch (final TicketValidationException e) {
|
||||
// TODO get error message
|
||||
throw new BadCredentialsException("", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected UserDetailsService getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(final UserDetailsService userDetailsService) {
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
public void setServiceProperties(final ServiceProperties serviceProperties) {
|
||||
this.serviceProperties = serviceProperties;
|
||||
this.serviceProperties = serviceProperties;
|
||||
}
|
||||
|
||||
protected String getKey() {
|
||||
@@ -190,15 +181,15 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
return ticketValidator;
|
||||
}
|
||||
|
||||
public void setMessageSource(final MessageSource messageSource) {
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
public void setStatelessTicketCache(final StatelessTicketCache statelessTicketCache) {
|
||||
public void setStatelessTicketCache(StatelessTicketCache statelessTicketCache) {
|
||||
this.statelessTicketCache = statelessTicketCache;
|
||||
}
|
||||
|
||||
public void setTicketValidator(final TicketValidator ticketValidator) {
|
||||
public void setTicketValidator(TicketValidator ticketValidator) {
|
||||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
Bundle-SymbolicName: org.springframework.security.cas
|
||||
Bundle-Name: Spring Security CAS
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-Version: ${version}
|
||||
Bundle-ManifestVersion: 2
|
||||
Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
|
||||
org.jasig.cas.client.*;version="[3.1.1,3.2)",
|
||||
org.springframework.security.*;version="[${version}, ${version}]",
|
||||
org.springframework.beans.factory;version="[2.0.8, 3.1.0)",
|
||||
org.springframework.context.*;version="[2.0.8, 3.1.0)",
|
||||
org.springframework.dao;version="[2.0.8, 3.1.0)",
|
||||
org.springframework.util;version="[2.0.8, 3.1.0)",
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
javax.servlet.*;version="0"
|
||||
|
||||
+36
-12
@@ -3,9 +3,9 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.9.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core-tiger</artifactId>
|
||||
<name>Spring Security - Java 5 (Tiger)</name>
|
||||
|
||||
@@ -21,12 +21,7 @@
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-remoting</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
@@ -59,10 +54,39 @@
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<configuration>
|
||||
<targetJdk>1.5</targetJdk>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
javax.annotation.*;version="[1.0.0, 2.0.0)",
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.core.*;version="${spring.version.osgi}"
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.include.res>
|
||||
src/main/resources
|
||||
</spring.osgi.include.res>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.annotation</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
+2
-4
@@ -39,10 +39,8 @@ public interface BusinessService {
|
||||
public void someUserMethod1();
|
||||
|
||||
@Secured({"ROLE_USER"})
|
||||
@RolesAllowed({"ROLE_USER"})
|
||||
@RolesAllowed({"ROLE_USER"})
|
||||
public void someUserMethod2();
|
||||
|
||||
public int someOther(String s);
|
||||
|
||||
|
||||
public int someOther(int input);
|
||||
}
|
||||
|
||||
+3
-7
@@ -26,11 +26,7 @@ public class BusinessServiceImpl<E extends Entity> implements BusinessService {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public int someOther(String s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int someOther(int input) {
|
||||
return input;
|
||||
}
|
||||
public int someOther(int input) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-7
@@ -27,11 +27,7 @@ public class Jsr250BusinessServiceImpl implements BusinessService {
|
||||
public void someAdminMethod() {
|
||||
}
|
||||
|
||||
public int someOther(String input) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int someOther(int input) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
}
|
||||
+14
-108
@@ -1,12 +1,13 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.security.config.ConfigTestUtils.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
@@ -14,12 +15,10 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
@@ -28,36 +27,29 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private BusinessService target;
|
||||
|
||||
public void loadContext() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>" +
|
||||
" <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/global-method-security.xml");
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
target = null;
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
loadContext();
|
||||
loadContext();
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
@@ -65,19 +57,20 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
loadContext();
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doesntInterfereWithBeanPostProcessing() {
|
||||
setContext(
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<global-method-security />" +
|
||||
// "<http auto-config='true'/>" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>" +
|
||||
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
|
||||
);
|
||||
@@ -86,75 +79,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithAspectJAutoproxy() {
|
||||
setContext(
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'" +
|
||||
" access='ROLE_SOMETHING' />" +
|
||||
"</global-method-security>" +
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<aop:aspectj-autoproxy />" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>"
|
||||
);
|
||||
|
||||
UserDetailsService service = (UserDetailsService) appContext.getBean("myUserService");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
service.loadUserByUsername("notused");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsMethodArgumentsInPointcut() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.*(..))' access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// someOther(int) should not be matched by someOther(String), but should require ROLE_USER
|
||||
target.someOther(0);
|
||||
|
||||
try {
|
||||
// String version should required admin role
|
||||
target.someOther("somestring");
|
||||
fail("Expected AccessDeniedException");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsBooleanPointcutExpressions() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression=" +
|
||||
" 'execution(* org.springframework.security.annotation.BusinessService.*(..)) " +
|
||||
" and not execution(* org.springframework.security.annotation.BusinessService.someOther(String)))' " +
|
||||
" access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// String method should not be protected
|
||||
target.someOther("somestring");
|
||||
|
||||
// All others should require ROLE_USER
|
||||
try {
|
||||
target.someOther(0);
|
||||
fail("Expected AuthenticationCredentialsNotFoundException");
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() {
|
||||
setContext(
|
||||
@@ -162,27 +87,8 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
"<global-method-security />"
|
||||
);
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithoutTargetOrClass() {
|
||||
setContext(
|
||||
"<global-method-security secured-annotations='enabled'/>" +
|
||||
"<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>" +
|
||||
" <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>" +
|
||||
" <b:property name='serviceInterface' value='org.springframework.security.annotation.BusinessService'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
target = (BusinessService) appContext.getBean("businessService");
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+5
-8
@@ -3,6 +3,7 @@ package org.springframework.security.config;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
@@ -10,23 +11,19 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
private ClassPathXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
|
||||
"<global-method-security jsr250-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
appContext = new ClassPathXmlApplicationContext("/org/springframework/security/config/jsr250-annotated-method-security.xml");
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@@ -51,7 +48,7 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
@@ -69,4 +66,4 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -3,6 +3,7 @@ package org.springframework.security.config;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
@@ -10,23 +11,19 @@ import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecuredAnnotationDrivenBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
private ClassPathXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
|
||||
"<global-method-security secured-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/secured-annotated-method-security.xml");
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<b:bean id="target" class="org.springframework.security.annotation.BusinessServiceImpl"/>
|
||||
|
||||
<global-method-security>
|
||||
<protect-pointcut expression="execution(* *.someUser*(..))" access="ROLE_USER"/>
|
||||
<protect-pointcut expression="execution(* *.someAdmin*(..))" access="ROLE_ADMIN"/>
|
||||
</global-method-security>
|
||||
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
|
||||
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
|
||||
</b:beans>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<b:bean id="target" class="org.springframework.security.annotation.Jsr250BusinessServiceImpl"/>
|
||||
|
||||
<global-method-security jsr250-annotations="enabled"/>
|
||||
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
|
||||
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
|
||||
</b:beans>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<b:bean id="target" class="org.springframework.security.annotation.Jsr250BusinessServiceImpl"/>
|
||||
|
||||
<global-method-security secured-annotations="enabled"/>
|
||||
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
|
||||
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
|
||||
</b:beans>
|
||||
@@ -1,12 +0,0 @@
|
||||
Bundle-SymbolicName: org.springframework.security.annotation
|
||||
Bundle-Name: Spring Security Annotations
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-Version: ${version}
|
||||
Bundle-ManifestVersion: 2
|
||||
Ignored-Existing-Headers:
|
||||
Import-Package,
|
||||
Export-Package
|
||||
Import-Template:
|
||||
javax.annotation.security.*;version="0";resolution:=optional,
|
||||
org.springframework.security.*;version="[${version},${version}]",
|
||||
org.springframework.core.*;version="[2.0.8, 3.1.0)"
|
||||
@@ -1,11 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
pushd src/main/resources/org/springframework/security/config/
|
||||
|
||||
echo "Converting rnc file to xsd ..."
|
||||
java -jar ~/bin/trang.jar spring-security-2.0.6.rnc spring-security-2.0.6.xsd
|
||||
|
||||
echo "Applying XSL transformation to xsd ..."
|
||||
xsltproc --output spring-security-2.0.6.xsd spring-security.xsl spring-security-2.0.6.xsd
|
||||
|
||||
popd
|
||||
+72
-33
@@ -3,9 +3,9 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<version>2.0.9.CI-SNAPSHOT</version>
|
||||
<version>2.0.3</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<name>Spring Security - Core</name>
|
||||
|
||||
@@ -47,27 +47,27 @@
|
||||
<artifactId>spring-mock</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
@@ -95,7 +95,7 @@
|
||||
<artifactId>jaxen</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
@@ -135,25 +135,64 @@
|
||||
<version>1.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.8.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
!com.ibm.websphere.security,
|
||||
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.aopalliance.*;version="[1.0.0, 2.0.0)",
|
||||
org.apache.commons.codec.*;version="[1.3.0, 2.0.0)",
|
||||
org.apache.commons.collections.*;version="[3.2.0, 4.0.0)",
|
||||
org.apache.commons.lang.*;version="[2.1.0, 3.0.0)",
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.apache.directory.server.configuration.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.apache.directory.server.core.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.apache.directory.server.protocol.*;version="[1.0.2, 2.0.0)";resolution:=optional,
|
||||
org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional,
|
||||
org.jaxen.*;version="[1.1.1, 2.0.0)";resolution:=optional,
|
||||
org.springframework.aop.*;version="${spring.version.osgi}",
|
||||
org.springframework.beans.*;version="${spring.version.osgi}",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.core.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.ldap.*;version="[1.2.1.A, 2.0.0)";resolution:=optional,
|
||||
org.springframework.metadata.*;version="${spring.version.osgi}",
|
||||
org.springframework.mock.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.remoting.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
org.springframework.web.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
javax.crypto.*,
|
||||
javax.naming.*,
|
||||
javax.rmi.*,
|
||||
javax.security.*,
|
||||
javax.sql.*,
|
||||
javax.xml.parsers.*,
|
||||
org.w3c.dom.*,
|
||||
org.xml.sax.*,
|
||||
*;resolution:=optional
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
<!--
|
||||
<spring.osgi.include.res>
|
||||
src/main/resources
|
||||
</spring.osgi.include.res>
|
||||
-->
|
||||
<spring.osgi.symbolic.name>org.springframework.security.core</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -26,7 +26,7 @@ public abstract class AuthenticationException extends SpringSecurityException {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Authentication authentication;
|
||||
private transient Object extraInformation;
|
||||
private Object extraInformation;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
|
||||
@@ -21,13 +21,8 @@ import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Basic concrete implementation of a {@link GrantedAuthority}.
|
||||
*
|
||||
* <p>
|
||||
* Stores a <code>String</code> representation of an authority granted to the {@link Authentication} object.
|
||||
* <p>
|
||||
* If compared to a custom authority which returns null from {@link #getAuthority}, the <tt>compareTo</tt>
|
||||
* method will return -1, so the custom authority will take precedence.
|
||||
* Basic concrete implementation of a {@link GrantedAuthority}.<p>Stores a <code>String</code> representation of an
|
||||
* authority granted to the {@link Authentication} object.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -41,6 +36,7 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public GrantedAuthorityImpl(String role) {
|
||||
super();
|
||||
Assert.hasText(role, "A granted authority textual representation is required");
|
||||
this.role = role;
|
||||
}
|
||||
@@ -75,13 +71,8 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
|
||||
|
||||
public int compareTo(Object o) {
|
||||
if (o != null && o instanceof GrantedAuthority) {
|
||||
String rhsRole = ((GrantedAuthority) o).getAuthority();
|
||||
|
||||
if (rhsRole == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return role.compareTo(rhsRole);
|
||||
GrantedAuthority rhs = (GrantedAuthority) o;
|
||||
return this.role.compareTo(rhs.getAuthority());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
package org.springframework.security.authoritymapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class implements the Attributes2GrantedAuthoritiesMapper and
|
||||
* MappableAttributesRetriever interfaces based on the supplied Map.
|
||||
* It supports both one-to-one and one-to-many mappings. The granted
|
||||
* authorities to map to can be supplied either as a String or as a
|
||||
* GrantedAuthority object.
|
||||
* </p>
|
||||
* @author Ruud Senden
|
||||
*/
|
||||
public class MapBasedAttributes2GrantedAuthoritiesMapper implements Attributes2GrantedAuthoritiesMapper, MappableAttributesRetriever, InitializingBean {
|
||||
private Map attributes2grantedAuthoritiesMap = null;
|
||||
private String stringSeparator = ",";
|
||||
private String[] mappableAttributes = null;
|
||||
|
||||
/**
|
||||
* Check whether all properties have been set to correct values, and do some preprocessing.
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notEmpty(attributes2grantedAuthoritiesMap,"A non-empty attributes2grantedAuthoritiesMap must be supplied");
|
||||
attributes2grantedAuthoritiesMap = preProcessMap(attributes2grantedAuthoritiesMap);
|
||||
try {
|
||||
mappableAttributes = (String[])attributes2grantedAuthoritiesMap.keySet().toArray(new String[]{});
|
||||
} catch ( ArrayStoreException ase ) {
|
||||
throw new IllegalArgumentException("attributes2grantedAuthoritiesMap contains non-String objects as keys");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocess the given map
|
||||
* @param orgMap The map to process
|
||||
* @return the processed Map
|
||||
*/
|
||||
private Map preProcessMap(Map orgMap) {
|
||||
Map result = new HashMap(orgMap.size());
|
||||
Iterator it = orgMap.entrySet().iterator();
|
||||
while ( it.hasNext() ) {
|
||||
Map.Entry entry = (Map.Entry)it.next();
|
||||
result.put(entry.getKey(),getGrantedAuthorityCollection(entry.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given value to a collection of Granted Authorities
|
||||
*
|
||||
* @param value
|
||||
* The value to convert to a GrantedAuthority Collection
|
||||
* @return Collection containing the GrantedAuthority Collection
|
||||
*/
|
||||
private Collection getGrantedAuthorityCollection(Object value) {
|
||||
Collection result = new ArrayList();
|
||||
addGrantedAuthorityCollection(result,value);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given value to a collection of Granted Authorities,
|
||||
* adding the result to the given result collection.
|
||||
*
|
||||
* @param value
|
||||
* The value to convert to a GrantedAuthority Collection
|
||||
* @return Collection containing the GrantedAuthority Collection
|
||||
*/
|
||||
private void addGrantedAuthorityCollection(Collection result, Object value) {
|
||||
if ( value != null ) {
|
||||
if ( value instanceof Collection ) {
|
||||
addGrantedAuthorityCollection(result,(Collection)value);
|
||||
} else if ( value instanceof Object[] ) {
|
||||
addGrantedAuthorityCollection(result,(Object[])value);
|
||||
} else if ( value instanceof String ) {
|
||||
addGrantedAuthorityCollection(result,(String)value);
|
||||
} else if ( value instanceof GrantedAuthority ) {
|
||||
result.add(value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid object type: "+value.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addGrantedAuthorityCollection(Collection result, Collection value) {
|
||||
Iterator it = value.iterator();
|
||||
while ( it.hasNext() ) {
|
||||
addGrantedAuthorityCollection(result,it.next());
|
||||
}
|
||||
}
|
||||
|
||||
private void addGrantedAuthorityCollection(Collection result, Object[] value) {
|
||||
for ( int i = 0 ; i < value.length ; i++ ) {
|
||||
addGrantedAuthorityCollection(result,value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void addGrantedAuthorityCollection(Collection result, String value) {
|
||||
StringTokenizer st = new StringTokenizer(value,stringSeparator,false);
|
||||
while ( st.hasMoreTokens() ) {
|
||||
String nextToken = st.nextToken();
|
||||
if ( StringUtils.hasText(nextToken) ) {
|
||||
result.add(new GrantedAuthorityImpl(nextToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the given array of attributes to Spring Security GrantedAuthorities.
|
||||
*/
|
||||
public GrantedAuthority[] getGrantedAuthorities(String[] attributes) {
|
||||
List gaList = new ArrayList();
|
||||
for (int i = 0; i < attributes.length; i++) {
|
||||
Collection c = (Collection)attributes2grantedAuthoritiesMap.get(attributes[i]);
|
||||
if ( c != null ) { gaList.addAll(c); }
|
||||
}
|
||||
GrantedAuthority[] result = new GrantedAuthority[gaList.size()];
|
||||
result = (GrantedAuthority[])gaList.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the attributes2grantedAuthoritiesMap.
|
||||
*/
|
||||
public Map getAttributes2grantedAuthoritiesMap() {
|
||||
return attributes2grantedAuthoritiesMap;
|
||||
}
|
||||
/**
|
||||
* @param attributes2grantedAuthoritiesMap The attributes2grantedAuthoritiesMap to set.
|
||||
*/
|
||||
public void setAttributes2grantedAuthoritiesMap(Map attributes2grantedAuthoritiesMap) {
|
||||
this.attributes2grantedAuthoritiesMap = attributes2grantedAuthoritiesMap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.springframework.security.authoritymapping.MappableAttributesRetriever#getMappableAttributes()
|
||||
*/
|
||||
public String[] getMappableAttributes() {
|
||||
return mappableAttributes;
|
||||
}
|
||||
/**
|
||||
* @return Returns the stringSeparator.
|
||||
*/
|
||||
public String getStringSeparator() {
|
||||
return stringSeparator;
|
||||
}
|
||||
/**
|
||||
* @param stringSeparator The stringSeparator to set.
|
||||
*/
|
||||
public void setStringSeparator(String stringSeparator) {
|
||||
this.stringSeparator = stringSeparator;
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -61,13 +61,14 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
|
||||
filter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority);
|
||||
filter.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
|
||||
provider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER);
|
||||
|
||||
ManagedList authMgrProviderList = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
authMgrProviderList.add(provider);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
|
||||
+1
-2
@@ -22,7 +22,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
String alias = element.getAttribute(ATT_ALIAS);
|
||||
|
||||
@@ -33,7 +33,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
|
||||
String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
|
||||
|
||||
if (StringUtils.hasText(sessionControllerRef)) {
|
||||
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
|
||||
BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController",
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser
|
||||
parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
|
||||
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, id);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(id));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ public abstract class BeanIds {
|
||||
public static final String MAIN_ENTRY_POINT = "_mainEntryPoint";
|
||||
public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
|
||||
public static final String HTTP_SESSION_CONTEXT_INTEGRATION_FILTER = "_httpSessionContextIntegrationFilter";
|
||||
public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";
|
||||
public static final String LOGOUT_FILTER = "_logoutFilter";
|
||||
public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
|
||||
public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
|
||||
@@ -50,7 +49,6 @@ public abstract class BeanIds {
|
||||
public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager";
|
||||
public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
|
||||
public static final String REMEMBER_ME_SERVICES = "_rememberMeServices";
|
||||
public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider";
|
||||
public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
|
||||
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
||||
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
||||
@@ -68,4 +66,5 @@ public abstract class BeanIds {
|
||||
public static final String X509_AUTH_PROVIDER = "_x509AuthenticationProvider";
|
||||
public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
|
||||
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -9,12 +9,15 @@ import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
@@ -77,20 +80,21 @@ public abstract class ConfigUtils {
|
||||
* using the <security:provider /> tag or by other beans which have a dependency on the
|
||||
* authentication manager.
|
||||
*/
|
||||
static void registerProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
static BeanDefinition registerProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
|
||||
return;
|
||||
return parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
}
|
||||
|
||||
BeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class);
|
||||
authManager.getPropertyValues().addPropertyValue("providerBeanNames", new ArrayList());
|
||||
BeanDefinition authManager = new RootBeanDefinition(ProviderManager.class);
|
||||
authManager.getPropertyValues().addPropertyValue("providers", new ManagedList());
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager);
|
||||
|
||||
return authManager;
|
||||
}
|
||||
|
||||
static void addAuthenticationProvider(ParserContext parserContext, String beanName) {
|
||||
registerProviderManagerIfNecessary(parserContext);
|
||||
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName);
|
||||
static ManagedList getRegisteredProviders(ParserContext parserContext) {
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext);
|
||||
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
}
|
||||
|
||||
static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
|
||||
@@ -168,8 +172,7 @@ public abstract class ConfigUtils {
|
||||
}
|
||||
|
||||
static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
|
||||
registerProviderManagerIfNecessary(pc);
|
||||
BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
BeanDefinition authManager = registerProviderManagerIfNecessary(pc);
|
||||
PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
|
||||
|
||||
if (pv != null && pv.getValue() != null) {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import org.w3c.dom.Node;
|
||||
*/
|
||||
public class CustomAuthenticationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, holder.getBeanName());
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(holder.getBeanName()));
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
@@ -10,35 +10,34 @@ abstract class Elements {
|
||||
|
||||
public static final String AUTHENTICATION_MANAGER = "authentication-manager";
|
||||
public static final String USER_SERVICE = "user-service";
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
|
||||
public static final String INTERCEPT_METHODS = "intercept-methods";
|
||||
public static final String INTERCEPT_URL = "intercept-url";
|
||||
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
|
||||
public static final String HTTP = "http";
|
||||
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
|
||||
public static final String LDAP_SERVER = "ldap-server";
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
|
||||
public static final String INTERCEPT_METHODS = "intercept-methods";
|
||||
public static final String INTERCEPT_URL = "intercept-url";
|
||||
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
|
||||
public static final String HTTP = "http";
|
||||
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
|
||||
public static final String LDAP_SERVER = "ldap-server";
|
||||
public static final String LDAP_USER_SERVICE = "ldap-user-service";
|
||||
public static final String PROTECT_POINTCUT = "protect-pointcut";
|
||||
public static final String PROTECT = "protect";
|
||||
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
|
||||
public static final String LOGOUT = "logout";
|
||||
public static final String FORM_LOGIN = "form-login";
|
||||
public static final String OPENID_LOGIN = "openid-login";
|
||||
public static final String BASIC_AUTH = "http-basic";
|
||||
public static final String REMEMBER_ME = "remember-me";
|
||||
public static final String ANONYMOUS = "anonymous";
|
||||
public static final String FILTER_CHAIN = "filter-chain";
|
||||
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
|
||||
public static final String PASSWORD_ENCODER = "password-encoder";
|
||||
public static final String SALT_SOURCE = "salt-source";
|
||||
public static final String PORT_MAPPINGS = "port-mappings";
|
||||
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
|
||||
public static final String LOGOUT = "logout";
|
||||
public static final String FORM_LOGIN = "form-login";
|
||||
public static final String OPENID_LOGIN = "openid-login";
|
||||
public static final String BASIC_AUTH = "http-basic";
|
||||
public static final String REMEMBER_ME = "remember-me";
|
||||
public static final String ANONYMOUS = "anonymous";
|
||||
public static final String FILTER_CHAIN = "filter-chain";
|
||||
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
|
||||
public static final String PASSWORD_ENCODER = "password-encoder";
|
||||
public static final String SALT_SOURCE = "salt-source";
|
||||
public static final String PORT_MAPPINGS = "port-mappings";
|
||||
public static final String PORT_MAPPING = "port-mapping";
|
||||
public static final String CUSTOM_FILTER = "custom-filter";
|
||||
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
|
||||
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||
public static final String X509 = "x509";
|
||||
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 HTTP_FIREWALL = "http-firewall";
|
||||
}
|
||||
|
||||
+38
-26
@@ -20,13 +20,14 @@ import org.springframework.security.intercept.method.MapBasedMethodDefinitionSou
|
||||
import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Processes the top-level "global-method-security" element.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
@@ -41,26 +42,32 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String ATT_USE_JSR250 = "jsr250-annotations";
|
||||
private static final String ATT_USE_SECURED = "secured-annotations";
|
||||
|
||||
private void validatePresent(String className, Element element, ParserContext parserContext) {
|
||||
if (!ClassUtils.isPresent(className, parserContext.getReaderContext().getBeanClassLoader())) {
|
||||
parserContext.getReaderContext().error("Cannot locate '" + className + "'", element);
|
||||
}
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
// The list of method metadata delegates
|
||||
ManagedList delegates = new ManagedList();
|
||||
|
||||
|
||||
boolean jsr250Enabled = registerAnnotationBasedMethodDefinitionSources(element, parserContext, delegates);
|
||||
|
||||
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
|
||||
delegates.add(mapBasedMethodDefinitionSource);
|
||||
|
||||
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
|
||||
Map pointcutMap = parseProtectPointcuts(parserContext,
|
||||
|
||||
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
|
||||
Map pointcutMap = parseProtectPointcuts(parserContext,
|
||||
DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT));
|
||||
|
||||
|
||||
if (pointcutMap.size() > 0) {
|
||||
registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodDefinitionSource, source);
|
||||
}
|
||||
|
||||
|
||||
registerDelegatingMethodDefinitionSource(parserContext, delegates, source);
|
||||
|
||||
|
||||
// Register the applicable AccessDecisionManager, handling the special JSR 250 voter if being used
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
@@ -68,40 +75,45 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
|
||||
if (jsr250Enabled) {
|
||||
ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
|
||||
ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
|
||||
}
|
||||
|
||||
accessManagerId = BeanIds.ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
|
||||
registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
|
||||
|
||||
|
||||
registerAdvisor(parserContext, source);
|
||||
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether JSR-250 and/or Secured annotations are enabled and adds the appropriate
|
||||
* MethodDefinitionSource delegates if required.
|
||||
* Checks whether JSR-250 and/or Secured annotations are enabled and adds the appropriate
|
||||
* MethodDefinitionSource delegates if required.
|
||||
*/
|
||||
private boolean registerAnnotationBasedMethodDefinitionSources(Element element, ParserContext pc, ManagedList delegates) {
|
||||
boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
|
||||
|
||||
// Check the required classes are present
|
||||
if (useSecured) {
|
||||
validatePresent(SECURED_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
|
||||
validatePresent(SECURED_DEPENDENCY_CLASS, element, pc);
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
validatePresent(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
|
||||
validatePresent(JSR_250_VOTER_CLASS, element, pc);
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
|
||||
return useJsr250;
|
||||
}
|
||||
|
||||
|
||||
private void registerDelegatingMethodDefinitionSource(ParserContext parserContext, ManagedList delegates, Object source) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE)) {
|
||||
parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
|
||||
@@ -110,9 +122,9 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
delegatingMethodDefinitionSource.setSource(source);
|
||||
delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
|
||||
}
|
||||
|
||||
|
||||
private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map pointcutMap,
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource, Object source) {
|
||||
RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
|
||||
@@ -150,13 +162,13 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
|
||||
interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
interceptor.setSource(source);
|
||||
|
||||
|
||||
interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
|
||||
interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
|
||||
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
|
||||
new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
|
||||
}
|
||||
@@ -168,6 +180,6 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(BeanIds.METHOD_SECURITY_INTERCEPTOR);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||
}
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||
}
|
||||
}
|
||||
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* 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.addConstructorArg(ref);
|
||||
|
||||
pc.getReaderContext().registerWithGeneratedName(injector.getBeanDefinition());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
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.util.FilterChainProxy;
|
||||
import org.springframework.security.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;
|
||||
}
|
||||
}
|
||||
+127
-142
@@ -50,16 +50,16 @@ import org.w3c.dom.Element;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class);
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
static final String ATT_REALM = "realm";
|
||||
static final String DEF_REALM = "Spring Security Application";
|
||||
|
||||
static final String ATT_PATH_PATTERN = "pattern";
|
||||
|
||||
|
||||
static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
|
||||
static final String OPT_SESSION_FIXATION_NO_PROTECTION = "none";
|
||||
static final String OPT_SESSION_FIXATION_CLEAN_SESSION = "newSession";
|
||||
static final String OPT_SESSION_FIXATION_CLEAN_SESSION = "newSession";
|
||||
static final String OPT_SESSION_FIXATION_MIGRATE_SESSION = "migrateSession";
|
||||
|
||||
static final String ATT_PATH_TYPE = "path-type";
|
||||
@@ -91,9 +91,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
|
||||
static final String DEF_SERVLET_API_PROVISION = "true";
|
||||
|
||||
static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
|
||||
static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
|
||||
static final String ATT_ONCE_PER_REQUEST = "once-per-request";
|
||||
static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
@@ -106,20 +106,20 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
final boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
|
||||
final List interceptUrlElts = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
final Map filterChainMap = new LinkedHashMap();
|
||||
final LinkedHashMap channelRequestMap = new LinkedHashMap();
|
||||
|
||||
registerFilterChainProxy(parserContext, filterChainMap, matcher, source);
|
||||
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
boolean allowSessionCreation = registerHttpSessionIntegrationFilter(element, parserContext);
|
||||
|
||||
|
||||
registerServletApiFilter(element, parserContext);
|
||||
|
||||
|
||||
// Set up the access manager reference for http
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
@@ -127,7 +127,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
|
||||
accessManagerId = BeanIds.ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
|
||||
// Register the portMapper. A default will always be created, even if no element exists.
|
||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
|
||||
@@ -139,19 +139,19 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (channelRequestMap.size() > 0) {
|
||||
// At least one channel requirement has been specified
|
||||
registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
|
||||
}
|
||||
|
||||
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
|
||||
}
|
||||
|
||||
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext));
|
||||
|
||||
boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
|
||||
|
||||
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
|
||||
|
||||
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
|
||||
sessionControlEnabled);
|
||||
|
||||
boolean autoConfig = false;
|
||||
if ("true".equals(element.getAttribute(ATT_AUTO_CONFIG))) {
|
||||
autoConfig = true;
|
||||
autoConfig = true;
|
||||
}
|
||||
|
||||
Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
|
||||
@@ -159,8 +159,21 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
new AnonymousBeanDefinitionParser().parse(anonymousElt, parserContext);
|
||||
}
|
||||
|
||||
parseRememberMeAndLogout(element, autoConfig, parserContext);
|
||||
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(element, Elements.REMEMBER_ME);
|
||||
if (rememberMeElt != null || autoConfig) {
|
||||
new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext);
|
||||
// Post processor to inject RememberMeServices into filters which need it
|
||||
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
|
||||
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
|
||||
}
|
||||
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(element, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
new LogoutBeanDefinitionParser().parse(logoutElt, parserContext);
|
||||
}
|
||||
|
||||
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig, allowSessionCreation);
|
||||
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509);
|
||||
@@ -175,49 +188,27 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2);
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void parseRememberMeAndLogout(Element elt, boolean autoConfig, ParserContext pc) {
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME);
|
||||
String rememberMeServices = null;
|
||||
|
||||
if (rememberMeElt != null || autoConfig) {
|
||||
RememberMeBeanDefinitionParser rmbdp = new RememberMeBeanDefinitionParser();
|
||||
rmbdp.parse(rememberMeElt, pc);
|
||||
rememberMeServices = rmbdp.getServicesName();
|
||||
// Post processor to inject RememberMeServices into filters which need it
|
||||
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
|
||||
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
|
||||
}
|
||||
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
new LogoutBeanDefinitionParser(rememberMeServices).parse(logoutElt, pc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||
}
|
||||
|
||||
|
||||
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
|
||||
filterChainProxy.setSource(source);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
}
|
||||
|
||||
private boolean registerHttpSessionIntegrationFilter(Element element, ParserContext pc) {
|
||||
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
|
||||
boolean sessionCreationAllowed = true;
|
||||
|
||||
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
@@ -234,11 +225,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER));
|
||||
|
||||
|
||||
return sessionCreationAllowed;
|
||||
}
|
||||
|
||||
// Adds the servlet-api integration filter if required
|
||||
// Adds the servlet-api integration filter if required
|
||||
private void registerServletApiFilter(Element element, ParserContext pc) {
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
@@ -251,57 +242,57 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean registerConcurrentSessionControlBeansIfRequired(Element element, ParserContext parserContext) {
|
||||
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
|
||||
if (sessionControlElt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
|
||||
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
|
||||
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
|
||||
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
|
||||
sessionIntegrationFilter.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void registerExceptionTranslationFilter(Element element, ParserContext pc, boolean allowSessionCreation) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", new Boolean(allowSessionCreation));
|
||||
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
BeanDefinition accessDeniedHandler = new RootBeanDefinition(AccessDeniedHandlerImpl.class);
|
||||
accessDeniedHandler.getPropertyValues().addPropertyValue("errorPage", accessDeniedPage);
|
||||
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
accessDeniedHandler.setErrorPage(accessDeniedPage);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
|
||||
}
|
||||
|
||||
|
||||
private void registerFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher,
|
||||
String accessManagerId, LinkedHashMap filterInvocationDefinitionMap) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
||||
builder.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||
builder.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
|
||||
|
||||
|
||||
if ("false".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) {
|
||||
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
|
||||
}
|
||||
|
||||
DefaultFilterInvocationDefinitionSource fids =
|
||||
|
||||
DefaultFilterInvocationDefinitionSource fids =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap);
|
||||
fids.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
|
||||
builder.addPropertyValue("objectDefinitionSource", fids);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
|
||||
}
|
||||
|
||||
|
||||
private void registerChannelProcessingBeans(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
|
||||
@@ -309,7 +300,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource =
|
||||
new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap);
|
||||
channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
@@ -330,161 +321,161 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void registerSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
|
||||
if(!StringUtils.hasText(sessionFixationAttribute)) {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
}
|
||||
|
||||
|
||||
if (!sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION)) {
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionFilter.class);
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
|
||||
if (sessionControlEnabled) {
|
||||
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
sessionFixationFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void parseBasicFormLoginAndOpenID(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) {
|
||||
RootBeanDefinition formLoginFilter = null;
|
||||
RootBeanDefinition formLoginEntryPoint = null;
|
||||
String formLoginPage = null;
|
||||
String formLoginPage = null;
|
||||
RootBeanDefinition openIDFilter = null;
|
||||
RootBeanDefinition openIDEntryPoint = null;
|
||||
String openIDLoginPage = null;
|
||||
|
||||
|
||||
String realm = element.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
|
||||
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
|
||||
}
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
|
||||
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
|
||||
|
||||
if (formLoginElt != null || autoConfig) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
|
||||
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(formLoginElt, pc);
|
||||
formLoginFilter = parser.getFilterBean();
|
||||
formLoginEntryPoint = parser.getEntryPointBean();
|
||||
formLoginPage = parser.getLoginPage();
|
||||
}
|
||||
|
||||
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN);
|
||||
|
||||
if (openIDLoginElt != null) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
|
||||
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(openIDLoginElt, pc);
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
openIDLoginPage = parser.getLoginPage();
|
||||
|
||||
BeanDefinitionBuilder openIDProviderBuilder =
|
||||
|
||||
BeanDefinitionBuilder openIDProviderBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.providers.openid.OpenIDAuthenticationProvider");
|
||||
|
||||
|
||||
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
|
||||
if (StringUtils.hasText(userService)) {
|
||||
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
|
||||
}
|
||||
|
||||
|
||||
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
|
||||
ConfigUtils.addAuthenticationProvider(pc, BeanIds.OPEN_ID_PROVIDER);
|
||||
ConfigUtils.getRegisteredProviders(pc).add(new RuntimeBeanReference(BeanIds.OPEN_ID_PROVIDER));
|
||||
}
|
||||
|
||||
|
||||
boolean needLoginPage = false;
|
||||
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
needLoginPage = true;
|
||||
formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
}
|
||||
needLoginPage = true;
|
||||
formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
needLoginPage = true;
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
needLoginPage = true;
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
}
|
||||
|
||||
// If no login page has been defined, add in the default page generator.
|
||||
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
|
||||
logger.info("No login page configured. The default internal one will be used. Use the '"
|
||||
+ FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE + "' attribute to set the URL of the login page.");
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
}
|
||||
|
||||
|
||||
if (openIDFilter != null) {
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
|
||||
loginPageFilter.getBeanDefinition());
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
|
||||
loginPageFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
|
||||
}
|
||||
|
||||
|
||||
// We need to establish the main entry point.
|
||||
// First check if a custom entry point bean is set
|
||||
String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
|
||||
|
||||
|
||||
if (StringUtils.hasText(customEntryPoint)) {
|
||||
pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Basic takes precedence if explicit element is used and no others are configured
|
||||
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
|
||||
// has been set
|
||||
if (formLoginFilter != null && openIDLoginPage == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise use OpenID if enabled
|
||||
if (openIDFilter != null && formLoginFilter == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If X.509 has been enabled, use the preauth entry point.
|
||||
if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
|
||||
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
|
||||
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
|
||||
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
|
||||
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
|
||||
pc.extractSource(element));
|
||||
}
|
||||
|
||||
|
||||
static UrlMatcher createUrlMatcher(Element element) {
|
||||
String patternType = element.getAttribute(ATT_PATH_TYPE);
|
||||
if (!StringUtils.hasText(patternType)) {
|
||||
@@ -518,8 +509,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
// Default for regex is no change
|
||||
}
|
||||
|
||||
return matcher;
|
||||
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -563,7 +554,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
editor.setAsText(channelConfigAttribute);
|
||||
channelRequestMap.put(new RequestKey(path), (ConfigAttributeDefinition) editor.getValue());
|
||||
}
|
||||
|
||||
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
|
||||
if (StringUtils.hasText(filters)) {
|
||||
@@ -576,10 +567,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LinkedHashMap parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap();
|
||||
|
||||
|
||||
Iterator urlEltsIterator = urlElts.iterator();
|
||||
ConfigAttributeEditor editor = new ConfigAttributeEditor();
|
||||
|
||||
@@ -606,17 +597,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
// Convert the comma-separated list of access attributes to a ConfigAttributeDefinition
|
||||
if (StringUtils.hasText(access)) {
|
||||
editor.setAsText(access);
|
||||
Object key = new RequestKey(path, method);
|
||||
|
||||
if (filterInvocationDefinitionMap.containsKey(key)) {
|
||||
logger.warn("Duplicate URL defined: " + key + ". The original attribute values will be overwritten");
|
||||
}
|
||||
|
||||
filterInvocationDefinitionMap.put(key, editor.getValue());
|
||||
filterInvocationDefinitionMap.put(new RequestKey(path, method), editor.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return filterInvocationDefinitionMap;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
|
||||
if (StringUtils.hasText(groupAuthoritiesQuery)) {
|
||||
builder.addPropertyValue("enableGroups", Boolean.TRUE);
|
||||
builder.addPropertyValue("groupAuthoritiesByUsernameQuery", groupAuthoritiesQuery);
|
||||
builder.addPropertyValue("authoritiesByUsernameQuery", groupAuthoritiesQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -100,9 +100,8 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ldapProvider.addConstructorArg(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
ldapProvider.addPropertyValue("userDetailsContextMapper",
|
||||
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.LDAP_AUTHENTICATION_PROVIDER, ldapProvider.getBeanDefinition());
|
||||
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.LDAP_AUTHENTICATION_PROVIDER);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider.getBeanDefinition());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+30
-30
@@ -14,22 +14,22 @@ import org.w3c.dom.Element;
|
||||
* @since 2.0
|
||||
*/
|
||||
public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
public static final String ATT_SERVER = "server-ref";
|
||||
public static final String ATT_SERVER = "server-ref";
|
||||
public static final String ATT_USER_SEARCH_FILTER = "user-search-filter";
|
||||
public static final String ATT_USER_SEARCH_BASE = "user-search-base";
|
||||
public static final String DEF_USER_SEARCH_BASE = "";
|
||||
|
||||
public static final String ATT_GROUP_SEARCH_FILTER = "group-search-filter";
|
||||
public static final String ATT_GROUP_SEARCH_BASE = "group-search-base";
|
||||
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
|
||||
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
|
||||
public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})";
|
||||
public static final String DEF_GROUP_SEARCH_BASE = "";
|
||||
|
||||
public static final String DEF_GROUP_SEARCH_BASE = "ou=groups";
|
||||
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
static final String ATT_USER_CLASS = "user-details-class";
|
||||
static final String OPT_PERSON = "person";
|
||||
static final String OPT_INETORGPERSON = "inetOrgPerson";
|
||||
|
||||
|
||||
public static final String LDAP_SEARCH_CLASS = "org.springframework.security.ldap.search.FilterBasedLdapUserSearch";
|
||||
public static final String PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.PersonContextMapper";
|
||||
public static final String INET_ORG_PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper";
|
||||
@@ -45,42 +45,42 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
if (!StringUtils.hasText(elt.getAttribute(ATT_USER_SEARCH_FILTER))) {
|
||||
parserContext.getReaderContext().error("User search filter must be supplied", elt);
|
||||
}
|
||||
|
||||
|
||||
builder.addConstructorArg(parseSearchBean(elt, parserContext));
|
||||
builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext));
|
||||
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
|
||||
}
|
||||
|
||||
|
||||
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
|
||||
String userSearchFilter = elt.getAttribute(ATT_USER_SEARCH_FILTER);
|
||||
String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE);
|
||||
Object source = parserContext.extractSource(elt);
|
||||
|
||||
|
||||
if (StringUtils.hasText(userSearchBase)) {
|
||||
if(!StringUtils.hasText(userSearchFilter)) {
|
||||
parserContext.getReaderContext().error(ATT_USER_SEARCH_BASE + " cannot be used without a " + ATT_USER_SEARCH_FILTER, source);
|
||||
}
|
||||
} else {
|
||||
userSearchBase = DEF_USER_SEARCH_BASE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(userSearchFilter)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
BeanDefinitionBuilder searchBuilder = BeanDefinitionBuilder.rootBeanDefinition(LDAP_SEARCH_CLASS);
|
||||
searchBuilder.setSource(source);
|
||||
searchBuilder.addConstructorArg(userSearchBase);
|
||||
searchBuilder.addConstructorArg(userSearchFilter);
|
||||
searchBuilder.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
|
||||
|
||||
return (RootBeanDefinition) searchBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
||||
static RuntimeBeanReference parseServerReference(Element elt, ParserContext parserContext) {
|
||||
String server = elt.getAttribute(ATT_SERVER);
|
||||
boolean requiresDefaultName = false;
|
||||
|
||||
|
||||
if (!StringUtils.hasText(server)) {
|
||||
server = BeanIds.CONTEXT_SOURCE;
|
||||
requiresDefaultName = true;
|
||||
@@ -89,27 +89,27 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
RuntimeBeanReference contextSource = new RuntimeBeanReference(server);
|
||||
contextSource.setSource(parserContext.extractSource(elt));
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry(), requiresDefaultName);
|
||||
|
||||
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
|
||||
static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) {
|
||||
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
|
||||
|
||||
if (OPT_PERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
}
|
||||
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
|
||||
|
||||
if (OPT_PERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
}
|
||||
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
}
|
||||
|
||||
|
||||
static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
|
||||
String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER);
|
||||
String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE);
|
||||
String groupRoleAttribute = elt.getAttribute(ATT_GROUP_ROLE_ATTRIBUTE);
|
||||
String rolePrefix = elt.getAttribute(ATT_ROLE_PREFIX);
|
||||
|
||||
|
||||
if (!StringUtils.hasText(groupSearchFilter)) {
|
||||
groupSearchFilter = DEF_GROUP_SEARCH_FILTER;
|
||||
}
|
||||
@@ -117,25 +117,25 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
if (!StringUtils.hasText(groupSearchBase)) {
|
||||
groupSearchBase = DEF_GROUP_SEARCH_BASE;
|
||||
}
|
||||
|
||||
|
||||
BeanDefinitionBuilder populator = BeanDefinitionBuilder.rootBeanDefinition(LDAP_AUTHORITIES_POPULATOR_CLASS);
|
||||
populator.setSource(parserContext.extractSource(elt));
|
||||
populator.addConstructorArg(parseServerReference(elt, parserContext));
|
||||
populator.addConstructorArg(groupSearchBase);
|
||||
populator.addPropertyValue("groupSearchFilter", groupSearchFilter);
|
||||
populator.addPropertyValue("searchSubtree", Boolean.TRUE);
|
||||
|
||||
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
if ("none".equals(rolePrefix)) {
|
||||
rolePrefix = "";
|
||||
}
|
||||
populator.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.hasLength(groupRoleAttribute)) {
|
||||
populator.addPropertyValue("groupRoleAttribute", groupRoleAttribute);
|
||||
}
|
||||
|
||||
|
||||
return (RootBeanDefinition) populator.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-8
@@ -25,12 +25,6 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
static final String ATT_LOGOUT_URL = "logout-url";
|
||||
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
|
||||
|
||||
String rememberMeServices;
|
||||
|
||||
public LogoutBeanDefinitionParser(String rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String logoutUrl = null;
|
||||
@@ -72,8 +66,8 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
handlers.add(sclh);
|
||||
|
||||
if (rememberMeServices != null) {
|
||||
handlers.add(new RuntimeBeanReference(rememberMeServices));
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
|
||||
handlers.add(new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
|
||||
}
|
||||
|
||||
builder.addConstructorArg(handlers);
|
||||
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extended version of {@link ProviderManager the default authentication manager} which lazily initializes
|
||||
* the list of {@link AuthenticationProvider}s. This prevents some of the issues that have occurred with
|
||||
* namespace configuration where early instantiation of a security interceptor has caused the AuthenticationManager
|
||||
* and thus dependent beans (typically UserDetailsService implementations or DAOs) to be initialized too early.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class NamespaceAuthenticationManager extends ProviderManager implements BeanFactoryAware {
|
||||
BeanFactory beanFactory;
|
||||
List providerBeanNames;
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(providerBeanNames, "provideBeanNames has not been set");
|
||||
Assert.notEmpty(providerBeanNames, "No authentication providers were found in the application context");
|
||||
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to lazily-initialize the list of providers on first use.
|
||||
*/
|
||||
public List getProviders() {
|
||||
// We use the names array to determine whether the list has been set yet.
|
||||
if (providerBeanNames != null) {
|
||||
List providers = new ArrayList();
|
||||
Iterator beanNames = providerBeanNames.iterator();
|
||||
|
||||
while (beanNames.hasNext()) {
|
||||
providers.add(beanFactory.getBean((String) beanNames.next()));
|
||||
}
|
||||
providerBeanNames = null;
|
||||
|
||||
setProviders(providers);
|
||||
}
|
||||
|
||||
return super.getProviders();
|
||||
}
|
||||
|
||||
public void setProviderBeanNames(List provideBeanNames) {
|
||||
this.providerBeanNames = provideBeanNames;
|
||||
}
|
||||
}
|
||||
+18
-22
@@ -22,7 +22,7 @@ import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
|
||||
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
|
||||
* This allows user to add their own custom filters to the security chain. If the user's filter
|
||||
* already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
|
||||
*
|
||||
@@ -33,7 +33,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
|
||||
public static final String ATT_AFTER = "after";
|
||||
public static final String ATT_BEFORE = "before";
|
||||
public static final String ATT_POSITION = "position";
|
||||
public static final String ATT_POSITION = "position";
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
Element elt = (Element)node;
|
||||
@@ -48,7 +48,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
}
|
||||
|
||||
ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
|
||||
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
@@ -59,26 +59,22 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
String after = elt.getAttribute(ATT_AFTER);
|
||||
String before = elt.getAttribute(ATT_BEFORE);
|
||||
String position = elt.getAttribute(ATT_POSITION);
|
||||
|
||||
|
||||
if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) {
|
||||
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
|
||||
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
|
||||
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
|
||||
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.hasText(position)) {
|
||||
return Integer.toString(FilterChainOrder.getOrder(position));
|
||||
return Integer.toString(FilterChainOrder.getOrder(position));
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.hasText(after)) {
|
||||
int order = FilterChainOrder.getOrder(after);
|
||||
|
||||
return Integer.toString(order == Integer.MAX_VALUE ? order : order + 1);
|
||||
return Integer.toString(FilterChainOrder.getOrder(after) + 1);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(before)) {
|
||||
int order = FilterChainOrder.getOrder(before);
|
||||
|
||||
return Integer.toString(order == Integer.MIN_VALUE ? order : order - 1);
|
||||
return Integer.toString(FilterChainOrder.getOrder(before) - 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -125,12 +121,12 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
|
||||
return beanName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
|
||||
}
|
||||
|
||||
Filter getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
public String toString() {
|
||||
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
|
||||
}
|
||||
|
||||
Filter getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-12
@@ -32,7 +32,6 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_TOKEN_VALIDITY = "token-validity-seconds";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
private String servicesName;
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String tokenRepository = null;
|
||||
@@ -103,10 +102,8 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
services.setSource(source);
|
||||
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
servicesName = BeanIds.REMEMBER_ME_SERVICES;
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
} else {
|
||||
servicesName = rememberMeServicesRef;
|
||||
parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
|
||||
}
|
||||
|
||||
@@ -117,17 +114,13 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
String getServicesName() {
|
||||
return servicesName;
|
||||
}
|
||||
|
||||
private void registerProvider(ParserContext pc, Object source, String key) {
|
||||
//BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
private void registerProvider(ParserContext pc, Object source, String key) {
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(pc, BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER);
|
||||
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
providers.add(provider);
|
||||
}
|
||||
|
||||
private void registerFilter(ParserContext pc, Object source) {
|
||||
|
||||
+1
-2
@@ -51,8 +51,7 @@ public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostPro
|
||||
Map beans = beanFactory.getBeansOfType(RememberMeServices.class);
|
||||
|
||||
Assert.isTrue(beans.size() > 0, "No RememberMeServices configured");
|
||||
Assert.isTrue(beans.size() == 1, "Use of '<remember-me />' requires a single instance of RememberMeServices " +
|
||||
"in the application context, but more than one was found.");
|
||||
Assert.isTrue(beans.size() == 1, "More than one RememberMeServices bean found.");
|
||||
|
||||
return (RememberMeServices) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionParser(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationDefinitionSourceBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
|
||||
|
||||
// Decorators
|
||||
registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
|
||||
|
||||
+72
-70
@@ -2,6 +2,8 @@ package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
@@ -19,91 +21,91 @@ import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Registered by {@link HttpSecurityBeanDefinitionParser} to inject a UserDetailsService into
|
||||
* the X509Provider, RememberMeServices and OpenIDAuthenticationProvider instances created by
|
||||
* the namespace.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
|
||||
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
|
||||
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoOpenIDProvider(bean);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
|
||||
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
|
||||
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoOpenIDProvider(bean);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoRememberMeServices(AbstractRememberMeServices services) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
services.setUserDetailsService(getUserDetailsService());
|
||||
services.setUserDetailsService(getUserDetailsService());
|
||||
} else {
|
||||
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
services.setUserDetailsService(cachingUserService);
|
||||
}
|
||||
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
services.setUserDetailsService(cachingUserService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void injectUserDetailsServiceIntoX509Provider(PreAuthenticatedAuthenticationProvider provider) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService");
|
||||
UserDetailsByNameServiceWrapper wrapper = new UserDetailsByNameServiceWrapper();
|
||||
|
||||
|
||||
if (pv == null) {
|
||||
wrapper.setUserDetailsService(getUserDetailsService());
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
wrapper.setUserDetailsService(getUserDetailsService());
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
} else {
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
UserDetailsService cachingUserService = getCachingUserService(userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
wrapper.setUserDetailsService(cachingUserService);
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
}
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
UserDetailsService cachingUserService = getCachingUserService(userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
wrapper.setUserDetailsService(cachingUserService);
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void injectUserDetailsServiceIntoOpenIDProvider(Object bean) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.OPEN_ID_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
|
||||
beanWrapper.setPropertyValue("userDetailsService", getUserDetailsService());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a user details service for use in RememberMeServices etc. Will return a caching version
|
||||
* if available so should not be used for beans which need to separate the two.
|
||||
* if available so should not be used for beans which need to separate the two.
|
||||
*/
|
||||
UserDetailsService getUserDetailsService() {
|
||||
Map beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
beans = beanFactory.getBeansOfType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
Map beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
beans = beanFactory.getBeansOfType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new SecurityConfigurationException("No UserDetailsService registered.");
|
||||
|
||||
@@ -114,24 +116,24 @@ public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostPro
|
||||
|
||||
return (UserDetailsService) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
|
||||
private UserDetailsService getCachingUserService(Object userServiceRef) {
|
||||
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
|
||||
"userDetailsService property value must be a RuntimeBeanReference");
|
||||
|
||||
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
|
||||
// Overwrite with the caching version if available
|
||||
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (beanFactory.containsBeanDefinition(cachingId)) {
|
||||
return (UserDetailsService) beanFactory.getBean(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
|
||||
"userDetailsService property value must be a RuntimeBeanReference");
|
||||
|
||||
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
|
||||
// Overwrite with the caching version if available
|
||||
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (beanFactory.containsBeanDefinition(cachingId)) {
|
||||
return (UserDetailsService) beanFactory.getBean(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_AUTH_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.X509_AUTH_PROVIDER);
|
||||
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(BeanIds.X509_AUTH_PROVIDER));
|
||||
|
||||
String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
|
||||
+35
-46
@@ -15,30 +15,33 @@
|
||||
|
||||
package org.springframework.security.context.rmi;
|
||||
|
||||
import org.springframework.security.context.SecurityContext;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
|
||||
/**
|
||||
* The actual {@code RemoteInvocation} that is passed from the client to the server.
|
||||
* <p>
|
||||
* The principal and credentials information will be extracted from the current
|
||||
* security context and passed to the server as part of the invocation object.
|
||||
* <p>
|
||||
* To avoid potential serialization-based attacks, this implementation interprets the values as {@code String}s
|
||||
* and creates a {@code UsernamePasswordAuthenticationToken} on the server side to hold them. If a different
|
||||
* token type is required you can override the {@code createAuthenticationRequest} method.
|
||||
* The actual <code>RemoteInvocation</code> that is passed from the client to the server, which contains the
|
||||
* contents of {@link SecurityContextHolder}, being a {@link SecurityContext} object.<p>When constructed on the
|
||||
* client via {@link org.springframework.security.context.rmi.ContextPropagatingRemoteInvocationFactory}, the contents of the
|
||||
* <code>SecurityContext</code> are stored inside the object. The object is then passed to the server that is
|
||||
* processing the remote invocation. Upon the server invoking the remote invocation, it will retrieve the passed
|
||||
* contents of the <code>SecurityContextHolder</code> and set them to the server-side
|
||||
* <code>SecurityContextHolder</code> whilst the target object is invoked. When the target invocation has been
|
||||
* completed, the server-side <code>SecurityContextHolder</code> will be reset to a new instance of
|
||||
* <code>SecurityContextImpl</code>.</p>
|
||||
*
|
||||
* @author James Monaghan
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
@@ -47,40 +50,33 @@ public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final String principal;
|
||||
private final String credentials;
|
||||
private SecurityContext securityContext;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs the object, storing the principal and credentials extracted from the client-side
|
||||
* security context.
|
||||
/**
|
||||
* Constructs the object, storing the value of the client-side
|
||||
* <code>SecurityContextHolder</code> inside the object.
|
||||
*
|
||||
* @param methodInvocation the method to invoke
|
||||
*/
|
||||
public ContextPropagatingRemoteInvocation(MethodInvocation methodInvocation) {
|
||||
super(methodInvocation);
|
||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (currentUser != null) {
|
||||
principal = currentUser.getPrincipal().toString();
|
||||
credentials = currentUser.getCredentials().toString();
|
||||
} else {
|
||||
principal = credentials = null;
|
||||
}
|
||||
securityContext = SecurityContextHolder.getContext();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("RemoteInvocation now has principal: " + principal);
|
||||
logger.debug("RemoteInvocation now has SecurityContext: " + securityContext);
|
||||
}
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Invoked on the server-side.
|
||||
* <p>
|
||||
* The transmitted principal and credentials will be used to create an unauthenticated {@code Authentication}
|
||||
* instance for processing by the {@code AuthenticationManager}.
|
||||
* Invoked on the server-side as described in the class JavaDocs.<p>Invocations will always have their
|
||||
* {@link org.springframework.security.Authentication#setAuthenticated(boolean)} set to <code>false</code>, which is
|
||||
* guaranteed to always be accepted by <code>Authentication</code> implementations. This ensures that even
|
||||
* remotely authenticated <code>Authentication</code>s will be untrusted by the server-side, which is an
|
||||
* appropriate security measure.</p>
|
||||
*
|
||||
* @param targetObject the target object to apply the invocation to
|
||||
*
|
||||
@@ -91,16 +87,16 @@ public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
|
||||
* @throws InvocationTargetException if the method invocation resulted in an exception
|
||||
*/
|
||||
public Object invoke(Object targetObject)
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
if (principal != null) {
|
||||
Authentication request = createAuthenticationRequest(principal, credentials);
|
||||
request.setAuthenticated(false);
|
||||
SecurityContextHolder.getContext().setAuthentication(request);
|
||||
if ((SecurityContextHolder.getContext() != null)
|
||||
&& (SecurityContextHolder.getContext().getAuthentication() != null)) {
|
||||
SecurityContextHolder.getContext().getAuthentication().setAuthenticated(false);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Set SecurityContextHolder to contain: " + request);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Set SecurityContextHolder to contain: " + securityContext);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -109,15 +105,8 @@ public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
|
||||
SecurityContextHolder.clearContext();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cleared SecurityContextHolder.");
|
||||
logger.debug("Set SecurityContext to new instance of SecurityContextImpl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the server-side authentication request object.
|
||||
*/
|
||||
protected Authentication createAuthenticationRequest(String principal, String credentials) {
|
||||
return new UsernamePasswordAuthenticationToken(principal, credentials);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
package org.springframework.security.firewall;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Default implementation which wraps requests in order to provide consistent values of the {@code servletPath} and
|
||||
* {@code pathInfo}, which do not contain path parameters (as defined in
|
||||
* <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>). Different servlet containers
|
||||
* interpret the servlet spec differently as to how path parameters are treated and it is possible they might be added
|
||||
* in order to bypass particular security constraints. When using this implementation, they will be removed for all
|
||||
* requests as the request passes through the security filter chain. Note that this means that any segments in the
|
||||
* decoded path which contain a semi-colon, will have the part following the semi-colon removed for
|
||||
* request matching. Your application should not contain any valid paths which contain semi-colons.
|
||||
* <p>
|
||||
* If any un-normalized paths are found (containing directory-traversal character sequences), the request will be
|
||||
* rejected immediately. Most containers normalize the paths before performing the servlet-mapping, but again this is
|
||||
* not guaranteed by the servlet spec.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class DefaultHttpFirewall implements HttpFirewall {
|
||||
|
||||
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
|
||||
FirewalledRequest fwr = new RequestWrapper(request);
|
||||
|
||||
if (!isNormalized(fwr.getServletPath()) || !isNormalized(fwr.getPathInfo())) {
|
||||
throw new RequestRejectedException("Un-normalized paths are not supported: " + fwr.getServletPath() +
|
||||
(fwr.getPathInfo() != null ? fwr.getPathInfo() : ""));
|
||||
}
|
||||
|
||||
return fwr;
|
||||
}
|
||||
|
||||
public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
|
||||
return new FirewalledResponse(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a path is normalized (doesn't contain path traversal sequences like "./", "/../" or "/.")
|
||||
*
|
||||
* @param path the path to test
|
||||
* @return true if the path doesn't contain any path-traversal character sequences.
|
||||
*/
|
||||
private boolean isNormalized(String path) {
|
||||
if (path == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int j = path.length(); j > 0;) {
|
||||
int i = path.lastIndexOf('/', j - 1);
|
||||
int gap = j - i;
|
||||
|
||||
if (gap == 2 && path.charAt(i+1) == '.') {
|
||||
// ".", "/./" or "/."
|
||||
return false;
|
||||
} else if (gap == 3 && path.charAt(i+1) == '.'&& path.charAt(i+2) == '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
j = i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.springframework.security.firewall;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
/**
|
||||
* Request wrapper which is returned by the {@code HttpFirewall} interface.
|
||||
* <p>
|
||||
* The only difference is the {@code reset} method which allows some
|
||||
* or all of the state to be reset by the {@code FilterChainProxy} when the
|
||||
* request leaves the security filter chain.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public abstract class FirewalledRequest extends HttpServletRequestWrapper {
|
||||
/**
|
||||
* Constructs a request object wrapping the given request.
|
||||
*
|
||||
* @throws IllegalArgumentException if the request is null
|
||||
*/
|
||||
public FirewalledRequest(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called once the request has passed through the
|
||||
* security filter chain, when it is about to proceed to the application
|
||||
* proper.
|
||||
* <p>
|
||||
* An implementation can thus choose to modify the state of the request
|
||||
* for the security infrastructure, while still maintaining the
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package org.springframework.security.firewall;
|
||||
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
class FirewalledResponse extends HttpServletResponseWrapper {
|
||||
Pattern CR_OR_LF = Pattern.compile("\\r|\\n");
|
||||
|
||||
public FirewalledResponse(HttpServletResponse response) {
|
||||
super(response);
|
||||
}
|
||||
|
||||
public void sendRedirect(String location) throws IOException {
|
||||
// TODO: implement pluggable validation, instead of simple blacklisting.
|
||||
// SEC-1790. Prevent redirects containing CRLF
|
||||
if (CR_OR_LF.matcher(location).find()) {
|
||||
throw new IllegalArgumentException("Invalid characters (CR/LF) in redirect location");
|
||||
}
|
||||
super.sendRedirect(location);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.springframework.security.firewall;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Interface which can be used to reject potentially dangerous requests and/or wrap them to
|
||||
* control their behaviour.
|
||||
* <p>
|
||||
* The implementation is injected into the {@code FilterChainProxy} and will be invoked before
|
||||
* sending any request through the filter chain. It can also provide a response wrapper if the response
|
||||
* behaviour should also be restricted.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public interface HttpFirewall {
|
||||
|
||||
/**
|
||||
* Provides the request object which will be passed through the filter chain.
|
||||
*
|
||||
* @throws RequestRejectedException if the request should be rejected immediately
|
||||
*/
|
||||
FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException;
|
||||
|
||||
/**
|
||||
* Provides the response which will be passed through the filter chain.
|
||||
*
|
||||
* @param response the original response
|
||||
* @return either the original response or a replacement/wrapper.
|
||||
*/
|
||||
HttpServletResponse getFirewalledResponse(HttpServletResponse response);
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
package org.springframework.security.firewall;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class RequestRejectedException extends RuntimeException {
|
||||
public RequestRejectedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package org.springframework.security.firewall;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Request wrapper which ensures values of {@code servletPath} and {@code pathInfo} are returned which are suitable for
|
||||
* pattern matching against. It strips out path parameters and extra consecutive '/' characters.
|
||||
*
|
||||
* <h3>Path Parameters</h3>
|
||||
* Parameters (as defined in <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>) are stripped from the path
|
||||
* segments of the {@code servletPath} and {@code pathInfo} values of the request.
|
||||
* <p>
|
||||
* The parameter sequence is demarcated by a semi-colon, so each segment is checked for the occurrence of a ";"
|
||||
* character and truncated at that point if it is present.
|
||||
* <p>
|
||||
* The behaviour differs between servlet containers in how they interpret the servlet spec, which
|
||||
* does not clearly state what the behaviour should be. For consistency, we make sure they are always removed, to
|
||||
* avoid the risk of URL matching rules being bypassed by the malicious addition of parameters to the path component.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
final class RequestWrapper extends FirewalledRequest {
|
||||
private final String strippedServletPath;
|
||||
private final String strippedPathInfo;
|
||||
private boolean stripPaths = true;
|
||||
|
||||
public RequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
strippedServletPath = strip(request.getServletPath());
|
||||
String pathInfo = strip(request.getPathInfo());
|
||||
if (pathInfo != null && pathInfo.length() == 0) {
|
||||
pathInfo = null;
|
||||
}
|
||||
strippedPathInfo = pathInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes path parameters from each path segment in the supplied path and truncates sequences of multiple '/'
|
||||
* characters to a single '/'.
|
||||
*
|
||||
* @param path either the {@code servletPath} and {@code pathInfo} from the original request
|
||||
*
|
||||
* @return the supplied value, with path parameters removed and sequences of multiple '/' characters truncated,
|
||||
* or null if the supplied path was null.
|
||||
*/
|
||||
private String strip(String path) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int scIndex = path.indexOf(';');
|
||||
|
||||
if (scIndex < 0) {
|
||||
int doubleSlashIndex = path.indexOf("//");
|
||||
if (doubleSlashIndex < 0) {
|
||||
// Most likely case, no parameters in any segment and no '//', so no stripping required
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
StringTokenizer st = new StringTokenizer(path, "/");
|
||||
StringBuilder stripped = new StringBuilder(path.length());
|
||||
|
||||
if (path.charAt(0) == '/') {
|
||||
stripped.append('/');
|
||||
}
|
||||
|
||||
while(st.hasMoreTokens()) {
|
||||
String segment = st.nextToken();
|
||||
scIndex = segment.indexOf(';');
|
||||
|
||||
if (scIndex >= 0) {
|
||||
segment = segment.substring(0, scIndex);
|
||||
}
|
||||
stripped.append(segment).append('/');
|
||||
}
|
||||
|
||||
// Remove the trailing slash if the original path didn't have one
|
||||
if (path.charAt(path.length() - 1) != '/') {
|
||||
stripped.deleteCharAt(stripped.length() - 1);
|
||||
}
|
||||
|
||||
return stripped.toString();
|
||||
}
|
||||
|
||||
public String getPathInfo() {
|
||||
return stripPaths ? strippedPathInfo : super.getPathInfo();
|
||||
}
|
||||
|
||||
public String getServletPath() {
|
||||
return stripPaths ? strippedServletPath : super.getServletPath();
|
||||
}
|
||||
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
return this.stripPaths ? new FirewalledRequestAwareRequestDispatcher(path) : super.getRequestDispatcher(path);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.stripPaths = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures {@link FirewalledRequest#reset()} is called prior to performing a forward. It then delegates work to the
|
||||
* {@link RequestDispatcher} from the original {@link HttpServletRequest}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
private class FirewalledRequestAwareRequestDispatcher implements RequestDispatcher {
|
||||
private final String path;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path the {@code path} that will be used to obtain the delegate {@link RequestDispatcher} from the
|
||||
* original {@link HttpServletRequest}.
|
||||
*/
|
||||
public FirewalledRequestAwareRequestDispatcher(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException {
|
||||
reset();
|
||||
getDelegateDispatcher().forward(request, response);
|
||||
}
|
||||
|
||||
public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException {
|
||||
getDelegateDispatcher().include(request, response);
|
||||
}
|
||||
|
||||
private RequestDispatcher getDelegateDispatcher() {
|
||||
return RequestWrapper.super.getRequestDispatcher(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-16
@@ -26,10 +26,8 @@ import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.RunAsManager;
|
||||
|
||||
import org.springframework.security.context.SecurityContext;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.context.SecurityContextImpl;
|
||||
import org.springframework.security.event.authorization.AuthenticationCredentialsNotFoundEvent;
|
||||
import org.springframework.security.event.authorization.AuthorizationFailureEvent;
|
||||
import org.springframework.security.event.authorization.AuthorizedEvent;
|
||||
@@ -112,7 +110,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||
protected static final Log logger = LogFactory.getLog(AbstractSecurityInterceptor.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
private AccessDecisionManager accessDecisionManager;
|
||||
@@ -142,22 +140,21 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||
|
||||
if (token.isContextHolderRefreshRequired()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reverting to original Authentication: " + token.getSecurityContext().getAuthentication());
|
||||
logger.debug("Reverting to original Authentication: " + token.getAuthentication().toString());
|
||||
}
|
||||
|
||||
SecurityContextHolder.setContext(token.getSecurityContext());
|
||||
SecurityContextHolder.getContext().setAuthentication(token.getAuthentication());
|
||||
}
|
||||
|
||||
if (afterInvocationManager != null) {
|
||||
// Attempt after invocation handling
|
||||
try {
|
||||
returnedObject = afterInvocationManager.decide(token.getSecurityContext().getAuthentication(),
|
||||
token.getSecureObject(),
|
||||
returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
|
||||
token.getAttr(), returnedObject);
|
||||
}
|
||||
catch (AccessDeniedException accessDeniedException) {
|
||||
AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
|
||||
.getAttr(), token.getSecurityContext().getAuthentication(), accessDeniedException);
|
||||
.getAttr(), token.getAuthentication(), accessDeniedException);
|
||||
publishEvent(event);
|
||||
|
||||
throw accessDeniedException;
|
||||
@@ -288,20 +285,16 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||
}
|
||||
|
||||
// no further work post-invocation
|
||||
return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attr, object);
|
||||
return new InterceptorStatusToken(authenticated, false, attr, object);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Switching to RunAs Authentication: " + runAs);
|
||||
}
|
||||
|
||||
SecurityContext originalContext = SecurityContextHolder.getContext();
|
||||
SecurityContext runAsContext = new SecurityContextImpl();
|
||||
runAsContext.setAuthentication(runAs);
|
||||
SecurityContextHolder.getContext().setAuthentication(runAs);
|
||||
|
||||
SecurityContextHolder.setContext(runAsContext);
|
||||
|
||||
// revert to original context post-invocation
|
||||
return new InterceptorStatusToken(originalContext, true, attr, object);
|
||||
// revert to token.Authenticated post-invocation
|
||||
return new InterceptorStatusToken(authenticated, true, attr, object);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -17,7 +17,6 @@ package org.springframework.security.intercept;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.context.SecurityContext;
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,16 +32,16 @@ import org.springframework.security.context.SecurityContext;
|
||||
public class InterceptorStatusToken {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private SecurityContext context;
|
||||
private Authentication authentication;
|
||||
private ConfigAttributeDefinition attr;
|
||||
private Object secureObject;
|
||||
private boolean contextHolderRefreshRequired;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public InterceptorStatusToken(SecurityContext context, boolean contextHolderRefreshRequired,
|
||||
public InterceptorStatusToken(Authentication authentication, boolean contextHolderRefreshRequired,
|
||||
ConfigAttributeDefinition attr, Object secureObject) {
|
||||
this.context = context;
|
||||
this.authentication = authentication;
|
||||
this.contextHolderRefreshRequired = contextHolderRefreshRequired;
|
||||
this.attr = attr;
|
||||
this.secureObject = secureObject;
|
||||
@@ -54,8 +53,8 @@ public class InterceptorStatusToken {
|
||||
return attr;
|
||||
}
|
||||
|
||||
public SecurityContext getSecurityContext() {
|
||||
return context;
|
||||
public Authentication getAuthentication() {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public Object getSecureObject() {
|
||||
|
||||
+100
-101
@@ -18,11 +18,11 @@ import org.springframework.util.ObjectUtils;
|
||||
* Abstract implementation of {@link MethodDefinitionSource} that supports both Spring AOP and AspectJ and
|
||||
* caches configuration attribute resolution from: 1. specific target method; 2. target class; 3. declaring method;
|
||||
* 4. declaring class/interface.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This class mimics the behaviour of Spring's AbstractFallbackTransactionAttributeSource class.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Note that this class cannot extract security metadata where that metadata is expressed by way of
|
||||
* a target method/class (ie #1 and #2 above) AND the target method/class is encapsulated in another
|
||||
@@ -31,7 +31,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* another proxy), move the metadata to declared methods or interfaces the proxy implements, or provide
|
||||
* your own replacement <tt>MethodDefinitionSource</tt>.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
@@ -39,16 +39,15 @@ import org.springframework.util.ObjectUtils;
|
||||
public abstract class AbstractFallbackMethodDefinitionSource implements MethodDefinitionSource {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractFallbackMethodDefinitionSource.class);
|
||||
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
|
||||
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
|
||||
private final Map attributeCache = new HashMap();
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
|
||||
Assert.notNull(object, "Object cannot be null");
|
||||
|
||||
if (object instanceof MethodInvocation) {
|
||||
MethodInvocation mi = (MethodInvocation) object;
|
||||
Object target = mi.getThis();
|
||||
return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
|
||||
MethodInvocation mi = (MethodInvocation) object;
|
||||
return getAttributes(mi.getMethod(), mi.getThis().getClass());
|
||||
}
|
||||
|
||||
if (object instanceof JoinPoint) {
|
||||
@@ -60,143 +59,143 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
|
||||
|
||||
Method method = ClassUtils.getMethodIfAvailable(declaringType, targetMethodName, types);
|
||||
Assert.notNull(method, "Could not obtain target method from JoinPoint: '"+ jp + "'");
|
||||
|
||||
|
||||
return getAttributes(method, targetClass);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Object must be a MethodInvocation or JoinPoint");
|
||||
}
|
||||
|
||||
|
||||
public final boolean supports(Class clazz) {
|
||||
return (MethodInvocation.class.isAssignableFrom(clazz) || JoinPoint.class.isAssignableFrom(clazz));
|
||||
}
|
||||
|
||||
|
||||
public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = new DefaultCacheKey(method, targetClass);
|
||||
synchronized (this.attributeCache) {
|
||||
Object cached = this.attributeCache.get(cacheKey);
|
||||
if (cached != null) {
|
||||
// Value will either be canonical value indicating there is no config attribute,
|
||||
// or an actual config attribute.
|
||||
if (cached == NULL_CONFIG_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return (ConfigAttributeDefinition) cached;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need to work it out.
|
||||
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
|
||||
// Put it in the cache.
|
||||
if (cfgAtt == null) {
|
||||
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
|
||||
}
|
||||
this.attributeCache.put(cacheKey, cfgAtt);
|
||||
}
|
||||
return cfgAtt;
|
||||
}
|
||||
}
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = new DefaultCacheKey(method, targetClass);
|
||||
synchronized (this.attributeCache) {
|
||||
Object cached = this.attributeCache.get(cacheKey);
|
||||
if (cached != null) {
|
||||
// Value will either be canonical value indicating there is no config attribute,
|
||||
// or an actual config attribute.
|
||||
if (cached == NULL_CONFIG_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return (ConfigAttributeDefinition) cached;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need to work it out.
|
||||
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
|
||||
// Put it in the cache.
|
||||
if (cfgAtt == null) {
|
||||
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
|
||||
}
|
||||
this.attributeCache.put(cacheKey, cfgAtt);
|
||||
}
|
||||
return cfgAtt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for this invocation (may be <code>null</code>)
|
||||
*
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for this invocation (may be <code>null</code>)
|
||||
* @return
|
||||
*/
|
||||
private ConfigAttributeDefinition computeAttributes(Method method, Class targetClass) {
|
||||
// The method may be on an interface, but we need attributes from the target class.
|
||||
// If the target class is null, the method will be unchanged.
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
// First try is the method in the target class.
|
||||
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// The method may be on an interface, but we need attributes from the target class.
|
||||
// If the target class is null, the method will be unchanged.
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
// First try is the method in the target class.
|
||||
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
|
||||
// Second try is the config attribute on the target class.
|
||||
attr = findAttributes(specificMethod.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// Second try is the config attribute on the target class.
|
||||
attr = findAttributes(specificMethod.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
|
||||
if (specificMethod != method || targetClass == null) {
|
||||
// Fallback is to look at the original method.
|
||||
attr = findAttributes(method, method.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// Last fallback is the class of the original method.
|
||||
return findAttributes(method.getDeclaringClass());
|
||||
}
|
||||
return null;
|
||||
if (specificMethod != method) {
|
||||
// Fallback is to look at the original method.
|
||||
attr = findAttributes(method, method.getDeclaringClass());
|
||||
if (attr != null) {
|
||||
return attr;
|
||||
}
|
||||
// Last fallback is the class of the original method.
|
||||
return findAttributes(method.getDeclaringClass());
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the security metadata applicable to the specified method invocation.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Note that the {@link Method#getDeclaringClass()} may not equal the <code>targetClass</code>.
|
||||
* Both parameters are provided to assist subclasses which may wish to provide advanced
|
||||
* capabilities related to method metadata being "registered" against a method even if the
|
||||
* target class does not declare the method (i.e. the subclass may only inherit the method).
|
||||
*
|
||||
*
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for the invocation (may be <code>null</code>)
|
||||
* @return the security metadata (or null if no metadata applies)
|
||||
*/
|
||||
protected abstract ConfigAttributeDefinition findAttributes(Method method, Class targetClass);
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the security metadata registered against the specified class.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Subclasses should only return metadata expressed at a class level. Subclasses should NOT
|
||||
* aggregate metadata for each method registered against a class, as the abstract superclass
|
||||
* will separate invoke {@link #findAttributes(Method, Class)} for individual methods as
|
||||
* appropriate.
|
||||
*
|
||||
* appropriate.
|
||||
*
|
||||
* @param clazz the target class for the invocation (never <code>null</code>)
|
||||
* @return the security metadata (or null if no metadata applies)
|
||||
*/
|
||||
protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
|
||||
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
private static class DefaultCacheKey {
|
||||
private final Method method;
|
||||
private final Class targetClass;
|
||||
|
||||
private final Method method;
|
||||
private final Class targetClass;
|
||||
public DefaultCacheKey(Method method, Class targetClass) {
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
public DefaultCacheKey(Method method, Class targetClass) {
|
||||
this.method = method;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof DefaultCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) &&
|
||||
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof DefaultCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) &&
|
||||
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
|
||||
}
|
||||
}
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+124
-106
@@ -34,13 +34,13 @@ import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Stores a {@link ConfigAttributeDefinition} for a method or class signature.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This class is the preferred implementation of {@link MethodDefinitionSource} for XML-based
|
||||
* definition of method security metadata. To assist in XML-based definition, wildcard support
|
||||
* is provided.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
@@ -51,9 +51,9 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
private static final Log logger = LogFactory.getLog(MapBasedMethodDefinitionSource.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/** Map from RegisteredMethod to ConfigAttributeDefinition */
|
||||
/** Map from RegisteredMethod to ConfigAttributeDefinition */
|
||||
protected Map methodMap = new HashMap();
|
||||
|
||||
/** Map from RegisteredMethod to name pattern used for registration */
|
||||
@@ -74,37 +74,48 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
addSecureMethod((String)entry.getKey(), (ConfigAttributeDefinition)entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation does not support class-level attributes.
|
||||
*/
|
||||
protected ConfigAttributeDefinition findAttributes(Class clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will walk the method inheritance tree to find the most specific declaration applicable.
|
||||
*/
|
||||
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
|
||||
return findAttributesSpecifiedAgainst(method, targetClass);
|
||||
}
|
||||
|
||||
private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
|
||||
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
|
||||
if (methodMap.containsKey(registeredMethod)) {
|
||||
return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
|
||||
}
|
||||
// Search superclass
|
||||
if (clazz.getSuperclass() != null) {
|
||||
return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation does not support class-level attributes.
|
||||
* Add configuration attributes for a secure method.
|
||||
*
|
||||
* @param method the method to be secured
|
||||
* @param attr required authorities associated with the method
|
||||
*/
|
||||
protected ConfigAttributeDefinition findAttributes(Class clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will walk the method inheritance tree to find the most specific declaration applicable.
|
||||
*/
|
||||
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
|
||||
if (targetClass == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return findAttributesSpecifiedAgainst(method, targetClass);
|
||||
}
|
||||
|
||||
private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
|
||||
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
|
||||
if (methodMap.containsKey(registeredMethod)) {
|
||||
return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
|
||||
}
|
||||
// Search superclass
|
||||
if (clazz.getSuperclass() != null) {
|
||||
return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
|
||||
}
|
||||
return null;
|
||||
private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
|
||||
Assert.notNull(method, "RegisteredMethod required");
|
||||
Assert.notNull(attr, "Configuration attribute required");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
|
||||
}
|
||||
this.methodMap.put(method, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,7 +126,7 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
* @param attr required authorities associated with the method
|
||||
*/
|
||||
public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
|
||||
int lastDotIndex = name.lastIndexOf(".");
|
||||
int lastDotIndex = name.lastIndexOf(".");
|
||||
|
||||
if (lastDotIndex == -1) {
|
||||
throw new IllegalArgumentException("'" + name + "' is not a valid method name: format is FQN.methodName");
|
||||
@@ -123,17 +134,17 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
|
||||
String methodName = name.substring(lastDotIndex + 1);
|
||||
Assert.hasText(methodName, "Method not found for '" + name + "'");
|
||||
|
||||
|
||||
String typeName = name.substring(0, lastDotIndex);
|
||||
Class type = ClassUtils.resolveClassName(typeName, this.beanClassLoader);
|
||||
|
||||
|
||||
addSecureMethod(type, methodName, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add configuration attributes for a secure method. Mapped method names can end or start with <code>*</code>
|
||||
* for matching multiple methods.
|
||||
*
|
||||
*
|
||||
* @param javaType target interface or class the security configuration attribute applies to
|
||||
* @param mappedName mapped method name, which the javaType has declared or inherited
|
||||
* @param attr required authorities associated with the method
|
||||
@@ -181,38 +192,6 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds configuration attributes for a specific method, for example where the method has been
|
||||
* matched using a pointcut expression. If a match already exists in the map for the method, then
|
||||
* the existing match will be retained, so that if this method is called for a more general pointcut
|
||||
* it will not override a more specific one which has already been added. This
|
||||
*/
|
||||
public void addSecureMethod(Class javaType, Method method, ConfigAttributeDefinition attr) {
|
||||
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
||||
|
||||
if (methodMap.containsKey(key)) {
|
||||
logger.debug("Method [" + method + "] is already registered with attributes [" + methodMap.get(key) + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
methodMap.put(key, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add configuration attributes for a secure method.
|
||||
*
|
||||
* @param method the method to be secured
|
||||
* @param attr required authorities associated with the method
|
||||
*/
|
||||
private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
|
||||
Assert.notNull(method, "RegisteredMethod required");
|
||||
Assert.notNull(attr, "Configuration attribute required");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
|
||||
}
|
||||
this.methodMap.put(method, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the configuration attributes explicitly defined against this bean.
|
||||
*
|
||||
@@ -236,54 +215,93 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
||||
|| (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
Assert.notNull(beanClassLoader, "Bean class loader required");
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
protected ConfigAttributeDefinition lookupAttributes(Method method) {
|
||||
List attributesToReturn = new ArrayList();
|
||||
|
||||
/**
|
||||
* @return map size (for unit tests and diagnostics)
|
||||
*/
|
||||
public int getMethodMapSize() {
|
||||
return methodMap.size();
|
||||
}
|
||||
// Add attributes explicitly defined for this method invocation
|
||||
merge(attributesToReturn, (ConfigAttributeDefinition) this.methodMap.get(method));
|
||||
|
||||
/**
|
||||
* Stores both the Java Method as well as the Class we obtained the Method from. This is necessary because Method only
|
||||
* provides us access to the declaring class. It doesn't provide a way for us to introspect which Class the Method
|
||||
* was registered against. If a given Class inherits and redeclares a method (i.e. calls super();) the registered Class
|
||||
* and declaring Class are the same. If a given class merely inherits but does not redeclare a method, the registered
|
||||
* Class will be the Class we're invoking against and the Method will provide details of the declared class.
|
||||
*/
|
||||
private class RegisteredMethod {
|
||||
private Method method;
|
||||
private Class registeredJavaType;
|
||||
// Add attributes explicitly defined for this method invocation's interfaces
|
||||
Class[] interfaces = method.getDeclaringClass().getInterfaces();
|
||||
|
||||
public RegisteredMethod(Method method, Class registeredJavaType) {
|
||||
Assert.notNull(method, "Method required");
|
||||
Assert.notNull(registeredJavaType, "Registered Java Type required");
|
||||
this.method = method;
|
||||
this.registeredJavaType = registeredJavaType;
|
||||
}
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
Class clazz = interfaces[i];
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
try {
|
||||
// Look for the method on the current interface
|
||||
Method interfaceMethod = clazz.getDeclaredMethod(method.getName(), (Class[]) method.getParameterTypes());
|
||||
ConfigAttributeDefinition interfaceAssigned =
|
||||
(ConfigAttributeDefinition) this.methodMap.get(interfaceMethod);
|
||||
merge(attributesToReturn, interfaceAssigned);
|
||||
} catch (Exception e) {
|
||||
// skip this interface
|
||||
}
|
||||
if (obj != null && obj instanceof RegisteredMethod) {
|
||||
RegisteredMethod rhs = (RegisteredMethod) obj;
|
||||
return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return method.hashCode() * registeredJavaType.hashCode();
|
||||
// Return null if empty, as per abstract superclass contract
|
||||
if (attributesToReturn.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
|
||||
}
|
||||
return new ConfigAttributeDefinition(attributesToReturn);
|
||||
}
|
||||
|
||||
private void merge(List attributes, ConfigAttributeDefinition toMerge) {
|
||||
if (toMerge == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
attributes.addAll(toMerge.getConfigAttributes());
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
Assert.notNull(beanClassLoader, "Bean class loader required");
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return map size (for unit tests and diagnostics)
|
||||
*/
|
||||
public int getMethodMapSize() {
|
||||
return methodMap.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores both the Java Method as well as the Class we obtained the Method from. This is necessary because Method only
|
||||
* provides us access to the declaring class. It doesn't provide a way for us to introspect which Class the Method
|
||||
* was registered against. If a given Class inherits and redeclares a method (i.e. calls super();) the registered Class
|
||||
* and declaring Class are the same. If a given class merely inherits but does not redeclare a method, the registered
|
||||
* Class will be the Class we're invoking against and the Method will provide details of the declared class.
|
||||
*/
|
||||
private class RegisteredMethod {
|
||||
private Method method;
|
||||
private Class registeredJavaType;
|
||||
|
||||
public RegisteredMethod(Method method, Class registeredJavaType) {
|
||||
Assert.notNull(method, "Method required");
|
||||
Assert.notNull(registeredJavaType, "Registered Java Type required");
|
||||
this.method = method;
|
||||
this.registeredJavaType = registeredJavaType;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof RegisteredMethod) {
|
||||
RegisteredMethod rhs = (RegisteredMethod) obj;
|
||||
return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return method.hashCode() * registeredJavaType.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+88
-108
@@ -17,30 +17,29 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parses AspectJ pointcut expressions, registering methods that match the pointcut with a
|
||||
* traditional {@link MapBasedMethodDefinitionSource}.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This class provides a convenient way of declaring a list of pointcuts, and then
|
||||
* having every method of every bean defined in the Spring application context compared with
|
||||
* those pointcuts. Where a match is found, the matching method will be registered with the
|
||||
* {@link MapBasedMethodDefinitionSource}.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* It is very important to understand that only the <b>first</b> pointcut that matches a given
|
||||
* method will be taken as authoritative for that method. This is why pointcuts should be provided
|
||||
* as a <tt>LinkedHashMap</tt>, because their order is very important.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Note also that only beans defined in the Spring application context will be examined by this
|
||||
* class.
|
||||
* class.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Because this class registers method security metadata with {@link MapBasedMethodDefinitionSource},
|
||||
* normal Spring Security capabilities such as {@link MethodDefinitionSourceAdvisor} can be used.
|
||||
@@ -58,19 +57,18 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
|
||||
|
||||
private Map pointcutMap = new LinkedHashMap(); /** Key: string-based pointcut, value: ConfigAttributeDefinition */
|
||||
private MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource;
|
||||
private PointcutParser parser;
|
||||
private final Set processedBeans = new HashSet();
|
||||
|
||||
public ProtectPointcutPostProcessor(MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource) {
|
||||
Assert.notNull(mapBasedMethodDefinitionSource, "MapBasedMethodDefinitionSource to populate is required");
|
||||
this.mapBasedMethodDefinitionSource = mapBasedMethodDefinitionSource;
|
||||
|
||||
// Setup AspectJ pointcut expression parser
|
||||
Set supportedPrimitives = new HashSet();
|
||||
supportedPrimitives.add(PointcutPrimitive.EXECUTION);
|
||||
supportedPrimitives.add(PointcutPrimitive.ARGS);
|
||||
supportedPrimitives.add(PointcutPrimitive.REFERENCE);
|
||||
private MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource;
|
||||
private PointcutParser parser;
|
||||
|
||||
public ProtectPointcutPostProcessor(MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource) {
|
||||
Assert.notNull(mapBasedMethodDefinitionSource, "MapBasedMethodDefinitionSource to populate is required");
|
||||
this.mapBasedMethodDefinitionSource = mapBasedMethodDefinitionSource;
|
||||
|
||||
// Setup AspectJ pointcut expression parser
|
||||
Set supportedPrimitives = new HashSet();
|
||||
supportedPrimitives.add(PointcutPrimitive.EXECUTION);
|
||||
supportedPrimitives.add(PointcutPrimitive.ARGS);
|
||||
supportedPrimitives.add(PointcutPrimitive.REFERENCE);
|
||||
// supportedPrimitives.add(PointcutPrimitive.THIS);
|
||||
// supportedPrimitives.add(PointcutPrimitive.TARGET);
|
||||
// supportedPrimitives.add(PointcutPrimitive.WITHIN);
|
||||
@@ -78,97 +76,79 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
|
||||
// supportedPrimitives.add(PointcutPrimitive.AT_WITHIN);
|
||||
// supportedPrimitives.add(PointcutPrimitive.AT_ARGS);
|
||||
// supportedPrimitives.add(PointcutPrimitive.AT_TARGET);
|
||||
parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
|
||||
}
|
||||
parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (processedBeans.contains(beanName)) {
|
||||
// We already have the metadata for this bean
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
// Obtain methods for the present bean
|
||||
Method[] methods;
|
||||
try {
|
||||
methods = bean.getClass().getMethods();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
|
||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
Iterator iter = pointcutMap.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
String ex = iter.next().toString();
|
||||
|
||||
// Parse the presented AspectJ pointcut expression
|
||||
PointcutExpression expression = parser.parsePointcutExpression(ex);
|
||||
|
||||
// Obtain methods for the present bean
|
||||
Method[] methods;
|
||||
try {
|
||||
methods = bean.getClass().getMethods();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
|
||||
// Check to see if any of those methods are compatible with our pointcut expressions
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
Iterator iter = pointcutMap.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
String ex = iter.next().toString();
|
||||
|
||||
// Parse the presented AspectJ pointcut expression
|
||||
PointcutExpression expression = parser.parsePointcutExpression(ex);
|
||||
|
||||
// Try for the bean class directly
|
||||
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
||||
// We've found the first expression that matches this method, so move onto the next method now
|
||||
break; // the "while" loop, not the "for" loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processedBeans.add(beanName);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private boolean attemptMatch(Class targetClass, Method method, PointcutExpression expression, String beanName) {
|
||||
// Determine if the presented AspectJ pointcut expression matches this method
|
||||
boolean matches = expression.matchesMethodExecution(method).alwaysMatches();
|
||||
|
||||
// Handle accordingly
|
||||
if (matches) {
|
||||
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) pointcutMap.get(expression.getPointcutExpression());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'");
|
||||
}
|
||||
|
||||
mapBasedMethodDefinitionSource.addSecureMethod(targetClass, method, attr);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public void setPointcutMap(Map map) {
|
||||
Assert.notEmpty(map);
|
||||
Iterator i = map.keySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
String expression = i.next().toString();
|
||||
Object value = map.get(expression);
|
||||
Assert.isInstanceOf(ConfigAttributeDefinition.class, value, "Map keys must be instances of ConfigAttributeDefinition");
|
||||
addPointcut(expression, (ConfigAttributeDefinition) value);
|
||||
}
|
||||
}
|
||||
|
||||
private void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
|
||||
Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
|
||||
Assert.notNull(definition, "ConfigAttributeDefinition required");
|
||||
pointcutExpression = replaceBooleanOperators(pointcutExpression);
|
||||
pointcutMap.put(pointcutExpression, definition);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.aop.aspectj.AspectJExpressionPointcut#replaceBooleanOperators
|
||||
*/
|
||||
private String replaceBooleanOperators(String pcExpr) {
|
||||
pcExpr = StringUtils.replace(pcExpr," and "," && ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
|
||||
return pcExpr;
|
||||
}
|
||||
// Try for the bean class directly
|
||||
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
|
||||
// We've found the first expression that matches this method, so move onto the next method now
|
||||
break; // the "while" loop, not the "for" loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private boolean attemptMatch(Class targetClass, Method method, PointcutExpression expression, String beanName) {
|
||||
// Determine if the presented AspectJ pointcut expression matches this method
|
||||
boolean matches = expression.matchesMethodExecution(method).alwaysMatches();
|
||||
|
||||
// Handle accordingly
|
||||
if (matches) {
|
||||
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) pointcutMap.get(expression.getPointcutExpression());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'");
|
||||
}
|
||||
|
||||
mapBasedMethodDefinitionSource.addSecureMethod(targetClass, method.getName(), attr);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public void setPointcutMap(Map map) {
|
||||
Assert.notEmpty(map);
|
||||
Iterator i = map.keySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
String expression = i.next().toString();
|
||||
Object value = map.get(expression);
|
||||
Assert.isInstanceOf(ConfigAttributeDefinition.class, value, "Map keys must be instances of ConfigAttributeDefinition");
|
||||
addPointcut(expression, (ConfigAttributeDefinition) value);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
|
||||
Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
|
||||
Assert.notNull(definition, "ConfigAttributeDefinition required");
|
||||
pointcutMap.put(pointcutExpression, definition);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
-35
@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
|
||||
* Advisor driven by a {@link MethodDefinitionSource}, used to exclude a {@link MethodSecurityInterceptor} from
|
||||
* public (ie non-secure) methods.
|
||||
* <p>
|
||||
* Because the AOP framework caches advice calculations, this is normally faster than just letting the
|
||||
* Because the AOP framework caches advice calculations, this is normally faster than just letting the
|
||||
* <code>MethodSecurityInterceptor</code> run and find out itself that it has no work to do.
|
||||
* <p>
|
||||
* This class also allows the use of Spring's
|
||||
@@ -63,63 +63,64 @@ public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor imple
|
||||
* @deprecated use the decoupled approach instead
|
||||
*/
|
||||
public MethodDefinitionSourceAdvisor(MethodSecurityInterceptor advice) {
|
||||
Assert.notNull(advice.getObjectDefinitionSource(), "Cannot construct a MethodDefinitionSourceAdvisor using a " +
|
||||
"MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
|
||||
Assert.notNull(advice.getObjectDefinitionSource(), "Cannot construct a MethodDefinitionSourceAdvisor using a " +
|
||||
"MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
|
||||
|
||||
this.interceptor = advice;
|
||||
this.interceptor = advice;
|
||||
this.attributeSource = advice.getObjectDefinitionSource();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alternative constructor for situations where we want the advisor decoupled from the advice. Instead the advice
|
||||
* bean name should be set. This prevents eager instantiation of the interceptor
|
||||
* bean name should be set. This prevents eager instantiation of the interceptor
|
||||
* (and hence the AuthenticationManager). See SEC-773, for example.
|
||||
* <p>
|
||||
* This is essentially the approach taken by subclasses of {@link AbstractBeanFactoryPointcutAdvisor}, which this
|
||||
* class should extend in future. The original hierarchy and constructor have been retained for backwards
|
||||
* compatibility.
|
||||
*
|
||||
* class should extend in future. The original hierarchy and constructor have been retained for backwards
|
||||
* compatibilty.
|
||||
*
|
||||
* @param adviceBeanName name of the MethodSecurityInterceptor bean
|
||||
* @param attributeSource the attribute source (should be the same as the one used on the interceptor)
|
||||
*/
|
||||
public MethodDefinitionSourceAdvisor(String adviceBeanName, MethodDefinitionSource attributeSource) {
|
||||
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
|
||||
Assert.notNull(attributeSource, "The attributeSource cannot be null");
|
||||
|
||||
this.adviceBeanName = adviceBeanName;
|
||||
this.attributeSource = attributeSource;
|
||||
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
|
||||
Assert.notNull(attributeSource, "The attributeSource cannot be null");
|
||||
|
||||
this.adviceBeanName = adviceBeanName;
|
||||
this.attributeSource = attributeSource;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Pointcut getPointcut() {
|
||||
return pointcut;
|
||||
}
|
||||
public Pointcut getPointcut() {
|
||||
return pointcut;
|
||||
}
|
||||
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (interceptor == null) {
|
||||
Assert.notNull(adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
interceptor = (MethodSecurityInterceptor)
|
||||
beanFactory.getBean(this.adviceBeanName, MethodSecurityInterceptor.class);
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (interceptor == null) {
|
||||
Assert.notNull(adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
interceptor = (MethodSecurityInterceptor)
|
||||
beanFactory.getBean(this.adviceBeanName, MethodSecurityInterceptor.class);
|
||||
attributeSource = interceptor.getObjectDefinitionSource();
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
|
||||
class MethodDefinitionSourcePointcut extends StaticMethodMatcherPointcut {
|
||||
public boolean matches(Method m, Class targetClass) {
|
||||
return attributeSource.getAttributes(m, targetClass) != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents a <code>MethodInvocation</code>.
|
||||
* <p>
|
||||
@@ -152,7 +153,7 @@ public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor imple
|
||||
}
|
||||
|
||||
public Object getThis() {
|
||||
return this.targetClass;
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
public Object proceed() throws Throwable {
|
||||
|
||||
+1
-1
@@ -12,5 +12,5 @@ package org.springframework.security.intercept.method.aspectj;
|
||||
public interface AspectJAnnotationCallback {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
Object proceedWithObject() throws Throwable;
|
||||
Object proceedWithObject();
|
||||
}
|
||||
|
||||
@@ -54,16 +54,4 @@ public class RequestKey {
|
||||
|
||||
return method.equals(key.method);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(url.length() + 7);
|
||||
sb.append("[");
|
||||
if (method != null) {
|
||||
sb.append(method).append(",");
|
||||
}
|
||||
sb.append(url);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -71,7 +71,6 @@ public class DefaultSpringSecurityContextSource extends LdapContextSource implem
|
||||
|
||||
env.put(Context.SECURITY_PRINCIPAL, userDn);
|
||||
env.put(Context.SECURITY_CREDENTIALS, credentials);
|
||||
env.remove(SUN_LDAP_POOLING_FLAG);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating context with principal: '" + userDn + "'");
|
||||
|
||||
@@ -158,7 +158,7 @@ public final class LdapUtils {
|
||||
|
||||
if (url.startsWith("ldap:") || url.startsWith("ldaps:")) {
|
||||
URI uri = parseLdapUrl(url);
|
||||
urlRootDn = uri.getRawPath();
|
||||
urlRootDn = uri.getPath();
|
||||
} else {
|
||||
// Assume it's an embedded server
|
||||
urlRootDn = url;
|
||||
|
||||
+50
-64
@@ -15,21 +15,6 @@
|
||||
|
||||
package org.springframework.security.ldap;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.PartialResultException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.core.ContextExecutor;
|
||||
import org.springframework.ldap.core.ContextMapper;
|
||||
@@ -38,18 +23,33 @@ import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.LdapEncoder;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* Extension of Spring LDAP's LdapTemplate class which adds extra functionality required by Spring Security.
|
||||
* LDAP equivalent of the Spring JdbcTemplate class.
|
||||
* <p>
|
||||
* This is mainly intended to simplify Ldap access within Spring Security's LDAP-related services.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.LdapTemplate {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
private static final Log logger = LogFactory.getLog(SpringSecurityLdapTemplate.class);
|
||||
|
||||
@@ -136,14 +136,14 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
* @return the set of String values for the attribute as a union of the values found in all the matching entries.
|
||||
*/
|
||||
public Set searchForSingleAttributeValues(final String base, final String filter, final Object[] params,
|
||||
final String attributeName) {
|
||||
// Escape the params acording to RFC2254
|
||||
Object[] encodedParams = new String[params.length];
|
||||
|
||||
for (int i=0; i < params.length; i++) {
|
||||
encodedParams[i] = LdapEncoder.filterEncode(params[i].toString());
|
||||
}
|
||||
|
||||
final String attributeName) {
|
||||
// Escape the params acording to RFC2254
|
||||
Object[] encodedParams = new String[params.length];
|
||||
|
||||
for (int i=0; i < params.length; i++) {
|
||||
encodedParams[i] = LdapEncoder.filterEncode(params[i].toString());
|
||||
}
|
||||
|
||||
String formattedFilter = MessageFormat.format(filter, encodedParams);
|
||||
logger.debug("Using filter: " + formattedFilter);
|
||||
|
||||
@@ -175,15 +175,12 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
/**
|
||||
* Performs a search, with the requirement that the search shall return a single directory entry, and uses
|
||||
* the supplied mapper to create the object from that entry.
|
||||
* <p>
|
||||
* Ignores <tt>PartialResultException</tt> if thrown, for compatibility with Active Directory
|
||||
* (see {@link LdapTemplate#setIgnorePartialResultException(boolean)}).
|
||||
*
|
||||
* @param base the search base, relative to the base context supplied by the context source.
|
||||
* @param filter the LDAP search filter
|
||||
* @param params parameters to be substituted in the search.
|
||||
* @param base
|
||||
* @param filter
|
||||
* @param params
|
||||
*
|
||||
* @return a DirContextOperations instance created from the matching entry.
|
||||
* @return the object created by the mapper from the matching entry
|
||||
*
|
||||
* @throws IncorrectResultSizeDataAccessException if no results are found or the search returns more than one
|
||||
* result.
|
||||
@@ -191,43 +188,32 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
public DirContextOperations searchForSingleEntry(final String base, final String filter, final Object[] params) {
|
||||
|
||||
return (DirContextOperations) executeReadOnly(new ContextExecutor() {
|
||||
public Object executeWithContext(DirContext ctx) throws NamingException {
|
||||
DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Searching for entry in under DN '" + ctxBaseDn
|
||||
+ "', base = '" + base + "', filter = '" + filter + "'");
|
||||
}
|
||||
public Object executeWithContext(DirContext ctx)
|
||||
throws NamingException {
|
||||
|
||||
NamingEnumeration resultsEnum = ctx.search(base, filter, params, searchControls);
|
||||
Set results = new HashSet();
|
||||
try {
|
||||
while (resultsEnum.hasMore()) {
|
||||
SearchResult searchResult = (SearchResult) resultsEnum.next();
|
||||
// Work out the DN of the matched entry
|
||||
DistinguishedName dn = new DistinguishedName(searchResult.getName());
|
||||
NamingEnumeration results = ctx.search(base, filter, params, searchControls);
|
||||
|
||||
if (base.length() > 0) {
|
||||
dn.prepend(new DistinguishedName(base));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found DN: " + dn);
|
||||
}
|
||||
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
|
||||
}
|
||||
} catch (PartialResultException e) {
|
||||
logger.info("Ignoring PartialResultException");
|
||||
}
|
||||
|
||||
if (results.size() == 0) {
|
||||
if (!results.hasMore()) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, 0);
|
||||
}
|
||||
|
||||
if (results.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, results.size());
|
||||
SearchResult searchResult = (SearchResult) results.next();
|
||||
|
||||
if (results.hasMore()) {
|
||||
// We don't know how many results but set to 2 which is good enough
|
||||
throw new IncorrectResultSizeDataAccessException(1, 2);
|
||||
}
|
||||
|
||||
return results.toArray()[0];
|
||||
// Work out the DN of the matched entry
|
||||
StringBuffer dn = new StringBuffer(searchResult.getName());
|
||||
|
||||
if (base.length() > 0) {
|
||||
dn.append(",");
|
||||
dn.append(base);
|
||||
}
|
||||
|
||||
return new DirContextAdapter(searchResult.getAttributes(),
|
||||
new DistinguishedName(dn.toString()), new DistinguishedName(ctx.getNameInNamespace()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+18
-5
@@ -99,6 +99,8 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
*/
|
||||
private GrantedAuthority defaultRole;
|
||||
|
||||
private ContextSource contextSource;
|
||||
|
||||
private SpringSecurityLdapTemplate ldapTemplate;
|
||||
|
||||
/**
|
||||
@@ -141,10 +143,8 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
* context factory.
|
||||
*/
|
||||
public DefaultLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
|
||||
Assert.notNull(contextSource, "contextSource must not be null");
|
||||
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
|
||||
ldapTemplate.setSearchControls(searchControls);
|
||||
setGroupSearchBase(groupSearchBase);
|
||||
this.setContextSource(contextSource);
|
||||
this.setGroupSearchBase(groupSearchBase);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -226,7 +226,20 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
}
|
||||
|
||||
protected ContextSource getContextSource() {
|
||||
return ldapTemplate.getContextSource();
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ContextSource}
|
||||
*
|
||||
* @param contextSource supplies the contexts used to search for user roles.
|
||||
*/
|
||||
private void setContextSource(ContextSource contextSource) {
|
||||
Assert.notNull(contextSource, "contextSource must not be null");
|
||||
this.contextSource = contextSource;
|
||||
|
||||
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
|
||||
ldapTemplate.setSearchControls(searchControls);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,10 +144,17 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
checkIfValidList(this.providers);
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
exceptionMappings.putAll(additionalExceptionMappings);
|
||||
}
|
||||
|
||||
private void checkIfValidList(List listToCheck) {
|
||||
if ((listToCheck == null) || (listToCheck.size() == 0)) {
|
||||
throw new IllegalArgumentException("A list of AuthenticationProviders is required");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to authenticate the passed {@link Authentication} object.
|
||||
* <p>
|
||||
@@ -167,7 +174,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
* @throws AuthenticationException if authentication fails.
|
||||
*/
|
||||
public Authentication doAuthentication(Authentication authentication) throws AuthenticationException {
|
||||
Iterator iter = getProviders().iterator();
|
||||
Iterator iter = providers.iterator();
|
||||
|
||||
Class toTest = authentication.getClass();
|
||||
|
||||
@@ -266,11 +273,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
}
|
||||
|
||||
public List getProviders() {
|
||||
if (providers == null || providers.size() == 0) {
|
||||
throw new IllegalArgumentException("A list of AuthenticationProviders is required");
|
||||
}
|
||||
|
||||
return providers;
|
||||
return this.providers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,7 +303,8 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
|
||||
* AuthenticationProvider instance.
|
||||
*/
|
||||
public void setProviders(List providers) {
|
||||
Assert.notEmpty(providers, "A list of AuthenticationProviders is required");
|
||||
checkIfValidList(providers);
|
||||
|
||||
Iterator iter = providers.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
|
||||
-12
@@ -16,7 +16,6 @@
|
||||
package org.springframework.security.providers;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -35,17 +34,6 @@ public class TestingAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public TestingAuthenticationToken(Object principal, Object credentials) {
|
||||
super(null);
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
|
||||
public TestingAuthenticationToken(Object principal, Object credentials, String... authorities) {
|
||||
this(principal, credentials, AuthorityUtils.stringArrayToAuthorityArray(authorities));
|
||||
}
|
||||
|
||||
public TestingAuthenticationToken(Object principal, Object credentials, GrantedAuthority[] authorities) {
|
||||
super(authorities);
|
||||
this.principal = principal;
|
||||
+15
-13
@@ -15,28 +15,30 @@
|
||||
|
||||
package org.springframework.security.providers.anonymous;
|
||||
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.providers.AuthenticationProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.providers.AuthenticationProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation that validates {@link AnonymousAuthenticationToken}s.
|
||||
* <p>
|
||||
* To be successfully validated, the {@link AnonymousAuthenticationToken#getKeyHash()} must match this class'
|
||||
* {@link #getKey()}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* An {@link AuthenticationProvider} implementation that validates {@link
|
||||
* org.springframework.security.providers.anonymous.AnonymousAuthenticationToken}s.<p>To be successfully validated, the
|
||||
* {@link org.springframework.security.providers.anonymous.AnonymousAuthenticationToken#getKeyHash()} must match this class'
|
||||
* {@link #getKey()}.</p>
|
||||
*/
|
||||
public class AnonymousAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AnonymousAuthenticationProvider.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@@ -45,7 +47,7 @@ public class AnonymousAuthenticationProvider implements AuthenticationProvider,
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(key, "A Key is required");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
}
|
||||
|
||||
+2
-29
@@ -24,7 +24,6 @@ import org.springframework.security.providers.encoding.PasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.PlaintextPasswordEncoder;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -36,24 +35,10 @@ import org.springframework.util.Assert;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
/**
|
||||
* The plaintext password used to perform {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
|
||||
* not found to avoid SEC-2056.
|
||||
*/
|
||||
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
/**
|
||||
* The password used to perform {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
|
||||
* not found to avoid SEC-2056. This is necessary, because some {@link PasswordEncoder} implementations will short circuit if the
|
||||
* password is not in a valid format.
|
||||
*/
|
||||
private String userNotFoundEncodedPassword;
|
||||
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
|
||||
|
||||
private SaltSource saltSource;
|
||||
|
||||
@@ -61,10 +46,6 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
||||
|
||||
private boolean includeDetailsObject = true;
|
||||
|
||||
public DaoAuthenticationProvider() {
|
||||
setPasswordEncoder(new PlaintextPasswordEncoder());
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected void additionalAuthenticationChecks(UserDetails userDetails,
|
||||
@@ -104,13 +85,6 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
||||
catch (DataAccessException repositoryProblem) {
|
||||
throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
|
||||
}
|
||||
catch (UsernameNotFoundException notFound) {
|
||||
if(authentication.getCredentials() != null) {
|
||||
String presentedPassword = authentication.getCredentials().toString();
|
||||
passwordEncoder.isPasswordValid(userNotFoundEncodedPassword, presentedPassword, null);
|
||||
}
|
||||
throw notFound;
|
||||
}
|
||||
|
||||
if (loadedUser == null) {
|
||||
throw new AuthenticationServiceException(
|
||||
@@ -126,7 +100,6 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
||||
* @param passwordEncoder The passwordEncoder to use
|
||||
*/
|
||||
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||
this.userNotFoundEncodedPassword = passwordEncoder.encodePassword(USER_NOT_FOUND_PASSWORD, null);
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@@ -170,6 +143,6 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
||||
*/
|
||||
public void setIncludeDetailsObject(boolean includeDetailsObject) {
|
||||
this.includeDetailsObject = includeDetailsObject;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-2
@@ -158,7 +158,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
Assert.hasLength(loginContextName, "loginContextName must be set on " + getClass());
|
||||
|
||||
configureJaas(loginConfig);
|
||||
|
||||
|
||||
Assert.notNull(Configuration.getConfiguration(),
|
||||
"As per http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html "
|
||||
+ "\"If a Configuration object was set via the Configuration.setConfiguration method, then that object is "
|
||||
@@ -189,9 +189,13 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
|
||||
//Attempt to login the user, the LoginContext will call our InternalCallbackHandler at this point.
|
||||
loginContext.login();
|
||||
|
||||
//create a set to hold the authorities
|
||||
//create a set to hold the authorities, and add any that have already been applied.
|
||||
Set authorities = new HashSet();
|
||||
|
||||
if (request.getAuthorities() != null) {
|
||||
authorities.addAll(Arrays.asList(request.getAuthorities()));
|
||||
}
|
||||
|
||||
//get the subject principals and pass them to each of the AuthorityGranters
|
||||
Set principals = loginContext.getSubject().getPrincipals();
|
||||
|
||||
|
||||
+27
-51
@@ -15,27 +15,23 @@
|
||||
|
||||
package org.springframework.security.providers.ldap.authenticator;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.ldap.NamingException;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.ldap.SpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* An authenticator which binds as a user.
|
||||
@@ -95,42 +91,21 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
||||
return user;
|
||||
}
|
||||
|
||||
private DirContextOperations bindWithDn(String userDnStr, String username, String password) {
|
||||
BaseLdapPathContextSource ctxSource = (BaseLdapPathContextSource) getContextSource();
|
||||
DistinguishedName userDn = new DistinguishedName(userDnStr);
|
||||
DistinguishedName fullDn = new DistinguishedName(userDn);
|
||||
fullDn.prepend(ctxSource.getBaseLdapPath());
|
||||
BindWithSpecificDnContextSource specificDnContextSource = new BindWithSpecificDnContextSource(
|
||||
(SpringSecurityContextSource) getContextSource(), fullDn,
|
||||
password);
|
||||
logger.debug("Attemptimg to bind as " + fullDn);
|
||||
DirContext ctx = null;
|
||||
try {
|
||||
ctx = specificDnContextSource.getReadOnlyContext();
|
||||
private DirContextOperations bindWithDn(String userDn, String username, String password) {
|
||||
SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(
|
||||
new BindWithSpecificDnContextSource((SpringSecurityContextSource) getContextSource(), userDn, password));
|
||||
|
||||
Attributes attrs = ctx.getAttributes(userDn, getUserAttributes());
|
||||
try {
|
||||
return template.retrieveEntry(userDn, getUserAttributes());
|
||||
|
||||
DirContextAdapter result = new DirContextAdapter(attrs, userDn, ctxSource.getBaseLdapPath());
|
||||
|
||||
return result;
|
||||
} catch (NamingException e) {
|
||||
// This will be thrown if an invalid user name is used and the method may
|
||||
// be called multiple times to try different names, so we trap the exception
|
||||
// unless a subclass wishes to implement more specialized behaviour.
|
||||
if ((e instanceof org.springframework.ldap.AuthenticationException)
|
||||
|| (e instanceof org.springframework.ldap.OperationNotSupportedException)) {
|
||||
handleBindException(userDnStr, username, e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (javax.naming.NamingException e) {
|
||||
throw LdapUtils.convertLdapException(e);
|
||||
} finally {
|
||||
LdapUtils.closeContext(ctx);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (BadCredentialsException e) {
|
||||
// This will be thrown if an invalid user name is used and the method may
|
||||
// be called multiple times to try different names, so we trap the exception
|
||||
// unless a subclass wishes to implement more specialized behaviour.
|
||||
handleBindException(userDn, username, e.getCause());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,12 +120,13 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
||||
|
||||
private class BindWithSpecificDnContextSource implements ContextSource {
|
||||
private SpringSecurityContextSource ctxFactory;
|
||||
private DistinguishedName userDn;
|
||||
DistinguishedName userDn;
|
||||
private String password;
|
||||
|
||||
public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, DistinguishedName userDn, String password) {
|
||||
public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, String userDn, String password) {
|
||||
this.ctxFactory = ctxFactory;
|
||||
this.userDn = userDn;
|
||||
this.userDn = new DistinguishedName(userDn);
|
||||
this.userDn.prepend(ctxFactory.getBaseLdapPath());
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
+19
-19
@@ -86,9 +86,9 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
|
||||
sha.update(rawPass.getBytes("UTF-8"));
|
||||
} catch (java.security.NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("No SHA implementation available!");
|
||||
} catch (UnsupportedEncodingException ue) {
|
||||
throw new IllegalStateException("UTF-8 not supported!");
|
||||
}
|
||||
} catch (UnsupportedEncodingException ue) {
|
||||
throw new IllegalStateException("UTF-8 not supported!");
|
||||
}
|
||||
|
||||
if (salt != null) {
|
||||
Assert.isInstanceOf(byte[].class, salt, "Salt value must be a byte array");
|
||||
@@ -131,7 +131,7 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
|
||||
*/
|
||||
public boolean isPasswordValid(final String encPass, final String rawPass, Object salt) {
|
||||
String prefix = extractPrefix(encPass);
|
||||
|
||||
|
||||
if (prefix == null) {
|
||||
return encPass.equals(rawPass);
|
||||
}
|
||||
@@ -141,32 +141,32 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
|
||||
} else if (!prefix.equals(SHA_PREFIX) && !prefix.equals(SHA_PREFIX_LC)) {
|
||||
throw new IllegalArgumentException("Unsupported password prefix '" + prefix + "'");
|
||||
} else {
|
||||
// Standard SHA
|
||||
salt = null;
|
||||
// Standard SHA
|
||||
salt = null;
|
||||
}
|
||||
|
||||
int startOfHash = prefix.length();
|
||||
|
||||
int startOfHash = prefix.length() + 1;
|
||||
|
||||
String encodedRawPass = encodePassword(rawPass, salt).substring(startOfHash);
|
||||
|
||||
|
||||
return encodedRawPass.equals(encPass.substring(startOfHash));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the hash prefix or null if there isn't one.
|
||||
* Returns the hash prefix or null if there isn't one.
|
||||
*/
|
||||
private String extractPrefix(String encPass) {
|
||||
if (!encPass.startsWith("{")) {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
int secondBrace = encPass.lastIndexOf('}');
|
||||
|
||||
if (secondBrace < 0) {
|
||||
throw new IllegalArgumentException("Couldn't find closing brace for SHA prefix");
|
||||
}
|
||||
|
||||
return encPass.substring(0, secondBrace + 1);
|
||||
int secondBrace = encPass.lastIndexOf('}');
|
||||
|
||||
if (secondBrace < 0) {
|
||||
throw new IllegalArgumentException("Couldn't find closing brace for SHA prefix");
|
||||
}
|
||||
|
||||
return encPass.substring(0, secondBrace + 1);
|
||||
}
|
||||
|
||||
public void setForceLowerCasePrefix(boolean forceLowerCasePrefix) {
|
||||
|
||||
+3
-5
@@ -45,7 +45,7 @@ import java.security.cert.X509Certificate;
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @deprecated superceded by the preauth provider. Use the X.509 authentication support in org.springframework.security.ui.preauth.x509 instead
|
||||
* or namespace support via the <x509 /> element.
|
||||
* or namespace support via the <x509 /> element.
|
||||
* @version $Id$
|
||||
*/
|
||||
public class X509AuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
||||
@@ -61,7 +61,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(userCache, "An x509UserCache must be set");
|
||||
Assert.notNull(x509AuthoritiesPopulator, "An X509AuthoritiesPopulator must be set");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
@@ -101,9 +101,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi
|
||||
UserDetails user = userCache.getUserFromCache(clientCertificate);
|
||||
|
||||
if (user == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authenticating with certificate " + clientCertificate);
|
||||
}
|
||||
logger.debug("Authenticating with certificate " + clientCertificate);
|
||||
user = x509AuthoritiesPopulator.getUserDetails(clientCertificate);
|
||||
userCache.putUserInCache(clientCertificate, user);
|
||||
}
|
||||
|
||||
@@ -122,8 +122,7 @@ import javax.servlet.http.HttpSession;
|
||||
* The behaviour is turned off by default. Additionally there is a property <tt>migrateInvalidatedSessionAttributes</tt>
|
||||
* which tells if on session invalidation we are to migrate all session attributes from the old session to a newly
|
||||
* created one. This is turned on by default, but not used unless <tt>invalidateSessionOnSuccessfulAuthentication</tt>
|
||||
* is true. If you are using this feature in combination with concurrent session control, you should set the
|
||||
* <tt>sessionRegistry</tt> property to make sure that the session information is updated consistently.
|
||||
* is true.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -148,14 +147,10 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
|
||||
private Properties exceptionMappings = new Properties();
|
||||
|
||||
/**
|
||||
* Delay use of NullRememberMeServices until initialization so that namespace has a chance to inject
|
||||
* the RememberMeServices implementation into custom implementations.
|
||||
*/
|
||||
private RememberMeServices rememberMeServices = null;
|
||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||
|
||||
private TargetUrlResolver targetUrlResolver = new TargetUrlResolverImpl();
|
||||
|
||||
|
||||
/** Where to redirect the browser to if authentication fails */
|
||||
private String authenticationFailureUrl;
|
||||
|
||||
@@ -211,25 +206,23 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
private boolean migrateInvalidatedSessionAttributes = true;
|
||||
|
||||
private boolean allowSessionCreation = true;
|
||||
|
||||
|
||||
private boolean serverSideRedirect = false;
|
||||
|
||||
|
||||
private SessionRegistry sessionRegistry;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
|
||||
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultTargetUrl), defaultTargetUrl + " isn't a valid redirect URL");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultTargetUrl), defaultTargetUrl + " isn't a valid redirect URL");
|
||||
// Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(authenticationFailureUrl), authenticationFailureUrl + " isn't a valid redirect URL");
|
||||
Assert.notNull(authenticationManager, "authenticationManager must be specified");
|
||||
Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
|
||||
Assert.notNull(targetUrlResolver, "targetUrlResolver cannot be null");
|
||||
|
||||
if (rememberMeServices == null) {
|
||||
rememberMeServices = new NullRememberMeServices();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,8 +272,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
}
|
||||
|
||||
public static String obtainFullSavedRequestUrl(HttpServletRequest request) {
|
||||
SavedRequest savedRequest = getSavedRequest(request);
|
||||
|
||||
SavedRequest savedRequest = getSavedRequest(request);
|
||||
|
||||
return savedRequest == null ? null : savedRequest.getFullRequestUrl();
|
||||
}
|
||||
|
||||
@@ -293,9 +286,9 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
|
||||
SavedRequest savedRequest = (SavedRequest) session.getAttribute(SPRING_SECURITY_SAVED_REQUEST_KEY);
|
||||
|
||||
return savedRequest;
|
||||
}
|
||||
|
||||
return savedRequest;
|
||||
}
|
||||
|
||||
protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException {
|
||||
}
|
||||
@@ -388,8 +381,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
|
||||
protected String determineTargetUrl(HttpServletRequest request) {
|
||||
// Don't attempt to obtain the url from the saved request if alwaysUsedefaultTargetUrl is set
|
||||
String targetUrl = alwaysUseDefaultTargetUrl ? null :
|
||||
targetUrlResolver.determineTargetUrl(getSavedRequest(request), request, SecurityContextHolder.getContext().getAuthentication());
|
||||
String targetUrl = alwaysUseDefaultTargetUrl ? null :
|
||||
targetUrlResolver.determineTargetUrl(getSavedRequest(request), request, SecurityContextHolder.getContext().getAuthentication());
|
||||
|
||||
if (targetUrl == null) {
|
||||
targetUrl = getDefaultTargetUrl();
|
||||
@@ -425,13 +418,13 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
onUnsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
rememberMeServices.loginFail(request, response);
|
||||
|
||||
|
||||
if (failureUrl == null) {
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed:" + failed.getMessage());
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed:" + failed.getMessage());
|
||||
} else if (serverSideRedirect){
|
||||
request.getRequestDispatcher(failureUrl).forward(request, response);
|
||||
request.getRequestDispatcher(failureUrl).forward(request, response);
|
||||
} else {
|
||||
sendRedirect(request, response, failureUrl);
|
||||
sendRedirect(request, response, failureUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +475,7 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
this.defaultTargetUrl = defaultTargetUrl;
|
||||
}
|
||||
|
||||
protected Properties getExceptionMappings() {
|
||||
Properties getExceptionMappings() {
|
||||
return new Properties(exceptionMappings);
|
||||
}
|
||||
|
||||
@@ -556,33 +549,33 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
||||
this.allowSessionCreation = allowSessionCreation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the targetUrlResolver
|
||||
*/
|
||||
protected TargetUrlResolver getTargetUrlResolver() {
|
||||
return targetUrlResolver;
|
||||
}
|
||||
/**
|
||||
* @return the targetUrlResolver
|
||||
*/
|
||||
protected TargetUrlResolver getTargetUrlResolver() {
|
||||
return targetUrlResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetUrlResolver the targetUrlResolver to set
|
||||
*/
|
||||
public void setTargetUrlResolver(TargetUrlResolver targetUrlResolver) {
|
||||
this.targetUrlResolver = targetUrlResolver;
|
||||
}
|
||||
/**
|
||||
* @param targetUrlResolver the targetUrlResolver to set
|
||||
*/
|
||||
public void setTargetUrlResolver(TargetUrlResolver targetUrlResolver) {
|
||||
this.targetUrlResolver = targetUrlResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if we are to do a server side include of the error URL instead of a 302 redirect.
|
||||
*
|
||||
* @param serverSideRedirect
|
||||
*/
|
||||
public void setServerSideRedirect(boolean serverSideRedirect) {
|
||||
this.serverSideRedirect = serverSideRedirect;
|
||||
}
|
||||
*/
|
||||
public void setServerSideRedirect(boolean serverSideRedirect) {
|
||||
this.serverSideRedirect = serverSideRedirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* The session registry needs to be set if session fixation attack protection is in use (and concurrent
|
||||
* session control is enabled).
|
||||
*/
|
||||
/**
|
||||
* The session registry needs to be set if session fixation attack protection is in use (and concurrent
|
||||
* session control is enabled).
|
||||
*/
|
||||
public void setSessionRegistry(SessionRegistry sessionRegistry) {
|
||||
this.sessionRegistry = sessionRegistry;
|
||||
}
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class SessionFixationProtectionFilter extends SpringSecurityFilter {
|
||||
protected void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
// Session fixation isn't a problem if there's no session
|
||||
if(request.getSession(false) == null || request.getAttribute(FILTER_APPLIED) != null || !request.isRequestedSessionIdValid()) {
|
||||
if(request.getSession(false) == null || request.getAttribute(FILTER_APPLIED) != null) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,37 +28,38 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Default implementation for {@link TargetUrlResolver}
|
||||
* <p/>
|
||||
* Returns a target URL based from the contents of the configured <tt>targetUrlParameter</tt> if present on
|
||||
* the current request. Failing that, the SavedRequest in the session will be used.
|
||||
*
|
||||
* <p>
|
||||
* Returns a target URL based from the contents of the configured <tt>targetUrlParameter</tt> if present on
|
||||
* the current request. Failing that, the SavedRequest in the session will be used.
|
||||
*
|
||||
* @author Martino Piccinato
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public class TargetUrlResolverImpl implements TargetUrlResolver {
|
||||
public static String DEFAULT_TARGET_PARAMETER = "spring-security-redirect";
|
||||
|
||||
|
||||
/* SEC-213 */
|
||||
private String targetUrlParameter = DEFAULT_TARGET_PARAMETER;
|
||||
|
||||
/**
|
||||
* If <code>true</code>, will only use <code>SavedRequest</code> to determine the target URL on successful
|
||||
|
||||
/**
|
||||
* If <code>true</code>, will only use <code>SavedRequest</code> to determine the target URL on successful
|
||||
* authentication if the request that caused the authentication request was a GET.
|
||||
* It will then return null for a POST/PUT request.
|
||||
* Defaults to false.
|
||||
*/
|
||||
private boolean justUseSavedRequestOnGet = false;
|
||||
*/
|
||||
private boolean justUseSavedRequestOnGet = false;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.acegisecurity.ui.TargetUrlResolver#determineTargetUrl(org.acegisecurity.ui.savedrequest.SavedRequest, javax.servlet.http.HttpServletRequest, org.acegisecurity.Authentication)
|
||||
*/
|
||||
public String determineTargetUrl(SavedRequest savedRequest, HttpServletRequest currentRequest,
|
||||
Authentication auth) {
|
||||
* @see org.acegisecurity.ui.TargetUrlResolver#determineTargetUrl(org.acegisecurity.ui.savedrequest.SavedRequest, javax.servlet.http.HttpServletRequest, org.acegisecurity.Authentication)
|
||||
*/
|
||||
public String determineTargetUrl(SavedRequest savedRequest, HttpServletRequest currentRequest,
|
||||
Authentication auth) {
|
||||
|
||||
String targetUrl = currentRequest.getParameter(targetUrlParameter);
|
||||
|
||||
|
||||
if (StringUtils.hasText(targetUrl)) {
|
||||
try {
|
||||
return URLDecoder.decode(targetUrl, "UTF-8");
|
||||
@@ -74,34 +75,35 @@ public class TargetUrlResolverImpl implements TargetUrlResolver {
|
||||
}
|
||||
|
||||
return targetUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if just GET request will be used
|
||||
* to determine target URLs, <code>false</code> otherwise.
|
||||
*/
|
||||
protected boolean isJustUseSavedRequestOnGet() {
|
||||
return justUseSavedRequestOnGet;
|
||||
}
|
||||
/**
|
||||
* @return <code>true</code> if just GET request will be used
|
||||
* to determine target URLs, <code>false</code> otherwise.
|
||||
*/
|
||||
protected boolean isJustUseSavedRequestOnGet() {
|
||||
return justUseSavedRequestOnGet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param justUseSavedRequestOnGet set to <code>true</code> if
|
||||
* just GET request will be used to determine target URLs,
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public void setJustUseSavedRequestOnGet(boolean justUseSavedRequestOnGet) {
|
||||
this.justUseSavedRequestOnGet = justUseSavedRequestOnGet;
|
||||
}
|
||||
/**
|
||||
* @param justUseSavedRequestOnGet set to <code>true</code> if
|
||||
* just GET request will be used to determine target URLs,
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public void setJustUseSavedRequestOnGet(boolean justUseSavedRequestOnGet) {
|
||||
this.justUseSavedRequestOnGet = justUseSavedRequestOnGet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before checking the SavedRequest, the current request will be checked for this parameter
|
||||
* and the value used as the target URL if resent.
|
||||
*
|
||||
* @param targetUrlParameter the name of the parameter containing the encoded target URL. Defaults
|
||||
* to "redirect".
|
||||
*/
|
||||
public void setTargetUrlParameter(String targetUrlParameter) {
|
||||
Assert.hasText("targetUrlParameter cannot be null or empty");
|
||||
|
||||
/**
|
||||
* Before checking the SavedRequest, the current request will be checked for this parameter
|
||||
* and the value used as the target URL if resent.
|
||||
*
|
||||
* @param targetUrlParameter the name of the parameter containing the encoded target URL. Defaults
|
||||
* to "redirect".
|
||||
*/
|
||||
public void setTargetUrlParameter(String targetUrlParameter) {
|
||||
Assert.hasText("targetUrlParamete canot be null or empty");
|
||||
this.targetUrlParameter = targetUrlParameter;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-24
@@ -35,7 +35,6 @@ import org.springframework.security.ui.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.security.ui.SpringSecurityFilter;
|
||||
import org.springframework.security.ui.rememberme.NullRememberMeServices;
|
||||
import org.springframework.security.ui.rememberme.RememberMeServices;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -92,7 +91,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
private AuthenticationManager authenticationManager;
|
||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||
private RememberMeServices rememberMeServices;
|
||||
private boolean ignoreFailure = false;
|
||||
private String credentialsCharset = "UTF-8";
|
||||
|
||||
@@ -106,10 +105,10 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
}
|
||||
}
|
||||
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
public void doFilterHttp(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
String header = request.getHeader("Authorization");
|
||||
String header = httpRequest.getHeader("Authorization");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authorization header: " + header);
|
||||
@@ -117,7 +116,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
if ((header != null) && header.startsWith("Basic ")) {
|
||||
byte[] base64Token = header.substring(6).getBytes("UTF-8");
|
||||
String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(request));
|
||||
String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(httpRequest));
|
||||
|
||||
String username = "";
|
||||
String password = "";
|
||||
@@ -131,7 +130,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
if (authenticationIsRequired(username)) {
|
||||
UsernamePasswordAuthenticationToken authRequest =
|
||||
new UsernamePasswordAuthenticationToken(username, password);
|
||||
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
|
||||
authRequest.setDetails(authenticationDetailsSource.buildDetails(httpRequest));
|
||||
|
||||
Authentication authResult;
|
||||
|
||||
@@ -145,14 +144,14 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
rememberMeServices.loginFail(request, response);
|
||||
if (rememberMeServices != null) {
|
||||
rememberMeServices.loginFail(httpRequest, httpResponse);
|
||||
}
|
||||
|
||||
onUnsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
if (ignoreFailure) {
|
||||
chain.doFilter(request, response);
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
} else {
|
||||
authenticationEntryPoint.commence(request, response, failed);
|
||||
authenticationEntryPoint.commence(httpRequest, httpResponse, failed);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -165,13 +164,13 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authResult);
|
||||
|
||||
rememberMeServices.loginSuccess(request, response, authResult);
|
||||
|
||||
onSuccessfulAuthentication(request, response, authResult);
|
||||
if (rememberMeServices != null) {
|
||||
rememberMeServices.loginSuccess(httpRequest, httpResponse, authResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
}
|
||||
|
||||
private boolean authenticationIsRequired(String username) {
|
||||
@@ -203,14 +202,6 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authResult) throws IOException {
|
||||
}
|
||||
|
||||
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
}
|
||||
|
||||
protected AuthenticationEntryPoint getAuthenticationEntryPoint() {
|
||||
return authenticationEntryPoint;
|
||||
@@ -242,7 +233,6 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
|
||||
}
|
||||
|
||||
public void setRememberMeServices(RememberMeServices rememberMeServices) {
|
||||
Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -34,10 +34,10 @@ import javax.servlet.http.HttpSession;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecurityContextLogoutHandler implements LogoutHandler {
|
||||
private boolean invalidateHttpSession = true;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private boolean invalidateHttpSession = true;
|
||||
|
||||
/**
|
||||
* Requires the request to be passed in.
|
||||
*
|
||||
@@ -69,6 +69,6 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
|
||||
*/
|
||||
public void setInvalidateHttpSession(boolean invalidateHttpSession) {
|
||||
this.invalidateHttpSession = invalidateHttpSession;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-24
@@ -25,13 +25,6 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Base class for processing filters that handle pre-authenticated authentication requests. Subclasses must implement
|
||||
* the getPreAuthenticatedPrincipal() and getPreAuthenticatedCredentials() methods.
|
||||
* <p>
|
||||
* By default, the filter chain will proceed when an authentication attempt fails in order to allow other
|
||||
* authentication mechanisms to process the request. To reject the credentials immediately, set the
|
||||
* <tt>continueFilterChainOnUnsuccessfulAuthentication</tt> flag to false. The exception raised by the
|
||||
* <tt>AuthenticationManager</tt> will the be re-thrown. Note that this will not affect cases where the principal
|
||||
* returned by {@link #getPreAuthenticatedPrincipal} is null, when the chain will still proceed as normal.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ruud Senden
|
||||
@@ -45,8 +38,6 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
private AuthenticationManager authenticationManager = null;
|
||||
|
||||
private boolean continueFilterChainOnUnsuccessfulAuthentication = true;
|
||||
|
||||
/**
|
||||
* Check whether all required properties have been set.
|
||||
@@ -97,10 +88,6 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
|
||||
successfulAuthentication(request, response, authResult);
|
||||
} catch (AuthenticationException failed) {
|
||||
unsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
if (!continueFilterChainOnUnsuccessfulAuthentication) {
|
||||
throw failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,19 +143,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
public void setContinueFilterChainOnUnsuccessfulAuthentication(boolean shouldContinue) {
|
||||
continueFilterChainOnUnsuccessfulAuthentication = shouldContinue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to extract the principal information from the current request
|
||||
*/
|
||||
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Override to extract the credentials (if applicable) from the current request. Some implementations
|
||||
* may return a dummy value.
|
||||
*/
|
||||
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
|
||||
}
|
||||
|
||||
+17
-21
@@ -32,14 +32,14 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
public static final String SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY = "SPRING_SECURITY_REMEMBER_ME_COOKIE";
|
||||
public static final String DEFAULT_PARAMETER = "_spring_security_remember_me";
|
||||
|
||||
private static final String DELIMITER = ":";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
//~ Instance fields ================================================================================================
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
@@ -49,7 +49,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
private String cookieName = SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
|
||||
private String parameter = DEFAULT_PARAMETER;
|
||||
private String parameter = DEFAULT_PARAMETER;
|
||||
private boolean alwaysRemember;
|
||||
private String key;
|
||||
private int tokenValiditySeconds = 1209600; // 14 days
|
||||
@@ -232,14 +232,14 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
}
|
||||
|
||||
String paramValue = request.getParameter(parameter);
|
||||
|
||||
|
||||
if (paramValue != null) {
|
||||
if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on") ||
|
||||
paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on") ||
|
||||
paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Did not send remember-me cookie (principal did not set parameter '" + parameter + "')");
|
||||
}
|
||||
@@ -309,10 +309,6 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
|
||||
protected String getCookieName() {
|
||||
return cookieName;
|
||||
}
|
||||
|
||||
public void setAlwaysRemember(boolean alwaysRemember) {
|
||||
this.alwaysRemember = alwaysRemember;
|
||||
}
|
||||
@@ -320,11 +316,11 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
/**
|
||||
* Sets the name of the parameter which should be checked for to see if a remember-me has been requested
|
||||
* during a login request. This should be the same name you assign to the checkbox in your login form.
|
||||
*
|
||||
*
|
||||
* @param parameter the HTTP request parameter
|
||||
*/
|
||||
public void setParameter(String parameter) {
|
||||
Assert.hasText(parameter, "Parameter name cannot be null");
|
||||
Assert.hasText(parameter, "Parameter name cannot be null");
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@@ -337,7 +333,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
Assert.notNull(userDetailsService, "UserDetailsService canot be null");
|
||||
Assert.notNull(userDetailsService, "UserDetailsService canot be null");
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@@ -361,8 +357,8 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
||||
return authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource cannot be null");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource cannot be null");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -304,7 +304,8 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
|
||||
logger.debug("Switch User failed", failed);
|
||||
|
||||
if (switchFailureUrl != null) {
|
||||
sendRedirect(request, response, switchFailureUrl);
|
||||
switchFailureUrl = request.getContextPath() + switchFailureUrl;
|
||||
response.sendRedirect(response.encodeRedirectURL(switchFailureUrl));
|
||||
} else {
|
||||
response.getWriter().print("Switch user failed: " + failed.getMessage());
|
||||
response.flushBuffer();
|
||||
|
||||
-2
@@ -25,8 +25,6 @@ import org.springframework.dao.DataAccessException;
|
||||
* instead of only the directly assigned authorities.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
* @deprecated use a {@link RoleHierarchyVoter} instead of populating the user Authentication object
|
||||
* with the additional authorities.
|
||||
*/
|
||||
public class UserDetailsServiceWrapper implements UserDetailsService {
|
||||
|
||||
|
||||
-1
@@ -23,7 +23,6 @@ import org.springframework.security.userdetails.UserDetails;
|
||||
* delegated to the <tt>UserDetails</tt> implementation.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
* @deprecated use a {@link RoleHierarchyVoter} instead.
|
||||
*/
|
||||
public class UserDetailsWrapper implements UserDetails {
|
||||
|
||||
|
||||
@@ -47,53 +47,23 @@ import javax.sql.DataSource;
|
||||
|
||||
|
||||
/**
|
||||
* <tt>UserDetailsServiceRetrieves</tt> implementation which retrieves the user details
|
||||
* (username, password, enabled flag, and authorities) from a database using JDBC queries.
|
||||
*
|
||||
* <h3>Default Schema</h3>
|
||||
* A default database schema is assumed, with two tables "users" and "authorities".
|
||||
*
|
||||
* <h4>The Users table</h4>
|
||||
*
|
||||
* This table contains the login name, password and enabled status of the user.
|
||||
*
|
||||
* <table>
|
||||
* <tr><th>Column</th></tr>
|
||||
* <tr><td>username</td></tr>
|
||||
* <tr><td>password</td></tr>
|
||||
* <tr><td>enabled</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <h4>The Authorities Table</h4>
|
||||
*
|
||||
* <table>
|
||||
* <tr><th>Column</th></tr>
|
||||
* <tr><td>username</td></tr>
|
||||
* <tr><td>authority</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* If you are using an existing schema you will have to set the queries <tt>usersByUsernameQuery</tt> and
|
||||
* <tt>authoritiesByUsernameQuery</tt> to match your database setup
|
||||
* (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link #DEF_AUTHORITIES_BY_USERNAME_QUERY}).
|
||||
*
|
||||
* Retrieves user details (username, password, enabled flag, and authorities) from a JDBC location.
|
||||
* <p>
|
||||
* In order to minimise backward compatibility issues, this implementation doesn't recognise the expiration of user
|
||||
* A default database structure is assumed, (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link
|
||||
* #DEF_AUTHORITIES_BY_USERNAME_QUERY}, which most users of this class will need to override, if using an existing
|
||||
* scheme. This may be done by setting the default query strings used.
|
||||
* <p>
|
||||
* In order to minimise backward compatibility issues, this DAO does not recognise the expiration of user
|
||||
* accounts or the expiration of user credentials. However, it does recognise and honour the user enabled/disabled
|
||||
* column. This should map to a <tt>boolean</tt> type in the result set (the SQL type will depend on the
|
||||
* database you are using). All the other columns map to <tt>String</tt>s.
|
||||
*
|
||||
* <h3>Group Support</h3>
|
||||
* column.
|
||||
* <p>
|
||||
* Support for group-based authorities can be enabled by setting the <tt>enableGroups</tt> property to <tt>true</tt>
|
||||
* (you may also then wish to set <tt>enableAuthorities</tt> to <tt>false</tt> to disable loading of authorities
|
||||
* directly). With this approach, authorities are allocated to groups and a user's authorities are determined based
|
||||
* on the groups they are a member of. The net result is the same (a UserDetails containing a set of
|
||||
* <tt>GrantedAuthority</tt>s is loaded), but the different persistence strategy may be more suitable for the
|
||||
* administration of some applications.
|
||||
* <p>
|
||||
* When groups are being used, the tables "groups", "group_members" and "group_authorities" are used. See
|
||||
* {@link #DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY} for the default query which is used to load the group authorities.
|
||||
* Again you can customize this by setting the <tt>groupAuthoritiesByUsernameQuery</tt> property, but the format of
|
||||
* the rows returned should match the default.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author colin sampaleanu
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
|
||||
public Object executeWithContext(DirContext dirCtx) throws NamingException {
|
||||
LdapContext ctx = (LdapContext) dirCtx;
|
||||
ctx.removeFromEnvironment("com.sun.jndi.ldap.connect.pool");
|
||||
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, LdapUtils.getFullDn(dn, ctx).toString());
|
||||
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, LdapUtils.getFullDn(dn, ctx).toUrl());
|
||||
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, oldPassword);
|
||||
// TODO: reconnect doesn't appear to actually change the credentials
|
||||
try {
|
||||
|
||||
@@ -21,17 +21,11 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.security.firewall.DefaultHttpFirewall;
|
||||
import org.springframework.security.firewall.FirewalledRequest;
|
||||
import org.springframework.security.firewall.HttpFirewall;
|
||||
import org.springframework.security.intercept.web.*;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
@@ -40,7 +34,7 @@ import java.util.*;
|
||||
* Delegates <code>Filter</code> requests to a list of Spring-managed beans.
|
||||
* As of version 2.0, you shouldn't need to explicitly configure a <tt>FilterChainProxy</tt> bean in your application
|
||||
* context unless you need very fine control over the filter chain contents. Most cases should be adequately covered
|
||||
* by the default <tt><security:http /></tt> namespace configuration options.
|
||||
* by the default <tt><security:http /></tt> namespace configuration options.
|
||||
*
|
||||
* <p>The <code>FilterChainProxy</code> is loaded via a standard Spring {@link DelegatingFilterProxy} declaration in
|
||||
* <code>web.xml</code>. <code>FilterChainProxy</code> will then pass {@link #init(FilterConfig)}, {@link #destroy()}
|
||||
@@ -96,7 +90,6 @@ import java.util.*;
|
||||
* @author Carlos Sanchez
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
@@ -114,9 +107,7 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
/** Compiled pattern version of the filter chain map */
|
||||
private Map filterChainMap;
|
||||
private UrlMatcher matcher = new AntUrlPathMatcher();
|
||||
private boolean stripQueryStringFromUrls = true;
|
||||
private DefaultFilterInvocationDefinitionSource fids;
|
||||
private HttpFirewall firewall = new DefaultHttpFirewall();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -125,8 +116,8 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
if (fids != null) {
|
||||
Assert.isNull(uncompiledFilterChainMap, "Set the filterChainMap or FilterInvocationDefinitionSource but not both");
|
||||
FIDSToFilterChainMapConverter converter = new FIDSToFilterChainMapConverter(fids, applicationContext);
|
||||
setMatcher(converter.getMatcher());
|
||||
setFilterChainMap(converter.getFilterChainMap());
|
||||
setMatcher(converter.getMatcher());
|
||||
setFilterChainMap(converter.getFilterChainMap());
|
||||
fids = null;
|
||||
}
|
||||
|
||||
@@ -162,13 +153,10 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
}
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain)
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
FirewalledRequest fwRequest = firewall.getFirewalledRequest((HttpServletRequest) servletRequest);
|
||||
HttpServletResponse fwResponse = firewall.getFirewalledResponse((HttpServletResponse) response);
|
||||
|
||||
FilterInvocation fi = new FilterInvocation(fwRequest, fwResponse, chain);
|
||||
FilterInvocation fi = new FilterInvocation(request, response, chain);
|
||||
List filters = getFilters(fi.getRequestUrl());
|
||||
|
||||
if (filters == null || filters.size() == 0) {
|
||||
@@ -177,14 +165,12 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
filters == null ? " has no matching filters" : " has an empty filter list");
|
||||
}
|
||||
|
||||
fwRequest.reset();
|
||||
|
||||
chain.doFilter(fwRequest, response);
|
||||
chain.doFilter(request, response);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters, fwRequest);
|
||||
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters);
|
||||
virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
|
||||
}
|
||||
|
||||
@@ -195,16 +181,6 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
* @return an ordered array of Filters defining the filter chain
|
||||
*/
|
||||
public List getFilters(String url) {
|
||||
if (stripQueryStringFromUrls) {
|
||||
// String query string - see SEC-953
|
||||
int firstQuestionMarkIndex = url.indexOf("?");
|
||||
|
||||
if (firstQuestionMarkIndex != -1) {
|
||||
url = url.substring(0, firstQuestionMarkIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Iterator filterChains = filterChainMap.entrySet().iterator();
|
||||
|
||||
while (filterChains.hasNext()) {
|
||||
@@ -343,18 +319,6 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
return matcher;
|
||||
}
|
||||
|
||||
public void setFirewall(HttpFirewall firewall) {
|
||||
this.firewall = firewall;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to 'true', the query string will be stripped from the request URL before
|
||||
* attempting to find a matching filter chain. This is the default value.
|
||||
*/
|
||||
public void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) {
|
||||
this.stripQueryStringFromUrls = stripQueryStringFromUrls;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("FilterChainProxy[");
|
||||
@@ -377,13 +341,11 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
private static class VirtualFilterChain implements FilterChain {
|
||||
private FilterInvocation fi;
|
||||
private List additionalFilters;
|
||||
private FirewalledRequest firewalledRequest;
|
||||
private int currentPosition = 0;
|
||||
|
||||
private VirtualFilterChain(FilterInvocation filterInvocation, List additionalFilters, FirewalledRequest firewalledRequest) {
|
||||
private VirtualFilterChain(FilterInvocation filterInvocation, List additionalFilters) {
|
||||
this.fi = filterInvocation;
|
||||
this.additionalFilters = additionalFilters;
|
||||
this.firewalledRequest = firewalledRequest;
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response)
|
||||
@@ -393,8 +355,6 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
|
||||
logger.debug(fi.getRequestUrl()
|
||||
+ " reached end of additional filter chain; proceeding with original chain");
|
||||
}
|
||||
// Deactivate path stripping as we exit the security filter chain
|
||||
this.firewalledRequest.reset();
|
||||
|
||||
fi.getChain().doFilter(request, response);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
|
||||
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" +
|
||||
" xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n" +
|
||||
"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n" +
|
||||
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.6.xsd'>\n";
|
||||
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd'>\n";
|
||||
private static final String BEANS_CLOSE = "</b:beans>\n";
|
||||
|
||||
Resource inMemoryXml;
|
||||
|
||||
@@ -2,22 +2,18 @@ package org.springframework.security.util;
|
||||
|
||||
/**
|
||||
* Utilities for working with Strings and text.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class TextUtils {
|
||||
|
||||
public static String escapeEntities(String s) {
|
||||
if (s == null || s.length() == 0) {
|
||||
return s;
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
|
||||
for (int i=0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
|
||||
if(c == '<') {
|
||||
sb.append("<");
|
||||
} else if (c == '>') {
|
||||
@@ -26,14 +22,12 @@ public abstract class TextUtils {
|
||||
sb.append(""");
|
||||
} else if (c == '\'') {
|
||||
sb.append("'");
|
||||
} else if (c == '&') {
|
||||
sb.append("&");
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.springframework.security.vote;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.userdetails.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extended RoleVoter which uses a {@link RoleHierarchy} definition to determine the
|
||||
* roles allocated to the current user before voting.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class RoleHierarchyVoter extends RoleVoter {
|
||||
private RoleHierarchy roleHierarchy = null;
|
||||
|
||||
public RoleHierarchyVoter(RoleHierarchy roleHierarchy) {
|
||||
Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the <tt>RoleHierarchy</tt> to obtain the complete set of user authorities.
|
||||
*/
|
||||
GrantedAuthority[] extractAuthorities(Authentication authentication) {
|
||||
return roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,6 @@ public class RoleVoter implements AccessDecisionVoter {
|
||||
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
|
||||
int result = ACCESS_ABSTAIN;
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
GrantedAuthority[] authorities = extractAuthorities(authentication);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attribute = (ConfigAttribute) iter.next();
|
||||
@@ -103,6 +102,7 @@ public class RoleVoter implements AccessDecisionVoter {
|
||||
if (this.supports(attribute)) {
|
||||
result = ACCESS_DENIED;
|
||||
|
||||
GrantedAuthority[] authorities = authentication.getAuthorities();
|
||||
// Attempt to find a matching granted authority
|
||||
for (int i = 0; i < authorities.length; i++) {
|
||||
if (attribute.getAttribute().equals(authorities[i].getAuthority())) {
|
||||
@@ -114,8 +114,4 @@ public class RoleVoter implements AccessDecisionVoter {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GrantedAuthority[] extractAuthorities(Authentication authentication) {
|
||||
return authentication.getAuthorities();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user