Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 19f88e9179 | |||
| cf9b6bc0de | |||
| fc67550ff2 | |||
| af2a431f23 | |||
| 8d9b06afb4 | |||
| 0ecdd0e856 | |||
| edd2751ff1 | |||
| 8663ac4173 | |||
| 72213b5c69 | |||
| 2bbe70501b | |||
| da606d50c0 | |||
| d648a56e16 | |||
| 9c39a0e83e | |||
| c8692b6d0b | |||
| 45bbabd485 | |||
| 43fbeab106 | |||
| b719e0fbcc | |||
| 09bf290583 | |||
| 9a6f026dff | |||
| 269127c2c6 | |||
| 7074daac0e | |||
| 69446ab80f | |||
| 48bc0ad5f9 | |||
| db9584104c | |||
| b0701ea770 | |||
| 8cc9108601 | |||
| 41c9431fcc | |||
| 453e6332da | |||
| 969f3a7d1b | |||
| 4c19768e54 | |||
| ad1d858e2b | |||
| 7317c090cc | |||
| 485fbdc1ee | |||
| 22aa91c8e1 | |||
| ea873fb1b8 | |||
| 117f892c91 | |||
| 113b61e3a0 | |||
| dab4cf18b8 | |||
| be27ede0e9 | |||
| e8c9f75f9c | |||
| bc53945d89 | |||
| 432123daa2 | |||
| 92ae45a04d | |||
| a50d297f3a | |||
| 54dabb6433 | |||
| cd4a7e95cc | |||
| 07fb2af74b | |||
| ab1b7a1eb6 | |||
| 7c725a60e2 | |||
| 9b92d5a1e7 | |||
| e25b84c902 | |||
| 9654df2cc3 | |||
| a3df41b380 | |||
| abc445d5a7 | |||
| 518a1c3c08 | |||
| 1ca5946d74 | |||
| 76a2fb9488 | |||
| 2d448658cd | |||
| 4cafd575c0 | |||
| 0e36f85dab | |||
| b96cee7950 | |||
| e4517016ca | |||
| 08b1b56e2c | |||
| 316886affc | |||
| 75f57b96cb | |||
| 3832647ecf | |||
| aad4e70374 | |||
| 821333434d | |||
| 474d624e8e | |||
| 64938ebcfc | |||
| 3db01bd9d6 | |||
| 92c23fbbdc | |||
| a48cc18858 | |||
| ca0ffb8b5d | |||
| aed288da05 | |||
| 1f74ac811e | |||
| 350b48e3fd | |||
| 197ddb3cd1 | |||
| 848523e47a | |||
| 7b4a37f27e | |||
| 7b158d0525 | |||
| 0a118336d4 | |||
| 1a716d0593 | |||
| a67ef1c3a2 | |||
| 3099f92154 | |||
| a46ad0f446 | |||
| 013177c644 | |||
| 600927def6 | |||
| f1352ba492 | |||
| 81055feb82 | |||
| f548d89b27 | |||
| 1bca645add | |||
| e08e9cda00 | |||
| 09acc2b7a5 | |||
| 38e2e23b86 | |||
| b433cdda7e | |||
| 7000652fd1 | |||
| a1ff94a34e | |||
| 1087d19346 | |||
| d5dfeeca49 | |||
| 67762321f8 | |||
| 0bfbd2923a | |||
| 4fdfb8caba | |||
| 5fa5630bc3 | |||
| 0c77c2071b | |||
| ec89fdcfaa | |||
| 052bd32f40 | |||
| 5689383ab1 | |||
| e85e0de877 |
@@ -1,3 +1,5 @@
|
||||
image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
|
||||
|
||||
= Spring Security
|
||||
|
||||
Spring Security provides security services for the http://docs.spring.io[Spring IO Platform]. Spring Security 3.1 requires Spring 3.0.3 as
|
||||
|
||||
+14
-17
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<name>spring-security-acl</name>
|
||||
<description>spring-security-acl</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -30,12 +30,6 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
@@ -46,25 +40,22 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -76,13 +67,11 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -126,7 +115,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -138,22 +127,30 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.2.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
@@ -83,14 +83,14 @@ import org.springframework.util.StringUtils;
|
||||
* Alternatively, you could have used a common superclass or interface for the
|
||||
* {@link #processDomainObjectClass} if both <code>BankAccount</code> and
|
||||
* <code>Customer</code> had common parents.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If the principal does not have sufficient permissions, the voter will vote to deny
|
||||
* access.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* All comparisons and prefixes are case sensitive.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.springframework.security.acls;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -131,7 +132,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
p = permissionFactory.buildFromName(permString);
|
||||
}
|
||||
catch (IllegalArgumentException notfound) {
|
||||
p = permissionFactory.buildFromName(permString.toUpperCase());
|
||||
p = permissionFactory.buildFromName(permString.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
if (p != null) {
|
||||
|
||||
@@ -660,7 +660,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
private class StubAclParent implements Acl {
|
||||
private static class StubAclParent implements Acl {
|
||||
private final Long id;
|
||||
|
||||
public StubAclParent(Long id) {
|
||||
|
||||
@@ -192,7 +192,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
jdbcTemplate.update(insertClass, type);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
||||
return jdbcTemplate.queryForObject(classIdentityQuery, Long.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -252,7 +252,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
jdbcTemplate.update(insertSid, Boolean.valueOf(sidIsPrincipal), sidName);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
|
||||
return jdbcTemplate.queryForObject(sidIdentityQuery, Long.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -332,8 +332,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
*/
|
||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
try {
|
||||
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
|
||||
oid.getType(), oid.getIdentifier()));
|
||||
return jdbcTemplate.queryForObject(selectObjectIdentityPrimaryKey, Long.class,
|
||||
oid.getType(), oid.getIdentifier());
|
||||
}
|
||||
catch (DataAccessException notFound) {
|
||||
return null;
|
||||
|
||||
@@ -4,6 +4,8 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
@@ -36,4 +38,26 @@ public class AclPermissionEvaluatorTests {
|
||||
|
||||
assertTrue(pe.hasPermission(mock(Authentication.class), new Object(), "READ"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePermissionNonEnglishLocale() {
|
||||
Locale systemLocale = Locale.getDefault();
|
||||
Locale.setDefault(new Locale("tr"));
|
||||
|
||||
AclService service = mock(AclService.class);
|
||||
AclPermissionEvaluator pe = new AclPermissionEvaluator(service);
|
||||
ObjectIdentity oid = mock(ObjectIdentity.class);
|
||||
ObjectIdentityRetrievalStrategy oidStrategy = mock(ObjectIdentityRetrievalStrategy.class);
|
||||
when(oidStrategy.getObjectIdentity(anyObject())).thenReturn(oid);
|
||||
pe.setObjectIdentityRetrievalStrategy(oidStrategy);
|
||||
pe.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
|
||||
Acl acl = mock(Acl.class);
|
||||
|
||||
when(service.readAclById(any(ObjectIdentity.class), anyList())).thenReturn(acl);
|
||||
when(acl.isGranted(anyList(), anyList(), eq(false))).thenReturn(true);
|
||||
|
||||
assertTrue(pe.hasPermission(mock(Authentication.class), new Object(), "write"));
|
||||
|
||||
Locale.setDefault(systemLocale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,94 +9,94 @@
|
||||
-->
|
||||
|
||||
<beans>
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
||||
<property name="cacheManager">
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
|
||||
</property>
|
||||
<property name="cacheName" value="aclCache"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_USER"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
||||
<property name="cacheManager">
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
|
||||
</property>
|
||||
<property name="cacheName" value="aclCache"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_USER"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
|
||||
</bean>
|
||||
</bean>
|
||||
|
||||
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
<constructor-arg ref="aclAuthorizationStrategy"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
<constructor-arg ref="aclAuthorizationStrategy"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="lookupStrategy"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="lookupStrategy"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
|
||||
<!-- Uncomment to use PostgreSQL
|
||||
<property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))"/>
|
||||
<property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))"/>
|
||||
<property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))"/>
|
||||
<property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))"/>
|
||||
-->
|
||||
</bean>
|
||||
</bean>
|
||||
|
||||
<!-- PostgreSQL DataSource configuration
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.postgresql.Driver"/>
|
||||
<property name="url" value="jdbc:postgresql://localhost:5432/acltest"/>
|
||||
<property name="username" value="acltest"/>
|
||||
<property name="password" value="acltest"/>
|
||||
</bean>
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.postgresql.Driver"/>
|
||||
<property name="url" value="jdbc:postgresql://localhost:5432/acltest"/>
|
||||
<property name="username" value="acltest"/>
|
||||
<property name="password" value="acltest"/>
|
||||
</bean>
|
||||
-->
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="url" value="jdbc:hsqldb:mem:acltest"/>
|
||||
<property name="username" value="sa"/>
|
||||
<property name="password" value=""/>
|
||||
</bean>
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="url" value="jdbc:hsqldb:mem:acltest"/>
|
||||
<property name="username" value="sa"/>
|
||||
<property name="password" value=""/>
|
||||
</bean>
|
||||
|
||||
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
+14
-14
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<name>spring-security-aspects</name>
|
||||
<description>spring-security-aspects</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -30,35 +30,26 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -108,7 +99,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -120,16 +111,25 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.2.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
+19
-8
@@ -6,11 +6,11 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath("org.springframework.build.gradle:spring-io-plugin:0.0.3.RELEASE")
|
||||
classpath("io.spring.gradle:spring-io-plugin:0.0.4.RELEASE")
|
||||
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:1.2.5")
|
||||
classpath('me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1')
|
||||
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.1')
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.1")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ allprojects {
|
||||
|
||||
ext.releaseBuild = version.endsWith('RELEASE')
|
||||
ext.snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
ext.springVersion = '4.1.6.RELEASE'
|
||||
ext.springVersion = '4.2.2.RELEASE'
|
||||
ext.springLdapVersion = '2.0.2.RELEASE'
|
||||
|
||||
group = 'org.springframework.security'
|
||||
@@ -105,9 +105,15 @@ configure(coreModuleProjects) {
|
||||
jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
springIoTestRuntime {
|
||||
imports {
|
||||
mavenBom "io.spring.platform:platform-bom:${springIoVersion}"
|
||||
}
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
springIoVersions "io.spring.platform:platform-versions:${springIoVersion}@properties"
|
||||
jacoco "org.jacoco:org.jacoco.agent:0.6.2.201302030002:runtime"
|
||||
jacoco "org.jacoco:org.jacoco.agent:0.7.5.201505241946:runtime"
|
||||
}
|
||||
test {
|
||||
jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=${project.group}.*"
|
||||
@@ -129,7 +135,7 @@ task coreBuild {
|
||||
// Task for creating the distro zip
|
||||
|
||||
task dist(type: Zip) {
|
||||
dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' || task.name.endsWith('Zip') || task.name.endsWith('generatePom') }
|
||||
dependsOn { subprojects*.tasks*.matching { task -> task.name.endsWith('generatePom') } }
|
||||
classifier = 'dist'
|
||||
|
||||
evaluationDependsOn(':docs')
|
||||
@@ -139,14 +145,19 @@ task dist(type: Zip) {
|
||||
into(zipRootDir) {
|
||||
from(rootDir) {
|
||||
include '*.adoc'
|
||||
include '*.txt'
|
||||
}
|
||||
into('docs') {
|
||||
with(project(':docs').apiSpec)
|
||||
with(project(':docs:manual').spec)
|
||||
with(project(':docs:guides').spec)
|
||||
}
|
||||
into('dist') {
|
||||
from coreModuleProjects.collect {project -> project.libsDir }
|
||||
project.coreModuleProjects*.tasks*.withType(AbstractArchiveTask).flatten().each{ archiveTask ->
|
||||
if(archiveTask!=dist){
|
||||
into("$zipRootDir/dist") {
|
||||
from archiveTask.outputs.files
|
||||
}
|
||||
}
|
||||
}
|
||||
sampleProjects.each { project->
|
||||
into("$zipRootDir/samples/$project.name") {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package gae;
|
||||
|
||||
import com.google.appengine.tools.admin.AppCfg
|
||||
import org.gradle.api.*;
|
||||
|
||||
class GaePlugin implements Plugin<Project> {
|
||||
public void apply(Project project) {
|
||||
if (!project.hasProperty('appEngineSdkRoot')) {
|
||||
println "'appEngineSdkRoot' must be set in gradle.properties"
|
||||
} else {
|
||||
System.setProperty('appengine.sdk.root', project.property('appEngineSdkRoot'))
|
||||
}
|
||||
|
||||
File explodedWar = new File(project.buildDir, "gae-exploded")
|
||||
|
||||
project.task('gaeDeploy') << {
|
||||
AppCfg.main("update", explodedWar.toString())
|
||||
}
|
||||
|
||||
project.gaeDeploy.dependsOn project.war
|
||||
|
||||
project.war.doLast {
|
||||
ant.unzip(src: project.war.archivePath, dest: explodedWar)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
implementation-class=gae.GaePlugin
|
||||
+15
-15
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<name>spring-security-cas</name>
|
||||
<description>spring-security-cas</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -30,12 +30,6 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
@@ -46,31 +40,28 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -82,7 +73,6 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -126,7 +116,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -138,10 +128,20 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.2.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
+18
-18
@@ -1,23 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
<bean id="serviceProperties2"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example2.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
<bean id="serviceProperties2"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example2.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
|
||||
<constructor-arg ref="serviceProperties"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
|
||||
<constructor-arg ref="serviceProperties"/>
|
||||
</bean>
|
||||
</beans>
|
||||
+10
-10
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
<bean id="serviceProperties"
|
||||
class="org.springframework.security.cas.ServiceProperties">
|
||||
<property name="service"
|
||||
value="https://example.com/j_spring_security_cas"/>
|
||||
<property name="sendRenew" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
|
||||
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
|
||||
</beans>
|
||||
+26
-33
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<name>spring-security-config</name>
|
||||
<description>spring-security-config</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -30,12 +30,6 @@
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snasphot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
@@ -46,31 +40,27 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -96,63 +86,58 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-messaging</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-openid</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -267,7 +252,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -285,7 +270,7 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -297,31 +282,31 @@
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-support</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-core</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4-common</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-reflect</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -375,34 +360,42 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>4.0.0.CI-SNAPSHOT</version>
|
||||
<version>4.0.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>4.1.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.2.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
+150
-150
@@ -47,174 +47,174 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*
|
||||
*/
|
||||
class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSpec {
|
||||
def "default configuration"() {
|
||||
when:
|
||||
loadConfig(DefaultLdapConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "cn"
|
||||
provider.authoritiesPopulator.groupSearchBase == ""
|
||||
provider.authoritiesPopulator.groupSearchFilter == "(uniqueMember={0})"
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "ROLE_"
|
||||
def "default configuration"() {
|
||||
when:
|
||||
loadConfig(DefaultLdapConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "cn"
|
||||
provider.authoritiesPopulator.groupSearchBase == ""
|
||||
provider.authoritiesPopulator.groupSearchFilter == "(uniqueMember={0})"
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "ROLE_"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLdapConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLdapConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
|
||||
def "group roles custom"() {
|
||||
when:
|
||||
loadConfig(GroupRolesConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "group"
|
||||
}
|
||||
def "group roles custom"() {
|
||||
when:
|
||||
loadConfig(GroupRolesConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "group"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class GroupRolesConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupRoleAttribute("group")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class GroupRolesConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupRoleAttribute("group")
|
||||
}
|
||||
}
|
||||
|
||||
def "group search custom"() {
|
||||
when:
|
||||
loadConfig(GroupSearchConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupSearchFilter == "ou=groupName"
|
||||
}
|
||||
def "group search custom"() {
|
||||
when:
|
||||
loadConfig(GroupSearchConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
provider.authoritiesPopulator.groupSearchFilter == "ou=groupName"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class GroupSearchConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupSearchFilter("ou=groupName");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class GroupSearchConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.groupSearchFilter("ou=groupName");
|
||||
}
|
||||
}
|
||||
|
||||
def "role prefix custom"() {
|
||||
when:
|
||||
loadConfig(RolePrefixConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "role_"
|
||||
}
|
||||
def "role prefix custom"() {
|
||||
when:
|
||||
loadConfig(RolePrefixConfig)
|
||||
LdapAuthenticationProvider provider = ldapProvider()
|
||||
then:
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "role_"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RolePrefixConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.rolePrefix("role_")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RolePrefixConfig extends BaseLdapProviderConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.rolePrefix("role_")
|
||||
}
|
||||
}
|
||||
|
||||
def "bind authentication"() {
|
||||
when:
|
||||
loadConfig(BindAuthenticationConfig)
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
|
||||
}
|
||||
def "bind authentication"() {
|
||||
when:
|
||||
loadConfig(BindAuthenticationConfig)
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class BindAuthenticationConfig extends BaseLdapServerConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class BindAuthenticationConfig extends BaseLdapServerConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2472: Can use crypto PasswordEncoder"() {
|
||||
setup:
|
||||
loadConfig(PasswordEncoderConfig)
|
||||
when:
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
|
||||
}
|
||||
def "SEC-2472: Can use crypto PasswordEncoder"() {
|
||||
setup:
|
||||
loadConfig(PasswordEncoderConfig)
|
||||
when:
|
||||
AuthenticationManager auth = context.getBean(AuthenticationManager)
|
||||
then:
|
||||
auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class PasswordEncoderConfig extends BaseLdapServerConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.passwordEncoder(new BCryptPasswordEncoder())
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class PasswordEncoderConfig extends BaseLdapServerConfig {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.contextSource(contextSource())
|
||||
.passwordEncoder(new BCryptPasswordEncoder())
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people");
|
||||
}
|
||||
}
|
||||
|
||||
def ldapProvider() {
|
||||
context.getBean(AuthenticationManager).providers[0]
|
||||
}
|
||||
def ldapProvider() {
|
||||
context.getBean(AuthenticationManager).providers[0]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
||||
@Bean
|
||||
public ApacheDSContainer ldapServer() throws Exception {
|
||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
apacheDSContainer.setPort(getPort());
|
||||
return apacheDSContainer;
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
||||
@Bean
|
||||
public ApacheDSContainer ldapServer() throws Exception {
|
||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
apacheDSContainer.setPort(getPort());
|
||||
return apacheDSContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalAuthentication
|
||||
@Import(ObjectPostProcessorConfiguration)
|
||||
static abstract class BaseLdapProviderConfig {
|
||||
@Configuration
|
||||
@EnableGlobalAuthentication
|
||||
@Import(ObjectPostProcessorConfiguration)
|
||||
static abstract class BaseLdapProviderConfig {
|
||||
|
||||
@Bean
|
||||
public BaseLdapPathContextSource contextSource() throws Exception {
|
||||
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:"+ getPort() + "/dc=springframework,dc=org")
|
||||
contextSource.userDn = "uid=admin,ou=system"
|
||||
contextSource.password = "secret"
|
||||
contextSource.afterPropertiesSet()
|
||||
return contextSource;
|
||||
}
|
||||
@Bean
|
||||
public BaseLdapPathContextSource contextSource() throws Exception {
|
||||
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:"+ getPort() + "/dc=springframework,dc=org")
|
||||
contextSource.userDn = "uid=admin,ou=system"
|
||||
contextSource.password = "secret"
|
||||
contextSource.afterPropertiesSet()
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) {
|
||||
configure(auth)
|
||||
auth.build()
|
||||
}
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) {
|
||||
configure(auth)
|
||||
auth.build()
|
||||
}
|
||||
|
||||
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception
|
||||
}
|
||||
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception
|
||||
}
|
||||
|
||||
static Integer port;
|
||||
static Integer port;
|
||||
|
||||
static int getPort() {
|
||||
if(port == null) {
|
||||
ServerSocket socket = new ServerSocket(0)
|
||||
port = socket.localPort
|
||||
socket.close()
|
||||
}
|
||||
port
|
||||
}
|
||||
static int getPort() {
|
||||
if(port == null) {
|
||||
ServerSocket socket = new ServerSocket(0)
|
||||
port = socket.localPort
|
||||
socket.close()
|
||||
}
|
||||
port
|
||||
}
|
||||
}
|
||||
|
||||
+19
-19
@@ -37,24 +37,24 @@ import static org.springframework.security.config.annotation.authentication.ldap
|
||||
*/
|
||||
class LdapAuthenticationProviderConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "authentication-manager support multiple default ldap contexts (ports dynamically allocated)"() {
|
||||
when:
|
||||
loadConfig(MultiLdapAuthenticationProvidersConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
def "authentication-manager support multiple default ldap contexts (ports dynamically allocated)"() {
|
||||
when:
|
||||
loadConfig(MultiLdapAuthenticationProvidersConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.and()
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.and()
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-38
@@ -36,45 +36,45 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*
|
||||
*/
|
||||
class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
|
||||
def "ldap-authentication-provider"() {
|
||||
when:
|
||||
loadConfig(LdapAuthenticationProviderConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
def "ldap-authentication-provider"() {
|
||||
when:
|
||||
loadConfig(LdapAuthenticationProviderConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
|
||||
def "ldap-authentication-provider custom"() {
|
||||
when:
|
||||
loadConfig(CustomLdapAuthenticationProviderConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "cn"
|
||||
provider.authoritiesPopulator.groupSearchBase == "ou=groups"
|
||||
provider.authoritiesPopulator.groupSearchFilter == "(member={0})"
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "PREFIX_"
|
||||
provider.userDetailsContextMapper instanceof PersonContextMapper
|
||||
provider.authenticator.getUserDns("user") == ["uid=user,ou=people"]
|
||||
provider.authenticator.userSearch.searchBase == "ou=users"
|
||||
provider.authenticator.userSearch.searchFilter == "(uid={0})"
|
||||
}
|
||||
def "ldap-authentication-provider custom"() {
|
||||
when:
|
||||
loadConfig(CustomLdapAuthenticationProviderConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authoritiesPopulator.groupRoleAttribute == "cn"
|
||||
provider.authoritiesPopulator.groupSearchBase == "ou=groups"
|
||||
provider.authoritiesPopulator.groupSearchFilter == "(member={0})"
|
||||
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "PREFIX_"
|
||||
provider.userDetailsContextMapper instanceof PersonContextMapper
|
||||
provider.authenticator.getUserDns("user") == ["uid=user,ou=people"]
|
||||
provider.authenticator.userSearch.searchBase == "ou=users"
|
||||
provider.authenticator.userSearch.searchFilter == "(uid={0})"
|
||||
}
|
||||
|
||||
def "SEC-2490: ldap-authentication-provider custom LdapAuthoritiesPopulator"() {
|
||||
setup:
|
||||
LdapAuthoritiesPopulator LAP = Mock()
|
||||
CustomAuthoritiesPopulatorConfig.LAP = LAP
|
||||
when:
|
||||
loadConfig(CustomAuthoritiesPopulatorConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authoritiesPopulator == LAP
|
||||
}
|
||||
def "SEC-2490: ldap-authentication-provider custom LdapAuthoritiesPopulator"() {
|
||||
setup:
|
||||
LdapAuthoritiesPopulator LAP = Mock()
|
||||
CustomAuthoritiesPopulatorConfig.LAP = LAP
|
||||
when:
|
||||
loadConfig(CustomAuthoritiesPopulatorConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authoritiesPopulator == LAP
|
||||
}
|
||||
|
||||
def "ldap-authentication-provider password compare"() {
|
||||
when:
|
||||
loadConfig(PasswordCompareLdapConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authenticator instanceof PasswordComparisonAuthenticator
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
def "ldap-authentication-provider password compare"() {
|
||||
when:
|
||||
loadConfig(PasswordCompareLdapConfig)
|
||||
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
|
||||
then:
|
||||
provider.authenticator instanceof PasswordComparisonAuthenticator
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
}
|
||||
|
||||
+123
-123
@@ -21,161 +21,161 @@ import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper
|
||||
*/
|
||||
class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
|
||||
|
||||
// SEC-1182
|
||||
def multipleProvidersAreSupported() {
|
||||
xml.'ldap-server'(url: 'ldap://blah:389/dc=blah')
|
||||
xml.'authentication-manager'() {
|
||||
'ldap-authentication-provider'('group-search-filter': 'member={0}')
|
||||
'ldap-authentication-provider'('group-search-filter': 'uniqueMember={0}')
|
||||
}
|
||||
// SEC-1182
|
||||
def multipleProvidersAreSupported() {
|
||||
xml.'ldap-server'(url: 'ldap://blah:389/dc=blah')
|
||||
xml.'authentication-manager'() {
|
||||
'ldap-authentication-provider'('group-search-filter': 'member={0}')
|
||||
'ldap-authentication-provider'('group-search-filter': 'uniqueMember={0}')
|
||||
}
|
||||
|
||||
createAppContext('')
|
||||
createAppContext('')
|
||||
|
||||
def providers = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers
|
||||
def providers = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers
|
||||
|
||||
expect:
|
||||
expect:
|
||||
|
||||
providers.size() == 2
|
||||
providers[0].authoritiesPopulator.groupSearchFilter == "member={0}"
|
||||
providers[1].authoritiesPopulator.groupSearchFilter == "uniqueMember={0}"
|
||||
}
|
||||
providers.size() == 2
|
||||
providers[0].authoritiesPopulator.groupSearchFilter == "member={0}"
|
||||
providers[1].authoritiesPopulator.groupSearchFilter == "uniqueMember={0}"
|
||||
}
|
||||
|
||||
|
||||
def simpleProviderAuthenticatesCorrectly() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('group-search-filter':'member={0}')
|
||||
}
|
||||
def simpleProviderAuthenticatesCorrectly() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('group-search-filter':'member={0}')
|
||||
}
|
||||
|
||||
createAppContext('')
|
||||
createAppContext('')
|
||||
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
|
||||
def ben = auth.principal;
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
|
||||
def ben = auth.principal;
|
||||
|
||||
then:
|
||||
ben.authorities.size() == 3
|
||||
}
|
||||
then:
|
||||
ben.authorities.size() == 3
|
||||
}
|
||||
|
||||
def missingServerEltCausesConfigException() {
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'()
|
||||
}
|
||||
def missingServerEltCausesConfigException() {
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'()
|
||||
}
|
||||
|
||||
when:
|
||||
createAppContext('')
|
||||
when:
|
||||
createAppContext('')
|
||||
|
||||
then:
|
||||
thrown(ApplicationContextException)
|
||||
}
|
||||
then:
|
||||
thrown(ApplicationContextException)
|
||||
}
|
||||
|
||||
def supportsPasswordComparisonAuthentication() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people')
|
||||
'password-compare'
|
||||
}
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
def supportsPasswordComparisonAuthentication() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people')
|
||||
'password-compare'
|
||||
}
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
|
||||
|
||||
then:
|
||||
auth != null
|
||||
notThrown(AuthenticationException)
|
||||
}
|
||||
then:
|
||||
auth != null
|
||||
notThrown(AuthenticationException)
|
||||
}
|
||||
|
||||
def supportsPasswordComparisonAuthenticationWithHashAttribute() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'('password-attribute': 'uid', hash: 'plaintext')
|
||||
}
|
||||
}
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
def supportsPasswordComparisonAuthenticationWithHashAttribute() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'('password-attribute': 'uid', hash: 'plaintext')
|
||||
}
|
||||
}
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
|
||||
|
||||
then:
|
||||
auth != null
|
||||
notThrown(AuthenticationException)
|
||||
then:
|
||||
auth != null
|
||||
notThrown(AuthenticationException)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'('password-attribute': 'uid') {
|
||||
'password-encoder'(hash: 'plaintext')
|
||||
}
|
||||
}
|
||||
}
|
||||
def supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'('password-attribute': 'uid') {
|
||||
'password-encoder'(hash: 'plaintext')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
|
||||
|
||||
then:
|
||||
auth != null
|
||||
notThrown(AuthenticationException)
|
||||
}
|
||||
then:
|
||||
auth != null
|
||||
notThrown(AuthenticationException)
|
||||
}
|
||||
|
||||
def 'SEC-2472: Supports Crypto PasswordEncoder'() {
|
||||
setup:
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'() {
|
||||
'password-encoder'(ref: 'pe')
|
||||
}
|
||||
}
|
||||
}
|
||||
xml.'b:bean'(id:'pe','class':BCryptPasswordEncoder.class.name)
|
||||
def 'SEC-2472: Supports Crypto PasswordEncoder'() {
|
||||
setup:
|
||||
xml.'ldap-server'(ldif:'test-server.ldif')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
|
||||
'password-compare'() {
|
||||
'password-encoder'(ref: 'pe')
|
||||
}
|
||||
}
|
||||
}
|
||||
xml.'b:bean'(id:'pe','class':BCryptPasswordEncoder.class.name)
|
||||
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
createAppContext('')
|
||||
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
|
||||
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", 'password'))
|
||||
when:
|
||||
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", 'password'))
|
||||
|
||||
then:
|
||||
auth != null
|
||||
}
|
||||
then:
|
||||
auth != null
|
||||
}
|
||||
|
||||
def inetOrgContextMapperIsSupported() {
|
||||
xml.'ldap-server'(url: 'ldap://127.0.0.1:343/dc=springframework,dc=org')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-details-class' :'inetOrgPerson')
|
||||
}
|
||||
createAppContext('')
|
||||
def inetOrgContextMapperIsSupported() {
|
||||
xml.'ldap-server'(url: 'ldap://127.0.0.1:343/dc=springframework,dc=org')
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-details-class' :'inetOrgPerson')
|
||||
}
|
||||
createAppContext('')
|
||||
|
||||
expect:
|
||||
appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0].userDetailsContextMapper instanceof InetOrgPersonContextMapper
|
||||
}
|
||||
expect:
|
||||
appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0].userDetailsContextMapper instanceof InetOrgPersonContextMapper
|
||||
}
|
||||
|
||||
def ldapAuthenticationProviderWorksWithPlaceholders() {
|
||||
System.setProperty('udp','people')
|
||||
System.setProperty('gsf','member')
|
||||
def ldapAuthenticationProviderWorksWithPlaceholders() {
|
||||
System.setProperty('udp','people')
|
||||
System.setProperty('gsf','member')
|
||||
|
||||
xml.'ldap-server'()
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern':'uid={0},ou=${udp}','group-search-filter':'${gsf}={0}')
|
||||
}
|
||||
bean(PropertyPlaceholderConfigurer.class.name, PropertyPlaceholderConfigurer.class)
|
||||
xml.'ldap-server'()
|
||||
xml.'authentication-manager'{
|
||||
'ldap-authentication-provider'('user-dn-pattern':'uid={0},ou=${udp}','group-search-filter':'${gsf}={0}')
|
||||
}
|
||||
bean(PropertyPlaceholderConfigurer.class.name, PropertyPlaceholderConfigurer.class)
|
||||
|
||||
createAppContext('')
|
||||
def provider = this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0]
|
||||
createAppContext('')
|
||||
def provider = this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0]
|
||||
|
||||
expect:
|
||||
[new MessageFormat("uid={0},ou=people")] == FieldUtils.getFieldValue(provider,"authenticator.userDnFormat")
|
||||
"member={0}" == FieldUtils.getFieldValue(provider, "authoritiesPopulator.groupSearchFilter")
|
||||
}
|
||||
expect:
|
||||
[new MessageFormat("uid={0},ou=people")] == FieldUtils.getFieldValue(provider,"authenticator.userDnFormat")
|
||||
"member={0}" == FieldUtils.getFieldValue(provider, "authoritiesPopulator.groupSearchFilter")
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -85,8 +85,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext()
|
||||
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema "
|
||||
+ "with Spring Security 3.2. Please update your schema declarations to the 3.2 schema.",
|
||||
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema or spring-security-3.2.xsd schema "
|
||||
+ "with Spring Security 4.0. Please update your schema declarations to the 4.0 schema.",
|
||||
element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
|
||||
+7
-2
@@ -55,6 +55,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();
|
||||
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<SecurityConfigurer<O, B>>();
|
||||
|
||||
private final Map<Class<Object>, Object> sharedObjects = new HashMap<Class<Object>, Object>();
|
||||
|
||||
@@ -126,9 +127,9 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
|
||||
throws Exception {
|
||||
add(configurer);
|
||||
configurer.addObjectPostProcessor(objectPostProcessor);
|
||||
configurer.setBuilder((B) this);
|
||||
add(configurer);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@@ -202,7 +203,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
configs.add(configurer);
|
||||
this.configurers.put(clazz, configs);
|
||||
if (buildState.isInitializing()) {
|
||||
configurer.init((B) this);
|
||||
this.configurersAddedInInitializing.add(configurer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,6 +369,10 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
for (SecurityConfigurer<O, B> configurer : configurers) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
|
||||
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
|
||||
* Gets the {@link SecurityBuilder}. Cannot be null.
|
||||
*
|
||||
* @return the {@link SecurityBuilder}
|
||||
* @throw {@link IllegalStateException} if {@link SecurityBuilder} is null
|
||||
* @throws IllegalStateException if {@link SecurityBuilder} is null
|
||||
*/
|
||||
protected final B getBuilder() {
|
||||
if (securityBuilder == null) {
|
||||
|
||||
+2
-1
@@ -36,9 +36,10 @@ public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> ext
|
||||
* customizations must be done externally and the {@link ProviderManagerBuilder} is
|
||||
* returned immediately.
|
||||
*
|
||||
* Note that an Exception is thrown if an error occurs when adding the {@link AuthenticationProvider}.
|
||||
*
|
||||
* @return a {@link ProviderManagerBuilder} to allow further authentication to be
|
||||
* provided to the {@link ProviderManagerBuilder}
|
||||
* @throws Exception if an error occurs when adding the {@link AuthenticationProvider}
|
||||
*/
|
||||
B authenticationProvider(AuthenticationProvider authenticationProvider);
|
||||
}
|
||||
|
||||
+3
-4
@@ -61,7 +61,7 @@ public class AuthenticationManagerBuilder
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param the {@link ObjectPostProcessor} instance to use.
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
|
||||
*/
|
||||
public AuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor, true);
|
||||
@@ -196,7 +196,6 @@ public class AuthenticationManagerBuilder
|
||||
* <p>
|
||||
* This method <b>does NOT</b> ensure that a {@link UserDetailsService} is available
|
||||
* for the {@link #getDefaultUserDetailsService()} method.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link LdapAuthenticationProviderConfigurer} to allow customization of
|
||||
* the LDAP authentication
|
||||
@@ -216,11 +215,11 @@ public class AuthenticationManagerBuilder
|
||||
* <p>
|
||||
* This method <b>does NOT</b> ensure that the {@link UserDetailsService} is available
|
||||
* for the {@link #getDefaultUserDetailsService()} method.
|
||||
* </p>
|
||||
*
|
||||
* Note that an {@link Exception} might be thrown if an error occurs when adding the {@link AuthenticationProvider}.
|
||||
*
|
||||
* @return a {@link AuthenticationManagerBuilder} to allow further authentication to
|
||||
* be provided to the {@link AuthenticationManagerBuilder}
|
||||
* @throws Exception if an error occurs when adding the {@link AuthenticationProvider}
|
||||
*/
|
||||
public AuthenticationManagerBuilder authenticationProvider(
|
||||
AuthenticationProvider authenticationProvider) {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
* to have in memory authentication. It also allows easily adding users to the in memory
|
||||
* authentication.
|
||||
*
|
||||
* @param <B> the type of the {@link SecurityBuilder} that is being configured
|
||||
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
|
||||
+4
-5
@@ -38,7 +38,6 @@ import org.springframework.security.provisioning.JdbcUserDetailsManager;
|
||||
* <p>
|
||||
* The only required method is the {@link #dataSource(javax.sql.DataSource)} all other
|
||||
* methods have reasonable defaults.
|
||||
* </p>
|
||||
*
|
||||
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
|
||||
*
|
||||
@@ -82,7 +81,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
|
||||
* </code>
|
||||
* @param query The query to use for selecting the username, password, and if the user
|
||||
* is enabled by username. Must contain a single parameter for the username.
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
|
||||
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
|
||||
* customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -102,7 +101,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
|
||||
*
|
||||
* @param query The query to use for selecting the username, authority by username.
|
||||
* Must contain a single parameter for the username.
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
|
||||
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
|
||||
* customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -126,7 +125,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
|
||||
*
|
||||
* @param query The query to use for selecting the authorities by group. Must contain
|
||||
* a single parameter for the username.
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
|
||||
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
|
||||
* customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -181,7 +180,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
|
||||
/**
|
||||
* Populates the default schema that allows users and authorities to be stored.
|
||||
*
|
||||
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
|
||||
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
|
||||
* customizations
|
||||
*/
|
||||
public JdbcUserDetailsManagerConfigurer<B> withDefaultSchema() {
|
||||
|
||||
+2
-6
@@ -80,9 +80,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
|
||||
/**
|
||||
* Builds the user to be added. At minimum the username, password, and authorities
|
||||
* should provided. The remaining attributes have reasonable defaults.
|
||||
*
|
||||
* @param <T> the type of {@link UserDetailsManagerConfigurer} to return for chaining
|
||||
* methods.
|
||||
*/
|
||||
public class UserDetailsBuilder {
|
||||
private String username;
|
||||
@@ -103,11 +100,10 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link UserDetailsManagerRegistry} for method chaining (i.e. to add
|
||||
* Returns the {@link UserDetailsManagerConfigurer} for method chaining (i.e. to add
|
||||
* another user)
|
||||
*
|
||||
* @return the {@link UserDetailsManagerRegistry} for method chaining (i.e. to add
|
||||
* another user)
|
||||
* @return the {@link UserDetailsManagerConfigurer} for method chaining
|
||||
*/
|
||||
public C and() {
|
||||
return builder;
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*
|
||||
* @param <B> the type of the {@link SecurityBuilder}
|
||||
* @param <C> the {@link SecurityConfigurer} (or this)
|
||||
* @param <B> the type of the {@link ProviderManagerBuilder}
|
||||
* @param <C> the {@link UserDetailsServiceConfigurer} (or this)
|
||||
* @param <U> the type of UserDetailsService being used to allow for returning the
|
||||
* concrete UserDetailsService.
|
||||
*/
|
||||
|
||||
+1
-2
@@ -29,9 +29,8 @@ import org.springframework.security.config.annotation.configuration.ObjectPostPr
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Enables Spring Security global method security similar to the <global-method-security>
|
||||
* Enables Spring Security global method security similar to the <global-method-security>
|
||||
* xml support.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* More advanced configurations may wish to extend
|
||||
|
||||
-4
@@ -15,14 +15,10 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
|
||||
+5
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,9 +23,11 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -45,7 +47,6 @@ import org.springframework.security.access.intercept.AfterInvocationManager;
|
||||
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
|
||||
import org.springframework.security.access.intercept.RunAsManager;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
|
||||
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.method.MethodSecurityMetadataSource;
|
||||
@@ -317,21 +318,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
return preInvocationAdvice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the {@link MethodSecurityMetadataSourceAdvisor} to be used.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@Bean
|
||||
public MethodSecurityMetadataSourceAdvisor metaDataSourceAdvisor() {
|
||||
MethodSecurityMetadataSourceAdvisor methodAdvisor = new MethodSecurityMetadataSourceAdvisor(
|
||||
"methodSecurityInterceptor", methodSecurityMetadataSource(),
|
||||
"methodSecurityMetadataSource");
|
||||
methodAdvisor.setOrder(order());
|
||||
return methodAdvisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the attributes from {@link EnableGlobalMethodSecurity} if this class was
|
||||
* imported using the {@link EnableGlobalMethodSecurity} annotation.
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,13 +54,18 @@ final class GlobalMethodSecuritySelector implements ImportSelector {
|
||||
.isAssignableFrom(importingClass);
|
||||
|
||||
AdviceMode mode = attributes.getEnum("mode");
|
||||
String autoProxyClassName = AdviceMode.PROXY == mode ? AutoProxyRegistrar.class
|
||||
boolean isProxy = AdviceMode.PROXY == mode;
|
||||
String autoProxyClassName = isProxy ? AutoProxyRegistrar.class
|
||||
.getName() : GlobalMethodSecurityAspectJAutoProxyRegistrar.class
|
||||
.getName();
|
||||
|
||||
boolean jsr250Enabled = attributes.getBoolean("jsr250Enabled");
|
||||
|
||||
List<String> classNames = new ArrayList<String>(4);
|
||||
if(isProxy) {
|
||||
classNames.add(MethodSecurityMetadataSourceAdvisorRegistrar.class.getName());
|
||||
}
|
||||
|
||||
classNames.add(autoProxyClassName);
|
||||
|
||||
if (!skipMethodSecurityConfiguration) {
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Creates Spring Security's MethodSecurityMetadataSourceAdvisor only when
|
||||
* using proxy based method security (i.e. do not do it when using ASPECTJ).
|
||||
* The conditional logic is controlled through {@link GlobalMethodSecuritySelector}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 4.0.2
|
||||
* @see GlobalMethodSecuritySelector
|
||||
*/
|
||||
class MethodSecurityMetadataSourceAdvisorRegistrar implements
|
||||
ImportBeanDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
|
||||
* of the @{@link EnableGlobalMethodSecurity#proxyTargetClass()} attribute on the
|
||||
* importing {@code @Configuration} class.
|
||||
*/
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
|
||||
BeanDefinitionBuilder advisor = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
|
||||
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisor.addConstructorArgValue("methodSecurityInterceptor");
|
||||
advisor.addConstructorArgReference("methodSecurityMetadataSource");
|
||||
advisor.addConstructorArgValue("methodSecurityMetadataSource");
|
||||
|
||||
MultiValueMap<String,Object> attributes = importingClassMetadata.getAllAnnotationAttributes(EnableGlobalMethodSecurity.class.getName());
|
||||
Integer order = (Integer) attributes.getFirst("order");
|
||||
if(order != null) {
|
||||
advisor.addPropertyValue("order", order);
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition("metaDataSourceAdvisor",
|
||||
advisor.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
+16
-1
@@ -25,6 +25,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for
|
||||
@@ -48,6 +49,20 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return requestMatchers(ANY_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
|
||||
* instances.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use for any
|
||||
* {@link HttpMethod}.
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
*/
|
||||
public C antMatchers(HttpMethod method) {
|
||||
return antMatchers(method, new String[] { "/**" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
|
||||
@@ -55,7 +70,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create
|
||||
* @param antPatterns the ant patterns to create. If {@code null} or empty, then matches on nothing.
|
||||
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||
|
||||
+2
-2
@@ -142,11 +142,11 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
|
||||
* <li>{@link LogoutFilter}</li>
|
||||
* <li>{@link X509AuthenticationFilter}</li>
|
||||
* <li>{@link AbstractPreAuthenticatedProcessingFilter}</li>
|
||||
* <li>{@link org.springframework.security.cas.web.CasAuthenticationFilter}</li>
|
||||
* <li><a href="{@docRoot}/org/springframework/security/cas/web/CasAuthenticationFilter.html">CasAuthenticationFilter</a></li>
|
||||
* <li>{@link UsernamePasswordAuthenticationFilter}</li>
|
||||
* <li>{@link ConcurrentSessionFilter}</li>
|
||||
* <li>{@link OpenIDAuthenticationFilter}</li>
|
||||
* <li>{@link DefaultLoginPageGeneratingFilter}</li>
|
||||
* <li>{@link org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter}</li>
|
||||
* <li>{@link ConcurrentSessionFilter}</li>
|
||||
* <li>{@link DigestAuthenticationFilter}</li>
|
||||
* <li>{@link BasicAuthenticationFilter}</li>
|
||||
|
||||
+10
-6
@@ -71,7 +71,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the
|
||||
* A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the
|
||||
* namespace configuration. It allows configuring web based security for specific http
|
||||
* requests. By default it will be applied to all requests, but can be restricted using
|
||||
* {@link #requestMatcher(RequestMatcher)} or other similar methods.
|
||||
@@ -283,7 +283,7 @@ public final class HttpSecurity extends
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
* @see {@link HeadersConfigurer}
|
||||
* @see HeadersConfigurer
|
||||
*/
|
||||
public HeadersConfigurer<HttpSecurity> headers() throws Exception {
|
||||
return getOrApply(new HeadersConfigurer<HttpSecurity>());
|
||||
@@ -326,8 +326,8 @@ public final class HttpSecurity extends
|
||||
*
|
||||
* <pre>
|
||||
* <listener>
|
||||
* <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
|
||||
* </listener>
|
||||
* <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
|
||||
* </listener>
|
||||
* </pre>
|
||||
*
|
||||
* Alternatively,
|
||||
@@ -378,7 +378,7 @@ public final class HttpSecurity extends
|
||||
*
|
||||
* @return the {@link PortMapperConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
* @see {@link #requiresChannel()}
|
||||
* @see #requiresChannel()
|
||||
*/
|
||||
public PortMapperConfigurer<HttpSecurity> portMapper() throws Exception {
|
||||
return getOrApply(new PortMapperConfigurer<HttpSecurity>());
|
||||
@@ -716,7 +716,7 @@ public final class HttpSecurity extends
|
||||
* {@link org.springframework.security.authentication.AnonymousAuthenticationToken}
|
||||
* and contain the role "ROLE_ANONYMOUS".
|
||||
*
|
||||
* <h2>Example Configuration</h2
|
||||
* <h2>Example Configuration</h2>
|
||||
*
|
||||
* The following configuration demonstrates how to specify that anonymous users should
|
||||
* contain the role "ROLE_ANON" instead.
|
||||
@@ -908,6 +908,10 @@ public final class HttpSecurity extends
|
||||
return getOrApply(new HttpBasicConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
public <C> void setSharedObject(Class<C> sharedType, C object) {
|
||||
super.setSharedObject(sharedType, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeConfigure() throws Exception {
|
||||
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 4.0
|
||||
*/
|
||||
@Conditional(OnMissingBeanCondition.class)
|
||||
@interface ConditionalOnMissingBean {
|
||||
|
||||
Class<?> value();
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.ConfigurationCondition;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class OnMissingBeanCondition implements ConfigurationCondition {
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.REGISTER_BEAN;
|
||||
}
|
||||
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
Map<String, Object> attrs = metadata
|
||||
.getAnnotationAttributes(ConditionalOnMissingBean.class.getName());
|
||||
|
||||
Class<?> type = (Class) attrs.get("value");
|
||||
final Map<String, ?> beans = context.getBeanFactory().getBeansOfType(type);
|
||||
return beans.isEmpty();
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -29,7 +29,7 @@ import java.util.List;
|
||||
/**
|
||||
* Used to add a {@link RequestDataValueProcessor} for Spring MVC and Spring Security CSRF
|
||||
* integration. This configuration is added whenever {@link EnableWebMvc} is added by
|
||||
* {@link SpringWebMvcImportSelector} and the DispatcherServlet is present on the
|
||||
* <a href="{@docRoot}/org/springframework/security/config/annotation/web/configuration/SpringWebMvcImportSelector.html">SpringWebMvcImportSelector</a> and the DispatcherServlet is present on the
|
||||
* classpath. It also adds the {@link AuthenticationPrincipalArgumentResolver} as a
|
||||
* {@link HandlerMethodArgumentResolver}.
|
||||
*
|
||||
@@ -47,7 +47,6 @@ class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
|
||||
argumentResolvers.add(new CsrfTokenArgumentResolver());
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(RequestDataValueProcessor.class)
|
||||
@Bean
|
||||
public RequestDataValueProcessor requestDataValueProcessor() {
|
||||
return new CsrfRequestDataValueProcessor();
|
||||
|
||||
+2
-2
@@ -262,7 +262,7 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
* {@link #userDetailsService()} instead
|
||||
* @return
|
||||
* @throws Exception
|
||||
* @see {@link #userDetailsService()}
|
||||
* @see #userDetailsService()
|
||||
*/
|
||||
public UserDetailsService userDetailsServiceBean() throws Exception {
|
||||
AuthenticationManagerBuilder globalAuthBuilder = context
|
||||
@@ -273,7 +273,7 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
|
||||
/**
|
||||
* Allows modifying and accessing the {@link UserDetailsService} from
|
||||
* {@link #userDetailsServiceBean()()} without interacting with the
|
||||
* {@link #userDetailsServiceBean()} without interacting with the
|
||||
* {@link ApplicationContext}. Developers should override this method when changing
|
||||
* the instance of {@link #userDetailsServiceBean()}.
|
||||
*
|
||||
|
||||
+2
-2
@@ -178,8 +178,8 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the urls for {@link #failureUrl(String)} and
|
||||
* {@link #authenticationUrls(String)} are granted access to any user.
|
||||
* Ensures the urls for {@link #failureUrl(String)} as well as for the {@link HttpSecurityBuilder}, the
|
||||
* {@link #getLoginPage} and {@link #getLoginProcessingUrl} are granted access to any user.
|
||||
*
|
||||
* @param permitAll true to grant access to the URLs false to skip this step
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
|
||||
+5
-5
@@ -51,7 +51,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}
|
||||
* {@link AuthenticationManager}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
@@ -108,7 +108,6 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
|
||||
* @return the {@link AccessDecisionVoter} instances used to create the default
|
||||
* {@link AccessDecisionManager}
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
abstract List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http);
|
||||
|
||||
abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T>
|
||||
@@ -116,7 +115,7 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
|
||||
|
||||
/**
|
||||
* Allows setting the {@link AccessDecisionManager}. If none is provided, a
|
||||
* default {@l AccessDecisionManager} is created.
|
||||
* default {@link AccessDecisionManager} is created.
|
||||
*
|
||||
* @param accessDecisionManager the {@link AccessDecisionManager} to use
|
||||
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
|
||||
@@ -157,12 +156,13 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
|
||||
* @return the default {@code AccessDecisionManager}
|
||||
*/
|
||||
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
|
||||
return new AffirmativeBased(getDecisionVoters(http));
|
||||
AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
|
||||
return postProcess(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* If currently null, creates a default {@link AccessDecisionManager} using
|
||||
* {@link #createDefaultAccessDecisionManager()}. Otherwise returns the
|
||||
* {@link #createDefaultAccessDecisionManager(HttpSecurityBuilder)}. Otherwise returns the
|
||||
* {@link AccessDecisionManager}.
|
||||
*
|
||||
* @param http the builder to use
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @param accessDeniedUrl the URL to the access denied page (i.e. /errors/401)
|
||||
* @return the {@link ExceptionHandlingConfigurer} for further customization
|
||||
* @see AccessDeniedHandlerImpl
|
||||
* @see {@link #accessDeniedHandler(org.springframework.security.web.access.AccessDeniedHandler)}
|
||||
* @see #accessDeniedHandler(org.springframework.security.web.access.AccessDeniedHandler)
|
||||
*/
|
||||
public ExceptionHandlingConfigurer<H> accessDeniedPage(String accessDeniedUrl) {
|
||||
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
|
||||
+3
-3
@@ -70,7 +70,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()}
|
||||
* @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()
|
||||
*/
|
||||
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends
|
||||
@@ -339,7 +339,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry rememberMe() {
|
||||
return access(rememberMe);
|
||||
@@ -371,7 +371,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
*
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
* customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public ExpressionInterceptUrlRegistry fullyAuthenticated() {
|
||||
return access(fullyAuthenticated);
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link AuthenticationManager}</li>
|
||||
* <li>{@link org.springframework.security.authentication.AuthenticationManager}</li>
|
||||
* <li>{@link RememberMeServices} - is optionally used. See {@link RememberMeConfigurer}</li>
|
||||
* <li>{@link SessionAuthenticationStrategy} - is optionally used. See
|
||||
* {@link SessionManagementConfigurer}</li>
|
||||
|
||||
+1
-1
@@ -186,7 +186,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
* X-XSS-Protection: 1
|
||||
* </pre>
|
||||
*
|
||||
* or if {@link #setBlock(boolean)} is true
|
||||
* or if {@link XXssProtectionHeaderWriter#setBlock(boolean)} of the given {@link XXssProtectionHeaderWriter} is true
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
|
||||
+7
-1
@@ -29,6 +29,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
@@ -65,6 +66,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link AuthenticationManager}</li>
|
||||
* <li>{@link RememberMeServices}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
@@ -81,7 +83,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @throws Exception
|
||||
* @see {@link HttpSecurity#httpBasic()}
|
||||
* @see HttpSecurity#httpBasic()
|
||||
*/
|
||||
public HttpBasicConfigurer() throws Exception {
|
||||
realmName(DEFAULT_REALM);
|
||||
@@ -177,6 +179,10 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
basicAuthenticationFilter
|
||||
.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
}
|
||||
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
|
||||
if(rememberMeServices != null) {
|
||||
basicAuthenticationFilter.setRememberMeServices(rememberMeServices);
|
||||
}
|
||||
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
|
||||
http.addFilter(basicAuthenticationFilter);
|
||||
}
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
* Populates a {@link PreAuthenticatedAuthenticationProvider} into
|
||||
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
|
||||
* and a {@link Http403ForbiddenEntryPoint} into
|
||||
* {@link HttpSecurity#authenticationEntryPoint(org.springframework.security.web.AuthenticationEntryPoint)}
|
||||
* {@link HttpSecurityBuilder#setSharedObject(Class, Object)}
|
||||
*
|
||||
* @see org.springframework.security.config.annotation.SecurityConfigurerAdapter#init(org.springframework.security.config.annotation.SecurityBuilder)
|
||||
*/
|
||||
|
||||
+13
-1
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpSession;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
@@ -35,7 +36,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
/**
|
||||
* Adds logout support. Other {@link SecurityConfigurer} instances may invoke
|
||||
* {@link #addLogoutHandler(LogoutHandler)} in the {@link #init(HttpSecurity)} phase.
|
||||
* {@link #addLogoutHandler(LogoutHandler)} in the {@link #init(HttpSecurityBuilder)} phase.
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
@@ -88,6 +89,17 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if {@link SecurityContextLogoutHandler} should clear the {@link Authentication} at the time of logout.
|
||||
* @param clearAuthentication true {@link SecurityContextLogoutHandler} should clear the {@link Authentication} (default), or false otherwise.
|
||||
* @return the {@link LogoutConfigurer} for further customization
|
||||
*/
|
||||
public LogoutConfigurer<H> clearAuthentication(boolean clearAuthentication) {
|
||||
contextLogoutHandler.setClearAuthentication(clearAuthentication);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configures {@link SecurityContextLogoutHandler} to invalidate the
|
||||
* {@link HttpSession} at the time of logout.
|
||||
|
||||
+13
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -180,6 +180,18 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extend
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of cookie which store the token for remember me authentication. Defaults to 'remember-me'.
|
||||
*
|
||||
* @param rememberMeCookieName the name of cookie which store the token for remember me authentication
|
||||
* @return the {@link RememberMeConfigurer} for further customization
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public RememberMeConfigurer<H> rememberMeCookieName(String rememberMeCookieName) {
|
||||
this.rememberMeCookieName = rememberMeCookieName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows control over the destination a remembered user is sent to when they are
|
||||
* successfully authenticated. By default, the filter will just allow the current
|
||||
|
||||
+4
@@ -20,6 +20,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
|
||||
@@ -85,6 +86,9 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>> e
|
||||
|
||||
SecurityContextRepository securityContextRepository = http
|
||||
.getSharedObject(SecurityContextRepository.class);
|
||||
if(securityContextRepository == null) {
|
||||
securityContextRepository = new HttpSessionSecurityContextRepository();
|
||||
}
|
||||
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
|
||||
securityContextRepository);
|
||||
SessionManagementConfigurer<?> sessionManagement = http
|
||||
|
||||
+1
-1
@@ -199,7 +199,7 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* {@link HttpServletRequest} matches this URL the {@link OpenIDAuthenticationFilter}
|
||||
* will attempt to authenticate the request. The default is "/login/openid".
|
||||
*
|
||||
* @param loginUrl the URL used to perform authentication
|
||||
* @param loginProcessingUrl the URL used to perform authentication
|
||||
* @return the {@link OpenIDLoginConfigurer} for additional customization
|
||||
*/
|
||||
public OpenIDLoginConfigurer<H> loginProcessingUrl(String loginProcessingUrl) {
|
||||
|
||||
+31
-9
@@ -15,9 +15,17 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.messaging;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
|
||||
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
|
||||
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
|
||||
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcher;
|
||||
@@ -28,8 +36,6 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Allows mapping security constraints using {@link MessageMatcher} to the security
|
||||
* expressions.
|
||||
@@ -45,6 +51,8 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
private static final String fullyAuthenticated = "fullyAuthenticated";
|
||||
private static final String rememberMe = "rememberMe";
|
||||
|
||||
private SecurityExpressionHandler<Message<Object>> expressionHandler = new DefaultMessageSecurityExpressionHandler<Object>();
|
||||
|
||||
private final LinkedHashMap<MatcherBuilder, String> matcherToExpression = new LinkedHashMap<MatcherBuilder, String>();
|
||||
|
||||
private DelegatingPathMatcher pathMatcher = new DelegatingPathMatcher();
|
||||
@@ -97,7 +105,7 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
* {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)} .
|
||||
*
|
||||
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
|
||||
* @see {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}
|
||||
* @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
|
||||
*/
|
||||
public Constraint simpDestMatchers(String... patterns) {
|
||||
return simpDestMatchers(null, patterns);
|
||||
@@ -114,7 +122,7 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
* {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}.
|
||||
*
|
||||
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
|
||||
* @see {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}
|
||||
* @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
|
||||
*/
|
||||
public Constraint simpMessageDestMatchers(String... patterns) {
|
||||
return simpDestMatchers(SimpMessageType.MESSAGE, patterns);
|
||||
@@ -131,7 +139,7 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
* {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}.
|
||||
*
|
||||
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
|
||||
* @see {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}
|
||||
* @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
|
||||
*/
|
||||
public Constraint simpSubscribeDestMatchers(String... patterns) {
|
||||
return simpDestMatchers(SimpMessageType.SUBSCRIBE, patterns);
|
||||
@@ -200,6 +208,20 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
return new Constraint(builders);
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SecurityExpressionHandler} to be used. The
|
||||
* default is to use {@link DefaultMessageSecurityExpressionHandler}.
|
||||
*
|
||||
* @param expressionHandler the {@link SecurityExpressionHandler} to use. Cannot be null.
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
|
||||
* customization.
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry expressionHandler(SecurityExpressionHandler<Message<Object>> expressionHandler) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to create creating a {@link MessageSecurityMetadataSource}.
|
||||
*
|
||||
@@ -217,7 +239,7 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
matcherToExpression.put(entry.getKey().build(), entry.getValue());
|
||||
}
|
||||
return ExpressionBasedMessageSecurityMetadataSourceFactory
|
||||
.createExpressionMessageMetadataSource(matcherToExpression);
|
||||
.createExpressionMessageMetadataSource(matcherToExpression, expressionHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,7 +353,7 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
|
||||
* customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry rememberMe() {
|
||||
return access(rememberMe);
|
||||
@@ -363,7 +385,7 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
*
|
||||
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
|
||||
* customization
|
||||
* @see {@link RememberMeConfigurer}
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public MessageSecurityMetadataSourceRegistry fullyAuthenticated() {
|
||||
return access(fullyAuthenticated);
|
||||
@@ -410,7 +432,7 @@ public class MessageSecurityMetadataSourceRegistry {
|
||||
return "hasAnyAuthority('" + anyAuthorities + "')";
|
||||
}
|
||||
|
||||
private class PreBuiltMatcherBuilder implements MatcherBuilder {
|
||||
private static class PreBuiltMatcherBuilder implements MatcherBuilder {
|
||||
private MessageMatcher<?> matcher;
|
||||
|
||||
private PreBuiltMatcherBuilder(MessageMatcher<?> matcher) {
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
/**
|
||||
* Used to add a {@link RequestDataValueProcessor} for Spring MVC and Spring Security CSRF
|
||||
* integration. This configuration is added whenever {@link EnableWebMvc} is added by
|
||||
* {@link SpringWebMvcImportSelector} and the DispatcherServlet is present on the
|
||||
* <a href="{@docRoot}/org/springframework/security/config/annotation/web/configuration/SpringWebMvcImportSelector.html">SpringWebMvcImportSelector</a> and the DispatcherServlet is present on the
|
||||
* classpath. It also adds the {@link AuthenticationPrincipalArgumentResolver} as a
|
||||
* {@link HandlerMethodArgumentResolver}.
|
||||
*
|
||||
|
||||
+22
-2
@@ -26,10 +26,12 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
||||
import org.springframework.messaging.simp.config.ChannelRegistration;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
|
||||
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
|
||||
@@ -80,6 +82,8 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
|
||||
AbstractWebSocketMessageBrokerConfigurer implements SmartInitializingSingleton {
|
||||
private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry();
|
||||
|
||||
private SecurityExpressionHandler<Message<Object>> expressionHandler;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
@@ -145,8 +149,14 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
|
||||
public ChannelSecurityInterceptor inboundChannelSecurity() {
|
||||
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
|
||||
inboundMessageSecurityMetadataSource());
|
||||
MessageExpressionVoter<Object> voter = new MessageExpressionVoter<Object>();
|
||||
if(expressionHandler != null) {
|
||||
voter.setExpressionHandler(expressionHandler);
|
||||
}
|
||||
|
||||
List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>();
|
||||
voters.add(new MessageExpressionVoter<Object>());
|
||||
voters.add(voter);
|
||||
|
||||
AffirmativeBased manager = new AffirmativeBased(voters);
|
||||
channelSecurityInterceptor.setAccessDecisionManager(manager);
|
||||
return channelSecurityInterceptor;
|
||||
@@ -159,6 +169,9 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
|
||||
|
||||
@Bean
|
||||
public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() {
|
||||
if(expressionHandler != null) {
|
||||
inboundRegistry.expressionHandler(expressionHandler);
|
||||
}
|
||||
configureInbound(inboundRegistry);
|
||||
return inboundRegistry.createMetadataSource();
|
||||
}
|
||||
@@ -170,7 +183,7 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
}
|
||||
|
||||
private class WebSocketMessageSecurityMetadataSourceRegistry extends
|
||||
private static class WebSocketMessageSecurityMetadataSourceRegistry extends
|
||||
MessageSecurityMetadataSourceRegistry {
|
||||
@Override
|
||||
public MessageSecurityMetadataSource createMetadataSource() {
|
||||
@@ -193,6 +206,13 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setMessageExpessionHandler(List<SecurityExpressionHandler<Message<Object>>> expressionHandlers) {
|
||||
if(expressionHandlers.size() == 1) {
|
||||
this.expressionHandler = expressionHandlers.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterSingletonsInstantiated() {
|
||||
if (sameOriginDisabled()) {
|
||||
return;
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Stateful parser for the <password-encoder> element.
|
||||
* Stateful parser for the <password-encoder> element.
|
||||
*
|
||||
* Will produce a PasswordEncoder and (optionally) a SaltSource.
|
||||
*
|
||||
|
||||
+7
-25
@@ -131,6 +131,10 @@ final class AuthenticationConfigBuilder {
|
||||
private String loginProcessingUrl;
|
||||
private String openidLoginProcessingUrl;
|
||||
|
||||
private String formLoginPage;
|
||||
|
||||
private String openIDLoginPage;
|
||||
|
||||
public AuthenticationConfigBuilder(Element element, boolean forceAutoConfig,
|
||||
ParserContext pc, SessionCreationPolicy sessionPolicy,
|
||||
BeanReference requestCache, BeanReference authenticationManager,
|
||||
@@ -212,6 +216,7 @@ final class AuthenticationConfigBuilder {
|
||||
formFilter = parser.getFilterBean();
|
||||
formEntryPoint = parser.getEntryPointBean();
|
||||
loginProcessingUrl = parser.getLoginProcessingUrl();
|
||||
formLoginPage = parser.getLoginPage();
|
||||
}
|
||||
|
||||
if (formFilter != null) {
|
||||
@@ -242,6 +247,7 @@ final class AuthenticationConfigBuilder {
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
openidLoginProcessingUrl = parser.getLoginProcessingUrl();
|
||||
openIDLoginPage = parser.getLoginPage();
|
||||
|
||||
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt,
|
||||
Elements.OPENID_ATTRIBUTE_EXCHANGE);
|
||||
@@ -527,8 +533,6 @@ final class AuthenticationConfigBuilder {
|
||||
|
||||
void createLoginPageFilterIfNeeded() {
|
||||
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
|
||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
|
||||
|
||||
// If no login page has been defined, add in the default page generator.
|
||||
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
|
||||
@@ -556,7 +560,7 @@ final class AuthenticationConfigBuilder {
|
||||
void createLogoutFilter() {
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||
String formLoginPage = this.formLoginPage;
|
||||
if (formLoginPage == null) {
|
||||
formLoginPage = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
|
||||
}
|
||||
@@ -716,8 +720,6 @@ final class AuthenticationConfigBuilder {
|
||||
// If formLogin has been enabled either through an element or auto-config, then it
|
||||
// is used if no openID login page
|
||||
// has been set.
|
||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
|
||||
|
||||
if (formLoginPage != null && openIDLoginPage != null) {
|
||||
pc.getReaderContext().error(
|
||||
@@ -747,26 +749,6 @@ final class AuthenticationConfigBuilder {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getLoginFormUrl(BeanDefinition entryPoint) {
|
||||
if (entryPoint == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ConstructorArgumentValues cavs = entryPoint.getConstructorArgumentValues();
|
||||
ValueHolder vh = cavs.getIndexedArgumentValue(0, String.class);
|
||||
if (vh == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the login URL is the default one, then it is assumed not to have been set
|
||||
// explicitly
|
||||
if (DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL.equals(vh.getValue())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (String) vh.getValue();
|
||||
}
|
||||
|
||||
private void createUserDetailsServiceFactory() {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY)) {
|
||||
// Multiple <http> case
|
||||
|
||||
+35
-10
@@ -15,12 +15,24 @@
|
||||
*/
|
||||
package org.springframework.security.config.websocket;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import static org.springframework.security.config.Elements.*;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.*;
|
||||
import org.springframework.beans.factory.support.*;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
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.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
@@ -43,10 +55,6 @@ import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Parses Spring Security's websocket namespace support. A simple example is:
|
||||
*
|
||||
@@ -111,6 +119,11 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
ManagedMap<BeanDefinition, String> matcherToExpression = new ManagedMap<BeanDefinition, String>();
|
||||
|
||||
String id = element.getAttribute(ID_ATTR);
|
||||
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element,
|
||||
EXPRESSION_HANDLER);
|
||||
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
|
||||
boolean expressionHandlerDefined = StringUtils.hasText(expressionHandlerRef);
|
||||
|
||||
boolean sameOriginDisabled = Boolean.parseBoolean(element
|
||||
.getAttribute(DISABLED_ATTR));
|
||||
|
||||
@@ -130,11 +143,18 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
.rootBeanDefinition(ExpressionBasedMessageSecurityMetadataSourceFactory.class);
|
||||
mds.setFactoryMethod("createExpressionMessageMetadataSource");
|
||||
mds.addConstructorArgValue(matcherToExpression);
|
||||
if(expressionHandlerDefined) {
|
||||
mds.addConstructorArgReference(expressionHandlerRef);
|
||||
}
|
||||
|
||||
String mdsId = context.registerWithGeneratedName(mds.getBeanDefinition());
|
||||
|
||||
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>();
|
||||
voters.add(new RootBeanDefinition(MessageExpressionVoter.class));
|
||||
BeanDefinitionBuilder messageExpressionVoterBldr = BeanDefinitionBuilder.rootBeanDefinition(MessageExpressionVoter.class);
|
||||
if(expressionHandlerDefined) {
|
||||
messageExpressionVoterBldr.addPropertyReference("expressionHandler", expressionHandlerRef);
|
||||
}
|
||||
voters.add(messageExpressionVoterBldr.getBeanDefinition());
|
||||
BeanDefinitionBuilder adm = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(ConsensusBased.class);
|
||||
adm.addConstructorArgValue(voters);
|
||||
@@ -208,6 +228,11 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
static class MessageSecurityPostProcessor implements
|
||||
BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
/**
|
||||
* This is not available prior to Spring 4.2
|
||||
*/
|
||||
private static final String WEB_SOCKET_AMMH_CLASS_NAME = "org.springframework.web.socket.messaging.WebSocketAnnotationMethodMessageHandler";
|
||||
|
||||
private static final String CLIENT_INBOUND_CHANNEL_BEAN_ID = "clientInboundChannel";
|
||||
|
||||
private static final String INTERCEPTORS_PROP = "interceptors";
|
||||
@@ -231,7 +256,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
BeanDefinition bd = registry.getBeanDefinition(beanName);
|
||||
String beanClassName = bd.getBeanClassName();
|
||||
if (beanClassName.equals(SimpAnnotationMethodMessageHandler.class
|
||||
.getName())) {
|
||||
.getName()) || beanClassName.equals(WEB_SOCKET_AMMH_CLASS_NAME)) {
|
||||
PropertyValue current = bd.getPropertyValues().getPropertyValue(
|
||||
CUSTOM_ARG_RESOLVERS_PROP);
|
||||
ManagedList<Object> argResolvers = new ManagedList<Object>();
|
||||
|
||||
+5
-5
@@ -274,7 +274,7 @@ protect-pointcut.attlist &=
|
||||
|
||||
websocket-message-broker =
|
||||
## Allows securing a Message Broker. There are two modes. If no id is specified: ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel. If the id is specified, creates a ChannelSecurityInterceptor that can be manually registered with the clientInboundChannel.
|
||||
element websocket-message-broker { websocket-message-broker.attrlist, (intercept-message*) }
|
||||
element websocket-message-broker { websocket-message-broker.attrlist, (intercept-message* & expression-handler?) }
|
||||
|
||||
websocket-message-broker.attrlist &=
|
||||
## A bean identifier, used for referring to the bean elsewhere in the context. If specified, explicit configuration within clientInboundChannel is required. If not specified, ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel.
|
||||
@@ -291,10 +291,10 @@ intercept-message.attrlist &=
|
||||
## The destination ant pattern which will be mapped to the access attribute. For example, /** matches any message with a destination, /admin/** matches any message that has a destination that starts with admin.
|
||||
attribute pattern {xsd:token}?
|
||||
intercept-message.attrlist &=
|
||||
## The access configuration attributes that apply for the configured message. For example, permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role 'ROLE_ADMIN'.
|
||||
## The access configuration attributes that apply for the configured message. For example, permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role 'ROLE_ADMIN'.
|
||||
attribute access {xsd:token}?
|
||||
intercept-message.attrlist &=
|
||||
## The type of message to match on. Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER).
|
||||
## The type of message to match on. Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER).
|
||||
attribute type {"CONNECT" | "CONNECT_ACK" | "HEARTBEAT" | "MESSAGE" | "SUBSCRIBE"| "UNSUBSCRIBE" | "DISCONNECT" | "DISCONNECT_ACK" | "OTHER"}?
|
||||
|
||||
http-firewall =
|
||||
@@ -389,7 +389,7 @@ logout.attlist &=
|
||||
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /logout if unspecified.
|
||||
attribute logout-url {xsd:token}?
|
||||
logout.attlist &=
|
||||
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
|
||||
## Specifies the URL to display once the user has logged out. If not specified, defaults to <form-login-login-page>/?logout (i.e. /login?logout).
|
||||
attribute logout-success-url {xsd:token}?
|
||||
logout.attlist &=
|
||||
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
|
||||
@@ -704,7 +704,7 @@ user.attlist &=
|
||||
## Can be set to "true" to mark an account as locked and unusable.
|
||||
attribute locked {xsd:boolean}?
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as disabled and unusable.
|
||||
## Can be set to "true" to mark an account as disabled and unusable.
|
||||
attribute disabled {xsd:boolean}?
|
||||
|
||||
jdbc-user-service =
|
||||
|
||||
+15
-4
@@ -851,9 +851,20 @@
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:intercept-message"/>
|
||||
</xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="security:intercept-message"/>
|
||||
<xs:element name="expression-handler">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the SecurityExpressionHandler instance which will be used if expression-based
|
||||
access-control is enabled. A default implementation (with no ACL support) will be used if
|
||||
not supplied.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:ref"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="security:websocket-message-broker.attrlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
@@ -1344,7 +1355,7 @@
|
||||
<xs:attribute name="logout-success-url" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the URL to display once the user has logged out. If not specified, defaults to
|
||||
/.
|
||||
<form-login-login-page>/?logout (i.e. /login?logout).
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
+111
-111
@@ -44,127 +44,127 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
*
|
||||
*/
|
||||
class AuthenticationManagerBuilderTests extends BaseSpringSpec {
|
||||
def "add(AuthenticationProvider) does not perform registration"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
AuthenticationProvider provider = Mock()
|
||||
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(objectPostProcessor).objectPostProcessor(opp)
|
||||
when: "Adding an AuthenticationProvider"
|
||||
builder.authenticationProvider(provider)
|
||||
builder.build()
|
||||
then: "AuthenticationProvider is not passed into LifecycleManager (it should be managed externally)"
|
||||
0 * opp._(_ as AuthenticationProvider)
|
||||
}
|
||||
def "add(AuthenticationProvider) does not perform registration"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
AuthenticationProvider provider = Mock()
|
||||
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(objectPostProcessor).objectPostProcessor(opp)
|
||||
when: "Adding an AuthenticationProvider"
|
||||
builder.authenticationProvider(provider)
|
||||
builder.build()
|
||||
then: "AuthenticationProvider is not passed into LifecycleManager (it should be managed externally)"
|
||||
0 * opp._(_ as AuthenticationProvider)
|
||||
}
|
||||
|
||||
// https://github.com/SpringSource/spring-security-javaconfig/issues/132
|
||||
def "#132 Custom AuthenticationEventPublisher with Web configure(AuthenticationManagerBuilder)"() {
|
||||
setup:
|
||||
AuthenticationEventPublisher aep = Mock()
|
||||
when:
|
||||
AuthenticationManager am = new AuthenticationManagerBuilder(objectPostProcessor)
|
||||
.authenticationEventPublisher(aep)
|
||||
.inMemoryAuthentication()
|
||||
.and()
|
||||
.build()
|
||||
then:
|
||||
am.eventPublisher == aep
|
||||
}
|
||||
// https://github.com/SpringSource/spring-security-javaconfig/issues/132
|
||||
def "#132 Custom AuthenticationEventPublisher with Web configure(AuthenticationManagerBuilder)"() {
|
||||
setup:
|
||||
AuthenticationEventPublisher aep = Mock()
|
||||
when:
|
||||
AuthenticationManager am = new AuthenticationManagerBuilder(objectPostProcessor)
|
||||
.authenticationEventPublisher(aep)
|
||||
.inMemoryAuthentication()
|
||||
.and()
|
||||
.build()
|
||||
then:
|
||||
am.eventPublisher == aep
|
||||
}
|
||||
|
||||
def "authentication-manager support multiple DaoAuthenticationProvider's"() {
|
||||
setup:
|
||||
loadConfig(MultiAuthenticationProvidersConfig)
|
||||
when:
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.name == "user"
|
||||
auth.authorities*.authority == ['ROLE_USER']
|
||||
when:
|
||||
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin","password"))
|
||||
then:
|
||||
auth.name == "admin"
|
||||
auth.authorities*.authority.sort() == ['ROLE_ADMIN','ROLE_USER']
|
||||
}
|
||||
def "authentication-manager support multiple DaoAuthenticationProvider's"() {
|
||||
setup:
|
||||
loadConfig(MultiAuthenticationProvidersConfig)
|
||||
when:
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.name == "user"
|
||||
auth.authorities*.authority == ['ROLE_USER']
|
||||
when:
|
||||
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin","password"))
|
||||
then:
|
||||
auth.name == "admin"
|
||||
auth.authorities*.authority.sort() == ['ROLE_ADMIN','ROLE_USER']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.and()
|
||||
.inMemoryAuthentication()
|
||||
.withUser("admin").password("password").roles("USER","ADMIN")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.and()
|
||||
.inMemoryAuthentication()
|
||||
.withUser("admin").password("password").roles("USER","ADMIN")
|
||||
}
|
||||
}
|
||||
|
||||
def "isConfigured with AuthenticationProvider"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
AuthenticationProvider provider = Mock()
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||
when:
|
||||
auth
|
||||
.authenticationProvider(provider)
|
||||
then:
|
||||
auth.isConfigured()
|
||||
}
|
||||
def "isConfigured with AuthenticationProvider"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
AuthenticationProvider provider = Mock()
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||
when:
|
||||
auth
|
||||
.authenticationProvider(provider)
|
||||
then:
|
||||
auth.isConfigured()
|
||||
}
|
||||
|
||||
def "isConfigured with parent"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
AuthenticationManager parent = Mock()
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||
when:
|
||||
auth
|
||||
.parentAuthenticationManager(parent)
|
||||
then:
|
||||
auth.isConfigured()
|
||||
}
|
||||
def "isConfigured with parent"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
AuthenticationManager parent = Mock()
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||
when:
|
||||
auth
|
||||
.parentAuthenticationManager(parent)
|
||||
then:
|
||||
auth.isConfigured()
|
||||
}
|
||||
|
||||
def "isConfigured not configured"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
when:
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||
then:
|
||||
auth.isConfigured() == false
|
||||
}
|
||||
def "isConfigured not configured"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
when:
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||
then:
|
||||
auth.isConfigured() == false
|
||||
}
|
||||
|
||||
def "user from properties"() {
|
||||
setup:
|
||||
loadConfig(UserFromPropertiesConfig)
|
||||
AuthenticationManager manager = context.getBean(AuthenticationConfiguration).authenticationManager
|
||||
when:
|
||||
manager.authenticate(new UsernamePasswordAuthenticationToken("joe","joespassword"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "user from properties"() {
|
||||
setup:
|
||||
loadConfig(UserFromPropertiesConfig)
|
||||
AuthenticationManager manager = context.getBean(AuthenticationConfiguration).authenticationManager
|
||||
when:
|
||||
manager.authenticate(new UsernamePasswordAuthenticationToken("joe","joespassword"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalAuthentication
|
||||
@Import(ObjectPostProcessorConfiguration.class)
|
||||
static class UserFromPropertiesConfig {
|
||||
@Configuration
|
||||
@EnableGlobalAuthentication
|
||||
@Import(ObjectPostProcessorConfiguration.class)
|
||||
static class UserFromPropertiesConfig {
|
||||
|
||||
@Value("classpath:org/springframework/security/config/users.properties")
|
||||
Resource users;
|
||||
@Value("classpath:org/springframework/security/config/users.properties")
|
||||
Resource users;
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
return new ProviderManager(Arrays.asList(authenticationProvider()));
|
||||
}
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
return new ProviderManager(Arrays.asList(authenticationProvider()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationProvider authenticationProvider() {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setUserDetailsService(userDetailsService())
|
||||
return provider;
|
||||
}
|
||||
@Bean
|
||||
public AuthenticationProvider authenticationProvider() {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setUserDetailsService(userDetailsService())
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() {
|
||||
Properties properties = new Properties();
|
||||
properties.load(users.getInputStream());
|
||||
return new InMemoryUserDetailsManager(properties);
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() {
|
||||
Properties properties = new Properties();
|
||||
properties.load(users.getInputStream());
|
||||
return new InMemoryUserDetailsManager(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -34,11 +34,11 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
*/
|
||||
@Configuration
|
||||
class BaseAuthenticationConfig {
|
||||
@Autowired
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN").and()
|
||||
}
|
||||
@Autowired
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN").and()
|
||||
}
|
||||
}
|
||||
|
||||
+69
-69
@@ -32,80 +32,80 @@ import org.springframework.security.core.Authentication
|
||||
*
|
||||
*/
|
||||
class NamespaceAuthenticationManagerTests extends BaseSpringSpec {
|
||||
def "authentication-manager@erase-credentials=true (default)"() {
|
||||
when:
|
||||
loadConfig(EraseCredentialsTrueDefaultConfig)
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.principal.password == null
|
||||
auth.credentials == null
|
||||
when: "authenticate the same user"
|
||||
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then: "successfully authenticate again"
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "authentication-manager@erase-credentials=true (default)"() {
|
||||
when:
|
||||
loadConfig(EraseCredentialsTrueDefaultConfig)
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.principal.password == null
|
||||
auth.credentials == null
|
||||
when: "authenticate the same user"
|
||||
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then: "successfully authenticate again"
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
def "authentication-manager@erase-credentials=false"() {
|
||||
when:
|
||||
loadConfig(EraseCredentialsFalseConfig)
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.credentials == "password"
|
||||
auth.principal.password == "password"
|
||||
}
|
||||
def "authentication-manager@erase-credentials=false"() {
|
||||
when:
|
||||
loadConfig(EraseCredentialsFalseConfig)
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.credentials == "password"
|
||||
auth.principal.password == "password"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.eraseCredentials(false)
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.eraseCredentials(false)
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2533: global authentication-manager@erase-credentials=false"() {
|
||||
when:
|
||||
loadConfig(GlobalEraseCredentialsFalseConfig)
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.credentials == "password"
|
||||
auth.principal.password == "password"
|
||||
}
|
||||
def "SEC-2533: global authentication-manager@erase-credentials=false"() {
|
||||
when:
|
||||
loadConfig(GlobalEraseCredentialsFalseConfig)
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
auth.credentials == "password"
|
||||
auth.principal.password == "password"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.eraseCredentials(false)
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.eraseCredentials(false)
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+42
-42
@@ -31,51 +31,51 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
*
|
||||
*/
|
||||
class NamespaceAuthenticationProviderTests extends BaseSpringSpec {
|
||||
def "authentication-provider@ref"() {
|
||||
when:
|
||||
loadConfig(AuthenticationProviderRefConfig)
|
||||
then:
|
||||
authenticationProviders()[1] == AuthenticationProviderRefConfig.expected
|
||||
}
|
||||
def "authentication-provider@ref"() {
|
||||
when:
|
||||
loadConfig(AuthenticationProviderRefConfig)
|
||||
then:
|
||||
authenticationProviders()[1] == AuthenticationProviderRefConfig.expected
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
|
||||
static DaoAuthenticationProvider expected = new DaoAuthenticationProvider()
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.authenticationProvider(expected)
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
|
||||
static DaoAuthenticationProvider expected = new DaoAuthenticationProvider()
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.authenticationProvider(expected)
|
||||
}
|
||||
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
def "authentication-provider@user-service-ref"() {
|
||||
when:
|
||||
loadConfig(UserServiceRefConfig)
|
||||
then:
|
||||
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService == UserServiceRefConfig.expected
|
||||
}
|
||||
def "authentication-provider@user-service-ref"() {
|
||||
when:
|
||||
loadConfig(UserServiceRefConfig)
|
||||
then:
|
||||
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService == UserServiceRefConfig.expected
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class UserServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
static InMemoryUserDetailsManager expected = new InMemoryUserDetailsManager([] as Collection)
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.userDetailsService(expected)
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class UserServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
static InMemoryUserDetailsManager expected = new InMemoryUserDetailsManager([] as Collection)
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.userDetailsService(expected)
|
||||
}
|
||||
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+123
-123
@@ -41,145 +41,145 @@ import org.springframework.security.provisioning.JdbcUserDetailsManager
|
||||
*
|
||||
*/
|
||||
class NamespaceJdbcUserServiceTests extends BaseSpringSpec {
|
||||
def "jdbc-user-service"() {
|
||||
when:
|
||||
loadConfig(DataSourceConfig,JdbcUserServiceConfig)
|
||||
then:
|
||||
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService instanceof JdbcUserDetailsManager
|
||||
}
|
||||
def "jdbc-user-service"() {
|
||||
when:
|
||||
loadConfig(DataSourceConfig,JdbcUserServiceConfig)
|
||||
then:
|
||||
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService instanceof JdbcUserDetailsManager
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
@EnableWebSecurity
|
||||
static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
.dataSource(dataSource) // jdbc-user-service@data-source-ref
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
.dataSource(dataSource) // jdbc-user-service@data-source-ref
|
||||
}
|
||||
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
def "jdbc-user-service in memory testing sample"() {
|
||||
when:
|
||||
loadConfig(DataSourceConfig,JdbcUserServiceInMemorySampleConfig)
|
||||
then:
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
auth.authorities.collect {it.authority} == ['ROLE_USER']
|
||||
auth.name == "user"
|
||||
}
|
||||
def "jdbc-user-service in memory testing sample"() {
|
||||
when:
|
||||
loadConfig(DataSourceConfig,JdbcUserServiceInMemorySampleConfig)
|
||||
then:
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
auth.authorities.collect {it.authority} == ['ROLE_USER']
|
||||
auth.name == "user"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class JdbcUserServiceInMemorySampleConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
@EnableWebSecurity
|
||||
static class JdbcUserServiceInMemorySampleConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
.dataSource(dataSource)
|
||||
// imports the default schema (will fail if already exists)
|
||||
.withDefaultSchema()
|
||||
// adds this user automatically (will fail if already exists)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
.dataSource(dataSource)
|
||||
// imports the default schema (will fail if already exists)
|
||||
.withDefaultSchema()
|
||||
// adds this user automatically (will fail if already exists)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
}
|
||||
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DataSourceConfig {
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DataSourceConfig {
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
|
||||
def "jdbc-user-service custom"() {
|
||||
when:
|
||||
loadConfig(CustomDataSourceConfig,CustomJdbcUserServiceSampleConfig)
|
||||
then:
|
||||
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService.userCache instanceof CustomUserCache
|
||||
when:
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
then:
|
||||
auth.authorities.collect {it.authority}.sort() == ['ROLE_DBA','ROLE_USER']
|
||||
auth.name == 'user'
|
||||
}
|
||||
def "jdbc-user-service custom"() {
|
||||
when:
|
||||
loadConfig(CustomDataSourceConfig,CustomJdbcUserServiceSampleConfig)
|
||||
then:
|
||||
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService.userCache instanceof CustomUserCache
|
||||
when:
|
||||
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
then:
|
||||
auth.authorities.collect {it.authority}.sort() == ['ROLE_DBA','ROLE_USER']
|
||||
auth.name == 'user'
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomJdbcUserServiceSampleConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
@EnableWebSecurity
|
||||
static class CustomJdbcUserServiceSampleConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
// jdbc-user-service@dataSource
|
||||
.dataSource(dataSource)
|
||||
// jdbc-user-service@cache-ref
|
||||
.userCache(new CustomUserCache())
|
||||
// jdbc-user-service@users-byusername-query
|
||||
.usersByUsernameQuery("select principal,credentials,true from users where principal = ?")
|
||||
// jdbc-user-service@authorities-by-username-query
|
||||
.authoritiesByUsernameQuery("select principal,role from roles where principal = ?")
|
||||
// jdbc-user-service@group-authorities-by-username-query
|
||||
.groupAuthoritiesByUsername(JdbcUserDetailsManager.DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY)
|
||||
// jdbc-user-service@role-prefix
|
||||
.rolePrefix("ROLE_")
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
// jdbc-user-service@dataSource
|
||||
.dataSource(dataSource)
|
||||
// jdbc-user-service@cache-ref
|
||||
.userCache(new CustomUserCache())
|
||||
// jdbc-user-service@users-byusername-query
|
||||
.usersByUsernameQuery("select principal,credentials,true from users where principal = ?")
|
||||
// jdbc-user-service@authorities-by-username-query
|
||||
.authoritiesByUsernameQuery("select principal,role from roles where principal = ?")
|
||||
// jdbc-user-service@group-authorities-by-username-query
|
||||
.groupAuthoritiesByUsername(JdbcUserDetailsManager.DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY)
|
||||
// jdbc-user-service@role-prefix
|
||||
.rolePrefix("ROLE_")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
// Only necessary to have access to verify the AuthenticationManager
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
static class CustomUserCache implements UserCache {
|
||||
static class CustomUserCache implements UserCache {
|
||||
|
||||
@Override
|
||||
public UserDetails getUserFromCache(String username) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public UserDetails getUserFromCache(String username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putUserInCache(UserDetails user) {
|
||||
}
|
||||
@Override
|
||||
public void putUserInCache(UserDetails user) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUserFromCache(String username) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void removeUserFromCache(String username) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomDataSourceConfig {
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
// simulate that the DB already has the schema loaded and users in it
|
||||
.addScript("CustomJdbcUserServiceSampleConfig.sql")
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class CustomDataSourceConfig {
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
// simulate that the DB already has the schema loaded and users in it
|
||||
.addScript("CustomJdbcUserServiceSampleConfig.sql")
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+64
-64
@@ -43,78 +43,78 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
*
|
||||
*/
|
||||
class NamespacePasswordEncoderTests extends BaseSpringSpec {
|
||||
def "password-encoder@ref with in memory"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderWithInMemoryConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
def "password-encoder@ref with in memory"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderWithInMemoryConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
@EnableWebSecurity
|
||||
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password(encoder.encode("password")).roles("USER").and()
|
||||
.passwordEncoder(encoder)
|
||||
}
|
||||
}
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password(encoder.encode("password")).roles("USER").and()
|
||||
.passwordEncoder(encoder)
|
||||
}
|
||||
}
|
||||
|
||||
def "password-encoder@ref with jdbc"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderWithJdbcConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
def "password-encoder@ref with jdbc"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderWithJdbcConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
@EnableWebSecurity
|
||||
static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
.withDefaultSchema()
|
||||
.dataSource(dataSource())
|
||||
.withUser("user").password(encoder.encode("password")).roles("USER").and()
|
||||
.passwordEncoder(encoder)
|
||||
}
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
|
||||
auth
|
||||
.jdbcAuthentication()
|
||||
.withDefaultSchema()
|
||||
.dataSource(dataSource())
|
||||
.withUser("user").password(encoder.encode("password")).roles("USER").and()
|
||||
.passwordEncoder(encoder)
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
|
||||
def "password-encoder@ref with userdetailsservice"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderWithUserDetailsServiceConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
def "password-encoder@ref with userdetailsservice"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderWithUserDetailsServiceConfig)
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
@EnableWebSecurity
|
||||
static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
|
||||
User user = new User("user",encoder.encode("password"), AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager([user])
|
||||
auth
|
||||
.userDetailsService(uds)
|
||||
.passwordEncoder(encoder)
|
||||
}
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
|
||||
User user = new User("user",encoder.encode("password"), AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager([user])
|
||||
auth
|
||||
.userDetailsService(uds)
|
||||
.passwordEncoder(encoder)
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-13
@@ -44,18 +44,18 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*
|
||||
*/
|
||||
class PasswordEncoderConfigurerTests extends BaseSpringSpec {
|
||||
def "password-encoder@ref with No AuthenticationManager Bean"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderNoAuthManagerLoadsConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "password-encoder@ref with No AuthenticationManager Bean"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderNoAuthManagerLoadsConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def "password-encoder@ref with AuthenticationManagerBuilder"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderConfig)
|
||||
AuthenticationManager authMgr = authenticationManager()
|
||||
then:
|
||||
authMgr.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
def "password-encoder@ref with AuthenticationManagerBuilder"() {
|
||||
when:
|
||||
loadConfig(PasswordEncoderConfig)
|
||||
AuthenticationManager authMgr = authenticationManager()
|
||||
then:
|
||||
authMgr.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
}
|
||||
}
|
||||
|
||||
+262
-262
@@ -50,320 +50,320 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
|
||||
class AuthenticationConfigurationTests extends BaseSpringSpec {
|
||||
|
||||
def "Ordering Autowired on EnableGlobalMethodSecurity"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
when:
|
||||
loadConfig(GlobalMethodSecurityAutowiredConfigAndServicesConfig)
|
||||
then:
|
||||
context.getBean(Service).run()
|
||||
}
|
||||
def "Ordering Autowired on EnableGlobalMethodSecurity"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
when:
|
||||
loadConfig(GlobalMethodSecurityAutowiredConfigAndServicesConfig)
|
||||
then:
|
||||
context.getBean(Service).run()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import([GlobalMethodSecurityAutowiredConfig,ServicesConfig])
|
||||
static class GlobalMethodSecurityAutowiredConfigAndServicesConfig {}
|
||||
@Configuration
|
||||
@Import([GlobalMethodSecurityAutowiredConfig,ServicesConfig])
|
||||
static class GlobalMethodSecurityAutowiredConfigAndServicesConfig {}
|
||||
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
static class GlobalMethodSecurityAutowiredConfig {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
static class GlobalMethodSecurityAutowiredConfig {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
def "Ordering Autowired on EnableWebSecurity"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
when:
|
||||
loadConfig(GlobalMethodSecurityConfigAndServicesConfig)
|
||||
then:
|
||||
context.getBean(Service).run()
|
||||
}
|
||||
def "Ordering Autowired on EnableWebSecurity"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
when:
|
||||
loadConfig(GlobalMethodSecurityConfigAndServicesConfig)
|
||||
then:
|
||||
context.getBean(Service).run()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import([GlobalMethodSecurityConfig,WebSecurityConfig,ServicesConfig])
|
||||
static class GlobalMethodSecurityConfigAndServicesConfig {}
|
||||
@Configuration
|
||||
@Import([GlobalMethodSecurityConfig,WebSecurityConfig,ServicesConfig])
|
||||
static class GlobalMethodSecurityConfigAndServicesConfig {}
|
||||
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
static class GlobalMethodSecurityConfig {}
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
static class GlobalMethodSecurityConfig {}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
def "Ordering Autowired on EnableWebMvcSecurity"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
when:
|
||||
loadConfig(GlobalMethodSecurityMvcSecurityAndServicesConfig)
|
||||
then:
|
||||
context.getBean(Service).run()
|
||||
}
|
||||
def "Ordering Autowired on EnableWebMvcSecurity"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
when:
|
||||
loadConfig(GlobalMethodSecurityMvcSecurityAndServicesConfig)
|
||||
then:
|
||||
context.getBean(Service).run()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import([GlobalMethodSecurityConfig,WebMvcSecurityConfig,ServicesConfig])
|
||||
static class GlobalMethodSecurityMvcSecurityAndServicesConfig {}
|
||||
@Configuration
|
||||
@Import([GlobalMethodSecurityConfig,WebMvcSecurityConfig,ServicesConfig])
|
||||
static class GlobalMethodSecurityMvcSecurityAndServicesConfig {}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
def "no authentication getAuthenticationManager falls back to null"() {
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager == null
|
||||
}
|
||||
def "no authentication getAuthenticationManager falls back to null"() {
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager == null
|
||||
}
|
||||
|
||||
def "QuiesentGlobalAuthenticationConfiguererAdapter falls back to null"() {
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,QuiesentGlobalAuthenticationConfiguererAdapter)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager == null
|
||||
}
|
||||
def "QuiesentGlobalAuthenticationConfiguererAdapter falls back to null"() {
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,QuiesentGlobalAuthenticationConfiguererAdapter)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager == null
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class QuiesentGlobalAuthenticationConfiguererAdapter extends GlobalAuthenticationConfigurerAdapter {}
|
||||
@Configuration
|
||||
static class QuiesentGlobalAuthenticationConfiguererAdapter extends GlobalAuthenticationConfigurerAdapter {}
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
def "GlobalAuthenticationConfiguererAdapterImpl configures authentication successfully"() {
|
||||
setup:
|
||||
def token = new UsernamePasswordAuthenticationToken("user", "password")
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,GlobalAuthenticationConfiguererAdapterImpl)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token)?.name == "user"
|
||||
}
|
||||
def "GlobalAuthenticationConfiguererAdapterImpl configures authentication successfully"() {
|
||||
setup:
|
||||
def token = new UsernamePasswordAuthenticationToken("user", "password")
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,GlobalAuthenticationConfiguererAdapterImpl)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token)?.name == "user"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class GlobalAuthenticationConfiguererAdapterImpl extends GlobalAuthenticationConfigurerAdapter {
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class GlobalAuthenticationConfiguererAdapterImpl extends GlobalAuthenticationConfigurerAdapter {
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
def "AuthenticationManagerBean configures authentication successfully"() {
|
||||
setup:
|
||||
def token = new UsernamePasswordAuthenticationToken("user", "password")
|
||||
def auth = new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
AuthenticationManagerBeanConfig.AM = Mock(AuthenticationManager)
|
||||
1 * AuthenticationManagerBeanConfig.AM.authenticate(token) >> auth
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,AuthenticationManagerBeanConfig)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token).name == auth.name
|
||||
}
|
||||
def "AuthenticationManagerBean configures authentication successfully"() {
|
||||
setup:
|
||||
def token = new UsernamePasswordAuthenticationToken("user", "password")
|
||||
def auth = new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
AuthenticationManagerBeanConfig.AM = Mock(AuthenticationManager)
|
||||
1 * AuthenticationManagerBeanConfig.AM.authenticate(token) >> auth
|
||||
when:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,AuthenticationManagerBeanConfig)
|
||||
then:
|
||||
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token).name == auth.name
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AuthenticationManagerBeanConfig {
|
||||
static AuthenticationManager AM
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
AM
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AuthenticationManagerBeanConfig {
|
||||
static AuthenticationManager AM
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
AM
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
@Configuration
|
||||
static class ServicesConfig {
|
||||
@Bean
|
||||
public Service service() {
|
||||
return new ServiceImpl()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class ServicesConfig {
|
||||
@Bean
|
||||
public Service service() {
|
||||
return new ServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
static interface Service {
|
||||
public void run();
|
||||
}
|
||||
static interface Service {
|
||||
public void run();
|
||||
}
|
||||
|
||||
static class ServiceImpl implements Service {
|
||||
@Secured("ROLE_USER")
|
||||
public void run() {}
|
||||
}
|
||||
static class ServiceImpl implements Service {
|
||||
@Secured("ROLE_USER")
|
||||
public void run() {}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
def "GlobalAuthenticationConfigurerAdapter are ordered"() {
|
||||
setup:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.setGlobalAuthenticationConfigurers([new LowestOrderGlobalAuthenticationConfigurerAdapter(), new HighestOrderGlobalAuthenticationConfigurerAdapter(), new DefaultOrderGlobalAuthenticationConfigurerAdapter()])
|
||||
when:
|
||||
config.getAuthenticationManager()
|
||||
then:
|
||||
DefaultOrderGlobalAuthenticationConfigurerAdapter.inits == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
|
||||
DefaultOrderGlobalAuthenticationConfigurerAdapter.configs == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
|
||||
def "GlobalAuthenticationConfigurerAdapter are ordered"() {
|
||||
setup:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.setGlobalAuthenticationConfigurers([new LowestOrderGlobalAuthenticationConfigurerAdapter(), new HighestOrderGlobalAuthenticationConfigurerAdapter(), new DefaultOrderGlobalAuthenticationConfigurerAdapter()])
|
||||
when:
|
||||
config.getAuthenticationManager()
|
||||
then:
|
||||
DefaultOrderGlobalAuthenticationConfigurerAdapter.inits == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
|
||||
DefaultOrderGlobalAuthenticationConfigurerAdapter.configs == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
|
||||
static List inits = []
|
||||
static List configs = []
|
||||
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
|
||||
static List inits = []
|
||||
static List configs = []
|
||||
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
inits.add(getClass())
|
||||
}
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
inits.add(getClass())
|
||||
}
|
||||
|
||||
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
configs.add(getClass())
|
||||
}
|
||||
}
|
||||
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
configs.add(getClass())
|
||||
}
|
||||
}
|
||||
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
|
||||
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
static class HighestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
static class HighestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
def "Spring Boot not triggered when already configured"() {
|
||||
setup:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.setGlobalAuthenticationConfigurers([new ConfiguresInMemoryConfigurerAdapter(), new BootGlobalAuthenticationConfigurerAdapter()])
|
||||
AuthenticationManager authenticationManager = config.authenticationManager
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
|
||||
then:
|
||||
thrown(AuthenticationException)
|
||||
}
|
||||
def "Spring Boot not triggered when already configured"() {
|
||||
setup:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.setGlobalAuthenticationConfigurers([new ConfiguresInMemoryConfigurerAdapter(), new BootGlobalAuthenticationConfigurerAdapter()])
|
||||
AuthenticationManager authenticationManager = config.authenticationManager
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
|
||||
then:
|
||||
thrown(AuthenticationException)
|
||||
}
|
||||
|
||||
|
||||
def "Spring Boot is triggered when not already configured"() {
|
||||
setup:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.setGlobalAuthenticationConfigurers([new BootGlobalAuthenticationConfigurerAdapter()])
|
||||
AuthenticationManager authenticationManager = config.authenticationManager
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "Spring Boot is triggered when not already configured"() {
|
||||
setup:
|
||||
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.setGlobalAuthenticationConfigurers([new BootGlobalAuthenticationConfigurerAdapter()])
|
||||
AuthenticationManager authenticationManager = config.authenticationManager
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
|
||||
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
|
||||
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class BootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.apply(new DefaultBootGlobalAuthenticationConfigurerAdapter())
|
||||
}
|
||||
}
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class BootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.apply(new DefaultBootGlobalAuthenticationConfigurerAdapter())
|
||||
}
|
||||
}
|
||||
|
||||
static class DefaultBootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
if(auth.isConfigured()) {
|
||||
return;
|
||||
}
|
||||
static class DefaultBootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
if(auth.isConfigured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
User user = new User("boot","password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
User user = new User("boot","password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
|
||||
List<User> users = Arrays.asList(user);
|
||||
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
|
||||
List<User> users = Arrays.asList(user);
|
||||
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
|
||||
provider.userDetailsService = inMemory
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
|
||||
provider.userDetailsService = inMemory
|
||||
|
||||
auth.authenticationProvider(provider)
|
||||
}
|
||||
}
|
||||
auth.authenticationProvider(provider)
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2531: AuthenticationConfiguration#lazyBean should use BeanClassLoader on ProxyFactoryBean"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
Sec2531Config. opp = opp
|
||||
loadConfig(Sec2531Config)
|
||||
when:
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.getAuthenticationManager()
|
||||
then:
|
||||
1 * opp.postProcess(_ as ProxyFactoryBean) >> { args ->
|
||||
args[0]
|
||||
}
|
||||
}
|
||||
def "SEC-2531: AuthenticationConfiguration#lazyBean should use BeanClassLoader on ProxyFactoryBean"() {
|
||||
setup:
|
||||
ObjectPostProcessor opp = Mock()
|
||||
Sec2531Config. opp = opp
|
||||
loadConfig(Sec2531Config)
|
||||
when:
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.getAuthenticationManager()
|
||||
then:
|
||||
1 * opp.postProcess(_ as ProxyFactoryBean) >> { args ->
|
||||
args[0]
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(AuthenticationConfiguration)
|
||||
static class Sec2531Config {
|
||||
static ObjectPostProcessor opp
|
||||
@Configuration
|
||||
@Import(AuthenticationConfiguration)
|
||||
static class Sec2531Config {
|
||||
static ObjectPostProcessor opp
|
||||
|
||||
@Bean
|
||||
public ObjectPostProcessor objectPostProcessor() {
|
||||
opp
|
||||
}
|
||||
@Bean
|
||||
public ObjectPostProcessor objectPostProcessor() {
|
||||
opp
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager manager() {
|
||||
null
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public AuthenticationManager manager() {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2822: Cannot Force Authentication already built"() {
|
||||
setup:
|
||||
loadConfig(Sec2822WebSecurity,Sec2822UseAuth,Sec2822Config)
|
||||
when:
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.getAuthenticationManager()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "SEC-2822: Cannot Force Authentication already built"() {
|
||||
setup:
|
||||
loadConfig(Sec2822WebSecurity,Sec2822UseAuth,Sec2822Config)
|
||||
when:
|
||||
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||
config.getAuthenticationManager()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(AuthenticationConfiguration)
|
||||
static class Sec2822Config {}
|
||||
@Configuration
|
||||
@Import(AuthenticationConfiguration)
|
||||
static class Sec2822Config {}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class Sec2822WebSecurity extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class Sec2822WebSecurity extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Sec2822UseAuth {
|
||||
@Autowired
|
||||
public void useAuthenticationManager(AuthenticationConfiguration auth) {
|
||||
auth.authenticationManager
|
||||
}
|
||||
@Configuration
|
||||
static class Sec2822UseAuth {
|
||||
@Autowired
|
||||
public void useAuthenticationManager(AuthenticationConfiguration auth) {
|
||||
auth.authenticationManager
|
||||
}
|
||||
|
||||
// Ensures that Sec2822UseAuth is initialized before Sec2822WebSecurity
|
||||
// must have additional GlobalAuthenticationConfigurerAdapter to trigger SEC-2822
|
||||
@Bean
|
||||
public static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
|
||||
new BootGlobalAuthenticationConfigurerAdapter()
|
||||
}
|
||||
// Ensures that Sec2822UseAuth is initialized before Sec2822WebSecurity
|
||||
// must have additional GlobalAuthenticationConfigurerAdapter to trigger SEC-2822
|
||||
@Bean
|
||||
public static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
|
||||
new BootGlobalAuthenticationConfigurerAdapter()
|
||||
}
|
||||
|
||||
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { }
|
||||
}
|
||||
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { }
|
||||
}
|
||||
}
|
||||
+82
-82
@@ -42,100 +42,100 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
|
||||
*/
|
||||
class AutowireBeanFactoryObjectPostProcessorTests extends BaseSpringSpec {
|
||||
|
||||
def "Verify All Aware methods are invoked"() {
|
||||
setup:
|
||||
ApplicationContextAware contextAware = Mock(ApplicationContextAware)
|
||||
ApplicationEventPublisherAware publisher = Mock(ApplicationEventPublisherAware)
|
||||
BeanClassLoaderAware classloader = Mock(BeanClassLoaderAware)
|
||||
BeanFactoryAware beanFactory = Mock(BeanFactoryAware)
|
||||
EnvironmentAware environment = Mock(EnvironmentAware)
|
||||
MessageSourceAware messageSource = Mock(MessageSourceAware)
|
||||
ServletConfigAware servletConfig = Mock(ServletConfigAware)
|
||||
ServletContextAware servletContext = Mock(ServletContextAware)
|
||||
DisposableBean disposable = Mock(DisposableBean)
|
||||
def "Verify All Aware methods are invoked"() {
|
||||
setup:
|
||||
ApplicationContextAware contextAware = Mock(ApplicationContextAware)
|
||||
ApplicationEventPublisherAware publisher = Mock(ApplicationEventPublisherAware)
|
||||
BeanClassLoaderAware classloader = Mock(BeanClassLoaderAware)
|
||||
BeanFactoryAware beanFactory = Mock(BeanFactoryAware)
|
||||
EnvironmentAware environment = Mock(EnvironmentAware)
|
||||
MessageSourceAware messageSource = Mock(MessageSourceAware)
|
||||
ServletConfigAware servletConfig = Mock(ServletConfigAware)
|
||||
ServletContextAware servletContext = Mock(ServletContextAware)
|
||||
DisposableBean disposable = Mock(DisposableBean)
|
||||
|
||||
context = new AnnotationConfigWebApplicationContext([servletConfig:new MockServletConfig(),servletContext:new MockServletContext()])
|
||||
context.register(Config)
|
||||
context.refresh()
|
||||
context.start()
|
||||
context = new AnnotationConfigWebApplicationContext([servletConfig:new MockServletConfig(),servletContext:new MockServletContext()])
|
||||
context.register(Config)
|
||||
context.refresh()
|
||||
context.start()
|
||||
|
||||
ObjectPostProcessor opp = context.getBean(ObjectPostProcessor)
|
||||
when:
|
||||
opp.postProcess(contextAware)
|
||||
then:
|
||||
1 * contextAware.setApplicationContext(!null)
|
||||
ObjectPostProcessor opp = context.getBean(ObjectPostProcessor)
|
||||
when:
|
||||
opp.postProcess(contextAware)
|
||||
then:
|
||||
1 * contextAware.setApplicationContext(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(publisher)
|
||||
then:
|
||||
1 * publisher.setApplicationEventPublisher(!null)
|
||||
when:
|
||||
opp.postProcess(publisher)
|
||||
then:
|
||||
1 * publisher.setApplicationEventPublisher(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(classloader)
|
||||
then:
|
||||
1 * classloader.setBeanClassLoader(!null)
|
||||
when:
|
||||
opp.postProcess(classloader)
|
||||
then:
|
||||
1 * classloader.setBeanClassLoader(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(beanFactory)
|
||||
then:
|
||||
1 * beanFactory.setBeanFactory(!null)
|
||||
when:
|
||||
opp.postProcess(beanFactory)
|
||||
then:
|
||||
1 * beanFactory.setBeanFactory(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(environment)
|
||||
then:
|
||||
1 * environment.setEnvironment(!null)
|
||||
when:
|
||||
opp.postProcess(environment)
|
||||
then:
|
||||
1 * environment.setEnvironment(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(messageSource)
|
||||
then:
|
||||
1 * messageSource.setMessageSource(!null)
|
||||
when:
|
||||
opp.postProcess(messageSource)
|
||||
then:
|
||||
1 * messageSource.setMessageSource(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(servletConfig)
|
||||
then:
|
||||
1 * servletConfig.setServletConfig(!null)
|
||||
when:
|
||||
opp.postProcess(servletConfig)
|
||||
then:
|
||||
1 * servletConfig.setServletConfig(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(servletContext)
|
||||
then:
|
||||
1 * servletContext.setServletContext(!null)
|
||||
when:
|
||||
opp.postProcess(servletContext)
|
||||
then:
|
||||
1 * servletContext.setServletContext(!null)
|
||||
|
||||
when:
|
||||
opp.postProcess(disposable)
|
||||
context.close()
|
||||
context = null
|
||||
then:
|
||||
1 * disposable.destroy()
|
||||
}
|
||||
when:
|
||||
opp.postProcess(disposable)
|
||||
context.close()
|
||||
context = null
|
||||
then:
|
||||
1 * disposable.destroy()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2382: AutowireBeanFactoryObjectPostProcessor works with BeanNameAutoProxyCreator"() {
|
||||
when:
|
||||
// must load with XML for BeanPostProcessors to work
|
||||
context = new ClassPathXmlApplicationContext("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml", getClass());
|
||||
then:
|
||||
noExceptionThrown()
|
||||
and: "make sure autoproxying was actually enabled"
|
||||
context.getBean(MyAdvisedBean).doStuff() == "null"
|
||||
}
|
||||
def "SEC-2382: AutowireBeanFactoryObjectPostProcessor works with BeanNameAutoProxyCreator"() {
|
||||
when:
|
||||
// must load with XML for BeanPostProcessors to work
|
||||
context = new ClassPathXmlApplicationContext("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml", getClass());
|
||||
then:
|
||||
noExceptionThrown()
|
||||
and: "make sure autoproxying was actually enabled"
|
||||
context.getBean(MyAdvisedBean).doStuff() == "null"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class WithBanNameAutoProxyCreatorConfig {
|
||||
@Bean
|
||||
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory)
|
||||
}
|
||||
@Configuration
|
||||
static class WithBanNameAutoProxyCreatorConfig {
|
||||
@Bean
|
||||
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory)
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configure(ObjectPostProcessor<Object> p) {
|
||||
p.postProcess(new Object())
|
||||
}
|
||||
}
|
||||
@Autowired
|
||||
public void configure(ObjectPostProcessor<Object> p) {
|
||||
p.postProcess(new Object())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+323
-292
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.method.configuration
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.junit.After;
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor
|
||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter
|
||||
@@ -29,6 +32,7 @@ import org.aopalliance.intercept.MethodInterceptor
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.ApplicationListener
|
||||
import org.springframework.context.annotation.AdviceMode
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
@@ -44,357 +48,384 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.method.TestPermissionEvaluator;
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
|
||||
def "messages set when using GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
|
||||
then:
|
||||
authenticationManager.messages.messageSource instanceof ApplicationContext
|
||||
}
|
||||
def "messages set when using GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
|
||||
then:
|
||||
authenticationManager.messages.messageSource instanceof ApplicationContext
|
||||
}
|
||||
|
||||
def "AuthenticationEventPublisher is registered GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
|
||||
then:
|
||||
authenticationManager.eventPublisher instanceof DefaultAuthenticationEventPublisher
|
||||
when:
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken("user",null,AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
authenticationManager.eventPublisher.publishAuthenticationSuccess(auth)
|
||||
then:
|
||||
InMemoryAuthWithGlobalMethodSecurityConfig.EVENT.authentication == auth
|
||||
}
|
||||
def "AuthenticationEventPublisher is registered GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
|
||||
then:
|
||||
authenticationManager.eventPublisher instanceof DefaultAuthenticationEventPublisher
|
||||
when:
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken("user",null,AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
authenticationManager.eventPublisher.publishAuthenticationSuccess(auth)
|
||||
then:
|
||||
InMemoryAuthWithGlobalMethodSecurityConfig.EVENT.authentication == auth
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration implements ApplicationListener<AuthenticationSuccessEvent> {
|
||||
static AuthenticationSuccessEvent EVENT
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration implements ApplicationListener<AuthenticationSuccessEvent> {
|
||||
static AuthenticationSuccessEvent EVENT
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AuthenticationSuccessEvent e) {
|
||||
EVENT = e
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onApplicationEvent(AuthenticationSuccessEvent e) {
|
||||
EVENT = e
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticationManager getAuthenticationManager() {
|
||||
context.getBean(MethodInterceptor).authenticationManager
|
||||
}
|
||||
AuthenticationManager getAuthenticationManager() {
|
||||
context.getBean(MethodInterceptor).authenticationManager
|
||||
}
|
||||
|
||||
def "AuthenticationTrustResolver autowires"() {
|
||||
setup:
|
||||
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
|
||||
when:
|
||||
loadConfig(CustomTrustResolverConfig)
|
||||
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
|
||||
then:
|
||||
preAdviceVoter.preAdvice.expressionHandler.trustResolver == CustomTrustResolverConfig.TR
|
||||
}
|
||||
def "AuthenticationTrustResolver autowires"() {
|
||||
setup:
|
||||
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
|
||||
when:
|
||||
loadConfig(CustomTrustResolverConfig)
|
||||
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
|
||||
then:
|
||||
preAdviceVoter.preAdvice.expressionHandler.trustResolver == CustomTrustResolverConfig.TR
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class CustomTrustResolverConfig extends GlobalMethodSecurityConfiguration {
|
||||
static AuthenticationTrustResolver TR
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class CustomTrustResolverConfig extends GlobalMethodSecurityConfiguration {
|
||||
static AuthenticationTrustResolver TR
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationTrustResolver tr() {
|
||||
return TR
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public AuthenticationTrustResolver tr() {
|
||||
return TR
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2301: DefaultWebSecurityExpressionHandler has BeanResolver set"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(ExpressionHandlerHasBeanResolverSetConfig)
|
||||
def service = context.getBean(ServiceImpl)
|
||||
when: "service with bean reference on PreAuthorize invoked"
|
||||
service.message()
|
||||
then: "properly throws AccessDeniedException"
|
||||
thrown(AccessDeniedException)
|
||||
when: "service with bean reference on PreAuthorize invoked"
|
||||
context.getBean(CustomAuthzService).grantAccess = true
|
||||
service.message()
|
||||
then: "grants access too"
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "SEC-2301: DefaultWebSecurityExpressionHandler has BeanResolver set"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(ExpressionHandlerHasBeanResolverSetConfig)
|
||||
def service = context.getBean(ServiceImpl)
|
||||
when: "service with bean reference on PreAuthorize invoked"
|
||||
service.message()
|
||||
then: "properly throws AccessDeniedException"
|
||||
thrown(AccessDeniedException)
|
||||
when: "service with bean reference on PreAuthorize invoked"
|
||||
context.getBean(CustomAuthzService).grantAccess = true
|
||||
service.message()
|
||||
then: "grants access too"
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
|
||||
static class ExpressionHandlerHasBeanResolverSetConfig extends GlobalMethodSecurityConfiguration {
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
|
||||
static class ExpressionHandlerHasBeanResolverSetConfig extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServiceImpl service() {
|
||||
return new ServiceImpl()
|
||||
}
|
||||
@Bean
|
||||
public ServiceImpl service() {
|
||||
return new ServiceImpl()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CustomAuthzService authz() {
|
||||
return new CustomAuthzService()
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public CustomAuthzService authz() {
|
||||
return new CustomAuthzService()
|
||||
}
|
||||
}
|
||||
|
||||
static class ServiceImpl {
|
||||
@PreAuthorize("@authz.authorize()")
|
||||
public String message() {
|
||||
null
|
||||
}
|
||||
}
|
||||
static class ServiceImpl {
|
||||
@PreAuthorize("@authz.authorize()")
|
||||
public String message() {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomAuthzService {
|
||||
boolean grantAccess
|
||||
static class CustomAuthzService {
|
||||
boolean grantAccess
|
||||
|
||||
public boolean authorize() {
|
||||
grantAccess
|
||||
}
|
||||
}
|
||||
public boolean authorize() {
|
||||
grantAccess
|
||||
}
|
||||
}
|
||||
|
||||
def "Method Security supports annotations on interface parameter names"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(MethodSecurityServiceConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when: "service with annotated argument"
|
||||
service.postAnnotation('deny')
|
||||
then: "properly throws AccessDeniedException"
|
||||
thrown(AccessDeniedException)
|
||||
when: "service with annotated argument"
|
||||
service.postAnnotation('grant')
|
||||
then: "properly throws AccessDeniedException"
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "Method Security supports annotations on interface parameter names"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(MethodSecurityServiceConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when: "service with annotated argument"
|
||||
service.postAnnotation('deny')
|
||||
then: "properly throws AccessDeniedException"
|
||||
thrown(AccessDeniedException)
|
||||
when: "service with annotated argument"
|
||||
service.postAnnotation('grant')
|
||||
then: "properly throws AccessDeniedException"
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class MethodSecurityServiceConfig extends GlobalMethodSecurityConfiguration {
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class MethodSecurityServiceConfig extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "GlobalMethodSecurityConfiguration autowires PermissionEvaluator"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
PermissionEvaluator evaluator = Mock()
|
||||
AutowirePermissionEvaluatorConfig.PE = evaluator
|
||||
loadConfig(AutowirePermissionEvaluatorConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.hasPermission("something")
|
||||
then:
|
||||
1 * evaluator.hasPermission(_, "something", "read") >> true
|
||||
when:
|
||||
service.hasPermission("something")
|
||||
then:
|
||||
1 * evaluator.hasPermission(_, "something", "read") >> false
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
def "GlobalMethodSecurityConfiguration autowires PermissionEvaluator"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
PermissionEvaluator evaluator = Mock()
|
||||
AutowirePermissionEvaluatorConfig.PE = evaluator
|
||||
loadConfig(AutowirePermissionEvaluatorConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.hasPermission("something")
|
||||
then:
|
||||
1 * evaluator.hasPermission(_, "something", "read") >> true
|
||||
when:
|
||||
service.hasPermission("something")
|
||||
then:
|
||||
1 * evaluator.hasPermission(_, "something", "read") >> false
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class AutowirePermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
|
||||
static PermissionEvaluator PE
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class AutowirePermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
|
||||
static PermissionEvaluator PE
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionEvaluator pe() {
|
||||
PE
|
||||
}
|
||||
@Bean
|
||||
public PermissionEvaluator pe() {
|
||||
PE
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "GlobalMethodSecurityConfiguration does not failw with multiple PermissionEvaluator"() {
|
||||
when:
|
||||
loadConfig(MultiPermissionEvaluatorConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "GlobalMethodSecurityConfiguration does not failw with multiple PermissionEvaluator"() {
|
||||
when:
|
||||
loadConfig(MultiPermissionEvaluatorConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class MultiPermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
|
||||
static PermissionEvaluator PE
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class MultiPermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
|
||||
static PermissionEvaluator PE = new TestPermissionEvaluator()
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionEvaluator pe() {
|
||||
PE
|
||||
}
|
||||
@Bean
|
||||
public PermissionEvaluator pe() {
|
||||
PE
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionEvaluator pe2() {
|
||||
PE
|
||||
}
|
||||
@Bean
|
||||
public PermissionEvaluator pe2() {
|
||||
PE
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2425: EnableGlobalMethodSecurity works on superclass"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(ParentConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
def "SEC-2425: EnableGlobalMethodSecurity works on superclass"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(ParentConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
static class ChildConfig extends ParentConfig {}
|
||||
static class ChildConfig extends ParentConfig {}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class ParentConfig {
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class ParentConfig {
|
||||
|
||||
@Autowired
|
||||
protected void configurGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Autowired
|
||||
protected void configurGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2479: Support AuthenticationManager in parent"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(Sec2479ParentConfig)
|
||||
def child = new AnnotationConfigApplicationContext()
|
||||
child.register(Sec2479ChildConfig)
|
||||
child.parent = context
|
||||
child.refresh()
|
||||
MethodSecurityService service = child.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
cleanup:
|
||||
child?.close()
|
||||
}
|
||||
def "SEC-2479: Support AuthenticationManager in parent"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(Sec2479ParentConfig)
|
||||
def child = new AnnotationConfigApplicationContext()
|
||||
child.register(Sec2479ChildConfig)
|
||||
child.parent = context
|
||||
child.refresh()
|
||||
MethodSecurityService service = child.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
cleanup:
|
||||
child?.close()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Sec2479ParentConfig {
|
||||
static AuthenticationManager AM
|
||||
@Configuration
|
||||
static class Sec2479ParentConfig {
|
||||
static AuthenticationManager AM
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager am() {
|
||||
AM
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public AuthenticationManager am() {
|
||||
AM
|
||||
}
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class Sec2479ChildConfig {
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class Sec2479ChildConfig {
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2815: @EnableGlobalMethodSecurity does not trigger eager initialization of Beans in GlobalAuthenticationConfigurer"() {
|
||||
setup:
|
||||
Sec2815Config.dataSource = Mock(DataSource)
|
||||
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
|
||||
loadConfig(Sec2815Config)
|
||||
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
|
||||
context.getBean(MockBeanPostProcessor).beforeInit['dataSource']
|
||||
context.getBean(MockBeanPostProcessor).afterInit['dataSource']
|
||||
}
|
||||
def "SEC-2815: @EnableGlobalMethodSecurity does not trigger eager initialization of Beans in GlobalAuthenticationConfigurer"() {
|
||||
setup:
|
||||
Sec2815Config.dataSource = Mock(DataSource)
|
||||
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
|
||||
loadConfig(Sec2815Config)
|
||||
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
|
||||
context.getBean(MockBeanPostProcessor).beforeInit['dataSource']
|
||||
context.getBean(MockBeanPostProcessor).afterInit['dataSource']
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class Sec2815Config {
|
||||
static DataSource dataSource;
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class Sec2815Config {
|
||||
static DataSource dataSource;
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MockBeanPostProcessor mockBeanPostProcessor() {
|
||||
new MockBeanPostProcessor()
|
||||
}
|
||||
@Bean
|
||||
public MockBeanPostProcessor mockBeanPostProcessor() {
|
||||
new MockBeanPostProcessor()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
dataSource
|
||||
}
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
dataSource
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
|
||||
@Autowired
|
||||
DataSource dataSource
|
||||
@Configuration
|
||||
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
|
||||
@Autowired
|
||||
DataSource dataSource
|
||||
|
||||
@Override
|
||||
void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class MockBeanPostProcessor implements BeanPostProcessor {
|
||||
Map<String,Object> beforeInit = new HashMap<String,Object>()
|
||||
Map<String,Object> afterInit = new HashMap<String,Object>()
|
||||
static class MockBeanPostProcessor implements BeanPostProcessor {
|
||||
Map<String,Object> beforeInit = new HashMap<String,Object>()
|
||||
Map<String,Object> afterInit = new HashMap<String,Object>()
|
||||
|
||||
@Override
|
||||
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
beforeInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
@Override
|
||||
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
beforeInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
|
||||
@Override
|
||||
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
afterInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
}
|
||||
@Override
|
||||
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
afterInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-3045: Global Security proxies security"() {
|
||||
setup:
|
||||
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
|
||||
loadConfig(Sec3005Config)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
|
||||
!Proxy.isProxyClass(service.getClass())
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, mode= AdviceMode.ASPECTJ)
|
||||
@EnableTransactionManagement
|
||||
static class Sec3005Config {
|
||||
static DataSource dataSource;
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -30,33 +30,33 @@ import org.springframework.security.core.Authentication
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public interface MethodSecurityService {
|
||||
@PreAuthorize("denyAll")
|
||||
public String preAuthorize();
|
||||
@PreAuthorize("denyAll")
|
||||
public String preAuthorize();
|
||||
|
||||
@Secured("ROLE_ADMIN")
|
||||
public String secured();
|
||||
@Secured("ROLE_ADMIN")
|
||||
public String secured();
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
public String securedUser();
|
||||
@Secured("ROLE_USER")
|
||||
public String securedUser();
|
||||
|
||||
@DenyAll
|
||||
public String jsr250();
|
||||
@DenyAll
|
||||
public String jsr250();
|
||||
|
||||
@PermitAll
|
||||
public String jsr250PermitAll();
|
||||
@PermitAll
|
||||
public String jsr250PermitAll();
|
||||
|
||||
@Secured(["ROLE_USER","RUN_AS_SUPER"])
|
||||
public Authentication runAs();
|
||||
@Secured(["ROLE_USER","RUN_AS_SUPER"])
|
||||
public Authentication runAs();
|
||||
|
||||
@PreAuthorize("permitAll")
|
||||
public String preAuthorizePermitAll();
|
||||
@PreAuthorize("permitAll")
|
||||
public String preAuthorizePermitAll();
|
||||
|
||||
@PreAuthorize("hasPermission(#object,'read')")
|
||||
public String hasPermission(String object);
|
||||
@PreAuthorize("hasPermission(#object,'read')")
|
||||
public String hasPermission(String object);
|
||||
|
||||
@PostAuthorize("hasPermission(#object,'read')")
|
||||
public String postHasPermission(String object);
|
||||
@PostAuthorize("hasPermission(#object,'read')")
|
||||
public String postHasPermission(String object);
|
||||
|
||||
@PostAuthorize("#o?.contains('grant')")
|
||||
public String postAnnotation(@P("o") String object);
|
||||
@PostAuthorize("#o?.contains('grant')")
|
||||
public String postAnnotation(@P("o") String object);
|
||||
}
|
||||
|
||||
+40
-40
@@ -25,53 +25,53 @@ import org.springframework.security.core.context.SecurityContextHolder
|
||||
*/
|
||||
public class MethodSecurityServiceImpl implements MethodSecurityService {
|
||||
|
||||
@Override
|
||||
public String preAuthorize() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String preAuthorize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String secured() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String secured() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String securedUser() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String securedUser() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jsr250() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String jsr250() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jsr250PermitAll() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String jsr250PermitAll() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication runAs() {
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
@Override
|
||||
public Authentication runAs() {
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String preAuthorizePermitAll() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String preAuthorizePermitAll() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String hasPermission(String object) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String hasPermission(String object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String postHasPermission(String object) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String postHasPermission(String object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String postAnnotation(String object) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String postAnnotation(String object) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+46
-46
@@ -40,53 +40,53 @@ import org.springframework.security.core.context.SecurityContextHolder
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class NamespaceGlobalMethodSecurityExpressionHandlerTests extends BaseSpringSpec {
|
||||
def setup() {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
}
|
||||
def setup() {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
}
|
||||
|
||||
def "global-method-security/expression-handler @PreAuthorize"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.hasPermission("granted")
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
service.hasPermission("denied")
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
def "global-method-security/expression-handler @PreAuthorize"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.hasPermission("granted")
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
service.hasPermission("denied")
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
def "global-method-security/expression-handler @PostAuthorize"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.postHasPermission("granted")
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
service.postHasPermission("denied")
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
def "global-method-security/expression-handler @PostAuthorize"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.postHasPermission("granted")
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
service.postHasPermission("denied")
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected MethodSecurityExpressionHandler createExpressionHandler() {
|
||||
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler()
|
||||
expressionHandler.permissionEvaluator = new PermissionEvaluator() {
|
||||
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
|
||||
"granted" == targetDomainObject
|
||||
}
|
||||
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
return expressionHandler
|
||||
}
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected MethodSecurityExpressionHandler createExpressionHandler() {
|
||||
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler()
|
||||
expressionHandler.permissionEvaluator = new PermissionEvaluator() {
|
||||
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
|
||||
"granted" == targetDomainObject
|
||||
}
|
||||
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
return expressionHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+328
-328
@@ -57,387 +57,387 @@ import org.springframework.security.core.context.SecurityContextHolder
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
|
||||
def setup() {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
}
|
||||
def setup() {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
}
|
||||
|
||||
// --- access-decision-manager-ref ---
|
||||
// --- access-decision-manager-ref ---
|
||||
|
||||
def "custom AccessDecisionManager can be used"() {
|
||||
setup: "Create an instance with an AccessDecisionManager that always denies access"
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
when:
|
||||
service.secured()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
def "custom AccessDecisionManager can be used"() {
|
||||
setup: "Create an instance with an AccessDecisionManager that always denies access"
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
when:
|
||||
service.secured()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AccessDecisionManager accessDecisionManager() {
|
||||
return new DenyAllAccessDecisionManager()
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AccessDecisionManager accessDecisionManager() {
|
||||
return new DenyAllAccessDecisionManager()
|
||||
}
|
||||
|
||||
public static class DenyAllAccessDecisionManager implements AccessDecisionManager {
|
||||
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) {
|
||||
throw new AccessDeniedException("Always Denied")
|
||||
}
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return true
|
||||
}
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
public static class DenyAllAccessDecisionManager implements AccessDecisionManager {
|
||||
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) {
|
||||
throw new AccessDeniedException("Always Denied")
|
||||
}
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return true
|
||||
}
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- authentication-manager-ref ---
|
||||
// --- authentication-manager-ref ---
|
||||
|
||||
def "custom AuthenticationManager can be used"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(CustomAuthenticationConfig)
|
||||
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
|
||||
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
|
||||
then:
|
||||
thrown(UnsupportedOperationException)
|
||||
}
|
||||
def "custom AuthenticationManager can be used"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(CustomAuthenticationConfig)
|
||||
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
|
||||
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
|
||||
then:
|
||||
thrown(UnsupportedOperationException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager() {
|
||||
return new AuthenticationManager() {
|
||||
Authentication authenticate(Authentication authentication) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager() {
|
||||
return new AuthenticationManager() {
|
||||
Authentication authenticate(Authentication authentication) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- jsr250-annotations ---
|
||||
// --- jsr250-annotations ---
|
||||
|
||||
def "enable jsr250"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(Jsr250Config)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then: "@Secured and @PreAuthorize are ignored"
|
||||
service.secured() == null
|
||||
service.preAuthorize() == null
|
||||
def "enable jsr250"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(Jsr250Config)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then: "@Secured and @PreAuthorize are ignored"
|
||||
service.secured() == null
|
||||
service.preAuthorize() == null
|
||||
|
||||
when: "@DenyAll method invoked"
|
||||
service.jsr250()
|
||||
then: "access is denied"
|
||||
thrown(AccessDeniedException)
|
||||
when: "@PermitAll method invoked"
|
||||
String jsr250PermitAll = service.jsr250PermitAll()
|
||||
then: "access is allowed"
|
||||
jsr250PermitAll == null
|
||||
}
|
||||
when: "@DenyAll method invoked"
|
||||
service.jsr250()
|
||||
then: "access is denied"
|
||||
thrown(AccessDeniedException)
|
||||
when: "@PermitAll method invoked"
|
||||
String jsr250PermitAll = service.jsr250PermitAll()
|
||||
then: "access is allowed"
|
||||
jsr250PermitAll == null
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(jsr250Enabled = true)
|
||||
@Configuration
|
||||
public static class Jsr250Config extends BaseMethodConfig {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(jsr250Enabled = true)
|
||||
@Configuration
|
||||
public static class Jsr250Config extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
// --- metadata-source-ref ---
|
||||
// --- metadata-source-ref ---
|
||||
|
||||
def "custom MethodSecurityMetadataSource can be used with higher priority than other sources"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomMethodSecurityMetadataSourceConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
when:
|
||||
service.secured()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
when:
|
||||
service.jsr250()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
def "custom MethodSecurityMetadataSource can be used with higher priority than other sources"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomMethodSecurityMetadataSourceConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
when:
|
||||
service.secured()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
when:
|
||||
service.jsr250()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class CustomMethodSecurityMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
|
||||
return new AbstractMethodSecurityMetadataSource() {
|
||||
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
|
||||
// require ROLE_NOBODY for any method on MethodSecurityService class
|
||||
return MethodSecurityService.isAssignableFrom(targetClass) ? [new SecurityConfig("ROLE_NOBODY")] : []
|
||||
}
|
||||
public Collection<ConfigAttribute> getAllConfigAttributes() {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class CustomMethodSecurityMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
|
||||
return new AbstractMethodSecurityMetadataSource() {
|
||||
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
|
||||
// require ROLE_NOBODY for any method on MethodSecurityService class
|
||||
return MethodSecurityService.isAssignableFrom(targetClass) ? [new SecurityConfig("ROLE_NOBODY")] : []
|
||||
}
|
||||
public Collection<ConfigAttribute> getAllConfigAttributes() {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- mode ---
|
||||
// --- mode ---
|
||||
|
||||
def "aspectj mode works"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(AspectJModeConfig)
|
||||
then:
|
||||
context.getBean(AnnotationSecurityAspect)
|
||||
context.getBean(AspectJMethodSecurityInterceptor)
|
||||
}
|
||||
def "aspectj mode works"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(AspectJModeConfig)
|
||||
then:
|
||||
context.getBean(AnnotationSecurityAspect)
|
||||
context.getBean(AspectJMethodSecurityInterceptor)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, proxyTargetClass = true)
|
||||
public static class AspectJModeConfig extends BaseMethodConfig {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, proxyTargetClass = true)
|
||||
public static class AspectJModeConfig extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
def "aspectj mode works extending GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,AspectJModeExtendsGMSCConfig)
|
||||
then:
|
||||
context.getBean(AnnotationSecurityAspect)
|
||||
context.getBean(AspectJMethodSecurityInterceptor)
|
||||
}
|
||||
def "aspectj mode works extending GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,AspectJModeExtendsGMSCConfig)
|
||||
then:
|
||||
context.getBean(AnnotationSecurityAspect)
|
||||
context.getBean(AspectJMethodSecurityInterceptor)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ)
|
||||
public static class AspectJModeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ)
|
||||
public static class AspectJModeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
|
||||
}
|
||||
|
||||
// --- order ---
|
||||
// --- order ---
|
||||
|
||||
def order() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(CustomOrderConfig)
|
||||
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
|
||||
then:
|
||||
advisor.order == 135
|
||||
}
|
||||
def order() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(CustomOrderConfig)
|
||||
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
|
||||
then:
|
||||
advisor.order == 135
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(order = 135)
|
||||
public static class CustomOrderConfig extends BaseMethodConfig {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(order = 135)
|
||||
public static class CustomOrderConfig extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when using @EnableGlobalMethodSecurity"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(DefaultOrderConfig)
|
||||
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
|
||||
then:
|
||||
advisor.order == Ordered.LOWEST_PRECEDENCE
|
||||
}
|
||||
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when using @EnableGlobalMethodSecurity"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(DefaultOrderConfig)
|
||||
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
|
||||
then:
|
||||
advisor.order == Ordered.LOWEST_PRECEDENCE
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class DefaultOrderConfig extends BaseMethodConfig {
|
||||
}
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class DefaultOrderConfig extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when extending GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,DefaultOrderExtendsMethodSecurityConfig)
|
||||
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
|
||||
then:
|
||||
advisor.order == Ordered.LOWEST_PRECEDENCE
|
||||
}
|
||||
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when extending GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,DefaultOrderExtendsMethodSecurityConfig)
|
||||
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
|
||||
then:
|
||||
advisor.order == Ordered.LOWEST_PRECEDENCE
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class DefaultOrderExtendsMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
|
||||
}
|
||||
@EnableGlobalMethodSecurity
|
||||
public static class DefaultOrderExtendsMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
|
||||
}
|
||||
|
||||
// --- pre-post-annotations ---
|
||||
// --- pre-post-annotations ---
|
||||
|
||||
def preAuthorize() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
def preAuthorize() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Configuration
|
||||
public static class PreAuthorizeConfig extends BaseMethodConfig {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Configuration
|
||||
public static class PreAuthorizeConfig extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
def "prePostEnabled extends GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,PreAuthorizeExtendsGMSCConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
def "prePostEnabled extends GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,PreAuthorizeExtendsGMSCConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Configuration
|
||||
public static class PreAuthorizeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Configuration
|
||||
public static class PreAuthorizeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
|
||||
}
|
||||
|
||||
// --- proxy-target-class ---
|
||||
// --- proxy-target-class ---
|
||||
|
||||
def "proxying classes works"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(ProxyTargetClass)
|
||||
MethodSecurityServiceImpl service = context.getBean(MethodSecurityServiceImpl)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "proxying classes works"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(ProxyTargetClass)
|
||||
MethodSecurityServiceImpl service = context.getBean(MethodSecurityServiceImpl)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(proxyTargetClass = true)
|
||||
@Configuration
|
||||
public static class ProxyTargetClass extends BaseMethodConfig {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(proxyTargetClass = true)
|
||||
@Configuration
|
||||
public static class ProxyTargetClass extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
def "proxying interfaces works"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then: "we get an instance of the interface"
|
||||
noExceptionThrown()
|
||||
when: "try to cast to the class"
|
||||
MethodSecurityServiceImpl serviceImpl = service
|
||||
then: "we get a class cast exception"
|
||||
thrown(ClassCastException)
|
||||
}
|
||||
def "proxying interfaces works"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then: "we get an instance of the interface"
|
||||
noExceptionThrown()
|
||||
when: "try to cast to the class"
|
||||
MethodSecurityServiceImpl serviceImpl = service
|
||||
then: "we get a class cast exception"
|
||||
thrown(ClassCastException)
|
||||
}
|
||||
|
||||
// --- run-as-manager-ref ---
|
||||
// --- run-as-manager-ref ---
|
||||
|
||||
def "custom RunAsManager"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomRunAsManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.runAs().authorities.find { it.authority == "ROLE_RUN_AS_SUPER"}
|
||||
}
|
||||
def "custom RunAsManager"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomRunAsManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.runAs().authorities.find { it.authority == "ROLE_RUN_AS_SUPER"}
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
public static class CustomRunAsManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected RunAsManager runAsManager() {
|
||||
RunAsManagerImpl runAsManager = new RunAsManagerImpl()
|
||||
runAsManager.setKey("some key")
|
||||
return runAsManager
|
||||
}
|
||||
}
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
public static class CustomRunAsManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected RunAsManager runAsManager() {
|
||||
RunAsManagerImpl runAsManager = new RunAsManagerImpl()
|
||||
runAsManager.setKey("some key")
|
||||
return runAsManager
|
||||
}
|
||||
}
|
||||
|
||||
// --- secured-annotation ---
|
||||
// --- secured-annotation ---
|
||||
|
||||
def "secured enabled"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(SecuredConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.secured()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
and: "service with ROLE_USER allowed"
|
||||
service.securedUser() == null
|
||||
and:
|
||||
service.preAuthorize() == null
|
||||
service.jsr250() == null
|
||||
}
|
||||
def "secured enabled"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(SecuredConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.secured()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
and: "service with ROLE_USER allowed"
|
||||
service.securedUser() == null
|
||||
and:
|
||||
service.preAuthorize() == null
|
||||
service.jsr250() == null
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
@Configuration
|
||||
public static class SecuredConfig extends BaseMethodConfig {
|
||||
}
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
@Configuration
|
||||
public static class SecuredConfig extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
// --- after-invocation-provider
|
||||
// --- after-invocation-provider
|
||||
|
||||
def "custom AfterInvocationManager"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAfterInvocationManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorizePermitAll()
|
||||
then:
|
||||
AccessDeniedException e = thrown()
|
||||
e.message == "custom AfterInvocationManager"
|
||||
}
|
||||
def "custom AfterInvocationManager"() {
|
||||
setup:
|
||||
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAfterInvocationManagerConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorizePermitAll()
|
||||
then:
|
||||
AccessDeniedException e = thrown()
|
||||
e.message == "custom AfterInvocationManager"
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class CustomAfterInvocationManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AfterInvocationManager afterInvocationManager() {
|
||||
return new AfterInvocationManagerStub()
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class CustomAfterInvocationManagerConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AfterInvocationManager afterInvocationManager() {
|
||||
return new AfterInvocationManagerStub()
|
||||
}
|
||||
|
||||
public static class AfterInvocationManagerStub implements AfterInvocationManager {
|
||||
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
throw new AccessDeniedException("custom AfterInvocationManager")
|
||||
}
|
||||
public static class AfterInvocationManagerStub implements AfterInvocationManager {
|
||||
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
throw new AccessDeniedException("custom AfterInvocationManager")
|
||||
}
|
||||
|
||||
boolean supports(ConfigAttribute attribute) {
|
||||
return true
|
||||
}
|
||||
boolean supports(Class<?> clazz) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean supports(ConfigAttribute attribute) {
|
||||
return true
|
||||
}
|
||||
boolean supports(Class<?> clazz) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- misc ---
|
||||
// --- misc ---
|
||||
|
||||
def "good error message when no Enable annotation"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(ExtendsNoEnableAnntotationConfig)
|
||||
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
|
||||
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.message.contains(EnableGlobalMethodSecurity.class.getName() + " is required")
|
||||
}
|
||||
def "good error message when no Enable annotation"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(ExtendsNoEnableAnntotationConfig)
|
||||
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
|
||||
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.message.contains(EnableGlobalMethodSecurity.class.getName() + " is required")
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class ExtendsNoEnableAnntotationConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager() {
|
||||
return new AuthenticationManager() {
|
||||
Authentication authenticate(Authentication authentication) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
public static class ExtendsNoEnableAnntotationConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager() {
|
||||
return new AuthenticationManager() {
|
||||
Authentication authenticate(Authentication authentication) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "import subclass of GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(ImportSubclassGMSCConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
def "import subclass of GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(ImportSubclassGMSCConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(PreAuthorizeExtendsGMSCConfig)
|
||||
public static class ImportSubclassGMSCConfig extends BaseMethodConfig {
|
||||
}
|
||||
@Configuration
|
||||
@Import(PreAuthorizeExtendsGMSCConfig)
|
||||
public static class ImportSubclassGMSCConfig extends BaseMethodConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class BaseMethodConfig extends BaseAuthenticationConfig {
|
||||
@Bean
|
||||
public MethodSecurityService methodSecurityService() {
|
||||
return new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
public static class BaseMethodConfig extends BaseAuthenticationConfig {
|
||||
@Bean
|
||||
public MethodSecurityService methodSecurityService() {
|
||||
return new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+71
-71
@@ -39,87 +39,87 @@ import org.springframework.security.core.context.SecurityContextHolder
|
||||
*
|
||||
*/
|
||||
public class SampleEnableGlobalMethodSecurityTests extends BaseSpringSpec {
|
||||
def setup() {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
}
|
||||
def setup() {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
}
|
||||
|
||||
def preAuthorize() {
|
||||
when:
|
||||
loadConfig(SampleWebSecurityConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
def preAuthorize() {
|
||||
when:
|
||||
loadConfig(SampleWebSecurityConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.secured() == null
|
||||
service.jsr250() == null
|
||||
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled=true)
|
||||
public static class SampleWebSecurityConfig {
|
||||
@Bean
|
||||
public MethodSecurityService methodSecurityService() {
|
||||
return new MethodSecurityServiceImpl()
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled=true)
|
||||
public static class SampleWebSecurityConfig {
|
||||
@Bean
|
||||
public MethodSecurityService methodSecurityService() {
|
||||
return new MethodSecurityServiceImpl()
|
||||
}
|
||||
|
||||
@Autowired
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
@Autowired
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
|
||||
def 'custom permission handler'() {
|
||||
when:
|
||||
loadConfig(CustomPermissionEvaluatorWebSecurityConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.hasPermission("allowed") == null
|
||||
def 'custom permission handler'() {
|
||||
when:
|
||||
loadConfig(CustomPermissionEvaluatorWebSecurityConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then:
|
||||
service.hasPermission("allowed") == null
|
||||
|
||||
when:
|
||||
service.hasPermission("denied") == null
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
when:
|
||||
service.hasPermission("denied") == null
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled=true)
|
||||
public static class CustomPermissionEvaluatorWebSecurityConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Bean
|
||||
public MethodSecurityService methodSecurityService() {
|
||||
return new MethodSecurityServiceImpl()
|
||||
}
|
||||
@EnableGlobalMethodSecurity(prePostEnabled=true)
|
||||
public static class CustomPermissionEvaluatorWebSecurityConfig extends GlobalMethodSecurityConfiguration {
|
||||
@Bean
|
||||
public MethodSecurityService methodSecurityService() {
|
||||
return new MethodSecurityServiceImpl()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MethodSecurityExpressionHandler createExpressionHandler() {
|
||||
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
|
||||
return expressionHandler;
|
||||
}
|
||||
@Override
|
||||
protected MethodSecurityExpressionHandler createExpressionHandler() {
|
||||
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
|
||||
return expressionHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomPermissionEvaluator implements PermissionEvaluator {
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Object targetDomainObject, Object permission) {
|
||||
return !"denied".equals(targetDomainObject);
|
||||
}
|
||||
static class CustomPermissionEvaluator implements PermissionEvaluator {
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Object targetDomainObject, Object permission) {
|
||||
return !"denied".equals(targetDomainObject);
|
||||
}
|
||||
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Serializable targetId, String targetType, Object permission) {
|
||||
return !"denied".equals(targetId);
|
||||
}
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Serializable targetId, String targetType, Object permission) {
|
||||
return !"denied".equals(targetId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+61
-61
@@ -29,69 +29,69 @@ import spock.lang.Specification
|
||||
*/
|
||||
class UserDetailsManagerConfigurerTests extends Specification {
|
||||
|
||||
def "all attributes supported"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.disabled(true)
|
||||
.accountExpired(true)
|
||||
.accountLocked(true)
|
||||
.credentialsExpired(true)
|
||||
.build()
|
||||
then:
|
||||
userDetails.username == 'user'
|
||||
userDetails.password == 'password'
|
||||
userDetails.authorities.collect { it.authority } == ["ROLE_USER"]
|
||||
!userDetails.accountNonExpired
|
||||
!userDetails.accountNonLocked
|
||||
!userDetails.credentialsNonExpired
|
||||
!userDetails.enabled
|
||||
}
|
||||
def "all attributes supported"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.disabled(true)
|
||||
.accountExpired(true)
|
||||
.accountLocked(true)
|
||||
.credentialsExpired(true)
|
||||
.build()
|
||||
then:
|
||||
userDetails.username == 'user'
|
||||
userDetails.password == 'password'
|
||||
userDetails.authorities.collect { it.authority } == ["ROLE_USER"]
|
||||
!userDetails.accountNonExpired
|
||||
!userDetails.accountNonLocked
|
||||
!userDetails.credentialsNonExpired
|
||||
!userDetails.enabled
|
||||
}
|
||||
|
||||
def "authorities(GrantedAuthorities...) works"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.authorities(authority)
|
||||
.build()
|
||||
then:
|
||||
userDetails.authorities == [authority] as Set
|
||||
}
|
||||
def "authorities(GrantedAuthorities...) works"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.authorities(authority)
|
||||
.build()
|
||||
then:
|
||||
userDetails.authorities == [authority] as Set
|
||||
}
|
||||
|
||||
def "authorities(String...) works"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
String authority = "ROLE_USER"
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.authorities(authority)
|
||||
.build()
|
||||
then:
|
||||
userDetails.authorities.collect { it.authority } == [authority]
|
||||
}
|
||||
def "authorities(String...) works"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
String authority = "ROLE_USER"
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.authorities(authority)
|
||||
.build()
|
||||
then:
|
||||
userDetails.authorities.collect { it.authority } == [authority]
|
||||
}
|
||||
|
||||
|
||||
def "authorities(List) works"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.authorities([authority])
|
||||
.build()
|
||||
then:
|
||||
userDetails.authorities == [authority] as Set
|
||||
}
|
||||
def "authorities(List) works"() {
|
||||
setup:
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
|
||||
when:
|
||||
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.authorities([authority])
|
||||
.build()
|
||||
then:
|
||||
userDetails.authorities == [authority] as Set
|
||||
}
|
||||
}
|
||||
|
||||
+121
-121
@@ -30,144 +30,144 @@ import spock.lang.Specification
|
||||
*/
|
||||
class AbstractConfiguredSecurityBuilderTests extends BaseSpringSpec {
|
||||
|
||||
ConcreteAbstractConfiguredBuilder builder
|
||||
ConcreteAbstractConfiguredBuilder builder
|
||||
|
||||
def setup() {
|
||||
builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor)
|
||||
}
|
||||
def setup() {
|
||||
builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor)
|
||||
}
|
||||
|
||||
def "Null ObjectPostProcessor rejected"() {
|
||||
when:
|
||||
new ConcreteAbstractConfiguredBuilder(null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
when:
|
||||
builder.objectPostProcessor(null);
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
def "Null ObjectPostProcessor rejected"() {
|
||||
when:
|
||||
new ConcreteAbstractConfiguredBuilder(null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
when:
|
||||
builder.objectPostProcessor(null);
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def "apply null is rejected"() {
|
||||
when:
|
||||
builder.apply(null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
def "apply null is rejected"() {
|
||||
when:
|
||||
builder.apply(null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def "Duplicate configurer is removed"() {
|
||||
when:
|
||||
builder.apply(new ConcreteConfigurer())
|
||||
builder.apply(new ConcreteConfigurer())
|
||||
then:
|
||||
ReflectionTestUtils.getField(builder,"configurers").size() == 1
|
||||
}
|
||||
def "Duplicate configurer is removed"() {
|
||||
when:
|
||||
builder.apply(new ConcreteConfigurer())
|
||||
builder.apply(new ConcreteConfigurer())
|
||||
then:
|
||||
ReflectionTestUtils.getField(builder,"configurers").size() == 1
|
||||
}
|
||||
|
||||
def "build twice fails"() {
|
||||
setup:
|
||||
builder.build()
|
||||
when:
|
||||
builder.build()
|
||||
then:
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
def "build twice fails"() {
|
||||
setup:
|
||||
builder.build()
|
||||
when:
|
||||
builder.build()
|
||||
then:
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
|
||||
def "getObject before build fails"() {
|
||||
when:
|
||||
builder.getObject()
|
||||
then:
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
def "getObject before build fails"() {
|
||||
when:
|
||||
builder.getObject()
|
||||
then:
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
|
||||
def "Configurer.init can apply another configurer"() {
|
||||
setup:
|
||||
DelegateConfigurer.CONF = Mock(SecurityConfigurerAdapter)
|
||||
when:
|
||||
builder.apply(new DelegateConfigurer())
|
||||
builder.build()
|
||||
then:
|
||||
1 * DelegateConfigurer.CONF.init(builder)
|
||||
1 * DelegateConfigurer.CONF.configure(builder)
|
||||
}
|
||||
def "Configurer.init can apply another configurer"() {
|
||||
setup:
|
||||
DelegateConfigurer.CONF = Mock(SecurityConfigurerAdapter)
|
||||
when:
|
||||
builder.apply(new DelegateConfigurer())
|
||||
builder.build()
|
||||
then:
|
||||
1 * DelegateConfigurer.CONF.init(builder)
|
||||
1 * DelegateConfigurer.CONF.configure(builder)
|
||||
}
|
||||
|
||||
def "getConfigurer with multi fails"() {
|
||||
setup:
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(new DelegateConfigurer())
|
||||
builder.apply(new DelegateConfigurer())
|
||||
when:
|
||||
builder.getConfigurer(DelegateConfigurer)
|
||||
then: "Fail due to trying to obtain a single DelegateConfigurer and multiple are provided"
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
def "getConfigurer with multi fails"() {
|
||||
setup:
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(new DelegateConfigurer())
|
||||
builder.apply(new DelegateConfigurer())
|
||||
when:
|
||||
builder.getConfigurer(DelegateConfigurer)
|
||||
then: "Fail due to trying to obtain a single DelegateConfigurer and multiple are provided"
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
|
||||
def "removeConfigurer with multi fails"() {
|
||||
setup:
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(new DelegateConfigurer())
|
||||
builder.apply(new DelegateConfigurer())
|
||||
when:
|
||||
builder.removeConfigurer(DelegateConfigurer)
|
||||
then: "Fail due to trying to remove and obtain a single DelegateConfigurer and multiple are provided"
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
def "removeConfigurer with multi fails"() {
|
||||
setup:
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(new DelegateConfigurer())
|
||||
builder.apply(new DelegateConfigurer())
|
||||
when:
|
||||
builder.removeConfigurer(DelegateConfigurer)
|
||||
then: "Fail due to trying to remove and obtain a single DelegateConfigurer and multiple are provided"
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
|
||||
def "removeConfigurers with multi"() {
|
||||
setup:
|
||||
DelegateConfigurer c1 = new DelegateConfigurer()
|
||||
DelegateConfigurer c2 = new DelegateConfigurer()
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(c1)
|
||||
builder.apply(c2)
|
||||
when:
|
||||
def result = builder.removeConfigurers(DelegateConfigurer)
|
||||
then:
|
||||
result.size() == 2
|
||||
result.contains(c1)
|
||||
result.contains(c2)
|
||||
builder.getConfigurers(DelegateConfigurer).empty
|
||||
}
|
||||
def "removeConfigurers with multi"() {
|
||||
setup:
|
||||
DelegateConfigurer c1 = new DelegateConfigurer()
|
||||
DelegateConfigurer c2 = new DelegateConfigurer()
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(c1)
|
||||
builder.apply(c2)
|
||||
when:
|
||||
def result = builder.removeConfigurers(DelegateConfigurer)
|
||||
then:
|
||||
result.size() == 2
|
||||
result.contains(c1)
|
||||
result.contains(c2)
|
||||
builder.getConfigurers(DelegateConfigurer).empty
|
||||
}
|
||||
|
||||
def "getConfigurers with multi"() {
|
||||
setup:
|
||||
DelegateConfigurer c1 = new DelegateConfigurer()
|
||||
DelegateConfigurer c2 = new DelegateConfigurer()
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(c1)
|
||||
builder.apply(c2)
|
||||
when:
|
||||
def result = builder.getConfigurers(DelegateConfigurer)
|
||||
then:
|
||||
result.size() == 2
|
||||
result.contains(c1)
|
||||
result.contains(c2)
|
||||
builder.getConfigurers(DelegateConfigurer).size() == 2
|
||||
}
|
||||
def "getConfigurers with multi"() {
|
||||
setup:
|
||||
DelegateConfigurer c1 = new DelegateConfigurer()
|
||||
DelegateConfigurer c2 = new DelegateConfigurer()
|
||||
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
|
||||
builder.apply(c1)
|
||||
builder.apply(c2)
|
||||
when:
|
||||
def result = builder.getConfigurers(DelegateConfigurer)
|
||||
then:
|
||||
result.size() == 2
|
||||
result.contains(c1)
|
||||
result.contains(c2)
|
||||
builder.getConfigurers(DelegateConfigurer).size() == 2
|
||||
}
|
||||
|
||||
private static class DelegateConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> {
|
||||
private static SecurityConfigurer<Object, ConcreteAbstractConfiguredBuilder> CONF;
|
||||
private static class DelegateConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> {
|
||||
private static SecurityConfigurer<Object, ConcreteAbstractConfiguredBuilder> CONF;
|
||||
|
||||
@Override
|
||||
public void init(ConcreteAbstractConfiguredBuilder builder)
|
||||
throws Exception {
|
||||
builder.apply(CONF);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void init(ConcreteAbstractConfiguredBuilder builder)
|
||||
throws Exception {
|
||||
builder.apply(CONF);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> { }
|
||||
private static class ConcreteConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> { }
|
||||
|
||||
private class ConcreteAbstractConfiguredBuilder extends AbstractConfiguredSecurityBuilder<Object, ConcreteAbstractConfiguredBuilder> {
|
||||
private class ConcreteAbstractConfiguredBuilder extends AbstractConfiguredSecurityBuilder<Object, ConcreteAbstractConfiguredBuilder> {
|
||||
|
||||
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
|
||||
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowMulti) {
|
||||
super(objectPostProcessor,allowMulti);
|
||||
}
|
||||
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowMulti) {
|
||||
super(objectPostProcessor,allowMulti);
|
||||
}
|
||||
|
||||
public Object performBuild() throws Exception {
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
public Object performBuild() throws Exception {
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+267
-267
@@ -34,286 +34,286 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
*
|
||||
*/
|
||||
public class SampleWebSecurityConfigurerAdapterTests extends BaseSpringSpec {
|
||||
def "README HelloWorld Sample works"() {
|
||||
setup: "Sample Config is loaded"
|
||||
loadConfig(HelloWorldWebSecurityConfigurerAdapter)
|
||||
when:
|
||||
request.addHeader("Accept", "text/html")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.addHeader("Accept", "text/html")
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
}
|
||||
def "README HelloWorld Sample works"() {
|
||||
setup: "Sample Config is loaded"
|
||||
loadConfig(HelloWorldWebSecurityConfigurerAdapter)
|
||||
when:
|
||||
request.addHeader("Accept", "text/html")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.addHeader("Accept", "text/html")
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>
|
||||
* <http>
|
||||
* <intercept-url pattern="/resources/**" access="permitAll"/>
|
||||
* <intercept-url pattern="/**" access="authenticated"/>
|
||||
* <logout
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login" <!-- Except Spring Security renders the login page -->
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* password-parameter="password"
|
||||
* username-parameter="username"
|
||||
* />
|
||||
* </http>
|
||||
* <authentication-manager>
|
||||
* <authentication-provider>
|
||||
* <user-service>
|
||||
* <user username="user" password="password" authorities="ROLE_USER"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </code>
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <code>
|
||||
* <http>
|
||||
* <intercept-url pattern="/resources/**" access="permitAll"/>
|
||||
* <intercept-url pattern="/**" access="authenticated"/>
|
||||
* <logout
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login" <!-- Except Spring Security renders the login page -->
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* password-parameter="password"
|
||||
* username-parameter="username"
|
||||
* />
|
||||
* </http>
|
||||
* <authentication-manager>
|
||||
* <authentication-provider>
|
||||
* <user-service>
|
||||
* <user username="user" password="password" authorities="ROLE_USER"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </code>
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
}
|
||||
|
||||
def "README Sample works"() {
|
||||
setup: "Sample Config is loaded"
|
||||
loadConfig(SampleWebSecurityConfigurerAdapter)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
}
|
||||
def "README Sample works"() {
|
||||
setup: "Sample Config is loaded"
|
||||
loadConfig(SampleWebSecurityConfigurerAdapter)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>
|
||||
* <http security="none" pattern="/resources/**"/>
|
||||
* <http>
|
||||
* <intercept-url pattern="/logout" access="permitAll"/>
|
||||
* <intercept-url pattern="/login" access="permitAll"/>
|
||||
* <intercept-url pattern="/signup" access="permitAll"/>
|
||||
* <intercept-url pattern="/about" access="permitAll"/>
|
||||
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
|
||||
* <logout
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login"
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* password-parameter="password"
|
||||
* username-parameter="username"
|
||||
* />
|
||||
* </http>
|
||||
* <authentication-manager>
|
||||
* <authentication-provider>
|
||||
* <user-service>
|
||||
* <user username="user" password="password" authorities="ROLE_USER"/>
|
||||
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </code>
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public static class SampleWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
/**
|
||||
* <code>
|
||||
* <http security="none" pattern="/resources/**"/>
|
||||
* <http>
|
||||
* <intercept-url pattern="/logout" access="permitAll"/>
|
||||
* <intercept-url pattern="/login" access="permitAll"/>
|
||||
* <intercept-url pattern="/signup" access="permitAll"/>
|
||||
* <intercept-url pattern="/about" access="permitAll"/>
|
||||
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
|
||||
* <logout
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login"
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* password-parameter="password"
|
||||
* username-parameter="username"
|
||||
* />
|
||||
* </http>
|
||||
* <authentication-manager>
|
||||
* <authentication-provider>
|
||||
* <user-service>
|
||||
* <user username="user" password="password" authorities="ROLE_USER"/>
|
||||
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </code>
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public static class SampleWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/signup","/about").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
// set permitAll for all URLs associated with Form Login
|
||||
.permitAll();
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/signup","/about").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
// set permitAll for all URLs associated with Form Login
|
||||
.permitAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
|
||||
def "README Multi http Sample works"() {
|
||||
setup:
|
||||
loadConfig(SampleMultiHttpSecurityConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
def "README Multi http Sample works"() {
|
||||
setup:
|
||||
loadConfig(SampleMultiHttpSecurityConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
|
||||
when: "request protected API URL"
|
||||
super.setup()
|
||||
request.servletPath = "/api/admin/test"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "get 401"
|
||||
response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when: "request protected API URL"
|
||||
super.setup()
|
||||
request.servletPath = "/api/admin/test"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "get 401"
|
||||
response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED
|
||||
|
||||
when: "request API for admins with user"
|
||||
super.setup()
|
||||
request.servletPath = "/api/admin/test"
|
||||
request.addHeader("Authorization", "Basic " + "user:password".bytes.encodeBase64().toString())
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "get 403"
|
||||
response.getStatus() == HttpServletResponse.SC_FORBIDDEN
|
||||
when: "request API for admins with user"
|
||||
super.setup()
|
||||
request.servletPath = "/api/admin/test"
|
||||
request.addHeader("Authorization", "Basic " + "user:password".bytes.encodeBase64().toString())
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "get 403"
|
||||
response.getStatus() == HttpServletResponse.SC_FORBIDDEN
|
||||
|
||||
when: "request API for admins with admin"
|
||||
super.setup()
|
||||
request.servletPath = "/api/admin/test"
|
||||
request.addHeader("Authorization", "Basic " + "admin:password".bytes.encodeBase64().toString())
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "get 200"
|
||||
response.getStatus() == HttpServletResponse.SC_OK
|
||||
}
|
||||
when: "request API for admins with admin"
|
||||
super.setup()
|
||||
request.servletPath = "/api/admin/test"
|
||||
request.addHeader("Authorization", "Basic " + "admin:password".bytes.encodeBase64().toString())
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "get 200"
|
||||
response.getStatus() == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>
|
||||
* <http security="none" pattern="/resources/**"/>
|
||||
* <http pattern="/api/**">
|
||||
* <intercept-url pattern="/api/admin/**" access="hasRole('ROLE_ADMIN')"/>
|
||||
* <intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/>
|
||||
* <http-basic />
|
||||
* </http>
|
||||
* <http>
|
||||
* <intercept-url pattern="/logout" access="permitAll"/>
|
||||
* <intercept-url pattern="/login" access="permitAll"/>
|
||||
* <intercept-url pattern="/signup" access="permitAll"/>
|
||||
* <intercept-url pattern="/about" access="permitAll"/>
|
||||
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
|
||||
* <logout
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login"
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* password-parameter="password"
|
||||
* username-parameter="username"
|
||||
* />
|
||||
* </http>
|
||||
* <authentication-manager>
|
||||
* <authentication-provider>
|
||||
* <user-service>
|
||||
* <user username="user" password="password" authorities="ROLE_USER"/>
|
||||
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </code>
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public static class SampleMultiHttpSecurityConfig {
|
||||
@Autowired
|
||||
protected void configure(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
/**
|
||||
* <code>
|
||||
* <http security="none" pattern="/resources/**"/>
|
||||
* <http pattern="/api/**">
|
||||
* <intercept-url pattern="/api/admin/**" access="hasRole('ROLE_ADMIN')"/>
|
||||
* <intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/>
|
||||
* <http-basic />
|
||||
* </http>
|
||||
* <http>
|
||||
* <intercept-url pattern="/logout" access="permitAll"/>
|
||||
* <intercept-url pattern="/login" access="permitAll"/>
|
||||
* <intercept-url pattern="/signup" access="permitAll"/>
|
||||
* <intercept-url pattern="/about" access="permitAll"/>
|
||||
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
|
||||
* <logout
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login"
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* password-parameter="password"
|
||||
* username-parameter="username"
|
||||
* />
|
||||
* </http>
|
||||
* <authentication-manager>
|
||||
* <authentication-provider>
|
||||
* <user-service>
|
||||
* <user username="user" password="password" authorities="ROLE_USER"/>
|
||||
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </code>
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public static class SampleMultiHttpSecurityConfig {
|
||||
@Autowired
|
||||
protected void configure(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Order(1)
|
||||
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/api/**")
|
||||
.authorizeRequests()
|
||||
.antMatchers("/api/admin/**").hasRole("ADMIN")
|
||||
.antMatchers("/api/**").hasRole("USER")
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@Order(1)
|
||||
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/api/**")
|
||||
.authorizeRequests()
|
||||
.antMatchers("/api/admin/**").hasRole("ADMIN")
|
||||
.antMatchers("/api/**").hasRole("USER")
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
@Configuration
|
||||
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/signup","/about").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.permitAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/signup","/about").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.permitAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+200
-200
@@ -56,240 +56,240 @@ import org.springframework.web.filter.OncePerRequestFilter
|
||||
*/
|
||||
class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
|
||||
|
||||
def "MessageSources populated on AuthenticationProviders"() {
|
||||
when:
|
||||
loadConfig(MessageSourcesPopulatedConfig)
|
||||
List<AuthenticationProvider> providers = authenticationProviders()
|
||||
then:
|
||||
providers*.messages*.messageSource == [context,context,context,context]
|
||||
}
|
||||
def "MessageSources populated on AuthenticationProviders"() {
|
||||
when:
|
||||
loadConfig(MessageSourcesPopulatedConfig)
|
||||
List<AuthenticationProvider> providers = authenticationProviders()
|
||||
then:
|
||||
providers*.messages*.messageSource == [context,context,context,context]
|
||||
}
|
||||
|
||||
def "messages set when using WebSecurityConfigurerAdapter"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
|
||||
then:
|
||||
authenticationManager.messages.messageSource instanceof ApplicationContext
|
||||
}
|
||||
def "messages set when using WebSecurityConfigurerAdapter"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
|
||||
then:
|
||||
authenticationManager.messages.messageSource instanceof ApplicationContext
|
||||
}
|
||||
|
||||
def "headers are populated by default"() {
|
||||
setup: "load config that overrides http and accepts defaults"
|
||||
loadConfig(HeadersArePopulatedByDefaultConfig)
|
||||
request.secure = true
|
||||
when: "invoke the springSecurityFilterChain"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "the default headers are added"
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Pragma':'no-cache',
|
||||
'Expires' : '0',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
def "headers are populated by default"() {
|
||||
setup: "load config that overrides http and accepts defaults"
|
||||
loadConfig(HeadersArePopulatedByDefaultConfig)
|
||||
request.secure = true
|
||||
when: "invoke the springSecurityFilterChain"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "the default headers are added"
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Pragma':'no-cache',
|
||||
'Expires' : '0',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HeadersArePopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class HeadersArePopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "webasync populated by default"() {
|
||||
when: "load config that overrides http and accepts defaults"
|
||||
loadConfig(WebAsyncPopulatedByDefaultConfig)
|
||||
then: "WebAsyncManagerIntegrationFilter is populated"
|
||||
findFilter(WebAsyncManagerIntegrationFilter)
|
||||
}
|
||||
def "webasync populated by default"() {
|
||||
when: "load config that overrides http and accepts defaults"
|
||||
loadConfig(WebAsyncPopulatedByDefaultConfig)
|
||||
then: "WebAsyncManagerIntegrationFilter is populated"
|
||||
findFilter(WebAsyncManagerIntegrationFilter)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebAsyncPopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class WebAsyncPopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "AuthenticationEventPublisher is registered for Web configure(AuthenticationManagerBuilder auth)"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
|
||||
then:
|
||||
authenticationManager.parent.eventPublisher instanceof DefaultAuthenticationEventPublisher
|
||||
when:
|
||||
Authentication token = new UsernamePasswordAuthenticationToken("user","password")
|
||||
authenticationManager.authenticate(token)
|
||||
then: "We only receive the AuthenticationSuccessEvent once"
|
||||
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS.size() == 1
|
||||
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS[0].authentication.name == token.principal
|
||||
}
|
||||
def "AuthenticationEventPublisher is registered for Web configure(AuthenticationManagerBuilder auth)"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
|
||||
then:
|
||||
authenticationManager.parent.eventPublisher instanceof DefaultAuthenticationEventPublisher
|
||||
when:
|
||||
Authentication token = new UsernamePasswordAuthenticationToken("user","password")
|
||||
authenticationManager.authenticate(token)
|
||||
then: "We only receive the AuthenticationSuccessEvent once"
|
||||
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS.size() == 1
|
||||
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS[0].authentication.name == token.principal
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InMemoryAuthWithWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter implements ApplicationListener<AuthenticationSuccessEvent> {
|
||||
static List<AuthenticationSuccessEvent> EVENTS = []
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class InMemoryAuthWithWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter implements ApplicationListener<AuthenticationSuccessEvent> {
|
||||
static List<AuthenticationSuccessEvent> EVENTS = []
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AuthenticationSuccessEvent e) {
|
||||
EVENTS.add(e)
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onApplicationEvent(AuthenticationSuccessEvent e) {
|
||||
EVENTS.add(e)
|
||||
}
|
||||
}
|
||||
|
||||
def "Override ContentNegotiationStrategy with @Bean"() {
|
||||
setup:
|
||||
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
|
||||
when:
|
||||
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
|
||||
then:
|
||||
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||
}
|
||||
def "Override ContentNegotiationStrategy with @Bean"() {
|
||||
setup:
|
||||
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
|
||||
when:
|
||||
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
|
||||
then:
|
||||
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
|
||||
static ContentNegotiationStrategy CNS
|
||||
@EnableWebSecurity
|
||||
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
|
||||
static ContentNegotiationStrategy CNS
|
||||
|
||||
@Bean
|
||||
public ContentNegotiationStrategy cns() {
|
||||
return CNS
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public ContentNegotiationStrategy cns() {
|
||||
return CNS
|
||||
}
|
||||
}
|
||||
|
||||
def "ContentNegotiationStrategy shareObject defaults to Header with no @Bean"() {
|
||||
when:
|
||||
loadConfig(ContentNegotiationStrategyDefaultSharedObjectConfig)
|
||||
then:
|
||||
context.getBean(ContentNegotiationStrategyDefaultSharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy).class == HeaderContentNegotiationStrategy
|
||||
}
|
||||
def "ContentNegotiationStrategy shareObject defaults to Header with no @Bean"() {
|
||||
when:
|
||||
loadConfig(ContentNegotiationStrategyDefaultSharedObjectConfig)
|
||||
then:
|
||||
context.getBean(ContentNegotiationStrategyDefaultSharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy).class == HeaderContentNegotiationStrategy
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ContentNegotiationStrategyDefaultSharedObjectConfig extends WebSecurityConfigurerAdapter {}
|
||||
@EnableWebSecurity
|
||||
static class ContentNegotiationStrategyDefaultSharedObjectConfig extends WebSecurityConfigurerAdapter {}
|
||||
|
||||
def "UserDetailsService lazy"() {
|
||||
setup:
|
||||
loadConfig(RequiresUserDetailsServiceConfig,UserDetailsServiceConfig)
|
||||
when:
|
||||
findFilter(MyFilter).userDetailsService.loadUserByUsername("user")
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
findFilter(MyFilter).userDetailsService.loadUserByUsername("admin")
|
||||
then:
|
||||
thrown(UsernameNotFoundException)
|
||||
}
|
||||
def "UserDetailsService lazy"() {
|
||||
setup:
|
||||
loadConfig(RequiresUserDetailsServiceConfig,UserDetailsServiceConfig)
|
||||
when:
|
||||
findFilter(MyFilter).userDetailsService.loadUserByUsername("user")
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
findFilter(MyFilter).userDetailsService.loadUserByUsername("admin")
|
||||
then:
|
||||
thrown(UsernameNotFoundException)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RequiresUserDetailsServiceConfig {
|
||||
@Bean
|
||||
public MyFilter myFilter(UserDetailsService uds) {
|
||||
return new MyFilter(uds)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RequiresUserDetailsServiceConfig {
|
||||
@Bean
|
||||
public MyFilter myFilter(UserDetailsService uds) {
|
||||
return new MyFilter(uds)
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class UserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private MyFilter myFilter;
|
||||
@EnableWebSecurity
|
||||
static class UserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private MyFilter myFilter;
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public UserDetailsService userDetailsServiceBean() {
|
||||
return super.userDetailsServiceBean()
|
||||
}
|
||||
@Bean
|
||||
@Override
|
||||
public UserDetailsService userDetailsServiceBean() {
|
||||
return super.userDetailsServiceBean()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterBefore(myFilter,UsernamePasswordAuthenticationFilter)
|
||||
}
|
||||
@Override
|
||||
public void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterBefore(myFilter,UsernamePasswordAuthenticationFilter)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object"() {
|
||||
when:
|
||||
loadConfig(ApplicationContextSharedObjectConfig)
|
||||
then:
|
||||
context.getBean(ApplicationContextSharedObjectConfig).http.getSharedObject(ApplicationContext) == context
|
||||
}
|
||||
def "SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object"() {
|
||||
when:
|
||||
loadConfig(ApplicationContextSharedObjectConfig)
|
||||
then:
|
||||
context.getBean(ApplicationContextSharedObjectConfig).http.getSharedObject(ApplicationContext) == context
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ApplicationContextSharedObjectConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class ApplicationContextSharedObjectConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class MyFilter extends OncePerRequestFilter {
|
||||
private UserDetailsService userDetailsService
|
||||
public MyFilter(UserDetailsService uds) {
|
||||
assert uds != null
|
||||
this.userDetailsService = uds
|
||||
}
|
||||
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
|
||||
chain.doFilter(request,response)
|
||||
}
|
||||
}
|
||||
static class MyFilter extends OncePerRequestFilter {
|
||||
private UserDetailsService userDetailsService
|
||||
public MyFilter(UserDetailsService uds) {
|
||||
assert uds != null
|
||||
this.userDetailsService = uds
|
||||
}
|
||||
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
|
||||
chain.doFilter(request,response)
|
||||
}
|
||||
}
|
||||
|
||||
def "AuthenticationTrustResolver populated as defaultObject"() {
|
||||
setup:
|
||||
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
|
||||
when:
|
||||
loadConfig(CustomTrustResolverConfig)
|
||||
then:
|
||||
context.getBean(CustomTrustResolverConfig).http.getSharedObject(AuthenticationTrustResolver) == CustomTrustResolverConfig.TR
|
||||
}
|
||||
def "AuthenticationTrustResolver populated as defaultObject"() {
|
||||
setup:
|
||||
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
|
||||
when:
|
||||
loadConfig(CustomTrustResolverConfig)
|
||||
then:
|
||||
context.getBean(CustomTrustResolverConfig).http.getSharedObject(AuthenticationTrustResolver) == CustomTrustResolverConfig.TR
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomTrustResolverConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationTrustResolver TR
|
||||
@EnableWebSecurity
|
||||
static class CustomTrustResolverConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationTrustResolver TR
|
||||
|
||||
@Bean
|
||||
public AuthenticationTrustResolver tr() {
|
||||
return TR
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public AuthenticationTrustResolver tr() {
|
||||
return TR
|
||||
}
|
||||
}
|
||||
|
||||
def "WebSecurityConfigurerAdapter has Ordered between 0 and lowest priority"() {
|
||||
when:
|
||||
def lowestConfig = new LowestPriorityWebSecurityConfig()
|
||||
def defaultConfig = new DefaultOrderWebSecurityConfig()
|
||||
def compare = new AnnotationAwareOrderComparator()
|
||||
then: "the default ordering is between 0 and lowest priority (Boot adapters)"
|
||||
compare.compare(lowestConfig, defaultConfig) > 0
|
||||
}
|
||||
def "WebSecurityConfigurerAdapter has Ordered between 0 and lowest priority"() {
|
||||
when:
|
||||
def lowestConfig = new LowestPriorityWebSecurityConfig()
|
||||
def defaultConfig = new DefaultOrderWebSecurityConfig()
|
||||
def compare = new AnnotationAwareOrderComparator()
|
||||
then: "the default ordering is between 0 and lowest priority (Boot adapters)"
|
||||
compare.compare(lowestConfig, defaultConfig) > 0
|
||||
}
|
||||
|
||||
class DefaultOrderWebSecurityConfig extends WebSecurityConfigurerAdapter {}
|
||||
class DefaultOrderWebSecurityConfig extends WebSecurityConfigurerAdapter {}
|
||||
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class LowestPriorityWebSecurityConfig extends WebSecurityConfigurerAdapter {}
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class LowestPriorityWebSecurityConfig extends WebSecurityConfigurerAdapter {}
|
||||
}
|
||||
|
||||
+70
-70
@@ -41,81 +41,81 @@ import spock.lang.Unroll;
|
||||
*
|
||||
*/
|
||||
public class HttpSecurityTests extends BaseSpringSpec {
|
||||
def "addFilter with unregistered Filter"() {
|
||||
when:
|
||||
loadConfig(UnregisteredFilterConfig)
|
||||
then:
|
||||
BeanCreationException success = thrown()
|
||||
success.message.contains "The Filter class ${UnregisteredFilter.name} does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."
|
||||
}
|
||||
def "addFilter with unregistered Filter"() {
|
||||
when:
|
||||
loadConfig(UnregisteredFilterConfig)
|
||||
then:
|
||||
BeanCreationException success = thrown()
|
||||
success.message.contains "The Filter class ${UnregisteredFilter.name} does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UnregisteredFilterConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilter(new UnregisteredFilter())
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class UnregisteredFilterConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilter(new UnregisteredFilter())
|
||||
}
|
||||
}
|
||||
|
||||
static class UnregisteredFilter extends OncePerRequestFilter {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
static class UnregisteredFilter extends OncePerRequestFilter {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/SpringSource/spring-security-javaconfig/issues/104
|
||||
def "#104 addFilter CasAuthenticationFilter"() {
|
||||
when:
|
||||
loadConfig(CasAuthenticationFilterConfig)
|
||||
then:
|
||||
findFilter(CasAuthenticationFilter)
|
||||
}
|
||||
// https://github.com/SpringSource/spring-security-javaconfig/issues/104
|
||||
def "#104 addFilter CasAuthenticationFilter"() {
|
||||
when:
|
||||
loadConfig(CasAuthenticationFilterConfig)
|
||||
then:
|
||||
findFilter(CasAuthenticationFilter)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CasAuthenticationFilterConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilter(new CasAuthenticationFilter())
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class CasAuthenticationFilterConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilter(new CasAuthenticationFilter())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Unroll
|
||||
def "requestMatchers javadoc"() {
|
||||
setup: "load configuration like the config on the requestMatchers() javadoc"
|
||||
loadConfig(RequestMatcherRegistryConfigs)
|
||||
when:
|
||||
super.setup()
|
||||
request.servletPath = "/oauth/a"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
where:
|
||||
servletPath | _
|
||||
"/oauth/a" | _
|
||||
"/oauth/b" | _
|
||||
"/api/a" | _
|
||||
"/api/b" | _
|
||||
"/oauth2/b" | _
|
||||
"/api2/b" | _
|
||||
}
|
||||
@Unroll
|
||||
def "requestMatchers javadoc"() {
|
||||
setup: "load configuration like the config on the requestMatchers() javadoc"
|
||||
loadConfig(RequestMatcherRegistryConfigs)
|
||||
when:
|
||||
super.setup()
|
||||
request.servletPath = "/oauth/a"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
where:
|
||||
servletPath | _
|
||||
"/oauth/a" | _
|
||||
"/oauth/b" | _
|
||||
"/api/a" | _
|
||||
"/api/b" | _
|
||||
"/oauth2/b" | _
|
||||
"/api2/b" | _
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RequestMatcherRegistryConfigs extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requestMatchers()
|
||||
.antMatchers("/api/**")
|
||||
.antMatchers("/oauth/**")
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/**").hasRole("USER")
|
||||
.and()
|
||||
.httpBasic()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class RequestMatcherRegistryConfigs extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requestMatchers()
|
||||
.antMatchers("/api/**")
|
||||
.antMatchers("/oauth/**")
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/**").hasRole("USER")
|
||||
.and()
|
||||
.httpBasic()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+104
-46
@@ -13,8 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
package org.springframework.security.config.annotation.web.configuration
|
||||
|
||||
import org.springframework.mock.web.MockServletContext
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.security.core.context.SecurityContext
|
||||
import org.springframework.security.core.context.SecurityContextImpl
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
import org.springframework.test.context.web.WebAppConfiguration
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
@@ -25,61 +39,105 @@ import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter
|
||||
import org.springframework.security.web.debug.DebugFilter;
|
||||
import org.springframework.security.web.debug.DebugFilter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
class EnableWebSecurityTests extends BaseSpringSpec {
|
||||
|
||||
def "@Bean(BeanIds.AUTHENTICATION_MANAGER) includes HttpSecurity's AuthenticationManagerBuilder"() {
|
||||
when:
|
||||
loadConfig(SecurityConfig)
|
||||
AuthenticationManager authenticationManager = context.getBean(AuthenticationManager)
|
||||
AnonymousAuthenticationToken anonymousAuthToken = findFilter(AnonymousAuthenticationFilter).createAuthentication(new MockHttpServletRequest())
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
authenticationManager.authenticate(anonymousAuthToken)
|
||||
def "@Bean(BeanIds.AUTHENTICATION_MANAGER) includes HttpSecurity's AuthenticationManagerBuilder"() {
|
||||
when:
|
||||
loadConfig(SecurityConfig)
|
||||
AuthenticationManager authenticationManager = context.getBean(AuthenticationManager)
|
||||
AnonymousAuthenticationToken anonymousAuthToken = findFilter(AnonymousAuthenticationFilter).createAuthentication(new MockHttpServletRequest())
|
||||
then:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
authenticationManager.authenticate(anonymousAuthToken)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EnableWebSecurity
|
||||
static class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/*").hasRole("USER")
|
||||
.and()
|
||||
.formLogin();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/*").hasRole("USER")
|
||||
.and()
|
||||
.formLogin();
|
||||
}
|
||||
}
|
||||
|
||||
def "@EnableWebSecurity on superclass"() {
|
||||
when:
|
||||
loadConfig(ChildSecurityConfig)
|
||||
then:
|
||||
context.getBean("springSecurityFilterChain", DebugFilter)
|
||||
}
|
||||
def "@EnableWebSecurity on superclass"() {
|
||||
when:
|
||||
loadConfig(ChildSecurityConfig)
|
||||
then:
|
||||
context.getBean("springSecurityFilterChain", DebugFilter)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ChildSecurityConfig extends DebugSecurityConfig {
|
||||
}
|
||||
@Configuration
|
||||
static class ChildSecurityConfig extends DebugSecurityConfig {
|
||||
}
|
||||
|
||||
@EnableWebSecurity(debug=true)
|
||||
static class DebugSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity(debug=true)
|
||||
static class DebugSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2942: EnableWebSecurity adds AuthenticationPrincipalArgumentResolver"() {
|
||||
setup:
|
||||
def username = "test"
|
||||
context = new AnnotationConfigWebApplicationContext()
|
||||
context.servletContext = new MockServletContext()
|
||||
context.register(AuthenticationPrincipalConfig)
|
||||
context.refresh()
|
||||
SecurityContext securityContext = new SecurityContextImpl(authentication: new TestingAuthenticationToken(username, "pass", "ROLE_USER"))
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup(context)
|
||||
.addFilters(springSecurityFilterChain)
|
||||
.build()
|
||||
when:
|
||||
String body = mockMvc
|
||||
.perform(get("/").sessionAttr(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext))
|
||||
.andReturn().response.contentAsString
|
||||
then:
|
||||
body == username
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
@Configuration
|
||||
static class AuthenticationPrincipalConfig {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class AuthController {
|
||||
|
||||
@RequestMapping("/")
|
||||
String principal(@AuthenticationPrincipal String principal) {
|
||||
principal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+254
-254
@@ -47,295 +47,295 @@ import org.springframework.test.util.ReflectionTestUtils
|
||||
*/
|
||||
class WebSecurityConfigurationTests extends BaseSpringSpec {
|
||||
|
||||
def "WebSecurityConfigurers are sorted"() {
|
||||
when:
|
||||
loadConfig(SortedWebSecurityConfigurerAdaptersConfig);
|
||||
List<SecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
|
||||
then:
|
||||
filterChains[0].requestMatcher.pattern == "/ignore1"
|
||||
filterChains[0].filters.empty
|
||||
filterChains[1].requestMatcher.pattern == "/ignore2"
|
||||
filterChains[1].filters.empty
|
||||
def "WebSecurityConfigurers are sorted"() {
|
||||
when:
|
||||
loadConfig(SortedWebSecurityConfigurerAdaptersConfig);
|
||||
List<SecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
|
||||
then:
|
||||
filterChains[0].requestMatcher.pattern == "/ignore1"
|
||||
filterChains[0].filters.empty
|
||||
filterChains[1].requestMatcher.pattern == "/ignore2"
|
||||
filterChains[1].filters.empty
|
||||
|
||||
filterChains[2].requestMatcher.pattern == "/role1/**"
|
||||
filterChains[3].requestMatcher.pattern == "/role2/**"
|
||||
filterChains[4].requestMatcher.pattern == "/role3/**"
|
||||
filterChains[5].requestMatcher.class == AnyRequestMatcher
|
||||
}
|
||||
filterChains[2].requestMatcher.pattern == "/role1/**"
|
||||
filterChains[3].requestMatcher.pattern == "/role2/**"
|
||||
filterChains[4].requestMatcher.pattern == "/role3/**"
|
||||
filterChains[5].requestMatcher.class == AnyRequestMatcher
|
||||
}
|
||||
|
||||
|
||||
@EnableWebSecurity
|
||||
static class SortedWebSecurityConfigurerAdaptersConfig {
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new AuthenticationManagerBuilder()
|
||||
.inMemoryAuthentication()
|
||||
.withUser("marissa").password("koala").roles("USER").and()
|
||||
.withUser("paul").password("emu").roles("USER").and()
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class SortedWebSecurityConfigurerAdaptersConfig {
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new AuthenticationManagerBuilder()
|
||||
.inMemoryAuthentication()
|
||||
.withUser("marissa").password("koala").roles("USER").and()
|
||||
.withUser("paul").password("emu").roles("USER").and()
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Order(1)
|
||||
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/ignore1","/ignore2");
|
||||
}
|
||||
@Configuration
|
||||
@Order(1)
|
||||
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/ignore1","/ignore2");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role1/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("1");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role1/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("1");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Order(2)
|
||||
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role2/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("2");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@Order(2)
|
||||
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role2/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("2");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Order(3)
|
||||
public static class WebConfigurer3 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role3/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("3");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@Order(3)
|
||||
public static class WebConfigurer3 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role3/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("3");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class WebConfigurer4 extends WebSecurityConfigurerAdapter {
|
||||
@Configuration
|
||||
public static class WebConfigurer4 extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("4");
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("4");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "WebSecurityConfigurers fails with duplicate order"() {
|
||||
when:
|
||||
loadConfig(DuplicateOrderConfig);
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.message.contains "@Order on WebSecurityConfigurers must be unique"
|
||||
}
|
||||
def "WebSecurityConfigurers fails with duplicate order"() {
|
||||
when:
|
||||
loadConfig(DuplicateOrderConfig);
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.message.contains "@Order on WebSecurityConfigurers must be unique"
|
||||
}
|
||||
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DuplicateOrderConfig {
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new AuthenticationManagerBuilder()
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class DuplicateOrderConfig {
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new AuthenticationManagerBuilder()
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
|
||||
@Configuration
|
||||
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role1/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("1");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role1/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("1");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role2/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("2");
|
||||
}
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/role2/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "Override privilegeEvaluator"() {
|
||||
setup:
|
||||
WebInvocationPrivilegeEvaluator privilegeEvaluator = Mock()
|
||||
PrivilegeEvaluatorConfigurerAdapterConfig.PE = privilegeEvaluator
|
||||
when:
|
||||
loadConfig(PrivilegeEvaluatorConfigurerAdapterConfig)
|
||||
then:
|
||||
context.getBean(WebInvocationPrivilegeEvaluator) == privilegeEvaluator
|
||||
}
|
||||
def "Override privilegeEvaluator"() {
|
||||
setup:
|
||||
WebInvocationPrivilegeEvaluator privilegeEvaluator = Mock()
|
||||
PrivilegeEvaluatorConfigurerAdapterConfig.PE = privilegeEvaluator
|
||||
when:
|
||||
loadConfig(PrivilegeEvaluatorConfigurerAdapterConfig)
|
||||
then:
|
||||
context.getBean(WebInvocationPrivilegeEvaluator) == privilegeEvaluator
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PrivilegeEvaluatorConfigurerAdapterConfig extends WebSecurityConfigurerAdapter {
|
||||
static WebInvocationPrivilegeEvaluator PE
|
||||
@EnableWebSecurity
|
||||
static class PrivilegeEvaluatorConfigurerAdapterConfig extends WebSecurityConfigurerAdapter {
|
||||
static WebInvocationPrivilegeEvaluator PE
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.privilegeEvaluator(PE)
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.privilegeEvaluator(PE)
|
||||
}
|
||||
}
|
||||
|
||||
def "Override webSecurityExpressionHandler"() {
|
||||
setup:
|
||||
SecurityExpressionHandler expressionHandler = Mock()
|
||||
ExpressionParser parser = Mock()
|
||||
WebSecurityExpressionHandlerConfig.EH = expressionHandler
|
||||
when:
|
||||
loadConfig(WebSecurityExpressionHandlerConfig)
|
||||
then:
|
||||
context.getBean(SecurityExpressionHandler) == expressionHandler
|
||||
1 * expressionHandler.getExpressionParser() >> parser
|
||||
}
|
||||
def "Override webSecurityExpressionHandler"() {
|
||||
setup:
|
||||
SecurityExpressionHandler expressionHandler = Mock()
|
||||
ExpressionParser parser = Mock()
|
||||
WebSecurityExpressionHandlerConfig.EH = expressionHandler
|
||||
when:
|
||||
loadConfig(WebSecurityExpressionHandlerConfig)
|
||||
then:
|
||||
context.getBean(SecurityExpressionHandler) == expressionHandler
|
||||
1 * expressionHandler.getExpressionParser() >> parser
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
|
||||
static SecurityExpressionHandler EH
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
|
||||
static SecurityExpressionHandler EH
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.expressionHandler(EH)
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.expressionHandler(EH)
|
||||
.anyRequest().authenticated()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.expressionHandler(EH)
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.expressionHandler(EH)
|
||||
.anyRequest().authenticated()
|
||||
}
|
||||
}
|
||||
|
||||
def "#138 webSecurityExpressionHandler defaults"() {
|
||||
when:
|
||||
loadConfig(WebSecurityExpressionHandlerDefaultsConfig)
|
||||
then:
|
||||
SecurityExpressionHandler wseh = context.getBean(SecurityExpressionHandler)
|
||||
wseh instanceof DefaultWebSecurityExpressionHandler
|
||||
}
|
||||
def "#138 webSecurityExpressionHandler defaults"() {
|
||||
when:
|
||||
loadConfig(WebSecurityExpressionHandlerDefaultsConfig)
|
||||
then:
|
||||
SecurityExpressionHandler wseh = context.getBean(SecurityExpressionHandler)
|
||||
wseh instanceof DefaultWebSecurityExpressionHandler
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityExpressionHandlerDefaultsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityExpressionHandlerDefaultsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
}
|
||||
}
|
||||
|
||||
def "#138 WebInvocationPrivilegeEvaluator defaults"() {
|
||||
when:
|
||||
loadConfig(WebInvocationPrivilegeEvaluatorDefaultsConfig)
|
||||
then:
|
||||
WebInvocationPrivilegeEvaluator wipe = context.getBean(WebInvocationPrivilegeEvaluator)
|
||||
wipe instanceof DefaultWebInvocationPrivilegeEvaluator
|
||||
wipe.securityInterceptor != null
|
||||
}
|
||||
def "#138 WebInvocationPrivilegeEvaluator defaults"() {
|
||||
when:
|
||||
loadConfig(WebInvocationPrivilegeEvaluatorDefaultsConfig)
|
||||
then:
|
||||
WebInvocationPrivilegeEvaluator wipe = context.getBean(WebInvocationPrivilegeEvaluator)
|
||||
wipe instanceof DefaultWebInvocationPrivilegeEvaluator
|
||||
wipe.securityInterceptor != null
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebInvocationPrivilegeEvaluatorDefaultsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class WebInvocationPrivilegeEvaluatorDefaultsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2303: DefaultExpressionHandler has bean resolver set"() {
|
||||
when:
|
||||
loadConfig(DefaultExpressionHandlerSetsBeanResolverConfig)
|
||||
then: "the exposed bean has a BeanResolver set"
|
||||
ReflectionTestUtils.getField(context.getBean(SecurityExpressionHandler),"br")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "we can use the BeanResolver with a grant"
|
||||
noExceptionThrown()
|
||||
when: "we can use the Beanresolver with a deny"
|
||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(method:'POST'), response, chain)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "SEC-2303: DefaultExpressionHandler has bean resolver set"() {
|
||||
when:
|
||||
loadConfig(DefaultExpressionHandlerSetsBeanResolverConfig)
|
||||
then: "the exposed bean has a BeanResolver set"
|
||||
ReflectionTestUtils.getField(context.getBean(SecurityExpressionHandler),"br")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "we can use the BeanResolver with a grant"
|
||||
noExceptionThrown()
|
||||
when: "we can use the Beanresolver with a deny"
|
||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(method:'POST'), response, chain)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultExpressionHandlerSetsBeanResolverConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class DefaultExpressionHandlerSetsBeanResolverConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().access("request.method == 'GET' ? @b.grant() : @b.deny()")
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().access("request.method == 'GET' ? @b.grant() : @b.deny()")
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyBean b() {
|
||||
new MyBean()
|
||||
}
|
||||
@Bean
|
||||
public MyBean b() {
|
||||
new MyBean()
|
||||
}
|
||||
|
||||
static class MyBean {
|
||||
boolean deny() {
|
||||
false
|
||||
}
|
||||
static class MyBean {
|
||||
boolean deny() {
|
||||
false
|
||||
}
|
||||
|
||||
boolean grant() {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean grant() {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2461: Multiple WebSecurityConfiguration instances cause null springSecurityFilterChain"() {
|
||||
setup:
|
||||
def parent = loadConfig(ParentConfig)
|
||||
def child = new AnnotationConfigApplicationContext()
|
||||
child.register(ChildConfig)
|
||||
child.parent = parent
|
||||
when:
|
||||
child.refresh()
|
||||
then: "springSecurityFilterChain can be found in parent and child"
|
||||
parent.getBean("springSecurityFilterChain")
|
||||
child.getBean("springSecurityFilterChain")
|
||||
and: "springSecurityFilterChain is defined in both parent and child (don't search parent)"
|
||||
parent.containsBeanDefinition("springSecurityFilterChain")
|
||||
child.containsBeanDefinition("springSecurityFilterChain")
|
||||
cleanup:
|
||||
child?.close()
|
||||
// parent.close() is in superclass
|
||||
}
|
||||
def "SEC-2461: Multiple WebSecurityConfiguration instances cause null springSecurityFilterChain"() {
|
||||
setup:
|
||||
def parent = loadConfig(ParentConfig)
|
||||
def child = new AnnotationConfigApplicationContext()
|
||||
child.register(ChildConfig)
|
||||
child.parent = parent
|
||||
when:
|
||||
child.refresh()
|
||||
then: "springSecurityFilterChain can be found in parent and child"
|
||||
parent.getBean("springSecurityFilterChain")
|
||||
child.getBean("springSecurityFilterChain")
|
||||
and: "springSecurityFilterChain is defined in both parent and child (don't search parent)"
|
||||
parent.containsBeanDefinition("springSecurityFilterChain")
|
||||
child.containsBeanDefinition("springSecurityFilterChain")
|
||||
cleanup:
|
||||
child?.close()
|
||||
// parent.close() is in superclass
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ParentConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class ParentConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ChildConfig extends WebSecurityConfigurerAdapter { }
|
||||
@EnableWebSecurity
|
||||
static class ChildConfig extends WebSecurityConfigurerAdapter { }
|
||||
|
||||
def "SEC-2773: delegatingApplicationListener is static method"() {
|
||||
expect: 'delegatingApplicationListener to prevent premature instantiation of WebSecurityConfiguration'
|
||||
Modifier.isStatic(WebSecurityConfiguration.metaClass.methods.find { it.name == 'delegatingApplicationListener'}.modifiers)
|
||||
}
|
||||
def "SEC-2773: delegatingApplicationListener is static method"() {
|
||||
expect: 'delegatingApplicationListener to prevent premature instantiation of WebSecurityConfiguration'
|
||||
Modifier.isStatic(WebSecurityConfiguration.metaClass.methods.find { it.name == 'delegatingApplicationListener'}.modifiers)
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -22,17 +22,17 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
|
||||
|
||||
public class Sec2377Tests extends BaseSpringSpec {
|
||||
|
||||
def "SEC-2377: Error reporting with multiple EnableWebSecurity from other packages"() {
|
||||
when:
|
||||
AnnotationConfigWebApplicationContext parent = new AnnotationConfigWebApplicationContext()
|
||||
parent.register(Sec2377AConfig)
|
||||
parent.refresh()
|
||||
def "SEC-2377: Error reporting with multiple EnableWebSecurity from other packages"() {
|
||||
when:
|
||||
AnnotationConfigWebApplicationContext parent = new AnnotationConfigWebApplicationContext()
|
||||
parent.register(Sec2377AConfig)
|
||||
parent.refresh()
|
||||
|
||||
AnnotationConfigWebApplicationContext child = new AnnotationConfigWebApplicationContext()
|
||||
child.register(Sec2377BConfig)
|
||||
child.parent = parent
|
||||
child.refresh()
|
||||
then:
|
||||
noExceptionThrown();
|
||||
}
|
||||
AnnotationConfigWebApplicationContext child = new AnnotationConfigWebApplicationContext()
|
||||
child.register(Sec2377BConfig)
|
||||
child.parent = parent
|
||||
child.refresh()
|
||||
then:
|
||||
noExceptionThrown();
|
||||
}
|
||||
}
|
||||
|
||||
+33
-33
@@ -29,43 +29,43 @@ import spock.lang.Specification
|
||||
*
|
||||
*/
|
||||
class AbstractConfigAttributeRequestMatcherRegistryTests extends Specification {
|
||||
ConcreteAbstractRequestMatcherMappingConfigurer registry = new ConcreteAbstractRequestMatcherMappingConfigurer()
|
||||
ConcreteAbstractRequestMatcherMappingConfigurer registry = new ConcreteAbstractRequestMatcherMappingConfigurer()
|
||||
|
||||
def "regexMatchers(GET,'/a.*') uses RegexRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.regexMatchers(HttpMethod.GET,"/a.*")
|
||||
then: 'matcher is a RegexRequestMatcher'
|
||||
matchers.collect {it.class } == [RegexRequestMatcher]
|
||||
}
|
||||
def "regexMatchers(GET,'/a.*') uses RegexRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.regexMatchers(HttpMethod.GET,"/a.*")
|
||||
then: 'matcher is a RegexRequestMatcher'
|
||||
matchers.collect {it.class } == [RegexRequestMatcher]
|
||||
}
|
||||
|
||||
def "regexMatchers('/a.*') uses RegexRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.regexMatchers("/a.*")
|
||||
then: 'matcher is a RegexRequestMatcher'
|
||||
matchers.collect {it.class } == [RegexRequestMatcher]
|
||||
}
|
||||
def "regexMatchers('/a.*') uses RegexRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.regexMatchers("/a.*")
|
||||
then: 'matcher is a RegexRequestMatcher'
|
||||
matchers.collect {it.class } == [RegexRequestMatcher]
|
||||
}
|
||||
|
||||
def "antMatchers(GET,'/a.*') uses AntPathRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.antMatchers(HttpMethod.GET, "/a.*")
|
||||
then: 'matcher is a RegexRequestMatcher'
|
||||
matchers.collect {it.class } == [AntPathRequestMatcher]
|
||||
}
|
||||
def "antMatchers(GET,'/a.*') uses AntPathRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.antMatchers(HttpMethod.GET, "/a.*")
|
||||
then: 'matcher is a RegexRequestMatcher'
|
||||
matchers.collect {it.class } == [AntPathRequestMatcher]
|
||||
}
|
||||
|
||||
def "antMatchers('/a.*') uses AntPathRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.antMatchers("/a.*")
|
||||
then: 'matcher is a AntPathRequestMatcher'
|
||||
matchers.collect {it.class } == [AntPathRequestMatcher]
|
||||
}
|
||||
def "antMatchers('/a.*') uses AntPathRequestMatcher"() {
|
||||
when:
|
||||
def matchers = registry.antMatchers("/a.*")
|
||||
then: 'matcher is a AntPathRequestMatcher'
|
||||
matchers.collect {it.class } == [AntPathRequestMatcher]
|
||||
}
|
||||
|
||||
static class ConcreteAbstractRequestMatcherMappingConfigurer extends AbstractConfigAttributeRequestMatcherRegistry<List<RequestMatcher>> {
|
||||
List<AccessDecisionVoter> decisionVoters() {
|
||||
return null;
|
||||
}
|
||||
static class ConcreteAbstractRequestMatcherMappingConfigurer extends AbstractConfigAttributeRequestMatcherRegistry<List<RequestMatcher>> {
|
||||
List<AccessDecisionVoter> decisionVoters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RequestMatcher> chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return requestMatchers;
|
||||
}
|
||||
}
|
||||
List<RequestMatcher> chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return requestMatchers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -31,23 +31,23 @@ import org.springframework.security.web.authentication.logout.LogoutFilter
|
||||
*/
|
||||
class AnonymousConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "invoke logout twice does not override"() {
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
then:
|
||||
findFilter(AnonymousAuthenticationFilter).key == "custom"
|
||||
}
|
||||
def "invoke logout twice does not override"() {
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
then:
|
||||
findFilter(AnonymousAuthenticationFilter).key == "custom"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.anonymous()
|
||||
.key("custom")
|
||||
.and()
|
||||
.anonymous()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.anonymous()
|
||||
.key("custom")
|
||||
.and()
|
||||
.anonymous()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-38
@@ -33,46 +33,46 @@ import org.springframework.security.web.access.channel.SecureChannelProcessor
|
||||
*/
|
||||
class ChannelSecurityConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "requiresChannel ObjectPostProcessor"() {
|
||||
setup: "initialize the AUTH_FILTER as a mock"
|
||||
AnyObjectPostProcessor objectPostProcessor = Mock()
|
||||
when:
|
||||
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
|
||||
http
|
||||
.requiresChannel()
|
||||
.anyRequest().requiresSecure()
|
||||
.and()
|
||||
.build()
|
||||
def "requiresChannel ObjectPostProcessor"() {
|
||||
setup: "initialize the AUTH_FILTER as a mock"
|
||||
AnyObjectPostProcessor objectPostProcessor = Mock()
|
||||
when:
|
||||
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
|
||||
http
|
||||
.requiresChannel()
|
||||
.anyRequest().requiresSecure()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "InsecureChannelProcessor is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as InsecureChannelProcessor) >> {InsecureChannelProcessor o -> o}
|
||||
and: "SecureChannelProcessor is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as SecureChannelProcessor) >> {SecureChannelProcessor o -> o}
|
||||
and: "ChannelDecisionManagerImpl is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as ChannelDecisionManagerImpl) >> {ChannelDecisionManagerImpl o -> o}
|
||||
and: "ChannelProcessingFilter is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as ChannelProcessingFilter) >> {ChannelProcessingFilter o -> o}
|
||||
}
|
||||
then: "InsecureChannelProcessor is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as InsecureChannelProcessor) >> {InsecureChannelProcessor o -> o}
|
||||
and: "SecureChannelProcessor is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as SecureChannelProcessor) >> {SecureChannelProcessor o -> o}
|
||||
and: "ChannelDecisionManagerImpl is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as ChannelDecisionManagerImpl) >> {ChannelDecisionManagerImpl o -> o}
|
||||
and: "ChannelProcessingFilter is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as ChannelProcessingFilter) >> {ChannelProcessingFilter o -> o}
|
||||
}
|
||||
|
||||
def "invoke requiresChannel twice does not override"() {
|
||||
setup:
|
||||
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost"
|
||||
}
|
||||
def "invoke requiresChannel twice does not override"() {
|
||||
setup:
|
||||
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requiresChannel()
|
||||
.anyRequest().requiresSecure()
|
||||
.and()
|
||||
.requiresChannel()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requiresChannel()
|
||||
.anyRequest().requiresSecure()
|
||||
.and()
|
||||
.requiresChannel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+385
-385
@@ -42,428 +42,428 @@ import spock.lang.Unroll
|
||||
*/
|
||||
class CsrfConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
@Unroll
|
||||
def "csrf applied by default"() {
|
||||
setup:
|
||||
loadConfig(CsrfAppliedDefaultConfig)
|
||||
request.method = httpMethod
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
httpMethod | httpStatus
|
||||
'POST' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PUT' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PATCH' | HttpServletResponse.SC_FORBIDDEN
|
||||
'DELETE' | HttpServletResponse.SC_FORBIDDEN
|
||||
'INVALID' | HttpServletResponse.SC_FORBIDDEN
|
||||
'GET' | HttpServletResponse.SC_OK
|
||||
'HEAD' | HttpServletResponse.SC_OK
|
||||
'TRACE' | HttpServletResponse.SC_OK
|
||||
'OPTIONS' | HttpServletResponse.SC_OK
|
||||
}
|
||||
@Unroll
|
||||
def "csrf applied by default"() {
|
||||
setup:
|
||||
loadConfig(CsrfAppliedDefaultConfig)
|
||||
request.method = httpMethod
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
httpMethod | httpStatus
|
||||
'POST' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PUT' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PATCH' | HttpServletResponse.SC_FORBIDDEN
|
||||
'DELETE' | HttpServletResponse.SC_FORBIDDEN
|
||||
'INVALID' | HttpServletResponse.SC_FORBIDDEN
|
||||
'GET' | HttpServletResponse.SC_OK
|
||||
'HEAD' | HttpServletResponse.SC_OK
|
||||
'TRACE' | HttpServletResponse.SC_OK
|
||||
'OPTIONS' | HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def "csrf default creates CsrfRequestDataValueProcessor"() {
|
||||
when:
|
||||
loadConfig(CsrfAppliedDefaultConfig)
|
||||
then:
|
||||
context.getBean(RequestDataValueProcessor)
|
||||
}
|
||||
def "csrf default creates CsrfRequestDataValueProcessor"() {
|
||||
when:
|
||||
loadConfig(CsrfAppliedDefaultConfig)
|
||||
then:
|
||||
context.getBean(RequestDataValueProcessor)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
|
||||
def "csrf disable"() {
|
||||
setup:
|
||||
loadConfig(DisableCsrfConfig)
|
||||
request.method = "POST"
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!findFilter(CsrfFilter)
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
def "csrf disable"() {
|
||||
setup:
|
||||
loadConfig(DisableCsrfConfig)
|
||||
request.method = "POST"
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!findFilter(CsrfFilter)
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DisableCsrfConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class DisableCsrfConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2498: Disable CSRF enables RequestCache for any method"() {
|
||||
setup:
|
||||
loadConfig(DisableCsrfEnablesRequestCacheConfig)
|
||||
request.requestURI = '/tosave'
|
||||
request.method = "POST"
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl
|
||||
when:
|
||||
super.setupWeb(request.session)
|
||||
request.method = "POST"
|
||||
request.servletPath = '/login'
|
||||
request.parameters['username'] = ['user'] as String[]
|
||||
request.parameters['password'] = ['password'] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == 'http://localhost/tosave'
|
||||
}
|
||||
def "SEC-2498: Disable CSRF enables RequestCache for any method"() {
|
||||
setup:
|
||||
loadConfig(DisableCsrfEnablesRequestCacheConfig)
|
||||
request.requestURI = '/tosave'
|
||||
request.method = "POST"
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl
|
||||
when:
|
||||
super.setupWeb(request.session)
|
||||
request.method = "POST"
|
||||
request.servletPath = '/login'
|
||||
request.parameters['username'] = ['user'] as String[]
|
||||
request.parameters['password'] = ['password'] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == 'http://localhost/tosave'
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DisableCsrfEnablesRequestCacheConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class DisableCsrfEnablesRequestCacheConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin().and()
|
||||
.csrf().disable()
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin().and()
|
||||
.csrf().disable()
|
||||
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
|
||||
setup:
|
||||
loadConfig(InvalidSessionUrlConfig)
|
||||
request.session.clearAttributes()
|
||||
request.setParameter("_csrf","abc")
|
||||
request.method = "POST"
|
||||
when: "No existing expected CsrfToken (session times out) and a POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the session timeout page page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/error/sessionError"
|
||||
when: "Existing expected CsrfToken and a POST (invalid token provided)"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session, method:'POST')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access Denied occurs"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
|
||||
setup:
|
||||
loadConfig(InvalidSessionUrlConfig)
|
||||
request.session.clearAttributes()
|
||||
request.setParameter("_csrf","abc")
|
||||
request.method = "POST"
|
||||
when: "No existing expected CsrfToken (session times out) and a POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the session timeout page page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/error/sessionError"
|
||||
when: "Existing expected CsrfToken and a POST (invalid token provided)"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session, method:'POST')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access Denied occurs"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().and()
|
||||
.sessionManagement()
|
||||
.invalidSessionUrl("/error/sessionError")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().and()
|
||||
.sessionManagement()
|
||||
.invalidSessionUrl("/error/sessionError")
|
||||
}
|
||||
}
|
||||
|
||||
def "csrf requireCsrfProtectionMatcher"() {
|
||||
setup:
|
||||
RequireCsrfProtectionMatcherConfig.matcher = Mock(RequestMatcher)
|
||||
RequireCsrfProtectionMatcherConfig.matcher.matches(_) >>> [false,true]
|
||||
loadConfig(RequireCsrfProtectionMatcherConfig)
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "csrf requireCsrfProtectionMatcher"() {
|
||||
setup:
|
||||
RequireCsrfProtectionMatcherConfig.matcher = Mock(RequestMatcher)
|
||||
RequireCsrfProtectionMatcherConfig.matcher.matches(_) >>> [false,true]
|
||||
loadConfig(RequireCsrfProtectionMatcherConfig)
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
|
||||
static RequestMatcher matcher
|
||||
@EnableWebSecurity
|
||||
static class RequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
|
||||
static RequestMatcher matcher
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf()
|
||||
.requireCsrfProtectionMatcher(matcher)
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf()
|
||||
.requireCsrfProtectionMatcher(matcher)
|
||||
}
|
||||
}
|
||||
|
||||
def "csrf csrfTokenRepository"() {
|
||||
setup:
|
||||
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
|
||||
loadConfig(CsrfTokenRepositoryConfig)
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
def "csrf csrfTokenRepository"() {
|
||||
setup:
|
||||
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
|
||||
loadConfig(CsrfTokenRepositoryConfig)
|
||||
clearCsrfToken()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def "csrf clears on logout"() {
|
||||
setup:
|
||||
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
|
||||
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
|
||||
loadConfig(CsrfTokenRepositoryConfig)
|
||||
login()
|
||||
request.method = "POST"
|
||||
request.servletPath = "/logout"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
1 * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
|
||||
}
|
||||
def "csrf clears on logout"() {
|
||||
setup:
|
||||
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
|
||||
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
|
||||
loadConfig(CsrfTokenRepositoryConfig)
|
||||
login()
|
||||
request.method = "POST"
|
||||
request.servletPath = "/logout"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
1 * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
|
||||
}
|
||||
|
||||
def "csrf clears on login"() {
|
||||
setup:
|
||||
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfTokenRepositoryConfig)
|
||||
request.method = "POST"
|
||||
request.getSession()
|
||||
request.servletPath = "/login"
|
||||
request.setParameter("username", "user")
|
||||
request.setParameter("password", "password")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/"
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
|
||||
}
|
||||
def "csrf clears on login"() {
|
||||
setup:
|
||||
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfTokenRepositoryConfig)
|
||||
request.method = "POST"
|
||||
request.getSession()
|
||||
request.servletPath = "/login"
|
||||
request.setParameter("username", "user")
|
||||
request.setParameter("password", "password")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/"
|
||||
(1.._) * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CsrfTokenRepositoryConfig extends WebSecurityConfigurerAdapter {
|
||||
static CsrfTokenRepository repo
|
||||
@EnableWebSecurity
|
||||
static class CsrfTokenRepositoryConfig extends WebSecurityConfigurerAdapter {
|
||||
static CsrfTokenRepository repo
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.csrf()
|
||||
.csrfTokenRepository(repo)
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.csrf()
|
||||
.csrfTokenRepository(repo)
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
def "csrf access denied handler"() {
|
||||
setup:
|
||||
AccessDeniedHandlerConfig.deniedHandler = Mock(AccessDeniedHandler)
|
||||
1 * AccessDeniedHandlerConfig.deniedHandler.handle(_, _, _)
|
||||
loadConfig(AccessDeniedHandlerConfig)
|
||||
clearCsrfToken()
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
def "csrf access denied handler"() {
|
||||
setup:
|
||||
AccessDeniedHandlerConfig.deniedHandler = Mock(AccessDeniedHandler)
|
||||
1 * AccessDeniedHandlerConfig.deniedHandler.handle(_, _, _)
|
||||
loadConfig(AccessDeniedHandlerConfig)
|
||||
clearCsrfToken()
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
@EnableWebSecurity
|
||||
static class AccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.accessDeniedHandler(deniedHandler)
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.accessDeniedHandler(deniedHandler)
|
||||
}
|
||||
}
|
||||
|
||||
def "formLogin requires CSRF token"() {
|
||||
setup:
|
||||
loadConfig(FormLoginConfig)
|
||||
clearCsrfToken()
|
||||
request.setParameter("username", "user")
|
||||
request.setParameter("password", "password")
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
currentAuthentication == null
|
||||
}
|
||||
def "formLogin requires CSRF token"() {
|
||||
setup:
|
||||
loadConfig(FormLoginConfig)
|
||||
clearCsrfToken()
|
||||
request.setParameter("username", "user")
|
||||
request.setParameter("password", "password")
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
currentAuthentication == null
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
@EnableWebSecurity
|
||||
static class FormLoginConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "logout requires CSRF token"() {
|
||||
setup:
|
||||
loadConfig(LogoutConfig)
|
||||
clearCsrfToken()
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "logout is not allowed and user is still authenticated"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
currentAuthentication != null
|
||||
}
|
||||
def "logout requires CSRF token"() {
|
||||
setup:
|
||||
loadConfig(LogoutConfig)
|
||||
clearCsrfToken()
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "logout is not allowed and user is still authenticated"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
currentAuthentication != null
|
||||
}
|
||||
|
||||
def "SEC-2543: CSRF means logout requires POST"() {
|
||||
setup:
|
||||
loadConfig(LogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "GET"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "logout with GET is not performed"
|
||||
currentAuthentication != null
|
||||
}
|
||||
def "SEC-2543: CSRF means logout requires POST"() {
|
||||
setup:
|
||||
loadConfig(LogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "GET"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "logout with GET is not performed"
|
||||
currentAuthentication != null
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class LogoutConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
@EnableWebSecurity
|
||||
static class LogoutConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "CSRF can explicitly enable GET for logout"() {
|
||||
setup:
|
||||
loadConfig(LogoutAllowsGetConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "GET"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "logout with GET is not performed"
|
||||
currentAuthentication == null
|
||||
}
|
||||
def "CSRF can explicitly enable GET for logout"() {
|
||||
setup:
|
||||
loadConfig(LogoutAllowsGetConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "GET"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "logout with GET is not performed"
|
||||
currentAuthentication == null
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class LogoutAllowsGetConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
@EnableWebSecurity
|
||||
static class LogoutAllowsGetConfig extends WebSecurityConfigurerAdapter {
|
||||
static AccessDeniedHandler deniedHandler
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin().and()
|
||||
.logout()
|
||||
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin().and()
|
||||
.logout()
|
||||
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||
}
|
||||
}
|
||||
|
||||
def "csrf disables POST requests from RequestCache"() {
|
||||
setup:
|
||||
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "POST"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
super.setupWeb(request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default success because we don't want csrf attempts made prior to authentication to pass"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
def "csrf disables POST requests from RequestCache"() {
|
||||
setup:
|
||||
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "POST"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
super.setupWeb(request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default success because we don't want csrf attempts made prior to authentication to pass"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
|
||||
def "csrf enables GET requests with RequestCache"() {
|
||||
setup:
|
||||
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "GET"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
super.setupWeb(request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to original URL since it was a GET"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/some-url"
|
||||
}
|
||||
def "csrf enables GET requests with RequestCache"() {
|
||||
setup:
|
||||
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
|
||||
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "GET"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
super.setupWeb(request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to original URL since it was a GET"
|
||||
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/some-url"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CsrfDisablesPostRequestFromRequestCacheConfig extends WebSecurityConfigurerAdapter {
|
||||
static CsrfTokenRepository repo
|
||||
@EnableWebSecurity
|
||||
static class CsrfDisablesPostRequestFromRequestCacheConfig extends WebSecurityConfigurerAdapter {
|
||||
static CsrfTokenRepository repo
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.csrf()
|
||||
.csrfTokenRepository(repo)
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.csrf()
|
||||
.csrfTokenRepository(repo)
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
def 'SEC-2749: requireCsrfProtectionMatcher null'() {
|
||||
when:
|
||||
new CsrfConfigurer<>().requireCsrfProtectionMatcher(null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
def 'SEC-2749: requireCsrfProtectionMatcher null'() {
|
||||
when:
|
||||
new CsrfConfigurer<>().requireCsrfProtectionMatcher(null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def clearCsrfToken() {
|
||||
request.removeAllParameters()
|
||||
}
|
||||
def clearCsrfToken() {
|
||||
request.removeAllParameters()
|
||||
}
|
||||
}
|
||||
|
||||
+89
-89
@@ -54,103 +54,103 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher
|
||||
*/
|
||||
class DefaultFiltersTests extends BaseSpringSpec {
|
||||
|
||||
def "Default the WebSecurityConfigurerAdapter"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(FilterChainProxyBuilderMissingConfig)
|
||||
then:
|
||||
context.getBean(FilterChainProxy) != null
|
||||
}
|
||||
def "Default the WebSecurityConfigurerAdapter"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(FilterChainProxyBuilderMissingConfig)
|
||||
then:
|
||||
context.getBean(FilterChainProxy) != null
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FilterChainProxyBuilderMissingConfig {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FilterChainProxyBuilderMissingConfig {
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FilterChainProxyBuilderNoSecurityFilterBuildersConfig {
|
||||
@Bean
|
||||
public WebSecurity filterChainProxyBuilder(ObjectPostProcessor<Object> opp) {
|
||||
new WebSecurity(opp)
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FilterChainProxyBuilderNoSecurityFilterBuildersConfig {
|
||||
@Bean
|
||||
public WebSecurity filterChainProxyBuilder(ObjectPostProcessor<Object> opp) {
|
||||
new WebSecurity(opp)
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**")
|
||||
}
|
||||
}
|
||||
|
||||
def "null WebInvocationPrivilegeEvaluator"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(NullWebInvocationPrivilegeEvaluatorConfig)
|
||||
then:
|
||||
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
|
||||
filterChains.size() == 1
|
||||
filterChains[0].requestMatcher instanceof AnyRequestMatcher
|
||||
filterChains[0].filters.size() == 1
|
||||
filterChains[0].filters.find { it instanceof UsernamePasswordAuthenticationFilter }
|
||||
}
|
||||
def "null WebInvocationPrivilegeEvaluator"() {
|
||||
when:
|
||||
context = new AnnotationConfigApplicationContext(NullWebInvocationPrivilegeEvaluatorConfig)
|
||||
then:
|
||||
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
|
||||
filterChains.size() == 1
|
||||
filterChains[0].requestMatcher instanceof AnyRequestMatcher
|
||||
filterChains[0].filters.size() == 1
|
||||
filterChains[0].filters.find { it instanceof UsernamePasswordAuthenticationFilter }
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NullWebInvocationPrivilegeEvaluatorConfig extends BaseWebConfig {
|
||||
NullWebInvocationPrivilegeEvaluatorConfig() {
|
||||
super(true)
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class NullWebInvocationPrivilegeEvaluatorConfig extends BaseWebConfig {
|
||||
NullWebInvocationPrivilegeEvaluatorConfig() {
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.formLogin()
|
||||
}
|
||||
}
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "FilterChainProxyBuilder ignoring resources"() {
|
||||
when:
|
||||
loadConfig(FilterChainProxyBuilderIgnoringConfig)
|
||||
then:
|
||||
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
|
||||
filterChains.size() == 2
|
||||
filterChains[0].requestMatcher.pattern == '/resources/**'
|
||||
filterChains[0].filters.empty
|
||||
filterChains[1].requestMatcher instanceof AnyRequestMatcher
|
||||
filterChains[1].filters.collect { it.class } ==
|
||||
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, RequestCacheAwareFilter,
|
||||
SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter,
|
||||
ExceptionTranslationFilter, FilterSecurityInterceptor ]
|
||||
}
|
||||
def "FilterChainProxyBuilder ignoring resources"() {
|
||||
when:
|
||||
loadConfig(FilterChainProxyBuilderIgnoringConfig)
|
||||
then:
|
||||
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
|
||||
filterChains.size() == 2
|
||||
filterChains[0].requestMatcher.pattern == '/resources/**'
|
||||
filterChains[0].filters.empty
|
||||
filterChains[1].requestMatcher instanceof AnyRequestMatcher
|
||||
filterChains[1].filters.collect { it.class } ==
|
||||
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, RequestCacheAwareFilter,
|
||||
SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter,
|
||||
ExceptionTranslationFilter, FilterSecurityInterceptor ]
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FilterChainProxyBuilderIgnoringConfig extends BaseWebConfig {
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
builder
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FilterChainProxyBuilderIgnoringConfig extends BaseWebConfig {
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
builder
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
|
||||
def "DefaultFilters.permitAll()"() {
|
||||
when:
|
||||
loadConfig(DefaultFiltersConfigPermitAll)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(servletPath : uri, queryString: query, method:"POST")
|
||||
setupCsrf()
|
||||
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
where:
|
||||
uri | query
|
||||
"/logout" | null
|
||||
}
|
||||
when:
|
||||
loadConfig(DefaultFiltersConfigPermitAll)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(servletPath : uri, queryString: query, method:"POST")
|
||||
setupCsrf()
|
||||
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
where:
|
||||
uri | query
|
||||
"/logout" | null
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultFiltersConfigPermitAll extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class DefaultFiltersConfigPermitAll extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+263
-265
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
@@ -42,295 +40,295 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
|
||||
*
|
||||
*/
|
||||
public class DefaultLoginPageConfigurerTests extends BaseSpringSpec {
|
||||
def "http/form-login default login generating page"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
findFilter(DefaultLoginPageGeneratingFilter)
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "request the login page"
|
||||
super.setup()
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def "http/form-login default login generating page"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
findFilter(DefaultLoginPageGeneratingFilter)
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "request the login page"
|
||||
super.setup()
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
</form></body></html>"""
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "request the error page"
|
||||
HttpSession session = request.session
|
||||
super.setup()
|
||||
request.session = session
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "error"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "request the error page"
|
||||
HttpSession session = request.session
|
||||
super.setup()
|
||||
request.session = session
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "error"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
<p><font color='red'>Your login attempt was not successful, try again.<br/><br/>Reason: Bad credentials</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
</form></body></html>"""
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
}
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
}
|
||||
|
||||
def "logout success renders"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageConfig)
|
||||
when: "logout success"
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "logout"
|
||||
request.method = "GET"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default success page"
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def "logout success renders"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageConfig)
|
||||
when: "logout success"
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "logout"
|
||||
request.method = "GET"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default success page"
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
<p><font color='green'>You have been logged out</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLoginPageConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLoginPageConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "custom logout success handler prevents rendering"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageCustomLogoutSuccessHandlerConfig)
|
||||
when: "logout success"
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "logout"
|
||||
request.method = "GET"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "default success page is NOT rendered (application is in charge of it)"
|
||||
response.getContentAsString() == ""
|
||||
}
|
||||
def "custom logout success handler prevents rendering"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageCustomLogoutSuccessHandlerConfig)
|
||||
when: "logout success"
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "logout"
|
||||
request.method = "GET"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "default success page is NOT rendered (application is in charge of it)"
|
||||
response.getContentAsString() == ""
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "custom logout success url prevents rendering"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageCustomLogoutConfig)
|
||||
when: "logout success"
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "logout"
|
||||
request.method = "GET"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "default success page is NOT rendered (application is in charge of it)"
|
||||
response.getContentAsString() == ""
|
||||
}
|
||||
def "custom logout success url prevents rendering"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageCustomLogoutConfig)
|
||||
when: "logout success"
|
||||
request.requestURI = "/login"
|
||||
request.queryString = "logout"
|
||||
request.method = "GET"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "default success page is NOT rendered (application is in charge of it)"
|
||||
response.getContentAsString() == ""
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLoginPageCustomLogoutConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessUrl("/login?logout")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLoginPageCustomLogoutConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessUrl("/login?logout")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/form-login default login with remember me"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageWithRememberMeConfig)
|
||||
when: "request the login page"
|
||||
super.setup()
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def "http/form-login default login with remember me"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageWithRememberMeConfig)
|
||||
when: "request the login page"
|
||||
super.setup()
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLoginPageWithRememberMeConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLoginPageWithRememberMeConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/form-login default login with openid"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageWithOpenIDConfig)
|
||||
when: "request the login page"
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' method='POST'>
|
||||
<table>
|
||||
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
</table>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
def "http/form-login default login with openid"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageWithOpenIDConfig)
|
||||
when: "request the login page"
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' method='POST'>
|
||||
<table>
|
||||
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
</table>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLoginPageWithOpenIDConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLoginPageWithOpenIDConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/form-login default login with openid, form login, and rememberme"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig)
|
||||
when: "request the login page"
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def "http/form-login default login with openid, form login, and rememberme"() {
|
||||
setup:
|
||||
loadConfig(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig)
|
||||
when: "request the login page"
|
||||
request.requestURI = "/login"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</table>
|
||||
</form><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' method='POST'>
|
||||
<table>
|
||||
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
|
||||
<tr><td><input type='checkbox' name='remember-me'></td><td>Remember me on this computer.</td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
</table>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
<table>
|
||||
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
|
||||
<tr><td><input type='checkbox' name='remember-me'></td><td>Remember me on this computer.</td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
</table>
|
||||
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.rememberMe()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.openidLogin()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.rememberMe()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.openidLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "default login with custom AuthenticationEntryPoint"() {
|
||||
when:
|
||||
loadConfig(DefaultLoginWithCustomAuthenticationEntryPointConfig)
|
||||
then:
|
||||
!findFilter(DefaultLoginPageGeneratingFilter)
|
||||
}
|
||||
def "default login with custom AuthenticationEntryPoint"() {
|
||||
when:
|
||||
loadConfig(DefaultLoginWithCustomAuthenticationEntryPointConfig)
|
||||
then:
|
||||
!findFilter(DefaultLoginPageGeneratingFilter)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "DefaultLoginPage ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor objectPostProcessor = Mock()
|
||||
when:
|
||||
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
|
||||
DefaultLoginPageConfigurer defaultLoginConfig = new DefaultLoginPageConfigurer([builder:http])
|
||||
defaultLoginConfig.addObjectPostProcessor(objectPostProcessor)
|
||||
http
|
||||
// must set builder manually due to groovy not selecting correct method
|
||||
.apply(defaultLoginConfig).and()
|
||||
.exceptionHandling()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.build()
|
||||
def "DefaultLoginPage ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor objectPostProcessor = Mock()
|
||||
when:
|
||||
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
|
||||
DefaultLoginPageConfigurer defaultLoginConfig = new DefaultLoginPageConfigurer([builder:http])
|
||||
defaultLoginConfig.addObjectPostProcessor(objectPostProcessor)
|
||||
http
|
||||
// must set builder manually due to groovy not selecting correct method
|
||||
.apply(defaultLoginConfig).and()
|
||||
.exceptionHandling()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "DefaultLoginPageGeneratingFilter is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as DefaultLoginPageGeneratingFilter) >> {DefaultLoginPageGeneratingFilter o -> o}
|
||||
1 * objectPostProcessor.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
|
||||
1 * objectPostProcessor.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
|
||||
1 * objectPostProcessor.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
|
||||
}
|
||||
then: "DefaultLoginPageGeneratingFilter is registered with LifecycleManager"
|
||||
1 * objectPostProcessor.postProcess(_ as DefaultLoginPageGeneratingFilter) >> {DefaultLoginPageGeneratingFilter o -> o}
|
||||
1 * objectPostProcessor.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
|
||||
1 * objectPostProcessor.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
|
||||
1 * objectPostProcessor.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
|
||||
}
|
||||
}
|
||||
|
||||
+133
-133
@@ -46,153 +46,153 @@ import spock.lang.Unroll
|
||||
*/
|
||||
class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "exception ObjectPostProcessor"() {
|
||||
setup: "initialize the AUTH_FILTER as a mock"
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
when:
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
http
|
||||
.exceptionHandling()
|
||||
.and()
|
||||
.build()
|
||||
def "exception ObjectPostProcessor"() {
|
||||
setup: "initialize the AUTH_FILTER as a mock"
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
when:
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
http
|
||||
.exceptionHandling()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "ExceptionTranslationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
|
||||
}
|
||||
then: "ExceptionTranslationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "SEC-2199: defaultEntryPoint for httpBasic and formLogin"(String acceptHeader, int httpStatus) {
|
||||
setup:
|
||||
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
|
||||
when:
|
||||
request.addHeader("Accept", acceptHeader)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
acceptHeader | httpStatus
|
||||
MediaType.APPLICATION_XHTML_XML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.IMAGE_GIF_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.IMAGE_JPEG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.IMAGE_PNG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.TEXT_HTML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.TEXT_PLAIN_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.APPLICATION_ATOM_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_FORM_URLENCODED_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_JSON_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_OCTET_STREAM_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.MULTIPART_FORM_DATA_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.TEXT_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
@Unroll
|
||||
def "SEC-2199: defaultEntryPoint for httpBasic and formLogin"(String acceptHeader, int httpStatus) {
|
||||
setup:
|
||||
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
|
||||
when:
|
||||
request.addHeader("Accept", acceptHeader)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
acceptHeader | httpStatus
|
||||
MediaType.APPLICATION_XHTML_XML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.IMAGE_GIF_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.IMAGE_JPEG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.IMAGE_PNG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.TEXT_HTML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.TEXT_PLAIN_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
MediaType.APPLICATION_ATOM_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_FORM_URLENCODED_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_JSON_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_OCTET_STREAM_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.APPLICATION_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.MULTIPART_FORM_DATA_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
MediaType.TEXT_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
def "ContentNegotiationStrategy defaults to HeaderContentNegotiationStrategy"() {
|
||||
when:
|
||||
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
|
||||
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
then:
|
||||
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy.class} == [HeaderContentNegotiationStrategy,HeaderContentNegotiationStrategy]
|
||||
}
|
||||
def "ContentNegotiationStrategy defaults to HeaderContentNegotiationStrategy"() {
|
||||
when:
|
||||
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
|
||||
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
then:
|
||||
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy.class} == [HeaderContentNegotiationStrategy,HeaderContentNegotiationStrategy]
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpBasicAndFormLoginEntryPointsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class HttpBasicAndFormLoginEntryPointsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "ContentNegotiationStrategy overrides with @Bean"() {
|
||||
setup:
|
||||
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
|
||||
when:
|
||||
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
|
||||
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
then:
|
||||
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy} == [OverrideContentNegotiationStrategySharedObjectConfig.CNS,OverrideContentNegotiationStrategySharedObjectConfig.CNS]
|
||||
}
|
||||
def "ContentNegotiationStrategy overrides with @Bean"() {
|
||||
setup:
|
||||
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
|
||||
when:
|
||||
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
|
||||
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
then:
|
||||
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy} == [OverrideContentNegotiationStrategySharedObjectConfig.CNS,OverrideContentNegotiationStrategySharedObjectConfig.CNS]
|
||||
}
|
||||
|
||||
def "Override ContentNegotiationStrategy with @Bean"() {
|
||||
setup:
|
||||
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
|
||||
when:
|
||||
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
|
||||
then:
|
||||
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||
}
|
||||
def "Override ContentNegotiationStrategy with @Bean"() {
|
||||
setup:
|
||||
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
|
||||
when:
|
||||
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
|
||||
then:
|
||||
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
|
||||
static ContentNegotiationStrategy CNS
|
||||
@EnableWebSecurity
|
||||
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
|
||||
static ContentNegotiationStrategy CNS
|
||||
|
||||
@Bean
|
||||
public ContentNegotiationStrategy cns() {
|
||||
return CNS
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
public ContentNegotiationStrategy cns() {
|
||||
return CNS
|
||||
}
|
||||
}
|
||||
|
||||
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is LoginUrlAuthenticationEntryPoint when using DefaultHttpConf"() {
|
||||
when:
|
||||
loadConfig(DefaultHttpConf)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.class == LoginUrlAuthenticationEntryPoint
|
||||
}
|
||||
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is LoginUrlAuthenticationEntryPoint when using DefaultHttpConf"() {
|
||||
when:
|
||||
loadConfig(DefaultHttpConf)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.class == LoginUrlAuthenticationEntryPoint
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultHttpConf extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class DefaultHttpConf extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
|
||||
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is BasicAuthenticationEntryPoint when httpBasic before formLogin"() {
|
||||
when:
|
||||
loadConfig(BasicAuthenticationEntryPointBeforeFormLoginConf)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.defaultEntryPoint.class == BasicAuthenticationEntryPoint
|
||||
}
|
||||
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is BasicAuthenticationEntryPoint when httpBasic before formLogin"() {
|
||||
when:
|
||||
loadConfig(BasicAuthenticationEntryPointBeforeFormLoginConf)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.defaultEntryPoint.class == BasicAuthenticationEntryPoint
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class BasicAuthenticationEntryPointBeforeFormLoginConf extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class BasicAuthenticationEntryPointBeforeFormLoginConf extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "invoke exceptionHandling twice does not override"() {
|
||||
setup:
|
||||
InvokeTwiceDoesNotOverrideConfig.AEP = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.AEP
|
||||
}
|
||||
def "invoke exceptionHandling twice does not override"() {
|
||||
setup:
|
||||
InvokeTwiceDoesNotOverrideConfig.AEP = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.AEP
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint AEP
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(AEP)
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint AEP
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(AEP)
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+500
-453
File diff suppressed because it is too large
Load Diff
+229
-233
@@ -56,266 +56,262 @@ import spock.lang.Unroll
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class FormLoginConfigurerTests extends BaseSpringSpec {
|
||||
def "Form Login"() {
|
||||
when: "load formLogin()"
|
||||
context = new AnnotationConfigApplicationContext(FormLoginConfig)
|
||||
def "Form Login"() {
|
||||
when: "load formLogin()"
|
||||
context = new AnnotationConfigApplicationContext(FormLoginConfig)
|
||||
|
||||
then: "FilterChains configured correctly"
|
||||
def filterChains = filterChains()
|
||||
filterChains.size() == 2
|
||||
filterChains[0].requestMatcher.pattern == '/resources/**'
|
||||
filterChains[0].filters.empty
|
||||
filterChains[1].requestMatcher instanceof AnyRequestMatcher
|
||||
filterChains[1].filters.collect { it.class.name.contains('$') ? it.class.superclass : it.class } ==
|
||||
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, UsernamePasswordAuthenticationFilter,
|
||||
RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter,
|
||||
AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, FilterSecurityInterceptor ]
|
||||
then: "FilterChains configured correctly"
|
||||
def filterChains = filterChains()
|
||||
filterChains.size() == 2
|
||||
filterChains[0].requestMatcher.pattern == '/resources/**'
|
||||
filterChains[0].filters.empty
|
||||
filterChains[1].requestMatcher instanceof AnyRequestMatcher
|
||||
filterChains[1].filters.collect { it.class.name.contains('$') ? it.class.superclass : it.class } ==
|
||||
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, UsernamePasswordAuthenticationFilter,
|
||||
RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter,
|
||||
AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, FilterSecurityInterceptor ]
|
||||
|
||||
and: "UsernamePasswordAuthentictionFilter is configured correctly"
|
||||
UsernamePasswordAuthenticationFilter authFilter = findFilter(UsernamePasswordAuthenticationFilter,1)
|
||||
authFilter.usernameParameter == "username"
|
||||
authFilter.passwordParameter == "password"
|
||||
authFilter.failureHandler.defaultFailureUrl == "/login?error"
|
||||
authFilter.successHandler.defaultTargetUrl == "/"
|
||||
authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "POST"), new MockHttpServletResponse())
|
||||
!authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "GET"), new MockHttpServletResponse())
|
||||
and: "UsernamePasswordAuthentictionFilter is configured correctly"
|
||||
UsernamePasswordAuthenticationFilter authFilter = findFilter(UsernamePasswordAuthenticationFilter,1)
|
||||
authFilter.usernameParameter == "username"
|
||||
authFilter.passwordParameter == "password"
|
||||
authFilter.failureHandler.defaultFailureUrl == "/login?error"
|
||||
authFilter.successHandler.defaultTargetUrl == "/"
|
||||
authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "POST"), new MockHttpServletResponse())
|
||||
!authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "GET"), new MockHttpServletResponse())
|
||||
|
||||
and: "SessionFixationProtectionStrategy is configured correctly"
|
||||
SessionFixationProtectionStrategy sessionStrategy = ReflectionTestUtils.getField(authFilter,"sessionStrategy").delegateStrategies.find { SessionFixationProtectionStrategy }
|
||||
sessionStrategy.migrateSessionAttributes
|
||||
and: "Exception handling is configured correctly"
|
||||
AuthenticationEntryPoint authEntryPoint = filterChains[1].filters.find { it instanceof ExceptionTranslationFilter}.authenticationEntryPoint
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
authEntryPoint.commence(new MockHttpServletRequest(servletPath: "/private/"), response, new BadCredentialsException(""))
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
}
|
||||
|
||||
and: "Exception handling is configured correctly"
|
||||
AuthenticationEntryPoint authEntryPoint = filterChains[1].filters.find { it instanceof ExceptionTranslationFilter}.authenticationEntryPoint
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
authEntryPoint.commence(new MockHttpServletRequest(servletPath: "/private/"), response, new BadCredentialsException(""))
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FormLoginConfig extends BaseWebConfig {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginConfig extends BaseWebConfig {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
}
|
||||
}
|
||||
def "FormLogin.permitAll()"() {
|
||||
when: "load formLogin() with permitAll"
|
||||
context = new AnnotationConfigApplicationContext(FormLoginConfigPermitAll)
|
||||
FilterChainProxy filterChain = context.getBean(FilterChainProxy)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
|
||||
setupCsrf()
|
||||
|
||||
def "FormLogin.permitAll()"() {
|
||||
when: "load formLogin() with permitAll"
|
||||
context = new AnnotationConfigApplicationContext(FormLoginConfigPermitAll)
|
||||
FilterChainProxy filterChain = context.getBean(FilterChainProxy)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
|
||||
setupCsrf()
|
||||
then: "the formLogin URLs are granted access"
|
||||
filterChain.doFilter(request, response, new MockFilterChain())
|
||||
response.redirectedUrl == redirectUrl
|
||||
|
||||
then: "the formLogin URLs are granted access"
|
||||
filterChain.doFilter(request, response, new MockFilterChain())
|
||||
response.redirectedUrl == redirectUrl
|
||||
where:
|
||||
servletPath | method | query | redirectUrl
|
||||
"/login" | "GET" | null | null
|
||||
"/login" | "POST" | null | "/login?error"
|
||||
"/login" | "GET" | "error" | null
|
||||
}
|
||||
|
||||
where:
|
||||
servletPath | method | query | redirectUrl
|
||||
"/login" | "GET" | null | null
|
||||
"/login" | "POST" | null | "/login?error"
|
||||
"/login" | "GET" | "error" | null
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FormLoginConfigPermitAll extends BaseWebConfig {
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginConfigPermitAll extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
@Unroll
|
||||
def "FormLogin loginConventions changes defaults"() {
|
||||
when: "load formLogin() with permitAll"
|
||||
loadConfig(FormLoginDefaultsConfig)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
|
||||
setupCsrf()
|
||||
|
||||
@Unroll
|
||||
def "FormLogin loginConventions changes defaults"() {
|
||||
when: "load formLogin() with permitAll"
|
||||
loadConfig(FormLoginDefaultsConfig)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
|
||||
setupCsrf()
|
||||
then: "the other default login/logout URLs are updated and granted access"
|
||||
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
|
||||
response.redirectedUrl == redirectUrl
|
||||
|
||||
then: "the other default login/logout URLs are updated and granted access"
|
||||
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
|
||||
response.redirectedUrl == redirectUrl
|
||||
where:
|
||||
servletPath | method | query | redirectUrl
|
||||
"/authenticate" | "GET" | null | null
|
||||
"/authenticate" | "POST" | null | "/authenticate?error"
|
||||
"/authenticate" | "GET" | "error" | null
|
||||
"/logout" | "POST" | null | "/authenticate?logout"
|
||||
"/authenticate" | "GET" | "logout"| null
|
||||
}
|
||||
|
||||
where:
|
||||
servletPath | method | query | redirectUrl
|
||||
"/authenticate" | "GET" | null | null
|
||||
"/authenticate" | "POST" | null | "/authenticate?error"
|
||||
"/authenticate" | "GET" | "error" | null
|
||||
"/logout" | "POST" | null | "/authenticate?logout"
|
||||
"/authenticate" | "GET" | "logout"| null
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FormLoginDefaultsConfig extends BaseWebConfig {
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginDefaultsConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/authenticate")
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/authenticate")
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
def "FormLogin loginProcessingUrl"() {
|
||||
setup:
|
||||
loadConfig(FormLoginLoginProcessingUrlConfig)
|
||||
request.servletPath = "/loginCheck"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
|
||||
then:
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
|
||||
def "FormLogin loginProcessingUrl"() {
|
||||
setup:
|
||||
loadConfig(FormLoginLoginProcessingUrlConfig)
|
||||
request.servletPath = "/loginCheck"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
|
||||
then:
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FormLoginLoginProcessingUrlConfig extends BaseWebConfig {
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginLoginProcessingUrlConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginProcessingUrl("/loginCheck")
|
||||
.loginPage("/login")
|
||||
//.failureUrl("/loginFailure")
|
||||
.defaultSuccessUrl("/", true)
|
||||
.passwordParameter("password")
|
||||
.usernameParameter("username")
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessUrl("/login")
|
||||
.logoutUrl("/logout")
|
||||
.deleteCookies("JSESSIONID")
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginProcessingUrl("/loginCheck")
|
||||
.loginPage("/login")
|
||||
//.failureUrl("/loginFailure")
|
||||
.defaultSuccessUrl("/", true)
|
||||
.passwordParameter("password")
|
||||
.usernameParameter("username")
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessUrl("/login")
|
||||
.logoutUrl("/logout")
|
||||
.deleteCookies("JSESSIONID")
|
||||
}
|
||||
}
|
||||
def "FormLogin uses PortMapper"() {
|
||||
when: "load formLogin() with permitAll"
|
||||
FormLoginUsesPortMapperConfig.PORT_MAPPER = Mock(PortMapper)
|
||||
loadConfig(FormLoginUsesPortMapperConfig)
|
||||
then: "the formLogin URLs are granted access"
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.portMapper == FormLoginUsesPortMapperConfig.PORT_MAPPER
|
||||
}
|
||||
|
||||
def "FormLogin uses PortMapper"() {
|
||||
when: "load formLogin() with permitAll"
|
||||
FormLoginUsesPortMapperConfig.PORT_MAPPER = Mock(PortMapper)
|
||||
loadConfig(FormLoginUsesPortMapperConfig)
|
||||
then: "the formLogin URLs are granted access"
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.portMapper == FormLoginUsesPortMapperConfig.PORT_MAPPER
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FormLoginUsesPortMapperConfig extends BaseWebConfig {
|
||||
static PortMapper PORT_MAPPER
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginUsesPortMapperConfig extends BaseWebConfig {
|
||||
static PortMapper PORT_MAPPER
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll()
|
||||
.and()
|
||||
.portMapper()
|
||||
.portMapper(PORT_MAPPER)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll()
|
||||
.and()
|
||||
.portMapper()
|
||||
.portMapper(PORT_MAPPER)
|
||||
}
|
||||
}
|
||||
def "FormLogin permitAll ignores failureUrl when failureHandler set"() {
|
||||
setup:
|
||||
PermitAllIgnoresFailureHandlerConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
|
||||
loadConfig(PermitAllIgnoresFailureHandlerConfig)
|
||||
FilterChainProxy springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when: "access default failureUrl and configured explicit FailureHandler"
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(servletPath:"/login",requestURI:"/login",queryString:"error",method:"GET")
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
springSecurityFilterChain.doFilter(request,response,new MockFilterChain())
|
||||
then: "access is not granted to the failure handler (sent to login page)"
|
||||
response.status == 302
|
||||
}
|
||||
|
||||
def "FormLogin permitAll ignores failureUrl when failureHandler set"() {
|
||||
setup:
|
||||
PermitAllIgnoresFailureHandlerConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
|
||||
loadConfig(PermitAllIgnoresFailureHandlerConfig)
|
||||
FilterChainProxy springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when: "access default failureUrl and configured explicit FailureHandler"
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(servletPath:"/login",requestURI:"/login",queryString:"error",method:"GET")
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
springSecurityFilterChain.doFilter(request,response,new MockFilterChain())
|
||||
then: "access is not granted to the failure handler (sent to login page)"
|
||||
response.status == 302
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class PermitAllIgnoresFailureHandlerConfig extends BaseWebConfig {
|
||||
static AuthenticationFailureHandler FAILURE_HANDLER
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PermitAllIgnoresFailureHandlerConfig extends BaseWebConfig {
|
||||
static AuthenticationFailureHandler FAILURE_HANDLER
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.failureHandler(FAILURE_HANDLER)
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.failureHandler(FAILURE_HANDLER)
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
def "duplicate formLogin does not override"() {
|
||||
setup:
|
||||
DuplicateInvocationsDoesNotOverrideConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
|
||||
when:
|
||||
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(UsernamePasswordAuthenticationFilter).usernameParameter == "custom-username"
|
||||
}
|
||||
|
||||
def "duplicate formLogin does not override"() {
|
||||
setup:
|
||||
DuplicateInvocationsDoesNotOverrideConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
|
||||
when:
|
||||
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(UsernamePasswordAuthenticationFilter).usernameParameter == "custom-username"
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class DuplicateInvocationsDoesNotOverrideConfig extends BaseWebConfig {
|
||||
static AuthenticationFailureHandler FAILURE_HANDLER
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DuplicateInvocationsDoesNotOverrideConfig extends BaseWebConfig {
|
||||
static AuthenticationFailureHandler FAILURE_HANDLER
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.formLogin()
|
||||
.usernameParameter("custom-username")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.formLogin()
|
||||
.usernameParameter("custom-username")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
def "formLogin ObjectPostProcessor"() {
|
||||
setup: "initialize the AUTH_FILTER as a mock"
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.exceptionHandling()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
def "formLogin ObjectPostProcessor"() {
|
||||
setup: "initialize the AUTH_FILTER as a mock"
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.exceptionHandling()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "UsernamePasswordAuthenticationFilter is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
|
||||
and: "LoginUrlAuthenticationEntryPoint is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
|
||||
and: "ExceptionTranslationFilter is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
|
||||
}
|
||||
then: "UsernamePasswordAuthenticationFilter is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
|
||||
and: "LoginUrlAuthenticationEntryPoint is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
|
||||
and: "ExceptionTranslationFilter is registered with ObjectPostProcessor"
|
||||
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
|
||||
}
|
||||
}
|
||||
|
||||
+139
-139
@@ -39,163 +39,163 @@ import spock.lang.Unroll;
|
||||
*/
|
||||
class HeadersConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "headers"() {
|
||||
setup:
|
||||
loadConfig(HeadersConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
def "headers"() {
|
||||
setup:
|
||||
loadConfig(HeadersConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HeadersConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class HeadersConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.headers()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.headers()
|
||||
}
|
||||
}
|
||||
|
||||
def "headers.contentType"() {
|
||||
setup:
|
||||
loadConfig(ContentTypeOptionsConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff']
|
||||
}
|
||||
def "headers.contentType"() {
|
||||
setup:
|
||||
loadConfig(ContentTypeOptionsConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.contentTypeOptions()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.contentTypeOptions()
|
||||
}
|
||||
}
|
||||
|
||||
def "headers.frameOptions"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options':'DENY']
|
||||
}
|
||||
def "headers.frameOptions"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options':'DENY']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.frameOptions()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.frameOptions()
|
||||
}
|
||||
}
|
||||
|
||||
def "headers.hsts"() {
|
||||
setup:
|
||||
loadConfig(HstsConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
|
||||
}
|
||||
def "headers.hsts"() {
|
||||
setup:
|
||||
loadConfig(HstsConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HstsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class HstsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
}
|
||||
}
|
||||
|
||||
def "headers.cacheControl"() {
|
||||
setup:
|
||||
loadConfig(CacheControlConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache']
|
||||
}
|
||||
def "headers.cacheControl"() {
|
||||
setup:
|
||||
loadConfig(CacheControlConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CacheControlConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class CacheControlConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.cacheControl()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.cacheControl()
|
||||
}
|
||||
}
|
||||
|
||||
def "headers.xssProtection"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
def "headers.xssProtection"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
}
|
||||
}
|
||||
|
||||
def "headers custom x-frame-options"() {
|
||||
setup:
|
||||
loadConfig(HeadersCustomSameOriginConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'SAMEORIGIN',
|
||||
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
def "headers custom x-frame-options"() {
|
||||
setup:
|
||||
loadConfig(HeadersCustomSameOriginConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'SAMEORIGIN',
|
||||
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.frameOptions().sameOrigin()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.frameOptions().sameOrigin()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+111
-85
@@ -24,6 +24,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
|
||||
|
||||
@@ -33,101 +34,126 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
|
||||
*/
|
||||
class HttpBasicConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "httBasic ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.build()
|
||||
def "httBasic ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "ExceptionTranslationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as BasicAuthenticationFilter) >> {BasicAuthenticationFilter o -> o}
|
||||
}
|
||||
then: "ExceptionTranslationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as BasicAuthenticationFilter) >> {BasicAuthenticationFilter o -> o}
|
||||
}
|
||||
|
||||
def "SEC-2198: http.httpBasic() defaults AuthenticationEntryPoint"() {
|
||||
setup:
|
||||
loadConfig(DefaultsEntryPointConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == 401
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="Realm"'
|
||||
}
|
||||
def "SEC-2198: http.httpBasic() defaults AuthenticationEntryPoint"() {
|
||||
setup:
|
||||
loadConfig(DefaultsEntryPointConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == 401
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="Realm"'
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultsEntryPointConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic()
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class DefaultsEntryPointConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
def "http.httpBasic().authenticationEntryPoint used for AuthenticationEntryPoint"() {
|
||||
setup:
|
||||
CustomAuthenticationEntryPointConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(CustomAuthenticationEntryPointConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == CustomAuthenticationEntryPointConfig.ENTRY_POINT
|
||||
}
|
||||
def "http.httpBasic().authenticationEntryPoint used for AuthenticationEntryPoint"() {
|
||||
setup:
|
||||
CustomAuthenticationEntryPointConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(CustomAuthenticationEntryPointConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == CustomAuthenticationEntryPointConfig.ENTRY_POINT
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRY_POINT
|
||||
@EnableWebSecurity
|
||||
static class CustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRY_POINT
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.authenticationEntryPoint(ENTRY_POINT)
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.authenticationEntryPoint(ENTRY_POINT)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
def "duplicate httpBasic invocations does not override"() {
|
||||
setup:
|
||||
DuplicateDoesNotOverrideConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(DuplicateDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == DuplicateDoesNotOverrideConfig.ENTRY_POINT
|
||||
}
|
||||
def "duplicate httpBasic invocations does not override"() {
|
||||
setup:
|
||||
DuplicateDoesNotOverrideConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(DuplicateDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == DuplicateDoesNotOverrideConfig.ENTRY_POINT
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRY_POINT
|
||||
@EnableWebSecurity
|
||||
static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRY_POINT
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.authenticationEntryPoint(ENTRY_POINT)
|
||||
.and()
|
||||
.httpBasic()
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.authenticationEntryPoint(ENTRY_POINT)
|
||||
.and()
|
||||
.httpBasic()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-3019: Basic Authentication uses RememberMe Config"() {
|
||||
when:
|
||||
loadConfig(BasicUsesRememberMeConfig)
|
||||
then:
|
||||
findFilter(BasicAuthenticationFilter).rememberMeServices == findFilter(RememberMeAuthenticationFilter).rememberMeServices
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class BasicUsesRememberMeConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic().and()
|
||||
.rememberMe()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-31
@@ -31,38 +31,38 @@ import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthe
|
||||
*/
|
||||
class JeeConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "jee ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.jee()
|
||||
.and()
|
||||
.build()
|
||||
def "jee ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.jee()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "J2eePreAuthenticatedProcessingFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as J2eePreAuthenticatedProcessingFilter) >> {J2eePreAuthenticatedProcessingFilter o -> o}
|
||||
and: "J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource) >> {J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource o -> o}
|
||||
}
|
||||
then: "J2eePreAuthenticatedProcessingFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as J2eePreAuthenticatedProcessingFilter) >> {J2eePreAuthenticatedProcessingFilter o -> o}
|
||||
and: "J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource) >> {J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource o -> o}
|
||||
}
|
||||
|
||||
def "invoke jee twice does not override"() {
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
then:
|
||||
findFilter(J2eePreAuthenticatedProcessingFilter).authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER"] as Set
|
||||
}
|
||||
def "invoke jee twice does not override"() {
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
then:
|
||||
findFilter(J2eePreAuthenticatedProcessingFilter).authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER"] as Set
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.jee()
|
||||
.mappableRoles("USER")
|
||||
.and()
|
||||
.jee()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.jee()
|
||||
.mappableRoles("USER")
|
||||
.and()
|
||||
.jee()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+70
-70
@@ -30,85 +30,85 @@ import org.springframework.security.web.authentication.logout.LogoutFilter
|
||||
*/
|
||||
class LogoutConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "logout ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.logout()
|
||||
.and()
|
||||
.build()
|
||||
def "logout ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.logout()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "LogoutFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as LogoutFilter) >> {LogoutFilter o -> o}
|
||||
}
|
||||
then: "LogoutFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as LogoutFilter) >> {LogoutFilter o -> o}
|
||||
}
|
||||
|
||||
def "invoke logout twice does not override"() {
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
request.method = "POST"
|
||||
request.servletPath = "/custom/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
}
|
||||
def "invoke logout twice does not override"() {
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
request.method = "POST"
|
||||
request.servletPath = "/custom/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.logout()
|
||||
.logoutUrl("/custom/logout")
|
||||
.and()
|
||||
.logout()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.logout()
|
||||
.logoutUrl("/custom/logout")
|
||||
.and()
|
||||
.logout()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2311: Logout allows other methods if CSRF is disabled"() {
|
||||
when:
|
||||
loadConfig(CsrfDisabledConfig)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
}
|
||||
def "SEC-2311: Logout allows other methods if CSRF is disabled"() {
|
||||
when:
|
||||
loadConfig(CsrfDisabledConfig)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
.logout()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
.logout()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def "SEC-2311: Logout allows other methods if CSRF is disabled with custom logout URL"() {
|
||||
when:
|
||||
loadConfig(CsrfDisabledCustomLogoutUrlConfig)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/custom/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
}
|
||||
def "SEC-2311: Logout allows other methods if CSRF is disabled with custom logout URL"() {
|
||||
when:
|
||||
loadConfig(CsrfDisabledCustomLogoutUrlConfig)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/custom/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CsrfDisabledCustomLogoutUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class CsrfDisabledCustomLogoutUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.logout()
|
||||
.logoutUrl("/custom/logout")
|
||||
.and()
|
||||
.csrf().disable()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.logout()
|
||||
.logoutUrl("/custom/logout")
|
||||
.and()
|
||||
.csrf().disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -64,14 +64,14 @@ import spock.lang.Ignore;
|
||||
*
|
||||
*/
|
||||
public class NamespaceDebugTests extends BaseSpringSpec {
|
||||
def "debug=true"() {
|
||||
when: "Load configuraiton with debug enabled"
|
||||
loadConfig(DebugWebSecurity)
|
||||
then: "The DebugFilter is present"
|
||||
context.getBean("springSecurityFilterChain").class == DebugFilter
|
||||
}
|
||||
def "debug=true"() {
|
||||
when: "Load configuraiton with debug enabled"
|
||||
loadConfig(DebugWebSecurity)
|
||||
then: "The DebugFilter is present"
|
||||
context.getBean("springSecurityFilterChain").class == DebugFilter
|
||||
}
|
||||
|
||||
@EnableWebSecurity(debug=true)
|
||||
static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
@EnableWebSecurity(debug=true)
|
||||
static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
+36
-36
@@ -37,44 +37,44 @@ import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpAccessDeniedHandlerTests extends BaseSpringSpec {
|
||||
def "http/access-denied-handler@error-page"() {
|
||||
when:
|
||||
loadConfig(AccessDeniedPageConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
|
||||
}
|
||||
def "http/access-denied-handler@error-page"() {
|
||||
when:
|
||||
loadConfig(AccessDeniedPageConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AccessDeniedPageConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.
|
||||
exceptionHandling()
|
||||
.accessDeniedPage("/AccessDeniedPageConfig")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AccessDeniedPageConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.
|
||||
exceptionHandling()
|
||||
.accessDeniedPage("/AccessDeniedPageConfig")
|
||||
}
|
||||
}
|
||||
|
||||
def "http/access-denied-handler@ref"() {
|
||||
when:
|
||||
loadConfig(AccessDeniedHandlerRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).accessDeniedHandler.class == AccessDeniedHandlerRefConfig.CustomAccessDeniedHandler
|
||||
}
|
||||
def "http/access-denied-handler@ref"() {
|
||||
when:
|
||||
loadConfig(AccessDeniedHandlerRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).accessDeniedHandler.class == AccessDeniedHandlerRefConfig.CustomAccessDeniedHandler
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AccessDeniedHandlerRefConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler()
|
||||
http.
|
||||
exceptionHandling()
|
||||
.accessDeniedHandler(accessDeniedHandler)
|
||||
}
|
||||
@Configuration
|
||||
static class AccessDeniedHandlerRefConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler()
|
||||
http.
|
||||
exceptionHandling()
|
||||
.accessDeniedHandler(accessDeniedHandler)
|
||||
}
|
||||
|
||||
static class CustomAccessDeniedHandler implements AccessDeniedHandler {
|
||||
public void handle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AccessDeniedException accessDeniedException)
|
||||
throws IOException, ServletException {
|
||||
}
|
||||
}
|
||||
}
|
||||
static class CustomAccessDeniedHandler implements AccessDeniedHandler {
|
||||
public void handle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AccessDeniedException accessDeniedException)
|
||||
throws IOException, ServletException {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+84
-84
@@ -32,98 +32,98 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpAnonymousTests extends BaseSpringSpec {
|
||||
def "http/anonymous@enabled = true (default)"() {
|
||||
when:
|
||||
loadConfig(AnonymousConfig)
|
||||
then:
|
||||
def filter = findFilter(AnonymousAuthenticationFilter)
|
||||
filter != null
|
||||
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
|
||||
}
|
||||
def "http/anonymous@enabled = true (default)"() {
|
||||
when:
|
||||
loadConfig(AnonymousConfig)
|
||||
then:
|
||||
def filter = findFilter(AnonymousAuthenticationFilter)
|
||||
filter != null
|
||||
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AnonymousConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AnonymousConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
|
||||
def "http/anonymous@enabled = false"() {
|
||||
when:
|
||||
loadConfig(AnonymousDisabledConfig)
|
||||
then:
|
||||
findFilter(AnonymousAuthenticationFilter) == null
|
||||
}
|
||||
def "http/anonymous@enabled = false"() {
|
||||
when:
|
||||
loadConfig(AnonymousDisabledConfig)
|
||||
then:
|
||||
findFilter(AnonymousAuthenticationFilter) == null
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AnonymousDisabledConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.anonymous().disable()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AnonymousDisabledConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.anonymous().disable()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/anonymous@granted-authority"() {
|
||||
when:
|
||||
loadConfig(AnonymousGrantedAuthorityConfig)
|
||||
then:
|
||||
findFilter(AnonymousAuthenticationFilter).authorities == AuthorityUtils.createAuthorityList("ROLE_ANON")
|
||||
}
|
||||
def "http/anonymous@granted-authority"() {
|
||||
when:
|
||||
loadConfig(AnonymousGrantedAuthorityConfig)
|
||||
then:
|
||||
findFilter(AnonymousAuthenticationFilter).authorities == AuthorityUtils.createAuthorityList("ROLE_ANON")
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AnonymousGrantedAuthorityConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.anonymous()
|
||||
.authorities("ROLE_ANON")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AnonymousGrantedAuthorityConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.anonymous()
|
||||
.authorities("ROLE_ANON")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def "http/anonymous@key"() {
|
||||
when:
|
||||
loadConfig(AnonymousKeyConfig)
|
||||
then:
|
||||
def filter = findFilter(AnonymousAuthenticationFilter)
|
||||
filter != null
|
||||
filter.key == "AnonymousKeyConfig"
|
||||
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
|
||||
}
|
||||
def "http/anonymous@key"() {
|
||||
when:
|
||||
loadConfig(AnonymousKeyConfig)
|
||||
then:
|
||||
def filter = findFilter(AnonymousAuthenticationFilter)
|
||||
filter != null
|
||||
filter.key == "AnonymousKeyConfig"
|
||||
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AnonymousKeyConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.anonymous().key("AnonymousKeyConfig")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AnonymousKeyConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.anonymous().key("AnonymousKeyConfig")
|
||||
}
|
||||
}
|
||||
|
||||
def "http/anonymous@username"() {
|
||||
when:
|
||||
loadConfig(AnonymousUsernameConfig)
|
||||
then:
|
||||
def filter = findFilter(AnonymousAuthenticationFilter)
|
||||
filter != null
|
||||
filter.principal == "AnonymousUsernameConfig"
|
||||
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).principal == "AnonymousUsernameConfig"
|
||||
}
|
||||
def "http/anonymous@username"() {
|
||||
when:
|
||||
loadConfig(AnonymousUsernameConfig)
|
||||
then:
|
||||
def filter = findFilter(AnonymousAuthenticationFilter)
|
||||
filter != null
|
||||
filter.principal == "AnonymousUsernameConfig"
|
||||
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).principal == "AnonymousUsernameConfig"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AnonymousUsernameConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.anonymous().principal("AnonymousUsernameConfig")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AnonymousUsernameConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.anonymous().principal("AnonymousUsernameConfig")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user