SEC-2915: More Tabs -> Spaces
This commit is contained in:
@@ -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>
|
||||
|
||||
+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>
|
||||
+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")
|
||||
}
|
||||
}
|
||||
|
||||
+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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+292
-292
@@ -53,348 +53,348 @@ import org.springframework.security.core.context.SecurityContextHolder
|
||||
* @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
|
||||
|
||||
@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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+44
-44
@@ -29,57 +29,57 @@ import org.springframework.security.web.debug.DebugFilter;
|
||||
|
||||
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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+249
-249
@@ -42,295 +42,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}" />
|
||||
<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}" />
|
||||
<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}" />
|
||||
<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}" />
|
||||
<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'>
|
||||
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>
|
||||
<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}" />
|
||||
<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}" />
|
||||
<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>
|
||||
<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}" />
|
||||
<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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+451
-451
@@ -37,494 +37,494 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
||||
|
||||
public class ExpressionUrlAuthorizationConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "hasAnyAuthority('ROLE_USER')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER")
|
||||
then:
|
||||
expression == "hasAnyAuthority('ROLE_USER')"
|
||||
}
|
||||
def "hasAnyAuthority('ROLE_USER')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER")
|
||||
then:
|
||||
expression == "hasAnyAuthority('ROLE_USER')"
|
||||
}
|
||||
|
||||
def "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER","ROLE_ADMIN")
|
||||
then:
|
||||
expression == "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"
|
||||
}
|
||||
def "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER","ROLE_ADMIN")
|
||||
then:
|
||||
expression == "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"
|
||||
}
|
||||
|
||||
def "hasAnyRole('USER')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyRole("USER")
|
||||
then:
|
||||
expression == "hasAnyRole('ROLE_USER')"
|
||||
}
|
||||
def "hasAnyRole('USER')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyRole("USER")
|
||||
then:
|
||||
expression == "hasAnyRole('ROLE_USER')"
|
||||
}
|
||||
|
||||
def "hasAnyRole('USER','ADMIN')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyRole("USER","ADMIN")
|
||||
then:
|
||||
expression == "hasAnyRole('ROLE_USER','ROLE_ADMIN')"
|
||||
}
|
||||
def "hasAnyRole('USER','ADMIN')"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyRole("USER","ADMIN")
|
||||
then:
|
||||
expression == "hasAnyRole('ROLE_USER','ROLE_ADMIN')"
|
||||
}
|
||||
|
||||
def "hasRole('ROLE_USER') is rejected due to starting with ROLE_"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasRole("ROLE_USER")
|
||||
then:
|
||||
IllegalArgumentException e = thrown()
|
||||
e.message == "role should not start with 'ROLE_' since it is automatically inserted. Got 'ROLE_USER'"
|
||||
}
|
||||
def "hasRole('ROLE_USER') is rejected due to starting with ROLE_"() {
|
||||
when:
|
||||
def expression = ExpressionUrlAuthorizationConfigurer.hasRole("ROLE_USER")
|
||||
then:
|
||||
IllegalArgumentException e = thrown()
|
||||
e.message == "role should not start with 'ROLE_' since it is automatically inserted. Got 'ROLE_USER'"
|
||||
}
|
||||
|
||||
def "authorizeRequests() uses AffirmativeBased AccessDecisionManager"() {
|
||||
when: "Load Config with no specific AccessDecisionManager"
|
||||
loadConfig(NoSpecificAccessDecessionManagerConfig)
|
||||
then: "AccessDecessionManager matches the HttpSecurityBuilder's default"
|
||||
findFilter(FilterSecurityInterceptor).accessDecisionManager.class == AffirmativeBased
|
||||
}
|
||||
def "authorizeRequests() uses AffirmativeBased AccessDecisionManager"() {
|
||||
when: "Load Config with no specific AccessDecisionManager"
|
||||
loadConfig(NoSpecificAccessDecessionManagerConfig)
|
||||
then: "AccessDecessionManager matches the HttpSecurityBuilder's default"
|
||||
findFilter(FilterSecurityInterceptor).accessDecisionManager.class == AffirmativeBased
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NoSpecificAccessDecessionManagerConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class NoSpecificAccessDecessionManagerConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() no requests"() {
|
||||
when: "Load Config with no requests"
|
||||
loadConfig(NoRequestsConfig)
|
||||
then: "A meaningful exception is thrown"
|
||||
BeanCreationException success = thrown()
|
||||
success.message.contains "At least one mapping is required (i.e. authorizeRequests().anyRequest.authenticated())"
|
||||
}
|
||||
def "authorizeRequests() no requests"() {
|
||||
when: "Load Config with no requests"
|
||||
loadConfig(NoRequestsConfig)
|
||||
then: "A meaningful exception is thrown"
|
||||
BeanCreationException success = thrown()
|
||||
success.message.contains "At least one mapping is required (i.e. authorizeRequests().anyRequest.authenticated())"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NoRequestsConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class NoRequestsConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() incomplete mapping"() {
|
||||
when: "Load Config with incomplete mapping"
|
||||
loadConfig(IncompleteMappingConfig)
|
||||
then: "A meaningful exception is thrown"
|
||||
BeanCreationException success = thrown()
|
||||
success.message.contains "An incomplete mapping was found for "
|
||||
}
|
||||
def "authorizeRequests() incomplete mapping"() {
|
||||
when: "Load Config with incomplete mapping"
|
||||
loadConfig(IncompleteMappingConfig)
|
||||
then: "A meaningful exception is thrown"
|
||||
BeanCreationException success = thrown()
|
||||
success.message.contains "An incomplete mapping was found for "
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class IncompleteMappingConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/a").authenticated()
|
||||
.anyRequest()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class IncompleteMappingConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/a").authenticated()
|
||||
.anyRequest()
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() hasAuthority"() {
|
||||
setup:
|
||||
loadConfig(HasAuthorityConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_INVALID")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "authorizeRequests() hasAuthority"() {
|
||||
setup:
|
||||
loadConfig(HasAuthorityConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_INVALID")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HasAuthorityConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasAuthority("ROLE_USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class HasAuthorityConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasAuthority("ROLE_USER")
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() hasAnyAuthority"() {
|
||||
setup:
|
||||
loadConfig(HasAnyAuthorityConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_ADMIN")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_DBA")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_INVALID")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "authorizeRequests() hasAnyAuthority"() {
|
||||
setup:
|
||||
loadConfig(HasAnyAuthorityConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_ADMIN")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_DBA")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login("user","ROLE_INVALID")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HasAnyAuthorityConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasAnyAuthority("ROLE_ADMIN","ROLE_DBA")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class HasAnyAuthorityConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasAnyAuthority("ROLE_ADMIN","ROLE_DBA")
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() hasIpAddress"() {
|
||||
setup:
|
||||
loadConfig(HasIpAddressConfig)
|
||||
when:
|
||||
request.remoteAddr = "192.168.1.1"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
request.remoteAddr = "192.168.1.0"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
def "authorizeRequests() hasIpAddress"() {
|
||||
setup:
|
||||
loadConfig(HasIpAddressConfig)
|
||||
when:
|
||||
request.remoteAddr = "192.168.1.1"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
request.remoteAddr = "192.168.1.0"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HasIpAddressConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasIpAddress("192.168.1.0")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class HasIpAddressConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasIpAddress("192.168.1.0")
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() anonymous"() {
|
||||
setup:
|
||||
loadConfig(AnonymousConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "authorizeRequests() anonymous"() {
|
||||
setup:
|
||||
loadConfig(AnonymousConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AnonymousConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().anonymous()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class AnonymousConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().anonymous()
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() rememberMe"() {
|
||||
setup:
|
||||
loadConfig(RememberMeConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
def "authorizeRequests() rememberMe"() {
|
||||
setup:
|
||||
loadConfig(RememberMeConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RememberMeConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.rememberMe()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().rememberMe()
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class RememberMeConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.rememberMe()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().rememberMe()
|
||||
}
|
||||
|
||||
@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 "authorizeRequests() denyAll"() {
|
||||
setup:
|
||||
loadConfig(DenyAllConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "authorizeRequests() denyAll"() {
|
||||
setup:
|
||||
loadConfig(DenyAllConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DenyAllConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class DenyAllConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll()
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() not denyAll"() {
|
||||
setup:
|
||||
loadConfig(NotDenyAllConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
def "authorizeRequests() not denyAll"() {
|
||||
setup:
|
||||
loadConfig(NotDenyAllConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NotDenyAllConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().not().denyAll()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class NotDenyAllConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().not().denyAll()
|
||||
}
|
||||
}
|
||||
|
||||
def "authorizeRequests() fullyAuthenticated"() {
|
||||
setup:
|
||||
loadConfig(FullyAuthenticatedConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
def "authorizeRequests() fullyAuthenticated"() {
|
||||
setup:
|
||||
loadConfig(FullyAuthenticatedConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
super.setup()
|
||||
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FullyAuthenticatedConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.rememberMe()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().fullyAuthenticated()
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class FullyAuthenticatedConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.rememberMe()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().fullyAuthenticated()
|
||||
}
|
||||
|
||||
@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 "authorizeRequests() access"() {
|
||||
setup:
|
||||
loadConfig(AccessConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is granted due to GET"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is granted due to role"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is denied"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
def "authorizeRequests() access"() {
|
||||
setup:
|
||||
loadConfig(AccessConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is granted due to GET"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is granted due to role"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
super.setup()
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is denied"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AccessConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.rememberMe()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().access("hasRole('ROLE_USER') or request.method == 'GET'")
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class AccessConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.rememberMe()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().access("hasRole('ROLE_USER') or request.method == 'GET'")
|
||||
}
|
||||
|
||||
@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 "invoke authorizeUrls twice does not reset"() {
|
||||
setup:
|
||||
loadConfig(InvokeTwiceDoesNotResetConfig)
|
||||
when:
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is denied"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
def "invoke authorizeUrls twice does not reset"() {
|
||||
setup:
|
||||
loadConfig(InvokeTwiceDoesNotResetConfig)
|
||||
when:
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access is denied"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotResetConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotResetConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
|
||||
def "All Properties are accessible and chain properly"() {
|
||||
when:
|
||||
loadConfig(AllPropertiesWorkConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "All Properties are accessible and chain properly"() {
|
||||
when:
|
||||
loadConfig(AllPropertiesWorkConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def "AuthorizedRequests withPostProcessor"() {
|
||||
setup:
|
||||
ApplicationListener al = Mock()
|
||||
AuthorizedRequestsWithPostProcessorConfig.AL = al
|
||||
loadConfig(AuthorizedRequestsWithPostProcessorConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
1 * al.onApplicationEvent(_ as AuthorizedEvent)
|
||||
}
|
||||
def "AuthorizedRequests withPostProcessor"() {
|
||||
setup:
|
||||
ApplicationListener al = Mock()
|
||||
AuthorizedRequestsWithPostProcessorConfig.AL = al
|
||||
loadConfig(AuthorizedRequestsWithPostProcessorConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
1 * al.onApplicationEvent(_ as AuthorizedEvent)
|
||||
}
|
||||
|
||||
def "Use @permission.check in access"() {
|
||||
setup:
|
||||
loadConfig(UseBeansInExpressions)
|
||||
when: "invoke standard expression that denies access"
|
||||
login()
|
||||
request.servletPath = "/admin/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get forbidden"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when: "invoke standard expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/user/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get ok"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/allow/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression allows access"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that denies access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/deny/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression denies access"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "Use @permission.check in access"() {
|
||||
setup:
|
||||
loadConfig(UseBeansInExpressions)
|
||||
when: "invoke standard expression that denies access"
|
||||
login()
|
||||
request.servletPath = "/admin/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get forbidden"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when: "invoke standard expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/user/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get ok"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/allow/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression allows access"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that denies access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/deny/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression denies access"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "Use custom expressionroot in access"() {
|
||||
setup:
|
||||
loadConfig(CustomExpressionRootConfig)
|
||||
when: "invoke standard expression that denies access"
|
||||
login()
|
||||
request.servletPath = "/admin/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get forbidden"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when: "invoke standard expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/user/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get ok"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/allow/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression allows access"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that denies access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/deny/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression denies access"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "Use custom expressionroot in access"() {
|
||||
setup:
|
||||
loadConfig(CustomExpressionRootConfig)
|
||||
when: "invoke standard expression that denies access"
|
||||
login()
|
||||
request.servletPath = "/admin/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get forbidden"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when: "invoke standard expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/user/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "standard expression works - get ok"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that allows access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/allow/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression allows access"
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: "invoke custom bean as expression that denies access"
|
||||
super.setup()
|
||||
login()
|
||||
request.servletPath = "/deny/1"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "custom bean expression denies access"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
}
|
||||
|
||||
+232
-232
@@ -56,266 +56,266 @@ 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: "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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+85
-85
@@ -33,101 +33,101 @@ 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
+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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+104
-104
@@ -40,117 +40,117 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
|
||||
*/
|
||||
public class NamespaceHttpBasicTests extends BaseSpringSpec {
|
||||
|
||||
def "http/http-basic"() {
|
||||
setup:
|
||||
loadConfig(HttpBasicConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
basicLogin("user","invalid")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "unauthorized"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="Realm"'
|
||||
when: "login success"
|
||||
super.setup()
|
||||
basicLogin()
|
||||
then: "sent to default succes page"
|
||||
!response.committed
|
||||
}
|
||||
def "http/http-basic"() {
|
||||
setup:
|
||||
loadConfig(HttpBasicConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
basicLogin("user","invalid")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "unauthorized"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="Realm"'
|
||||
when: "login success"
|
||||
super.setup()
|
||||
basicLogin()
|
||||
then: "sent to default succes page"
|
||||
!response.committed
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
}
|
||||
|
||||
def "http@realm"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpBasicConfig)
|
||||
when:
|
||||
basicLogin("user","invalid")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "unauthorized"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="Custom Realm"'
|
||||
}
|
||||
def "http@realm"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpBasicConfig)
|
||||
when:
|
||||
basicLogin("user","invalid")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "unauthorized"
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="Custom Realm"'
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomHttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.httpBasic().realmName("Custom Realm");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class CustomHttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.httpBasic().realmName("Custom Realm");
|
||||
}
|
||||
}
|
||||
|
||||
def "http-basic@authentication-details-source-ref"() {
|
||||
when:
|
||||
loadConfig(AuthenticationDetailsSourceHttpBasicConfig)
|
||||
then:
|
||||
findFilter(BasicAuthenticationFilter).authenticationDetailsSource.class == CustomAuthenticationDetailsSource
|
||||
}
|
||||
def "http-basic@authentication-details-source-ref"() {
|
||||
when:
|
||||
loadConfig(AuthenticationDetailsSourceHttpBasicConfig)
|
||||
then:
|
||||
findFilter(BasicAuthenticationFilter).authenticationDetailsSource.class == CustomAuthenticationDetailsSource
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AuthenticationDetailsSourceHttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.httpBasic()
|
||||
.authenticationDetailsSource(new CustomAuthenticationDetailsSource())
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AuthenticationDetailsSourceHttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.httpBasic()
|
||||
.authenticationDetailsSource(new CustomAuthenticationDetailsSource())
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
|
||||
static class CustomAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
|
||||
|
||||
def "http-basic@entry-point-ref"() {
|
||||
setup:
|
||||
loadConfig(EntryPointRefHttpBasicConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_INTERNAL_SERVER_ERROR
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
basicLogin("user","invalid")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "custom"
|
||||
response.status == HttpServletResponse.SC_INTERNAL_SERVER_ERROR
|
||||
when: "login success"
|
||||
super.setup()
|
||||
basicLogin()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
!response.committed
|
||||
}
|
||||
def "http-basic@entry-point-ref"() {
|
||||
setup:
|
||||
loadConfig(EntryPointRefHttpBasicConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_INTERNAL_SERVER_ERROR
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
basicLogin("user","invalid")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "custom"
|
||||
response.status == HttpServletResponse.SC_INTERNAL_SERVER_ERROR
|
||||
when: "login success"
|
||||
super.setup()
|
||||
basicLogin()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
!response.committed
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class EntryPointRefHttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.httpBasic()
|
||||
.authenticationEntryPoint(new AuthenticationEntryPoint() {
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class EntryPointRefHttpBasicConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.httpBasic()
|
||||
.authenticationEntryPoint(new AuthenticationEntryPoint() {
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
def basicLogin(String username="user",String password="password") {
|
||||
def credentials = username + ":" + password
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
}
|
||||
def basicLogin(String username="user",String password="password") {
|
||||
def credentials = username + ":" + password
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
}
|
||||
}
|
||||
|
||||
+86
-86
@@ -65,105 +65,105 @@ import spock.lang.Ignore;
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpCustomFilterTests extends BaseSpringSpec {
|
||||
def "http/custom-filter@before"() {
|
||||
when:
|
||||
loadConfig(CustomFilterBeforeConfig)
|
||||
then:
|
||||
filterChain().filters[0].class == CustomFilter
|
||||
}
|
||||
def "http/custom-filter@before"() {
|
||||
when:
|
||||
loadConfig(CustomFilterBeforeConfig)
|
||||
then:
|
||||
filterChain().filters[0].class == CustomFilter
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFilterBeforeConfig extends BaseWebConfig {
|
||||
CustomFilterBeforeConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
@Configuration
|
||||
static class CustomFilterBeforeConfig extends BaseWebConfig {
|
||||
CustomFilterBeforeConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/custom-filter@after"() {
|
||||
when:
|
||||
loadConfig(CustomFilterAfterConfig)
|
||||
then:
|
||||
filterChain().filters[1].class == CustomFilter
|
||||
}
|
||||
def "http/custom-filter@after"() {
|
||||
when:
|
||||
loadConfig(CustomFilterAfterConfig)
|
||||
then:
|
||||
filterChain().filters[1].class == CustomFilter
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFilterAfterConfig extends BaseWebConfig {
|
||||
CustomFilterAfterConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
@Configuration
|
||||
static class CustomFilterAfterConfig extends BaseWebConfig {
|
||||
CustomFilterAfterConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterAfter(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterAfter(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/custom-filter@position"() {
|
||||
when:
|
||||
loadConfig(CustomFilterPositionConfig)
|
||||
then:
|
||||
filterChain().filters.collect { it.class } == [CustomFilter]
|
||||
}
|
||||
def "http/custom-filter@position"() {
|
||||
when:
|
||||
loadConfig(CustomFilterPositionConfig)
|
||||
then:
|
||||
filterChain().filters.collect { it.class } == [CustomFilter]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFilterPositionConfig extends BaseWebConfig {
|
||||
CustomFilterPositionConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
@Configuration
|
||||
static class CustomFilterPositionConfig extends BaseWebConfig {
|
||||
CustomFilterPositionConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
// this works so long as the CustomFilter extends one of the standard filters
|
||||
// if not, use addFilterBefore or addFilterAfter
|
||||
.addFilter(new CustomFilter())
|
||||
}
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
// this works so long as the CustomFilter extends one of the standard filters
|
||||
// if not, use addFilterBefore or addFilterAfter
|
||||
.addFilter(new CustomFilter())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def "http/custom-filter no AuthenticationManager in HttpSecurity"() {
|
||||
when:
|
||||
loadConfig(NoAuthenticationManagerInHtppConfigurationConfig)
|
||||
then:
|
||||
filterChain().filters[0].class == CustomFilter
|
||||
}
|
||||
def "http/custom-filter no AuthenticationManager in HttpSecurity"() {
|
||||
when:
|
||||
loadConfig(NoAuthenticationManagerInHtppConfigurationConfig)
|
||||
then:
|
||||
filterChain().filters[0].class == CustomFilter
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NoAuthenticationManagerInHtppConfigurationConfig extends WebSecurityConfigurerAdapter {
|
||||
NoAuthenticationManagerInHtppConfigurationConfig() {
|
||||
super(true)
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class NoAuthenticationManagerInHtppConfigurationConfig extends WebSecurityConfigurerAdapter {
|
||||
NoAuthenticationManagerInHtppConfigurationConfig() {
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected AuthenticationManager authenticationManager()
|
||||
throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
protected AuthenticationManager authenticationManager()
|
||||
throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomFilter extends UsernamePasswordAuthenticationFilter {}
|
||||
static class CustomFilter extends UsernamePasswordAuthenticationFilter {}
|
||||
|
||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-21
@@ -30,27 +30,27 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpExpressionHandlerTests extends BaseSpringSpec {
|
||||
def "http/expression-handler@ref"() {
|
||||
when:
|
||||
def parser = new SpelExpressionParser()
|
||||
ExpressionHandlerConfig.EXPRESSION_HANDLER = Mock(SecurityExpressionHandler.class)
|
||||
ExpressionHandlerConfig.EXPRESSION_HANDLER.getExpressionParser() >> parser
|
||||
loadConfig(ExpressionHandlerConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
def "http/expression-handler@ref"() {
|
||||
when:
|
||||
def parser = new SpelExpressionParser()
|
||||
ExpressionHandlerConfig.EXPRESSION_HANDLER = Mock(SecurityExpressionHandler.class)
|
||||
ExpressionHandlerConfig.EXPRESSION_HANDLER.getExpressionParser() >> parser
|
||||
loadConfig(ExpressionHandlerConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ExpressionHandlerConfig extends BaseWebConfig {
|
||||
static EXPRESSION_HANDLER;
|
||||
@EnableWebSecurity
|
||||
static class ExpressionHandlerConfig extends BaseWebConfig {
|
||||
static EXPRESSION_HANDLER;
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.expressionHandler(EXPRESSION_HANDLER)
|
||||
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
}
|
||||
}
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.expressionHandler(EXPRESSION_HANDLER)
|
||||
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+59
-59
@@ -38,73 +38,73 @@ import org.springframework.security.web.firewall.RequestRejectedException
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpFirewallTests extends BaseSpringSpec {
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest()
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest()
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
def "http-firewall"() {
|
||||
setup:
|
||||
loadConfig(HttpFirewallConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
request.setPathInfo("/public/../private/")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "the default firewall is used"
|
||||
thrown(RequestRejectedException)
|
||||
}
|
||||
def "http-firewall"() {
|
||||
setup:
|
||||
loadConfig(HttpFirewallConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
request.setPathInfo("/public/../private/")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "the default firewall is used"
|
||||
thrown(RequestRejectedException)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HttpFirewallConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HttpFirewallConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
|
||||
def "http-firewall@ref"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpFirewallConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
request.setParameter("deny", "true")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "the custom firewall is used"
|
||||
thrown(RequestRejectedException)
|
||||
}
|
||||
def "http-firewall@ref"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpFirewallConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
request.setParameter("deny", "true")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "the custom firewall is used"
|
||||
thrown(RequestRejectedException)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomHttpFirewallConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) { }
|
||||
@Configuration
|
||||
static class CustomHttpFirewallConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) { }
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
builder
|
||||
.httpFirewall(new CustomHttpFirewall())
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
builder
|
||||
.httpFirewall(new CustomHttpFirewall())
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomHttpFirewall extends DefaultHttpFirewall {
|
||||
static class CustomHttpFirewall extends DefaultHttpFirewall {
|
||||
|
||||
@Override
|
||||
public FirewalledRequest getFirewalledRequest(HttpServletRequest request)
|
||||
throws RequestRejectedException {
|
||||
if(request.getParameter("deny")) {
|
||||
throw new RequestRejectedException("custom rejection")
|
||||
}
|
||||
return super.getFirewalledRequest(request)
|
||||
}
|
||||
@Override
|
||||
public FirewalledRequest getFirewalledRequest(HttpServletRequest request)
|
||||
throws RequestRejectedException {
|
||||
if(request.getParameter("deny")) {
|
||||
throw new RequestRejectedException("custom rejection")
|
||||
}
|
||||
return super.getFirewalledRequest(request)
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServletResponse getFirewalledResponse(
|
||||
HttpServletResponse response) {
|
||||
return super.getFirewalledRequest(response)
|
||||
}
|
||||
@Override
|
||||
public HttpServletResponse getFirewalledResponse(
|
||||
HttpServletResponse response) {
|
||||
return super.getFirewalledRequest(response)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+120
-120
@@ -38,133 +38,133 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpFormLoginTests extends BaseSpringSpec {
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
|
||||
def "http/form-login"() {
|
||||
setup:
|
||||
loadConfig(FormLoginConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
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 "http/form-login"() {
|
||||
setup:
|
||||
loadConfig(FormLoginConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
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() == "/"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FormLoginConfig extends BaseWebConfig {
|
||||
@Configuration
|
||||
static class FormLoginConfig extends BaseWebConfig {
|
||||
|
||||
@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) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/form-login custom"() {
|
||||
setup:
|
||||
loadConfig(FormLoginCustomConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/authentication/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/authentication/login?failed"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
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() == "/default"
|
||||
}
|
||||
def "http/form-login custom"() {
|
||||
setup:
|
||||
loadConfig(FormLoginCustomConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/authentication/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/authentication/login?failed"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
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() == "/default"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FormLoginCustomConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
boolean alwaysUseDefaultSuccess = true;
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.usernameParameter("username") // form-login@username-parameter
|
||||
.passwordParameter("password") // form-login@password-parameter
|
||||
.loginPage("/authentication/login") // form-login@login-page
|
||||
.failureUrl("/authentication/login?failed") // form-login@authentication-failure-url
|
||||
.loginProcessingUrl("/authentication/login/process") // form-login@login-processing-url
|
||||
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess) // form-login@default-target-url / form-login@always-use-default-target
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class FormLoginCustomConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
boolean alwaysUseDefaultSuccess = true;
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.usernameParameter("username") // form-login@username-parameter
|
||||
.passwordParameter("password") // form-login@password-parameter
|
||||
.loginPage("/authentication/login") // form-login@login-page
|
||||
.failureUrl("/authentication/login?failed") // form-login@authentication-failure-url
|
||||
.loginProcessingUrl("/authentication/login/process") // form-login@login-processing-url
|
||||
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess) // form-login@default-target-url / form-login@always-use-default-target
|
||||
}
|
||||
}
|
||||
|
||||
def "http/form-login custom refs"() {
|
||||
when:
|
||||
loadConfig(FormLoginCustomRefsConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
then: "CustomWebAuthenticationDetailsSource is used"
|
||||
findFilter(UsernamePasswordAuthenticationFilter).authenticationDetailsSource.class == CustomWebAuthenticationDetailsSource
|
||||
when: "fail to log in"
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/custom/failure"
|
||||
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() == "/custom/targetUrl"
|
||||
}
|
||||
def "http/form-login custom refs"() {
|
||||
when:
|
||||
loadConfig(FormLoginCustomRefsConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
then: "CustomWebAuthenticationDetailsSource is used"
|
||||
findFilter(UsernamePasswordAuthenticationFilter).authenticationDetailsSource.class == CustomWebAuthenticationDetailsSource
|
||||
when: "fail to log in"
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/custom/failure"
|
||||
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() == "/custom/targetUrl"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FormLoginCustomRefsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // form-login@authentication-failure-handler-ref
|
||||
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler( defaultTargetUrl : "/custom/targetUrl" )) // form-login@authentication-success-handler-ref
|
||||
.authenticationDetailsSource(new CustomWebAuthenticationDetailsSource()) // form-login@authentication-details-source-ref
|
||||
.and();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class FormLoginCustomRefsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // form-login@authentication-failure-handler-ref
|
||||
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler( defaultTargetUrl : "/custom/targetUrl" )) // form-login@authentication-success-handler-ref
|
||||
.authenticationDetailsSource(new CustomWebAuthenticationDetailsSource()) // form-login@authentication-details-source-ref
|
||||
.and();
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
|
||||
static class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
|
||||
}
|
||||
|
||||
+203
-203
@@ -38,230 +38,230 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
*/
|
||||
public class NamespaceHttpHeadersTests extends BaseSpringSpec {
|
||||
|
||||
def "http/headers"() {
|
||||
setup:
|
||||
loadConfig(HeadersDefaultConfig)
|
||||
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',
|
||||
'Pragma':'no-cache',
|
||||
'Expires' : '0',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
def "http/headers"() {
|
||||
setup:
|
||||
loadConfig(HeadersDefaultConfig)
|
||||
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',
|
||||
'Pragma':'no-cache',
|
||||
'Expires' : '0',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HeadersDefaultConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HeadersDefaultConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/cache-control"() {
|
||||
setup:
|
||||
loadConfig(HeadersCacheControlConfig)
|
||||
request.secure = true
|
||||
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 "http/headers/cache-control"() {
|
||||
setup:
|
||||
loadConfig(HeadersCacheControlConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HeadersCacheControlConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.cacheControl()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HeadersCacheControlConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.cacheControl()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/hsts"() {
|
||||
setup:
|
||||
loadConfig(HstsConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
|
||||
}
|
||||
def "http/headers/hsts"() {
|
||||
setup:
|
||||
loadConfig(HstsConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HstsConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HstsConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/hsts custom"() {
|
||||
setup:
|
||||
loadConfig(HstsCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=15768000']
|
||||
}
|
||||
def "http/headers/hsts custom"() {
|
||||
setup:
|
||||
loadConfig(HstsCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=15768000']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HstsCustomConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// hsts@request-matcher-ref, hsts@max-age-seconds, hsts@include-subdomains
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
.requestMatcher(AnyRequestMatcher.INSTANCE)
|
||||
.maxAgeInSeconds(15768000)
|
||||
.includeSubDomains(false)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HstsCustomConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// hsts@request-matcher-ref, hsts@max-age-seconds, hsts@include-subdomains
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
.requestMatcher(AnyRequestMatcher.INSTANCE)
|
||||
.maxAgeInSeconds(15768000)
|
||||
.includeSubDomains(false)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/frame-options@policy=SAMEORIGIN"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsSameOriginConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options': 'SAMEORIGIN']
|
||||
}
|
||||
def "http/headers/frame-options@policy=SAMEORIGIN"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsSameOriginConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options': 'SAMEORIGIN']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FrameOptionsSameOriginConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@policy=SAMEORIGIN
|
||||
.defaultsDisabled()
|
||||
.frameOptions()
|
||||
.sameOrigin()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class FrameOptionsSameOriginConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@policy=SAMEORIGIN
|
||||
.defaultsDisabled()
|
||||
.frameOptions()
|
||||
.sameOrigin()
|
||||
}
|
||||
}
|
||||
|
||||
// frame-options@strategy, frame-options@value, frame-options@parameter are not provided instead use frame-options@ref
|
||||
// frame-options@strategy, frame-options@value, frame-options@parameter are not provided instead use frame-options@ref
|
||||
|
||||
def "http/headers/frame-options"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsAllowFromConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options': 'ALLOW-FROM https://example.com']
|
||||
}
|
||||
def "http/headers/frame-options"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsAllowFromConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options': 'ALLOW-FROM https://example.com']
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class FrameOptionsAllowFromConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@ref
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new XFrameOptionsHeaderWriter(new StaticAllowFromStrategy(new URI("https://example.com"))))
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class FrameOptionsAllowFromConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@ref
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new XFrameOptionsHeaderWriter(new StaticAllowFromStrategy(new URI("https://example.com"))))
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/xss-protection"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection': '1; mode=block']
|
||||
}
|
||||
def "http/headers/xss-protection"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection': '1; mode=block']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class XssProtectionConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class XssProtectionConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/xss-protection custom"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection': '1']
|
||||
}
|
||||
def "http/headers/xss-protection custom"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection': '1']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class XssProtectionCustomConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection@enabled and xss-protection@block
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
.xssProtectionEnabled(true)
|
||||
.block(false)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class XssProtectionCustomConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection@enabled and xss-protection@block
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
.xssProtectionEnabled(true)
|
||||
.block(false)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/content-type-options"() {
|
||||
setup:
|
||||
loadConfig(ContentTypeOptionsConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options': 'nosniff']
|
||||
}
|
||||
def "http/headers/content-type-options"() {
|
||||
setup:
|
||||
loadConfig(ContentTypeOptionsConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options': 'nosniff']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ContentTypeOptionsConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// content-type-options
|
||||
.defaultsDisabled()
|
||||
.contentTypeOptions()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class ContentTypeOptionsConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// content-type-options
|
||||
.defaultsDisabled()
|
||||
.contentTypeOptions()
|
||||
}
|
||||
}
|
||||
|
||||
// header@name / header@value are not provided instead use header@ref
|
||||
// header@name / header@value are not provided instead use header@ref
|
||||
|
||||
def "http/headers/header@ref"() {
|
||||
setup:
|
||||
loadConfig(HeaderRefConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['customHeaderName': 'customHeaderValue']
|
||||
}
|
||||
def "http/headers/header@ref"() {
|
||||
setup:
|
||||
loadConfig(HeaderRefConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['customHeaderName': 'customHeaderValue']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HeaderRefConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue"))
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HeaderRefConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+118
-118
@@ -42,128 +42,128 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
|
||||
*/
|
||||
public class NamespaceHttpInterceptUrlTests extends BaseSpringSpec {
|
||||
|
||||
def "http/intercept-url denied when not logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
request.servletPath == "/users"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "http/intercept-url denied when not logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
request.servletPath == "/users"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "http/intercept-url denied when logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
login()
|
||||
request.setServletPath("/users")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "http/intercept-url denied when logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
login()
|
||||
request.setServletPath("/users")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "http/intercept-url allowed when logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
login("admin","ROLE_ADMIN")
|
||||
request.setServletPath("/users")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.isCommitted()
|
||||
}
|
||||
def "http/intercept-url allowed when logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
login("admin","ROLE_ADMIN")
|
||||
request.setServletPath("/users")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.isCommitted()
|
||||
}
|
||||
|
||||
def "http/intercept-url@method=POST"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
when:
|
||||
login()
|
||||
request.setServletPath("/admin/post")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.isCommitted()
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
request.setServletPath("/admin/post")
|
||||
request.setMethod("POST")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when:
|
||||
super.setup()
|
||||
login("admin","ROLE_ADMIN")
|
||||
request.setServletPath("/admin/post")
|
||||
request.setMethod("POST")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.committed
|
||||
}
|
||||
def "http/intercept-url@method=POST"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
when:
|
||||
login()
|
||||
request.setServletPath("/admin/post")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.isCommitted()
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
request.setServletPath("/admin/post")
|
||||
request.setMethod("POST")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when:
|
||||
super.setup()
|
||||
login("admin","ROLE_ADMIN")
|
||||
request.setServletPath("/admin/post")
|
||||
request.setMethod("POST")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.committed
|
||||
}
|
||||
|
||||
def "http/intercept-url@requires-channel"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
when:
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost/login"
|
||||
when:
|
||||
super.setup()
|
||||
request.setServletPath("/secured/a")
|
||||
request.setRequestURI("/secured/a")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost/secured/a"
|
||||
when:
|
||||
super.setup()
|
||||
request.setSecure(true)
|
||||
request.setScheme("https")
|
||||
request.setServletPath("/user")
|
||||
request.setRequestURI("/user")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "http://localhost/user"
|
||||
}
|
||||
def "http/intercept-url@requires-channel"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
when:
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost/login"
|
||||
when:
|
||||
super.setup()
|
||||
request.setServletPath("/secured/a")
|
||||
request.setRequestURI("/secured/a")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost/secured/a"
|
||||
when:
|
||||
super.setup()
|
||||
request.setSecure(true)
|
||||
request.setScheme("https")
|
||||
request.setServletPath("/user")
|
||||
request.setRequestURI("/user")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "http://localhost/user"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
// the line below is similar to intercept-url@pattern:
|
||||
// <intercept-url pattern="/users**" access="hasRole('ROLE_ADMIN')"/>
|
||||
// <intercept-url pattern="/sessions/**" access="hasRole('ROLE_ADMIN')"/>
|
||||
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
|
||||
// the line below is similar to intercept-url@method:
|
||||
// <intercept-url pattern="/admin/post" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
// <intercept-url pattern="/admin/another-post/**" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
.antMatchers(HttpMethod.POST, "/admin/post","/admin/another-post/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.requiresChannel()
|
||||
// NOTE: channel security is configured separately of authorization (i.e. intercept-url@access
|
||||
// the line below is similar to intercept-url@requires-channel="https":
|
||||
// <intercept-url pattern="/login" requires-channel="https"/>
|
||||
// <intercept-url pattern="/secured/**" requires-channel="https"/>
|
||||
.antMatchers("/login","/secured/**").requiresSecure()
|
||||
// the line below is similar to intercept-url@requires-channel="http":
|
||||
// <intercept-url pattern="/**" requires-channel="http"/>
|
||||
.anyRequest().requiresInsecure()
|
||||
}
|
||||
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(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
// the line below is similar to intercept-url@pattern:
|
||||
// <intercept-url pattern="/users**" access="hasRole('ROLE_ADMIN')"/>
|
||||
// <intercept-url pattern="/sessions/**" access="hasRole('ROLE_ADMIN')"/>
|
||||
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
|
||||
// the line below is similar to intercept-url@method:
|
||||
// <intercept-url pattern="/admin/post" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
// <intercept-url pattern="/admin/another-post/**" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
.antMatchers(HttpMethod.POST, "/admin/post","/admin/another-post/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.requiresChannel()
|
||||
// NOTE: channel security is configured separately of authorization (i.e. intercept-url@access
|
||||
// the line below is similar to intercept-url@requires-channel="https":
|
||||
// <intercept-url pattern="/login" requires-channel="https"/>
|
||||
// <intercept-url pattern="/secured/**" requires-channel="https"/>
|
||||
.antMatchers("/login","/secured/**").requiresSecure()
|
||||
// the line below is similar to intercept-url@requires-channel="http":
|
||||
// <intercept-url pattern="/**" requires-channel="http"/>
|
||||
.anyRequest().requiresInsecure()
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
-54
@@ -80,64 +80,64 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*/
|
||||
public class NamespaceHttpJeeTests extends BaseSpringSpec {
|
||||
|
||||
def "http/jee@mappable-roles"() {
|
||||
when:
|
||||
loadConfig(JeeMappableRolesConfig)
|
||||
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
|
||||
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == PreAuthenticatedGrantedAuthoritiesUserDetailsService
|
||||
}
|
||||
def "http/jee@mappable-roles"() {
|
||||
when:
|
||||
loadConfig(JeeMappableRolesConfig)
|
||||
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
|
||||
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == PreAuthenticatedGrantedAuthoritiesUserDetailsService
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableRoles("USER","ADMIN");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableRoles("USER","ADMIN");
|
||||
}
|
||||
}
|
||||
|
||||
def "http/jee@user-service-ref"() {
|
||||
when:
|
||||
loadConfig(JeeUserServiceRefConfig)
|
||||
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
|
||||
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == CustomUserService
|
||||
}
|
||||
def "http/jee@user-service-ref"() {
|
||||
when:
|
||||
loadConfig(JeeUserServiceRefConfig)
|
||||
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
|
||||
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == CustomUserService
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class JeeUserServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
public static class JeeUserServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableAuthorities("ROLE_USER","ROLE_ADMIN")
|
||||
.authenticatedUserDetailsService(new CustomUserService());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableAuthorities("ROLE_USER","ROLE_ADMIN")
|
||||
.authenticatedUserDetailsService(new CustomUserService());
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomUserService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
||||
public UserDetails loadUserDetails(
|
||||
PreAuthenticatedAuthenticationToken token)
|
||||
throws UsernameNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
static class CustomUserService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
||||
public UserDetails loadUserDetails(
|
||||
PreAuthenticatedAuthenticationToken token)
|
||||
throws UsernameNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+79
-79
@@ -72,90 +72,90 @@ import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
*/
|
||||
public class NamespaceHttpLogoutTests extends BaseSpringSpec {
|
||||
|
||||
def "http/logout"() {
|
||||
setup:
|
||||
loadConfig(HttpLogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!authenticated()
|
||||
!request.getSession(false)
|
||||
response.redirectedUrl == "/login?logout"
|
||||
!response.getCookies()
|
||||
}
|
||||
def "http/logout"() {
|
||||
setup:
|
||||
loadConfig(HttpLogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!authenticated()
|
||||
!request.getSession(false)
|
||||
response.redirectedUrl == "/login?logout"
|
||||
!response.getCookies()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HttpLogoutConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class HttpLogoutConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
|
||||
def "http/logout custom"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpLogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/custom-logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!authenticated()
|
||||
request.getSession(false)
|
||||
response.redirectedUrl == "/logout-success"
|
||||
response.getCookies().length == 1
|
||||
response.getCookies()[0].name == "remove"
|
||||
response.getCookies()[0].maxAge == 0
|
||||
}
|
||||
def "http/logout custom"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpLogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/custom-logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!authenticated()
|
||||
request.getSession(false)
|
||||
response.redirectedUrl == "/logout-success"
|
||||
response.getCookies().length == 1
|
||||
response.getCookies()[0].name == "remove"
|
||||
response.getCookies()[0].maxAge == 0
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomHttpLogoutConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.logout()
|
||||
.deleteCookies("remove") // logout@delete-cookies
|
||||
.invalidateHttpSession(false) // logout@invalidate-session=false (default is true)
|
||||
.logoutUrl("/custom-logout") // logout@logout-url (default is /logout)
|
||||
.logoutSuccessUrl("/logout-success") // logout@success-url (default is /login?logout)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class CustomHttpLogoutConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.logout()
|
||||
.deleteCookies("remove") // logout@delete-cookies
|
||||
.invalidateHttpSession(false) // logout@invalidate-session=false (default is true)
|
||||
.logoutUrl("/custom-logout") // logout@logout-url (default is /logout)
|
||||
.logoutSuccessUrl("/logout-success") // logout@success-url (default is /login?logout)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/logout@success-handler-ref"() {
|
||||
setup:
|
||||
loadConfig(SuccessHandlerRefHttpLogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!authenticated()
|
||||
!request.getSession(false)
|
||||
response.redirectedUrl == "/SuccessHandlerRefHttpLogoutConfig"
|
||||
!response.getCookies()
|
||||
}
|
||||
def "http/logout@success-handler-ref"() {
|
||||
setup:
|
||||
loadConfig(SuccessHandlerRefHttpLogoutConfig)
|
||||
login()
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
!authenticated()
|
||||
!request.getSession(false)
|
||||
response.redirectedUrl == "/SuccessHandlerRefHttpLogoutConfig"
|
||||
!response.getCookies()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SuccessHandlerRefHttpLogoutConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler(defaultTargetUrl:"/SuccessHandlerRefHttpLogoutConfig")
|
||||
http
|
||||
.logout()
|
||||
.logoutSuccessHandler(logoutSuccessHandler)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class SuccessHandlerRefHttpLogoutConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler(defaultTargetUrl:"/SuccessHandlerRefHttpLogoutConfig")
|
||||
http
|
||||
.logout()
|
||||
.logoutSuccessHandler(logoutSuccessHandler)
|
||||
}
|
||||
}
|
||||
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)
|
||||
repo.saveContext(new SecurityContextImpl(authentication: new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role))), requestResponseHolder.request, requestResponseHolder.response)
|
||||
}
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)
|
||||
repo.saveContext(new SecurityContextImpl(authentication: new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role))), requestResponseHolder.request, requestResponseHolder.response)
|
||||
}
|
||||
|
||||
def authenticated() {
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
new HttpSessionSecurityContextRepository().loadContext(requestResponseHolder)?.authentication?.authenticated
|
||||
}
|
||||
def authenticated() {
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
new HttpSessionSecurityContextRepository().loadContext(requestResponseHolder)?.authentication?.authenticated
|
||||
}
|
||||
}
|
||||
|
||||
+168
-168
@@ -44,185 +44,185 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpOpenIDLoginTests extends BaseSpringSpec {
|
||||
def "http/openid-login"() {
|
||||
when:
|
||||
loadConfig(OpenIDLoginConfig)
|
||||
then:
|
||||
findFilter(OpenIDAuthenticationFilter).consumer.class == OpenID4JavaConsumer
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login/openid"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
}
|
||||
def "http/openid-login"() {
|
||||
when:
|
||||
loadConfig(OpenIDLoginConfig)
|
||||
then:
|
||||
findFilter(OpenIDAuthenticationFilter).consumer.class == OpenID4JavaConsumer
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login/openid"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class OpenIDLoginConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
.permitAll();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class OpenIDLoginConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
.permitAll();
|
||||
}
|
||||
}
|
||||
|
||||
def "http/openid-login/attribute-exchange"() {
|
||||
when:
|
||||
loadConfig(OpenIDLoginAttributeExchangeConfig)
|
||||
OpenID4JavaConsumer consumer = findFilter(OpenIDAuthenticationFilter).consumer
|
||||
then:
|
||||
consumer.class == OpenID4JavaConsumer
|
||||
def "http/openid-login/attribute-exchange"() {
|
||||
when:
|
||||
loadConfig(OpenIDLoginAttributeExchangeConfig)
|
||||
OpenID4JavaConsumer consumer = findFilter(OpenIDAuthenticationFilter).consumer
|
||||
then:
|
||||
consumer.class == OpenID4JavaConsumer
|
||||
|
||||
def googleAttrs = consumer.attributesToFetchFactory.createAttributeList("https://www.google.com/1")
|
||||
googleAttrs[0].name == "email"
|
||||
googleAttrs[0].type == "http://axschema.org/contact/email"
|
||||
googleAttrs[0].required
|
||||
googleAttrs[1].name == "firstname"
|
||||
googleAttrs[1].type == "http://axschema.org/namePerson/first"
|
||||
googleAttrs[1].required
|
||||
googleAttrs[2].name == "lastname"
|
||||
googleAttrs[2].type == "http://axschema.org/namePerson/last"
|
||||
googleAttrs[2].required
|
||||
def googleAttrs = consumer.attributesToFetchFactory.createAttributeList("https://www.google.com/1")
|
||||
googleAttrs[0].name == "email"
|
||||
googleAttrs[0].type == "http://axschema.org/contact/email"
|
||||
googleAttrs[0].required
|
||||
googleAttrs[1].name == "firstname"
|
||||
googleAttrs[1].type == "http://axschema.org/namePerson/first"
|
||||
googleAttrs[1].required
|
||||
googleAttrs[2].name == "lastname"
|
||||
googleAttrs[2].type == "http://axschema.org/namePerson/last"
|
||||
googleAttrs[2].required
|
||||
|
||||
def yahooAttrs = consumer.attributesToFetchFactory.createAttributeList("https://rwinch.yahoo.com/rwinch/id")
|
||||
yahooAttrs[0].name == "email"
|
||||
yahooAttrs[0].type == "http://schema.openid.net/contact/email"
|
||||
yahooAttrs[0].required
|
||||
yahooAttrs[1].name == "fullname"
|
||||
yahooAttrs[1].type == "http://axschema.org/namePerson"
|
||||
yahooAttrs[1].required
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login/openid"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
}
|
||||
def yahooAttrs = consumer.attributesToFetchFactory.createAttributeList("https://rwinch.yahoo.com/rwinch/id")
|
||||
yahooAttrs[0].name == "email"
|
||||
yahooAttrs[0].type == "http://schema.openid.net/contact/email"
|
||||
yahooAttrs[0].required
|
||||
yahooAttrs[1].name == "fullname"
|
||||
yahooAttrs[1].type == "http://axschema.org/namePerson"
|
||||
yahooAttrs[1].required
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login/openid"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class OpenIDLoginAttributeExchangeConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
.attributeExchange("https://www.google.com/.*") // attribute-exchange@identifier-match
|
||||
.attribute("email") // openid-attribute@name
|
||||
.type("http://axschema.org/contact/email") // openid-attribute@type
|
||||
.required(true) // openid-attribute@required
|
||||
.count(1) // openid-attribute@count
|
||||
.and()
|
||||
.attribute("firstname")
|
||||
.type("http://axschema.org/namePerson/first")
|
||||
.required(true)
|
||||
.and()
|
||||
.attribute("lastname")
|
||||
.type("http://axschema.org/namePerson/last")
|
||||
.required(true)
|
||||
.and()
|
||||
.and()
|
||||
.attributeExchange(".*yahoo.com.*")
|
||||
.attribute("email")
|
||||
.type("http://schema.openid.net/contact/email")
|
||||
.required(true)
|
||||
.and()
|
||||
.attribute("fullname")
|
||||
.type("http://axschema.org/namePerson")
|
||||
.required(true)
|
||||
.and()
|
||||
.and()
|
||||
.permitAll();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class OpenIDLoginAttributeExchangeConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
.attributeExchange("https://www.google.com/.*") // attribute-exchange@identifier-match
|
||||
.attribute("email") // openid-attribute@name
|
||||
.type("http://axschema.org/contact/email") // openid-attribute@type
|
||||
.required(true) // openid-attribute@required
|
||||
.count(1) // openid-attribute@count
|
||||
.and()
|
||||
.attribute("firstname")
|
||||
.type("http://axschema.org/namePerson/first")
|
||||
.required(true)
|
||||
.and()
|
||||
.attribute("lastname")
|
||||
.type("http://axschema.org/namePerson/last")
|
||||
.required(true)
|
||||
.and()
|
||||
.and()
|
||||
.attributeExchange(".*yahoo.com.*")
|
||||
.attribute("email")
|
||||
.type("http://schema.openid.net/contact/email")
|
||||
.required(true)
|
||||
.and()
|
||||
.attribute("fullname")
|
||||
.type("http://axschema.org/namePerson")
|
||||
.required(true)
|
||||
.and()
|
||||
.and()
|
||||
.permitAll();
|
||||
}
|
||||
}
|
||||
|
||||
def "http/openid-login custom"() {
|
||||
setup:
|
||||
loadConfig(OpenIDLoginCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/authentication/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/authentication/login?failed"
|
||||
}
|
||||
def "http/openid-login custom"() {
|
||||
setup:
|
||||
loadConfig(OpenIDLoginCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/authentication/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/authentication/login?failed"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class OpenIDLoginCustomConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
boolean alwaysUseDefaultSuccess = true;
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
.permitAll()
|
||||
.loginPage("/authentication/login") // openid-login@login-page
|
||||
.failureUrl("/authentication/login?failed") // openid-login@authentication-failure-url
|
||||
.loginProcessingUrl("/authentication/login/process") // openid-login@login-processing-url
|
||||
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess) // openid-login@default-target-url / openid-login@always-use-default-target
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class OpenIDLoginCustomConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
boolean alwaysUseDefaultSuccess = true;
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
.permitAll()
|
||||
.loginPage("/authentication/login") // openid-login@login-page
|
||||
.failureUrl("/authentication/login?failed") // openid-login@authentication-failure-url
|
||||
.loginProcessingUrl("/authentication/login/process") // openid-login@login-processing-url
|
||||
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess) // openid-login@default-target-url / openid-login@always-use-default-target
|
||||
}
|
||||
}
|
||||
|
||||
def "http/openid-login custom refs"() {
|
||||
when:
|
||||
OpenIDLoginCustomRefsConfig.AUDS = Mock(AuthenticationUserDetailsService)
|
||||
loadConfig(OpenIDLoginCustomRefsConfig)
|
||||
then: "CustomWebAuthenticationDetailsSource is used"
|
||||
findFilter(OpenIDAuthenticationFilter).authenticationDetailsSource.class == CustomWebAuthenticationDetailsSource
|
||||
findAuthenticationProvider(OpenIDAuthenticationProvider).userDetailsService == OpenIDLoginCustomRefsConfig.AUDS
|
||||
when: "fail to log in"
|
||||
request.servletPath = "/login/openid"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/custom/failure"
|
||||
}
|
||||
def "http/openid-login custom refs"() {
|
||||
when:
|
||||
OpenIDLoginCustomRefsConfig.AUDS = Mock(AuthenticationUserDetailsService)
|
||||
loadConfig(OpenIDLoginCustomRefsConfig)
|
||||
then: "CustomWebAuthenticationDetailsSource is used"
|
||||
findFilter(OpenIDAuthenticationFilter).authenticationDetailsSource.class == CustomWebAuthenticationDetailsSource
|
||||
findAuthenticationProvider(OpenIDAuthenticationProvider).userDetailsService == OpenIDLoginCustomRefsConfig.AUDS
|
||||
when: "fail to log in"
|
||||
request.servletPath = "/login/openid"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/custom/failure"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class OpenIDLoginCustomRefsConfig extends BaseWebConfig {
|
||||
static AuthenticationUserDetailsService AUDS
|
||||
@Configuration
|
||||
static class OpenIDLoginCustomRefsConfig extends BaseWebConfig {
|
||||
static AuthenticationUserDetailsService AUDS
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
// if using UserDetailsService wrap with new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>()
|
||||
.authenticationUserDetailsService(AUDS) // openid-login@user-service-ref
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // openid-login@authentication-failure-handler-ref
|
||||
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler( defaultTargetUrl : "/custom/targetUrl" )) // openid-login@authentication-success-handler-ref
|
||||
.authenticationDetailsSource(new CustomWebAuthenticationDetailsSource()); // openid-login@authentication-details-source-ref
|
||||
}
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.openidLogin()
|
||||
// if using UserDetailsService wrap with new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>()
|
||||
.authenticationUserDetailsService(AUDS) // openid-login@user-service-ref
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // openid-login@authentication-failure-handler-ref
|
||||
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler( defaultTargetUrl : "/custom/targetUrl" )) // openid-login@authentication-success-handler-ref
|
||||
.authenticationDetailsSource(new CustomWebAuthenticationDetailsSource()); // openid-login@authentication-details-source-ref
|
||||
}
|
||||
|
||||
// only necessary to have easy access to the AuthenticationManager for testing/verification
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
// only necessary to have easy access to the AuthenticationManager for testing/verification
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
|
||||
static class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
|
||||
}
|
||||
|
||||
+68
-68
@@ -38,78 +38,78 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpPortMappingsTests extends BaseSpringSpec {
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest()
|
||||
request.setMethod("GET")
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest()
|
||||
request.setMethod("GET")
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
def "http/port-mapper works with http/intercept-url@requires-channel"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlWithPortMapperConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when:
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
request.setServerPort(9080);
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:9443/login"
|
||||
when:
|
||||
setup()
|
||||
request.setServletPath("/secured/a")
|
||||
request.setRequestURI("/secured/a")
|
||||
request.setServerPort(9080);
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:9443/secured/a"
|
||||
when:
|
||||
setup()
|
||||
request.setSecure(true)
|
||||
request.setScheme("https")
|
||||
request.setServerPort(9443);
|
||||
request.setServletPath("/user")
|
||||
request.setRequestURI("/user")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "http://localhost:9080/user"
|
||||
}
|
||||
def "http/port-mapper works with http/intercept-url@requires-channel"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlWithPortMapperConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when:
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
request.setServerPort(9080);
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:9443/login"
|
||||
when:
|
||||
setup()
|
||||
request.setServletPath("/secured/a")
|
||||
request.setRequestURI("/secured/a")
|
||||
request.setServerPort(9080);
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:9443/secured/a"
|
||||
when:
|
||||
setup()
|
||||
request.setSecure(true)
|
||||
request.setScheme("https")
|
||||
request.setServerPort(9443);
|
||||
request.setServletPath("/user")
|
||||
request.setRequestURI("/user")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "http://localhost:9080/user"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlWithPortMapperConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlWithPortMapperConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.portMapper()
|
||||
.http(9080).mapsTo(9443)
|
||||
.and()
|
||||
.requiresChannel()
|
||||
.antMatchers("/login","/secured/**").requiresSecure()
|
||||
.anyRequest().requiresInsecure()
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.portMapper()
|
||||
.http(9080).mapsTo(9443)
|
||||
.and()
|
||||
.requiresChannel()
|
||||
.antMatchers("/login","/secured/**").requiresSecure()
|
||||
.anyRequest().requiresInsecure()
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN")
|
||||
}
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN")
|
||||
}
|
||||
}
|
||||
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)
|
||||
repo.saveContext(new SecurityContextImpl(authentication: new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role))), requestResponseHolder.request, requestResponseHolder.response)
|
||||
}
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)
|
||||
repo.saveContext(new SecurityContextImpl(authentication: new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role))), requestResponseHolder.request, requestResponseHolder.response)
|
||||
}
|
||||
}
|
||||
|
||||
+28
-28
@@ -39,35 +39,35 @@ import org.springframework.security.web.savedrequest.RequestCache;
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpRequestCacheTests extends BaseSpringSpec {
|
||||
def "http/request-cache@ref"() {
|
||||
setup:
|
||||
RequestCacheRefConfig.REQUEST_CACHE = Mock(RequestCache)
|
||||
when:
|
||||
loadConfig(RequestCacheRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).requestCache == RequestCacheRefConfig.REQUEST_CACHE
|
||||
}
|
||||
def "http/request-cache@ref"() {
|
||||
setup:
|
||||
RequestCacheRefConfig.REQUEST_CACHE = Mock(RequestCache)
|
||||
when:
|
||||
loadConfig(RequestCacheRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).requestCache == RequestCacheRefConfig.REQUEST_CACHE
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RequestCacheRefConfig extends BaseWebConfig {
|
||||
static RequestCache REQUEST_CACHE
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.
|
||||
requestCache()
|
||||
.requestCache(REQUEST_CACHE)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RequestCacheRefConfig extends BaseWebConfig {
|
||||
static RequestCache REQUEST_CACHE
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.
|
||||
requestCache()
|
||||
.requestCache(REQUEST_CACHE)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/request-cache@ref defaults to HttpSessionRequestCache"() {
|
||||
when:
|
||||
loadConfig(DefaultRequestCacheRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).requestCache.class == HttpSessionRequestCache
|
||||
}
|
||||
def "http/request-cache@ref defaults to HttpSessionRequestCache"() {
|
||||
when:
|
||||
loadConfig(DefaultRequestCacheRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).requestCache.class == HttpSessionRequestCache
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultRequestCacheRefConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultRequestCacheRefConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+174
-174
@@ -55,201 +55,201 @@ import org.springframework.test.util.ReflectionTestUtils
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpX509Tests extends BaseSpringSpec {
|
||||
def "http/x509 can authenticate"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rod.cer")
|
||||
loadConfig(X509Config)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'rod'
|
||||
}
|
||||
def "http/x509 can authenticate"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rod.cer")
|
||||
loadConfig(X509Config)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'rod'
|
||||
}
|
||||
|
||||
def "http/x509"() {
|
||||
when:
|
||||
loadConfig(X509Config)
|
||||
X509AuthenticationFilter filter = findFilter(X509AuthenticationFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == WebAuthenticationDetailsSource
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == UserDetailsByNameServiceWrapper
|
||||
}
|
||||
def "http/x509"() {
|
||||
when:
|
||||
loadConfig(X509Config)
|
||||
X509AuthenticationFilter filter = findFilter(X509AuthenticationFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == WebAuthenticationDetailsSource
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == UserDetailsByNameServiceWrapper
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class X509Config extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
@EnableWebSecurity
|
||||
public static class X509Config extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509();
|
||||
}
|
||||
}
|
||||
|
||||
def "http/x509@authentication-details-source-ref"() {
|
||||
setup:
|
||||
AuthenticationDetailsSourceRefConfig.AUTHENTICATION_DETAILS_SOURCE = Mock(AuthenticationDetailsSource)
|
||||
when:
|
||||
loadConfig(AuthenticationDetailsSourceRefConfig)
|
||||
X509AuthenticationFilter filter = findFilter(X509AuthenticationFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource == AuthenticationDetailsSourceRefConfig.AUTHENTICATION_DETAILS_SOURCE
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == UserDetailsByNameServiceWrapper
|
||||
}
|
||||
def "http/x509@authentication-details-source-ref"() {
|
||||
setup:
|
||||
AuthenticationDetailsSourceRefConfig.AUTHENTICATION_DETAILS_SOURCE = Mock(AuthenticationDetailsSource)
|
||||
when:
|
||||
loadConfig(AuthenticationDetailsSourceRefConfig)
|
||||
X509AuthenticationFilter filter = findFilter(X509AuthenticationFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource == AuthenticationDetailsSourceRefConfig.AUTHENTICATION_DETAILS_SOURCE
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == UserDetailsByNameServiceWrapper
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class AuthenticationDetailsSourceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> AUTHENTICATION_DETAILS_SOURCE
|
||||
@EnableWebSecurity
|
||||
public static class AuthenticationDetailsSourceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> AUTHENTICATION_DETAILS_SOURCE
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.authenticationDetailsSource(AUTHENTICATION_DETAILS_SOURCE);
|
||||
}
|
||||
}
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.authenticationDetailsSource(AUTHENTICATION_DETAILS_SOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
def "http/x509@subject-principal-regex"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
|
||||
loadConfig(SubjectPrincipalRegexConfig)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'rod'
|
||||
}
|
||||
def "http/x509@subject-principal-regex"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
|
||||
loadConfig(SubjectPrincipalRegexConfig)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'rod'
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class SubjectPrincipalRegexConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
@EnableWebSecurity
|
||||
public static class SubjectPrincipalRegexConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.subjectPrincipalRegex('CN=(.*?)@example.com(?:,|$)');
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.subjectPrincipalRegex('CN=(.*?)@example.com(?:,|$)');
|
||||
}
|
||||
}
|
||||
|
||||
def "http/x509@user-service-ref"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
|
||||
loadConfig(UserDetailsServiceRefConfig)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'customuser'
|
||||
}
|
||||
def "http/x509@user-service-ref"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
|
||||
loadConfig(UserDetailsServiceRefConfig)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'customuser'
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class UserDetailsServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
@EnableWebSecurity
|
||||
public static class UserDetailsServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.userDetailsService(new CustomUserDetailsService());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.userDetailsService(new CustomUserDetailsService());
|
||||
}
|
||||
}
|
||||
|
||||
def "http/x509 custom AuthenticationUserDetailsService"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
|
||||
loadConfig(AuthenticationUserDetailsServiceConfig)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'customuser'
|
||||
}
|
||||
def "http/x509 custom AuthenticationUserDetailsService"() {
|
||||
setup:
|
||||
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
|
||||
loadConfig(AuthenticationUserDetailsServiceConfig)
|
||||
when:
|
||||
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
then:
|
||||
response.status == 200
|
||||
authentication().name == 'customuser'
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class AuthenticationUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> AUTHENTICATION_DETAILS_SOURCE
|
||||
@EnableWebSecurity
|
||||
public static class AuthenticationUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> AUTHENTICATION_DETAILS_SOURCE
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.
|
||||
inMemoryAuthentication()
|
||||
.withUser("rod").password("password").roles("USER","ADMIN");
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.userDetailsService(new CustomUserDetailsService());
|
||||
}
|
||||
}
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.x509()
|
||||
.userDetailsService(new CustomUserDetailsService());
|
||||
}
|
||||
}
|
||||
|
||||
def loadCert(String location) {
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
certFactory.generateCertificate(Thread.currentThread().contextClassLoader.getResourceAsStream(location))
|
||||
}
|
||||
def loadCert(String location) {
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
certFactory.generateCertificate(Thread.currentThread().contextClassLoader.getResourceAsStream(location))
|
||||
}
|
||||
|
||||
static class CustomUserDetailsService implements UserDetailsService {
|
||||
static class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
public UserDetails loadUserByUsername(String username)
|
||||
throws UsernameNotFoundException {
|
||||
return new User("customuser", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
}
|
||||
public UserDetails loadUserByUsername(String username)
|
||||
throws UsernameNotFoundException {
|
||||
return new User("customuser", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomAuthenticationUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
||||
public UserDetails loadUserDetails(
|
||||
PreAuthenticatedAuthenticationToken token)
|
||||
throws UsernameNotFoundException {
|
||||
return new User("customuser", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
}
|
||||
}
|
||||
static class CustomAuthenticationUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
||||
public UserDetails loadUserDetails(
|
||||
PreAuthenticatedAuthenticationToken token)
|
||||
throws UsernameNotFoundException {
|
||||
return new User("customuser", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
}
|
||||
}
|
||||
|
||||
def authentication() {
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
new HttpSessionSecurityContextRepository().loadContext(requestResponseHolder)?.authentication
|
||||
}
|
||||
def authentication() {
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
new HttpSessionSecurityContextRepository().loadContext(requestResponseHolder)?.authentication
|
||||
}
|
||||
}
|
||||
|
||||
+296
-296
@@ -55,333 +55,333 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*/
|
||||
public class NamespaceRememberMeTests extends BaseSpringSpec {
|
||||
|
||||
def "http/remember-me"() {
|
||||
setup:
|
||||
loadConfig(RememberMeConfig)
|
||||
when: "login with remember me"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
Cookie rememberMeCookie = getRememberMeCookie()
|
||||
then: "response contains remember me cookie"
|
||||
rememberMeCookie != null
|
||||
when: "session expires"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
MockHttpSession session = request.getSession()
|
||||
then: "initialized to RememberMeAuthenticationToken"
|
||||
SecurityContext context = new HttpSessionSecurityContextRepository().loadContext(new HttpRequestResponseHolder(request, response))
|
||||
context.getAuthentication() instanceof RememberMeAuthenticationToken
|
||||
when: "logout"
|
||||
super.setup()
|
||||
request.setSession(session)
|
||||
super.setupCsrf()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
rememberMeCookie = getRememberMeCookie()
|
||||
then: "logout cookie expired"
|
||||
response.getRedirectedUrl() == "/login?logout"
|
||||
rememberMeCookie.maxAge == 0
|
||||
when: "use remember me after logout"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default login page"
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
}
|
||||
def "http/remember-me"() {
|
||||
setup:
|
||||
loadConfig(RememberMeConfig)
|
||||
when: "login with remember me"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
Cookie rememberMeCookie = getRememberMeCookie()
|
||||
then: "response contains remember me cookie"
|
||||
rememberMeCookie != null
|
||||
when: "session expires"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
MockHttpSession session = request.getSession()
|
||||
then: "initialized to RememberMeAuthenticationToken"
|
||||
SecurityContext context = new HttpSessionSecurityContextRepository().loadContext(new HttpRequestResponseHolder(request, response))
|
||||
context.getAuthentication() instanceof RememberMeAuthenticationToken
|
||||
when: "logout"
|
||||
super.setup()
|
||||
request.setSession(session)
|
||||
super.setupCsrf()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
rememberMeCookie = getRememberMeCookie()
|
||||
then: "logout cookie expired"
|
||||
response.getRedirectedUrl() == "/login?logout"
|
||||
rememberMeCookie.maxAge == 0
|
||||
when: "use remember me after logout"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default login page"
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RememberMeConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RememberMeConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@services-ref"() {
|
||||
setup:
|
||||
RememberMeServicesRefConfig.REMEMBER_ME_SERVICES = Mock(RememberMeServices)
|
||||
when: "use custom remember-me services"
|
||||
loadConfig(RememberMeServicesRefConfig)
|
||||
then: "custom remember-me services used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices == RememberMeServicesRefConfig.REMEMBER_ME_SERVICES
|
||||
findFilter(UsernamePasswordAuthenticationFilter).rememberMeServices == RememberMeServicesRefConfig.REMEMBER_ME_SERVICES
|
||||
}
|
||||
def "http/remember-me@services-ref"() {
|
||||
setup:
|
||||
RememberMeServicesRefConfig.REMEMBER_ME_SERVICES = Mock(RememberMeServices)
|
||||
when: "use custom remember-me services"
|
||||
loadConfig(RememberMeServicesRefConfig)
|
||||
then: "custom remember-me services used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices == RememberMeServicesRefConfig.REMEMBER_ME_SERVICES
|
||||
findFilter(UsernamePasswordAuthenticationFilter).rememberMeServices == RememberMeServicesRefConfig.REMEMBER_ME_SERVICES
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RememberMeServicesRefConfig extends BaseWebConfig {
|
||||
static RememberMeServices REMEMBER_ME_SERVICES
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeServices(REMEMBER_ME_SERVICES)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RememberMeServicesRefConfig extends BaseWebConfig {
|
||||
static RememberMeServices REMEMBER_ME_SERVICES
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeServices(REMEMBER_ME_SERVICES)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@authentication-success-handler-ref"() {
|
||||
setup:
|
||||
AuthSuccessConfig.SUCCESS_HANDLER = Mock(AuthenticationSuccessHandler)
|
||||
when: "use custom success handler"
|
||||
loadConfig(AuthSuccessConfig)
|
||||
then: "custom remember-me success handler is used"
|
||||
findFilter(RememberMeAuthenticationFilter).successHandler == AuthSuccessConfig.SUCCESS_HANDLER
|
||||
}
|
||||
def "http/remember-me@authentication-success-handler-ref"() {
|
||||
setup:
|
||||
AuthSuccessConfig.SUCCESS_HANDLER = Mock(AuthenticationSuccessHandler)
|
||||
when: "use custom success handler"
|
||||
loadConfig(AuthSuccessConfig)
|
||||
then: "custom remember-me success handler is used"
|
||||
findFilter(RememberMeAuthenticationFilter).successHandler == AuthSuccessConfig.SUCCESS_HANDLER
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AuthSuccessConfig extends BaseWebConfig {
|
||||
static AuthenticationSuccessHandler SUCCESS_HANDLER
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.authenticationSuccessHandler(SUCCESS_HANDLER)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class AuthSuccessConfig extends BaseWebConfig {
|
||||
static AuthenticationSuccessHandler SUCCESS_HANDLER
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.authenticationSuccessHandler(SUCCESS_HANDLER)
|
||||
}
|
||||
}
|
||||
|
||||
// http/remember-me@data-source-ref is not supported directly. Instead use http/remember-me@token-repository-ref example
|
||||
// http/remember-me@data-source-ref is not supported directly. Instead use http/remember-me@token-repository-ref example
|
||||
|
||||
def "http/remember-me@key"() {
|
||||
when: "use custom key"
|
||||
loadConfig(KeyConfig)
|
||||
AuthenticationManager authManager = context.getBean(AuthenticationManager)
|
||||
then: "custom key services used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.key == "KeyConfig"
|
||||
authManager.authenticate(new RememberMeAuthenticationToken("KeyConfig", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
}
|
||||
def "http/remember-me@key"() {
|
||||
when: "use custom key"
|
||||
loadConfig(KeyConfig)
|
||||
AuthenticationManager authManager = context.getBean(AuthenticationManager)
|
||||
then: "custom key services used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.key == "KeyConfig"
|
||||
authManager.authenticate(new RememberMeAuthenticationToken("KeyConfig", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class KeyConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.key("KeyConfig")
|
||||
}
|
||||
@Configuration
|
||||
static class KeyConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.key("KeyConfig")
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
// http/remember-me@services-alias is not supported use standard aliasing instead (i.e. @Bean("alias"))
|
||||
// http/remember-me@services-alias is not supported use standard aliasing instead (i.e. @Bean("alias"))
|
||||
|
||||
def "http/remember-me@token-repository-ref"() {
|
||||
setup:
|
||||
TokenRepositoryRefConfig.TOKEN_REPOSITORY = Mock(PersistentTokenRepository)
|
||||
when: "use custom token services"
|
||||
loadConfig(TokenRepositoryRefConfig)
|
||||
then: "custom token services used with PersistentTokenBasedRememberMeServices"
|
||||
PersistentTokenBasedRememberMeServices rememberMeServices = findFilter(RememberMeAuthenticationFilter).rememberMeServices
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenRepository == TokenRepositoryRefConfig.TOKEN_REPOSITORY
|
||||
}
|
||||
def "http/remember-me@token-repository-ref"() {
|
||||
setup:
|
||||
TokenRepositoryRefConfig.TOKEN_REPOSITORY = Mock(PersistentTokenRepository)
|
||||
when: "use custom token services"
|
||||
loadConfig(TokenRepositoryRefConfig)
|
||||
then: "custom token services used with PersistentTokenBasedRememberMeServices"
|
||||
PersistentTokenBasedRememberMeServices rememberMeServices = findFilter(RememberMeAuthenticationFilter).rememberMeServices
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenRepository == TokenRepositoryRefConfig.TOKEN_REPOSITORY
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TokenRepositoryRefConfig extends BaseWebConfig {
|
||||
static PersistentTokenRepository TOKEN_REPOSITORY
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl()
|
||||
// tokenRepository.setDataSource(dataSource);
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.tokenRepository(TOKEN_REPOSITORY)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class TokenRepositoryRefConfig extends BaseWebConfig {
|
||||
static PersistentTokenRepository TOKEN_REPOSITORY
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl()
|
||||
// tokenRepository.setDataSource(dataSource);
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.tokenRepository(TOKEN_REPOSITORY)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@token-validity-seconds"() {
|
||||
when: "use token validity"
|
||||
loadConfig(TokenValiditySecondsConfig)
|
||||
then: "custom token validity used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenValiditySeconds == 1
|
||||
}
|
||||
def "http/remember-me@token-validity-seconds"() {
|
||||
when: "use token validity"
|
||||
loadConfig(TokenValiditySecondsConfig)
|
||||
then: "custom token validity used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenValiditySeconds == 1
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TokenValiditySecondsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.tokenValiditySeconds(1)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class TokenValiditySecondsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.tokenValiditySeconds(1)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@token-validity-seconds default"() {
|
||||
when: "use token validity"
|
||||
loadConfig(DefaultTokenValiditySecondsConfig)
|
||||
then: "custom token validity used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenValiditySeconds == AbstractRememberMeServices.TWO_WEEKS_S
|
||||
}
|
||||
def "http/remember-me@token-validity-seconds default"() {
|
||||
when: "use token validity"
|
||||
loadConfig(DefaultTokenValiditySecondsConfig)
|
||||
then: "custom token validity used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenValiditySeconds == AbstractRememberMeServices.TWO_WEEKS_S
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultTokenValiditySecondsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultTokenValiditySecondsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@use-secure-cookie"() {
|
||||
when: "use secure cookies = true"
|
||||
loadConfig(UseSecureCookieConfig)
|
||||
then: "secure cookies will be used"
|
||||
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "useSecureCookie") == true
|
||||
}
|
||||
def "http/remember-me@use-secure-cookie"() {
|
||||
when: "use secure cookies = true"
|
||||
loadConfig(UseSecureCookieConfig)
|
||||
then: "secure cookies will be used"
|
||||
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "useSecureCookie") == true
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UseSecureCookieConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.useSecureCookie(true)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class UseSecureCookieConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.useSecureCookie(true)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@remember-me-parameter"() {
|
||||
when: "use custom rememberMeParameter"
|
||||
loadConfig(RememberMeParameterConfig)
|
||||
then: "custom rememberMeParameter will be used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.parameter == "rememberMe"
|
||||
}
|
||||
def "http/remember-me@remember-me-parameter"() {
|
||||
when: "use custom rememberMeParameter"
|
||||
loadConfig(RememberMeParameterConfig)
|
||||
then: "custom rememberMeParameter will be used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.parameter == "rememberMe"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RememberMeParameterConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeParameter("rememberMe")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RememberMeParameterConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeParameter("rememberMe")
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-2880
|
||||
def "http/remember-me@remember-me-cookie"() {
|
||||
when: "use custom rememberMeCookieName"
|
||||
loadConfig(RememberMeCookieNameConfig)
|
||||
then: "custom rememberMeCookieName will be used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.cookieName == "rememberMe"
|
||||
}
|
||||
// SEC-2880
|
||||
def "http/remember-me@remember-me-cookie"() {
|
||||
when: "use custom rememberMeCookieName"
|
||||
loadConfig(RememberMeCookieNameConfig)
|
||||
then: "custom rememberMeCookieName will be used"
|
||||
findFilter(RememberMeAuthenticationFilter).rememberMeServices.cookieName == "rememberMe"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RememberMeCookieNameConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeCookieName("rememberMe")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RememberMeCookieNameConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeCookieName("rememberMe")
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@use-secure-cookie defaults"() {
|
||||
when: "use secure cookies not specified"
|
||||
loadConfig(DefaultUseSecureCookieConfig)
|
||||
then: "secure cookies will be null (use secure if the request is secure)"
|
||||
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "useSecureCookie") == null
|
||||
}
|
||||
def "http/remember-me@use-secure-cookie defaults"() {
|
||||
when: "use secure cookies not specified"
|
||||
loadConfig(DefaultUseSecureCookieConfig)
|
||||
then: "secure cookies will be null (use secure if the request is secure)"
|
||||
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "useSecureCookie") == null
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultUseSecureCookieConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class DefaultUseSecureCookieConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me defaults UserDetailsService with custom UserDetailsService"() {
|
||||
setup:
|
||||
DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE = Mock(UserDetailsService)
|
||||
loadConfig(DefaultsUserDetailsServiceWithDaoConfig)
|
||||
when:
|
||||
request.setCookies(createRememberMeCookie())
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "RememberMeServices defaults to the custom UserDetailsService"
|
||||
1 * DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE.loadUserByUsername("user")
|
||||
}
|
||||
def "http/remember-me defaults UserDetailsService with custom UserDetailsService"() {
|
||||
setup:
|
||||
DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE = Mock(UserDetailsService)
|
||||
loadConfig(DefaultsUserDetailsServiceWithDaoConfig)
|
||||
when:
|
||||
request.setCookies(createRememberMeCookie())
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "RememberMeServices defaults to the custom UserDetailsService"
|
||||
1 * DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE.loadUserByUsername("user")
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultsUserDetailsServiceWithDaoConfig extends WebSecurityConfigurerAdapter {
|
||||
static UserDetailsService USERDETAILS_SERVICE
|
||||
@EnableWebSecurity
|
||||
static class DefaultsUserDetailsServiceWithDaoConfig extends WebSecurityConfigurerAdapter {
|
||||
static UserDetailsService USERDETAILS_SERVICE
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.userDetailsService(USERDETAILS_SERVICE);
|
||||
}
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.userDetailsService(USERDETAILS_SERVICE);
|
||||
}
|
||||
}
|
||||
|
||||
def "http/remember-me@user-service-ref"() {
|
||||
setup:
|
||||
UserServiceRefConfig.USERDETAILS_SERVICE = Mock(UserDetailsService)
|
||||
when: "use custom UserDetailsService"
|
||||
loadConfig(UserServiceRefConfig)
|
||||
then: "custom UserDetailsService is used"
|
||||
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "userDetailsService") == UserServiceRefConfig.USERDETAILS_SERVICE
|
||||
}
|
||||
def "http/remember-me@user-service-ref"() {
|
||||
setup:
|
||||
UserServiceRefConfig.USERDETAILS_SERVICE = Mock(UserDetailsService)
|
||||
when: "use custom UserDetailsService"
|
||||
loadConfig(UserServiceRefConfig)
|
||||
then: "custom UserDetailsService is used"
|
||||
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "userDetailsService") == UserServiceRefConfig.USERDETAILS_SERVICE
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserServiceRefConfig extends BaseWebConfig {
|
||||
static UserDetailsService USERDETAILS_SERVICE
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.userDetailsService(USERDETAILS_SERVICE)
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class UserServiceRefConfig extends BaseWebConfig {
|
||||
static UserDetailsService USERDETAILS_SERVICE
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.userDetailsService(USERDETAILS_SERVICE)
|
||||
}
|
||||
}
|
||||
|
||||
Cookie createRememberMeCookie() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
super.setupCsrf("CSRF_TOKEN", request, response)
|
||||
Cookie createRememberMeCookie() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
super.setupCsrf("CSRF_TOKEN", request, response)
|
||||
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
response.getCookie("remember-me")
|
||||
}
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
response.getCookie("remember-me")
|
||||
}
|
||||
|
||||
Cookie getRememberMeCookie(String cookieName="remember-me") {
|
||||
response.getCookie(cookieName)
|
||||
}
|
||||
Cookie getRememberMeCookie(String cookieName="remember-me") {
|
||||
response.getCookie(cookieName)
|
||||
}
|
||||
}
|
||||
|
||||
+31
-31
@@ -30,40 +30,40 @@ import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
*
|
||||
*/
|
||||
class PermitAllSupportTests extends BaseSpringSpec {
|
||||
def "PermitAllSupport.ExactUrlRequestMatcher"() {
|
||||
expect:
|
||||
RequestMatcher matcher = new PermitAllSupport.ExactUrlRequestMatcher(processUrl)
|
||||
matcher.matches(new MockHttpServletRequest(requestURI:requestURI,contextPath:contextPath,queryString: query)) == matches
|
||||
where:
|
||||
processUrl | requestURI | contextPath | query | matches
|
||||
"/login" | "/sample/login" | "/sample" | null | true
|
||||
"/login" | "/sample/login" | "/sample" | "error" | false
|
||||
"/login?error" | "/sample/login" | "/sample" | "error" | true
|
||||
}
|
||||
def "PermitAllSupport.ExactUrlRequestMatcher"() {
|
||||
expect:
|
||||
RequestMatcher matcher = new PermitAllSupport.ExactUrlRequestMatcher(processUrl)
|
||||
matcher.matches(new MockHttpServletRequest(requestURI:requestURI,contextPath:contextPath,queryString: query)) == matches
|
||||
where:
|
||||
processUrl | requestURI | contextPath | query | matches
|
||||
"/login" | "/sample/login" | "/sample" | null | true
|
||||
"/login" | "/sample/login" | "/sample" | "error" | false
|
||||
"/login?error" | "/sample/login" | "/sample" | "error" | true
|
||||
}
|
||||
|
||||
def "PermitAllSupport throws Exception when authorizedUrls() not invoked"() {
|
||||
when:
|
||||
loadConfig(NoAuthorizedUrlsConfig)
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.message.contains "permitAll only works with HttpSecurity.authorizeRequests"
|
||||
def "PermitAllSupport throws Exception when authorizedUrls() not invoked"() {
|
||||
when:
|
||||
loadConfig(NoAuthorizedUrlsConfig)
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.message.contains "permitAll only works with HttpSecurity.authorizeRequests"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NoAuthorizedUrlsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class NoAuthorizedUrlsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.permitAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-23
@@ -36,28 +36,28 @@ import org.springframework.security.web.session.SessionManagementFilter
|
||||
*/
|
||||
class PortMapperConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "invoke portMapper twice does not override"() {
|
||||
setup:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
request.setServerPort(543)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:123"
|
||||
}
|
||||
def "invoke portMapper twice does not override"() {
|
||||
setup:
|
||||
loadConfig(InvokeTwiceDoesNotOverride)
|
||||
request.setServerPort(543)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:123"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requiresChannel()
|
||||
.anyRequest().requiresSecure()
|
||||
.and()
|
||||
.portMapper()
|
||||
.http(543).mapsTo(123)
|
||||
.and()
|
||||
.portMapper()
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requiresChannel()
|
||||
.anyRequest().requiresSecure()
|
||||
.and()
|
||||
.portMapper()
|
||||
.http(543).mapsTo(123)
|
||||
.and()
|
||||
.portMapper()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+135
-135
@@ -48,151 +48,151 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
|
||||
*/
|
||||
public class RememberMeConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "rememberMe() null UserDetailsService provides meaningful error"() {
|
||||
setup: "Load Config without UserDetailsService specified"
|
||||
loadConfig(NullUserDetailsConfig)
|
||||
when:
|
||||
request.setCookies(createRememberMeCookie())
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "A good error message is provided"
|
||||
Exception success = thrown()
|
||||
success.message.contains "UserDetailsService is required"
|
||||
}
|
||||
def "rememberMe() null UserDetailsService provides meaningful error"() {
|
||||
setup: "Load Config without UserDetailsService specified"
|
||||
loadConfig(NullUserDetailsConfig)
|
||||
when:
|
||||
request.setCookies(createRememberMeCookie())
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: "A good error message is provided"
|
||||
Exception success = thrown()
|
||||
success.message.contains "UserDetailsService is required"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NullUserDetailsConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class NullUserDetailsConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
User user = new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
|
||||
provider.userDetailsService = new InMemoryUserDetailsManager([user])
|
||||
auth
|
||||
.authenticationProvider(provider)
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
User user = new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
|
||||
provider.userDetailsService = new InMemoryUserDetailsManager([user])
|
||||
auth
|
||||
.authenticationProvider(provider)
|
||||
}
|
||||
}
|
||||
|
||||
def "rememberMe ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
|
||||
when:
|
||||
http
|
||||
.rememberMe()
|
||||
.userDetailsService(authenticationBldr.getDefaultUserDetailsService())
|
||||
.and()
|
||||
.build()
|
||||
def "rememberMe ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
|
||||
when:
|
||||
http
|
||||
.rememberMe()
|
||||
.userDetailsService(authenticationBldr.getDefaultUserDetailsService())
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "RememberMeAuthenticationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as RememberMeAuthenticationFilter) >> {RememberMeAuthenticationFilter o -> o}
|
||||
}
|
||||
then: "RememberMeAuthenticationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as RememberMeAuthenticationFilter) >> {RememberMeAuthenticationFilter o -> o}
|
||||
}
|
||||
|
||||
def "invoke rememberMe twice does not reset"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
|
||||
when:
|
||||
http
|
||||
.rememberMe()
|
||||
.userDetailsService(authenticationBldr.getDefaultUserDetailsService())
|
||||
.and()
|
||||
.rememberMe()
|
||||
then: "RememberMeAuthenticationFilter is registered with LifecycleManager"
|
||||
http.getConfigurer(RememberMeConfigurer).userDetailsService != null
|
||||
}
|
||||
def "invoke rememberMe twice does not reset"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
|
||||
when:
|
||||
http
|
||||
.rememberMe()
|
||||
.userDetailsService(authenticationBldr.getDefaultUserDetailsService())
|
||||
.and()
|
||||
.rememberMe()
|
||||
then: "RememberMeAuthenticationFilter is registered with LifecycleManager"
|
||||
http.getConfigurer(RememberMeConfigurer).userDetailsService != null
|
||||
}
|
||||
|
||||
|
||||
def "http/remember-me with Global AuthenticationManagerBuilder"() {
|
||||
setup:
|
||||
loadConfig(RememberMeConfig)
|
||||
when: "login with remember me"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
Cookie rememberMeCookie = getRememberMeCookie()
|
||||
then: "response contains remember me cookie"
|
||||
rememberMeCookie != null
|
||||
when: "session expires"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
MockHttpSession session = request.getSession()
|
||||
then: "initialized to RememberMeAuthenticationToken"
|
||||
SecurityContext context = new HttpSessionSecurityContextRepository().loadContext(new HttpRequestResponseHolder(request, response))
|
||||
context.getAuthentication() instanceof RememberMeAuthenticationToken
|
||||
when: "logout"
|
||||
super.setup()
|
||||
request.setSession(session)
|
||||
super.setupCsrf()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
rememberMeCookie = getRememberMeCookie()
|
||||
then: "logout cookie expired"
|
||||
response.getRedirectedUrl() == "/login?logout"
|
||||
rememberMeCookie.maxAge == 0
|
||||
when: "use remember me after logout"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default login page"
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
}
|
||||
def "http/remember-me with Global AuthenticationManagerBuilder"() {
|
||||
setup:
|
||||
loadConfig(RememberMeConfig)
|
||||
when: "login with remember me"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
Cookie rememberMeCookie = getRememberMeCookie()
|
||||
then: "response contains remember me cookie"
|
||||
rememberMeCookie != null
|
||||
when: "session expires"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
MockHttpSession session = request.getSession()
|
||||
then: "initialized to RememberMeAuthenticationToken"
|
||||
SecurityContext context = new HttpSessionSecurityContextRepository().loadContext(new HttpRequestResponseHolder(request, response))
|
||||
context.getAuthentication() instanceof RememberMeAuthenticationToken
|
||||
when: "logout"
|
||||
super.setup()
|
||||
request.setSession(session)
|
||||
super.setupCsrf()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.servletPath = "/logout"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
rememberMeCookie = getRememberMeCookie()
|
||||
then: "logout cookie expired"
|
||||
response.getRedirectedUrl() == "/login?logout"
|
||||
rememberMeCookie.maxAge == 0
|
||||
when: "use remember me after logout"
|
||||
super.setup()
|
||||
request.setCookies(rememberMeCookie)
|
||||
request.requestURI = "/abc"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default login page"
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RememberMeConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class RememberMeConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
}
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
}
|
||||
|
||||
Cookie createRememberMeCookie() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
super.setupCsrf("CSRF_TOKEN", request, response)
|
||||
Cookie createRememberMeCookie() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
super.setupCsrf("CSRF_TOKEN", request, response)
|
||||
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
response.getCookie("remember-me")
|
||||
}
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
request.parameters.'remember-me' = ["true"] as String[]
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
response.getCookie("remember-me")
|
||||
}
|
||||
|
||||
Cookie getRememberMeCookie(String cookieName="remember-me") {
|
||||
response.getCookie(cookieName)
|
||||
}
|
||||
Cookie getRememberMeCookie(String cookieName="remember-me") {
|
||||
response.getCookie(cookieName)
|
||||
}
|
||||
}
|
||||
|
||||
+134
-134
@@ -36,149 +36,149 @@ import spock.lang.Unroll;
|
||||
*/
|
||||
class RequestCacheConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "requestCache ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.requestCache()
|
||||
.and()
|
||||
.build()
|
||||
def "requestCache ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.requestCache()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "RequestCacheAwareFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as RequestCacheAwareFilter) >> {RequestCacheAwareFilter o -> o}
|
||||
}
|
||||
then: "RequestCacheAwareFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as RequestCacheAwareFilter) >> {RequestCacheAwareFilter o -> o}
|
||||
}
|
||||
|
||||
def "invoke requestCache twice does not reset"() {
|
||||
setup:
|
||||
RequestCache RC = Mock()
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.requestCache()
|
||||
.requestCache(RC)
|
||||
.and()
|
||||
.requestCache()
|
||||
def "invoke requestCache twice does not reset"() {
|
||||
setup:
|
||||
RequestCache RC = Mock()
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.requestCache()
|
||||
.requestCache(RC)
|
||||
.and()
|
||||
.requestCache()
|
||||
|
||||
then:
|
||||
http.getSharedObject(RequestCache) == RC
|
||||
}
|
||||
then:
|
||||
http.getSharedObject(RequestCache) == RC
|
||||
}
|
||||
|
||||
def "RequestCache disables faviocon.ico"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.servletPath = "/favicon.ico"
|
||||
request.requestURI = "/favicon.ico"
|
||||
request.method = "GET"
|
||||
when: "request favicon.ico"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
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 URL since it was favicon.ico"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
def "RequestCache disables faviocon.ico"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.servletPath = "/favicon.ico"
|
||||
request.requestURI = "/favicon.ico"
|
||||
request.method = "GET"
|
||||
when: "request favicon.ico"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
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 URL since it was favicon.ico"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
|
||||
def "SEC-2321: RequestCache disables application/json"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.addHeader("Accept", MediaType.APPLICATION_JSON_VALUE)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/messages"
|
||||
request.requestURI = "/messages"
|
||||
when: "request application/json"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
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 URL since it was application/json. This is desirable since JSON requests are typically not invoked directly from the browser and we don't want the browser to replay them"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
def "SEC-2321: RequestCache disables application/json"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.addHeader("Accept", MediaType.APPLICATION_JSON_VALUE)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/messages"
|
||||
request.requestURI = "/messages"
|
||||
when: "request application/json"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
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 URL since it was application/json. This is desirable since JSON requests are typically not invoked directly from the browser and we don't want the browser to replay them"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
|
||||
def "SEC-2321: RequestCache disables X-Requested-With"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.addHeader("X-Requested-With", "XMLHttpRequest")
|
||||
request.method = "GET"
|
||||
request.servletPath = "/messages"
|
||||
request.requestURI = "/messages"
|
||||
when: "request X-Requested-With"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
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 URL since it was X-Requested-With"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
def "SEC-2321: RequestCache disables X-Requested-With"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.addHeader("X-Requested-With", "XMLHttpRequest")
|
||||
request.method = "GET"
|
||||
request.servletPath = "/messages"
|
||||
request.requestURI = "/messages"
|
||||
when: "request X-Requested-With"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
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 URL since it was X-Requested-With"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "RequestCache saves #headerName: #headerValue"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.addHeader(headerName, headerValue)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/messages"
|
||||
request.requestURI = "/messages"
|
||||
when: "request content type"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
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 saved URL"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/messages"
|
||||
where:
|
||||
headerName << ["Accept", "Accept", "Accept", "X-Requested-With"]
|
||||
headerValue << [MediaType.ALL_VALUE, MediaType.TEXT_HTML, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","com.android"]
|
||||
@Unroll
|
||||
def "RequestCache saves #headerName: #headerValue"() {
|
||||
setup:
|
||||
loadConfig(RequestCacheDefautlsConfig)
|
||||
request.addHeader(headerName, headerValue)
|
||||
request.method = "GET"
|
||||
request.servletPath = "/messages"
|
||||
request.requestURI = "/messages"
|
||||
when: "request content type"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
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 saved URL"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/messages"
|
||||
where:
|
||||
headerName << ["Accept", "Accept", "Accept", "X-Requested-With"]
|
||||
headerValue << [MediaType.ALL_VALUE, MediaType.TEXT_HTML, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","com.android"]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RequestCacheDefautlsConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class RequestCacheDefautlsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-28
@@ -51,34 +51,34 @@ import spock.lang.Unroll;
|
||||
class RequestMatcherConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
|
||||
@Unroll
|
||||
def "SEC-2908 - multiple invocations of authorizeRequests() chains #path"(def path) {
|
||||
setup:
|
||||
loadConfig(Sec2908Config)
|
||||
request.servletPath = path
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
where:
|
||||
path << ['/oauth/abc','/api/abc']
|
||||
}
|
||||
@Unroll
|
||||
def "SEC-2908 - multiple invocations of authorizeRequests() chains #path"(def path) {
|
||||
setup:
|
||||
loadConfig(Sec2908Config)
|
||||
request.servletPath = path
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
where:
|
||||
path << ['/oauth/abc','/api/abc']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class Sec2908Config extends WebSecurityConfigurerAdapter {
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class Sec2908Config extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requestMatchers()
|
||||
.antMatchers("/api/**")
|
||||
.and()
|
||||
.requestMatchers()
|
||||
.antMatchers("/oauth/**")
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requestMatchers()
|
||||
.antMatchers("/api/**")
|
||||
.and()
|
||||
.requestMatchers()
|
||||
.antMatchers("/oauth/**")
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+32
-32
@@ -31,40 +31,40 @@ import org.springframework.security.web.context.SecurityContextRepository
|
||||
*/
|
||||
class SecurityContextConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "securityContext ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.securityContext()
|
||||
.and()
|
||||
.build()
|
||||
def "securityContext ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.securityContext()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "SecurityContextPersistenceFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as SecurityContextPersistenceFilter) >> {SecurityContextPersistenceFilter o -> o}
|
||||
}
|
||||
then: "SecurityContextPersistenceFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as SecurityContextPersistenceFilter) >> {SecurityContextPersistenceFilter o -> o}
|
||||
}
|
||||
|
||||
def "invoke securityContext twice does not override"() {
|
||||
setup:
|
||||
InvokeTwiceDoesNotOverrideConfig.SCR = Mock(SecurityContextRepository)
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(SecurityContextPersistenceFilter).repo == InvokeTwiceDoesNotOverrideConfig.SCR
|
||||
}
|
||||
def "invoke securityContext twice does not override"() {
|
||||
setup:
|
||||
InvokeTwiceDoesNotOverrideConfig.SCR = Mock(SecurityContextRepository)
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(SecurityContextPersistenceFilter).repo == InvokeTwiceDoesNotOverrideConfig.SCR
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static SecurityContextRepository SCR
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static SecurityContextRepository SCR
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.securityContext()
|
||||
.securityContextRepository(SCR)
|
||||
.and()
|
||||
.securityContext()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.securityContext()
|
||||
.securityContextRepository(SCR)
|
||||
.and()
|
||||
.securityContext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+98
-98
@@ -36,116 +36,116 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
|
||||
*/
|
||||
class ServletApiConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "servletApi ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.servletApi()
|
||||
.and()
|
||||
.build()
|
||||
def "servletApi ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.servletApi()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "SecurityContextHolderAwareRequestFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as SecurityContextHolderAwareRequestFilter) >> {SecurityContextHolderAwareRequestFilter o -> o}
|
||||
}
|
||||
then: "SecurityContextHolderAwareRequestFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as SecurityContextHolderAwareRequestFilter) >> {SecurityContextHolderAwareRequestFilter o -> o}
|
||||
}
|
||||
|
||||
def "SecurityContextHolderAwareRequestFilter properties set"() {
|
||||
when:
|
||||
loadConfig(ServletApiConfig)
|
||||
SecurityContextHolderAwareRequestFilter filter = findFilter(SecurityContextHolderAwareRequestFilter)
|
||||
then: "SEC-2215: authenticationManager != null"
|
||||
filter.authenticationManager != null
|
||||
and: "authenticationEntryPoint != null"
|
||||
filter.authenticationEntryPoint != null
|
||||
and: "requestFactory != null"
|
||||
filter.requestFactory != null
|
||||
and: "logoutHandlers populated"
|
||||
filter.logoutHandlers.collect { it.class } == [CsrfLogoutHandler, SecurityContextLogoutHandler]
|
||||
}
|
||||
def "SecurityContextHolderAwareRequestFilter properties set"() {
|
||||
when:
|
||||
loadConfig(ServletApiConfig)
|
||||
SecurityContextHolderAwareRequestFilter filter = findFilter(SecurityContextHolderAwareRequestFilter)
|
||||
then: "SEC-2215: authenticationManager != null"
|
||||
filter.authenticationManager != null
|
||||
and: "authenticationEntryPoint != null"
|
||||
filter.authenticationEntryPoint != null
|
||||
and: "requestFactory != null"
|
||||
filter.requestFactory != null
|
||||
and: "logoutHandlers populated"
|
||||
filter.logoutHandlers.collect { it.class } == [CsrfLogoutHandler, SecurityContextLogoutHandler]
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
@EnableWebSecurity
|
||||
static class ServletApiConfig extends WebSecurityConfigurerAdapter {
|
||||
@CompileStatic
|
||||
@EnableWebSecurity
|
||||
static class ServletApiConfig 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")
|
||||
}
|
||||
}
|
||||
|
||||
def "SecurityContextHolderAwareRequestFilter.authenticationEntryPoint = customEntryPoint"() {
|
||||
setup:
|
||||
CustomEntryPointConfig.ENTRYPOINT = Mock(AuthenticationEntryPoint)
|
||||
when: "load config with customEntryPoint"
|
||||
loadConfig(CustomEntryPointConfig)
|
||||
then: "SecurityContextHolderAwareRequestFilter.authenticationEntryPoint == customEntryPoint"
|
||||
findFilter(SecurityContextHolderAwareRequestFilter).authenticationEntryPoint == CustomEntryPointConfig.ENTRYPOINT
|
||||
}
|
||||
def "SecurityContextHolderAwareRequestFilter.authenticationEntryPoint = customEntryPoint"() {
|
||||
setup:
|
||||
CustomEntryPointConfig.ENTRYPOINT = Mock(AuthenticationEntryPoint)
|
||||
when: "load config with customEntryPoint"
|
||||
loadConfig(CustomEntryPointConfig)
|
||||
then: "SecurityContextHolderAwareRequestFilter.authenticationEntryPoint == customEntryPoint"
|
||||
findFilter(SecurityContextHolderAwareRequestFilter).authenticationEntryPoint == CustomEntryPointConfig.ENTRYPOINT
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomEntryPointConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRYPOINT
|
||||
@EnableWebSecurity
|
||||
static class CustomEntryPointConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRYPOINT
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(ENTRYPOINT)
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(ENTRYPOINT)
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
|
||||
@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 "invoke servletApi twice does not override"() {
|
||||
setup:
|
||||
InvokeTwiceDoesNotOverrideConfig.ENTRYPOINT = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(SecurityContextHolderAwareRequestFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.ENTRYPOINT
|
||||
}
|
||||
def "invoke servletApi twice does not override"() {
|
||||
setup:
|
||||
InvokeTwiceDoesNotOverrideConfig.ENTRYPOINT = Mock(AuthenticationEntryPoint)
|
||||
when:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
then:
|
||||
findFilter(SecurityContextHolderAwareRequestFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.ENTRYPOINT
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRYPOINT
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationEntryPoint ENTRYPOINT
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(ENTRYPOINT)
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(ENTRYPOINT)
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
}
|
||||
}
|
||||
|
||||
def "use sharedObject trustResolver"() {
|
||||
setup:
|
||||
SharedTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
|
||||
when:
|
||||
loadConfig(SharedTrustResolverConfig)
|
||||
then:
|
||||
findFilter(SecurityContextHolderAwareRequestFilter).trustResolver == SharedTrustResolverConfig.TR
|
||||
}
|
||||
def "use sharedObject trustResolver"() {
|
||||
setup:
|
||||
SharedTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
|
||||
when:
|
||||
loadConfig(SharedTrustResolverConfig)
|
||||
then:
|
||||
findFilter(SecurityContextHolderAwareRequestFilter).trustResolver == SharedTrustResolverConfig.TR
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class SharedTrustResolverConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationTrustResolver TR
|
||||
@EnableWebSecurity
|
||||
static class SharedTrustResolverConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationTrustResolver TR
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.setSharedObject(AuthenticationTrustResolver, TR)
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.setSharedObject(AuthenticationTrustResolver, TR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
-39
@@ -32,48 +32,48 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
||||
*/
|
||||
public class UrlAuthorizationsTests extends BaseSpringSpec {
|
||||
|
||||
def "hasAnyAuthority('ROLE_USER')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER")
|
||||
then:
|
||||
expression == ["ROLE_USER"]
|
||||
}
|
||||
def "hasAnyAuthority('ROLE_USER')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER")
|
||||
then:
|
||||
expression == ["ROLE_USER"]
|
||||
}
|
||||
|
||||
def "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER","ROLE_ADMIN")
|
||||
then:
|
||||
expression == ["ROLE_USER","ROLE_ADMIN"]
|
||||
}
|
||||
def "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER","ROLE_ADMIN")
|
||||
then:
|
||||
expression == ["ROLE_USER","ROLE_ADMIN"]
|
||||
}
|
||||
|
||||
def "hasAnyRole('USER')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyRole("USER")
|
||||
then:
|
||||
expression == ["ROLE_USER"]
|
||||
}
|
||||
def "hasAnyRole('USER')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyRole("USER")
|
||||
then:
|
||||
expression == ["ROLE_USER"]
|
||||
}
|
||||
|
||||
def "hasAnyRole('ROLE_USER','ROLE_ADMIN')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyRole("USER","ADMIN")
|
||||
then:
|
||||
expression == ["ROLE_USER","ROLE_ADMIN"]
|
||||
}
|
||||
def "hasAnyRole('ROLE_USER','ROLE_ADMIN')"() {
|
||||
when:
|
||||
def expression = UrlAuthorizationConfigurer.hasAnyRole("USER","ADMIN")
|
||||
then:
|
||||
expression == ["ROLE_USER","ROLE_ADMIN"]
|
||||
}
|
||||
|
||||
def "uses AffirmativeBased AccessDecisionManager"() {
|
||||
when: "Load Config with no specific AccessDecisionManager"
|
||||
loadConfig(NoSpecificAccessDecessionManagerConfig)
|
||||
then: "AccessDecessionManager matches the HttpSecurityBuilder's default"
|
||||
findFilter(FilterSecurityInterceptor).accessDecisionManager.class == AffirmativeBased
|
||||
}
|
||||
def "uses AffirmativeBased AccessDecisionManager"() {
|
||||
when: "Load Config with no specific AccessDecisionManager"
|
||||
loadConfig(NoSpecificAccessDecessionManagerConfig)
|
||||
then: "AccessDecessionManager matches the HttpSecurityBuilder's default"
|
||||
findFilter(FilterSecurityInterceptor).accessDecisionManager.class == AffirmativeBased
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NoSpecificAccessDecessionManagerConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.apply(new UrlAuthorizationConfigurer()).getRegistry()
|
||||
.antMatchers("/a").hasRole("ADMIN")
|
||||
.anyRequest().hasRole("USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class NoSpecificAccessDecessionManagerConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.apply(new UrlAuthorizationConfigurer()).getRegistry()
|
||||
.antMatchers("/a").hasRole("ADMIN")
|
||||
.anyRequest().hasRole("USER")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-25
@@ -30,31 +30,31 @@ import org.springframework.security.web.authentication.preauth.x509.X509Authenti
|
||||
*/
|
||||
class X509ConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "x509 ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.x509()
|
||||
.and()
|
||||
.build()
|
||||
def "x509 ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.x509()
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "X509AuthenticationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as X509AuthenticationFilter) >> {X509AuthenticationFilter o -> o}
|
||||
}
|
||||
then: "X509AuthenticationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as X509AuthenticationFilter) >> {X509AuthenticationFilter o -> o}
|
||||
}
|
||||
|
||||
def "invoke x509 twice does not override"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.x509()
|
||||
.subjectPrincipalRegex(".*")
|
||||
.and()
|
||||
.x509()
|
||||
then:
|
||||
http.getConfigurer(X509Configurer).subjectPrincipalRegex == ".*"
|
||||
}
|
||||
def "invoke x509 twice does not override"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
when:
|
||||
http
|
||||
.x509()
|
||||
.subjectPrincipalRegex(".*")
|
||||
.and()
|
||||
.x509()
|
||||
then:
|
||||
http.getConfigurer(X509Configurer).subjectPrincipalRegex == ".*"
|
||||
}
|
||||
}
|
||||
|
||||
+43
-43
@@ -34,53 +34,53 @@ import org.springframework.security.openid.OpenIDAuthenticationToken
|
||||
*/
|
||||
class OpenIDLoginConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "openidLogin ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
|
||||
when:
|
||||
http
|
||||
.openidLogin()
|
||||
.authenticationUserDetailsService(new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>(uds))
|
||||
.and()
|
||||
.build()
|
||||
def "openidLogin ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
|
||||
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
|
||||
when:
|
||||
http
|
||||
.openidLogin()
|
||||
.authenticationUserDetailsService(new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>(uds))
|
||||
.and()
|
||||
.build()
|
||||
|
||||
then: "OpenIDAuthenticationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as OpenIDAuthenticationFilter) >> {OpenIDAuthenticationFilter o -> o}
|
||||
and: "OpenIDAuthenticationProvider is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as OpenIDAuthenticationProvider) >> {OpenIDAuthenticationProvider o -> o}
|
||||
}
|
||||
then: "OpenIDAuthenticationFilter is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as OpenIDAuthenticationFilter) >> {OpenIDAuthenticationFilter o -> o}
|
||||
and: "OpenIDAuthenticationProvider is registered with LifecycleManager"
|
||||
1 * opp.postProcess(_ as OpenIDAuthenticationProvider) >> {OpenIDAuthenticationProvider o -> o}
|
||||
}
|
||||
|
||||
def "invoke openidLogin twice does not override"() {
|
||||
setup:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl.endsWith("/login/custom")
|
||||
def "invoke openidLogin twice does not override"() {
|
||||
setup:
|
||||
loadConfig(InvokeTwiceDoesNotOverrideConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl.endsWith("/login/custom")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.openidLogin()
|
||||
.loginPage("/login/custom")
|
||||
.and()
|
||||
.openidLogin()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.openidLogin()
|
||||
.loginPage("/login/custom")
|
||||
.and()
|
||||
.openidLogin()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-14
@@ -22,18 +22,18 @@ import org.springframework.security.web.debug.DebugFilter;
|
||||
|
||||
class SecurityDebugBeanFactoryPostProcessorTest extends AbstractHttpConfigTests {
|
||||
|
||||
// SEC-1885
|
||||
def 'SEC-1885 - SecurityDebugBeanFactoryPostProcessor works when dependencies have Autowired constructor'() {
|
||||
when: 'debug used and FilterChainProxy has dependency with @Autowired constructor'
|
||||
xml.debug()
|
||||
httpAutoConfig {}
|
||||
xml.'authentication-manager'() {
|
||||
'authentication-provider'('ref': 'authProvider')
|
||||
}
|
||||
xml.'context:component-scan'('base-package':'org.springframework.security.config.debug')
|
||||
createAppContext('')
|
||||
then: 'TestAuthenticationProvider.<init>() is not thrown'
|
||||
appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) instanceof DebugFilter
|
||||
appContext.getBean(BeanIds.FILTER_CHAIN_PROXY) instanceof FilterChainProxy
|
||||
}
|
||||
// SEC-1885
|
||||
def 'SEC-1885 - SecurityDebugBeanFactoryPostProcessor works when dependencies have Autowired constructor'() {
|
||||
when: 'debug used and FilterChainProxy has dependency with @Autowired constructor'
|
||||
xml.debug()
|
||||
httpAutoConfig {}
|
||||
xml.'authentication-manager'() {
|
||||
'authentication-provider'('ref': 'authProvider')
|
||||
}
|
||||
xml.'context:component-scan'('base-package':'org.springframework.security.config.debug')
|
||||
createAppContext('')
|
||||
then: 'TestAuthenticationProvider.<init>() is not thrown'
|
||||
appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) instanceof DebugFilter
|
||||
appContext.getBean(BeanIds.FILTER_CHAIN_PROXY) instanceof FilterChainProxy
|
||||
}
|
||||
}
|
||||
|
||||
+75
-75
@@ -10,104 +10,104 @@ import org.springframework.mock.web.MockHttpServletResponse
|
||||
*/
|
||||
class FormLoginBeanDefinitionParserTests extends AbstractHttpConfigTests {
|
||||
|
||||
def 'form-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def 'form-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
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>
|
||||
<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>
|
||||
</table>
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
def 'form-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'form-login'('login-processing-url':'/login_custom','username-parameter':'custom_user','password-parameter':'custom_password')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.custom_user.focus();'>
|
||||
def 'form-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'form-login'('login-processing-url':'/login_custom','username-parameter':'custom_user','password-parameter':'custom_password')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.custom_user.focus();'>
|
||||
<h3>Login with Username and Password</h3><form name='f' action='/login_custom' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='custom_user' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='custom_password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<tr><td>User:</td><td><input type='text' name='custom_user' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='custom_password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
</table>
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
def 'openid-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def 'openid-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
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>
|
||||
<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>
|
||||
</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 colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<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>
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
def 'openid-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'('login-processing-url':'/login_custom')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def 'openid-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'('login-processing-url':'/login_custom')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
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>
|
||||
<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>
|
||||
</table>
|
||||
</form><h3>Login with OpenID Identity</h3><form name='oidf' action='/login_custom' 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>
|
||||
<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>
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+81
-81
@@ -45,101 +45,101 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
|
||||
*/
|
||||
class SecurityContextHolderAwareRequestConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def withAutoConfig() {
|
||||
httpAutoConfig () {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
def withAutoConfig() {
|
||||
httpAutoConfig () {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl
|
||||
securityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers.size() == 1
|
||||
securityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
}
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl
|
||||
securityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers.size() == 1
|
||||
securityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
}
|
||||
|
||||
def explicitEntryPoint() {
|
||||
xml.http() {
|
||||
'http-basic'('entry-point-ref': 'ep')
|
||||
}
|
||||
bean('ep', BasicAuthenticationEntryPoint.class.name, ['realmName':'whocares'],[:])
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
def explicitEntryPoint() {
|
||||
xml.http() {
|
||||
'http-basic'('entry-point-ref': 'ep')
|
||||
}
|
||||
bean('ep', BasicAuthenticationEntryPoint.class.name, ['realmName':'whocares'],[:])
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint == getFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
securityContextAwareFilter.authenticationManager == getFilter(BasicAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers == null
|
||||
}
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint == getFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
securityContextAwareFilter.authenticationManager == getFilter(BasicAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers == null
|
||||
}
|
||||
|
||||
def formLogin() {
|
||||
xml.http() {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
def formLogin() {
|
||||
xml.http() {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl
|
||||
securityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers == null
|
||||
}
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl
|
||||
securityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers == null
|
||||
}
|
||||
|
||||
def multiHttp() {
|
||||
xml.http('authentication-manager-ref' : 'authManager', 'pattern' : '/first/**') {
|
||||
'form-login'('login-page' : '/login')
|
||||
'logout'('invalidate-session' : 'true')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
xml.http('authentication-manager-ref' : 'authManager2') {
|
||||
'form-login'('login-page' : '/login2')
|
||||
'logout'('invalidate-session' : 'false')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
def multiHttp() {
|
||||
xml.http('authentication-manager-ref' : 'authManager', 'pattern' : '/first/**') {
|
||||
'form-login'('login-page' : '/login')
|
||||
'logout'('invalidate-session' : 'true')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
xml.http('authentication-manager-ref' : 'authManager2') {
|
||||
'form-login'('login-page' : '/login2')
|
||||
'logout'('invalidate-session' : 'false')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
|
||||
String secondAuthManager = AUTH_PROVIDER_XML.replace("alias='authManager'", "id='authManager2'")
|
||||
createAppContext(AUTH_PROVIDER_XML + secondAuthManager)
|
||||
String secondAuthManager = AUTH_PROVIDER_XML.replace("alias='authManager'", "id='authManager2'")
|
||||
createAppContext(AUTH_PROVIDER_XML + secondAuthManager)
|
||||
|
||||
def securityContextAwareFilter = getFilters('/first/filters').find { it instanceof SecurityContextHolderAwareRequestFilter }
|
||||
def secondSecurityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
def securityContextAwareFilter = getFilters('/first/filters').find { it instanceof SecurityContextHolderAwareRequestFilter }
|
||||
def secondSecurityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == '/login'
|
||||
securityContextAwareFilter.authenticationManager == getFilters('/first/filters').find { it instanceof UsernamePasswordAuthenticationFilter}.authenticationManager
|
||||
securityContextAwareFilter.authenticationManager.parent == appContext.getBean('authManager')
|
||||
securityContextAwareFilter.logoutHandlers.size() == 1
|
||||
securityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
securityContextAwareFilter.logoutHandlers[0].invalidateHttpSession == true
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == '/login'
|
||||
securityContextAwareFilter.authenticationManager == getFilters('/first/filters').find { it instanceof UsernamePasswordAuthenticationFilter}.authenticationManager
|
||||
securityContextAwareFilter.authenticationManager.parent == appContext.getBean('authManager')
|
||||
securityContextAwareFilter.logoutHandlers.size() == 1
|
||||
securityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
securityContextAwareFilter.logoutHandlers[0].invalidateHttpSession == true
|
||||
|
||||
secondSecurityContextAwareFilter.authenticationEntryPoint.loginFormUrl == '/login2'
|
||||
secondSecurityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
secondSecurityContextAwareFilter.authenticationManager.parent == appContext.getBean('authManager2')
|
||||
securityContextAwareFilter.logoutHandlers.size() == 1
|
||||
secondSecurityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
secondSecurityContextAwareFilter.logoutHandlers[0].invalidateHttpSession == false
|
||||
}
|
||||
secondSecurityContextAwareFilter.authenticationEntryPoint.loginFormUrl == '/login2'
|
||||
secondSecurityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
secondSecurityContextAwareFilter.authenticationManager.parent == appContext.getBean('authManager2')
|
||||
securityContextAwareFilter.logoutHandlers.size() == 1
|
||||
secondSecurityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
secondSecurityContextAwareFilter.logoutHandlers[0].invalidateHttpSession == false
|
||||
}
|
||||
|
||||
def logoutCustom() {
|
||||
xml.http() {
|
||||
'form-login'('login-page' : '/login')
|
||||
'logout'('invalidate-session' : 'false', 'logout-success-url' : '/login?logout', 'delete-cookies' : 'JSESSIONID')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
def logoutCustom() {
|
||||
xml.http() {
|
||||
'form-login'('login-page' : '/login')
|
||||
'logout'('invalidate-session' : 'false', 'logout-success-url' : '/login?logout', 'delete-cookies' : 'JSESSIONID')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
def securityContextAwareFilter = getFilter(SecurityContextHolderAwareRequestFilter)
|
||||
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl
|
||||
securityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers.size() == 2
|
||||
securityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
securityContextAwareFilter.logoutHandlers[0].invalidateHttpSession == false
|
||||
securityContextAwareFilter.logoutHandlers[1].class == CookieClearingLogoutHandler
|
||||
securityContextAwareFilter.logoutHandlers[1].cookiesToClear == ['JSESSIONID']
|
||||
}
|
||||
expect:
|
||||
securityContextAwareFilter.authenticationEntryPoint.loginFormUrl == getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl
|
||||
securityContextAwareFilter.authenticationManager == getFilter(UsernamePasswordAuthenticationFilter).authenticationManager
|
||||
securityContextAwareFilter.logoutHandlers.size() == 2
|
||||
securityContextAwareFilter.logoutHandlers[0].class == SecurityContextLogoutHandler
|
||||
securityContextAwareFilter.logoutHandlers[0].invalidateHttpSession == false
|
||||
securityContextAwareFilter.logoutHandlers[1].class == CookieClearingLogoutHandler
|
||||
securityContextAwareFilter.logoutHandlers[1].cookiesToClear == ['JSESSIONID']
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -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:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
|
||||
|
||||
<context:annotation-config/>
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean class="org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessorTests$WithBanNameAutoProxyCreatorConfig"/>
|
||||
<bean class="org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessorTests$WithBanNameAutoProxyCreatorConfig"/>
|
||||
|
||||
<bean id="interceptor" class="org.springframework.security.config.annotation.configuration.AroundMethodInterceptor"/>
|
||||
<bean id="myBean" class="org.springframework.security.config.annotation.configuration.MyAdvisedBean"/>
|
||||
<bean id="autoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
|
||||
p:beanNames="myBean"
|
||||
p:interceptorNames="interceptor"/>
|
||||
<bean id="pointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"
|
||||
p:mappedName="doStuff"
|
||||
p:advice-ref="interceptor"/>
|
||||
<bean id="interceptor" class="org.springframework.security.config.annotation.configuration.AroundMethodInterceptor"/>
|
||||
<bean id="myBean" class="org.springframework.security.config.annotation.configuration.MyAdvisedBean"/>
|
||||
<bean id="autoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
|
||||
p:beanNames="myBean"
|
||||
p:interceptorNames="interceptor"/>
|
||||
<bean id="pointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"
|
||||
p:mappedName="doStuff"
|
||||
p:advice-ref="interceptor"/>
|
||||
</beans>
|
||||
|
||||
+36
-36
@@ -1,41 +1,41 @@
|
||||
<?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:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
|
||||
|
||||
<bean id="jaasAuthProvider"
|
||||
class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider">
|
||||
<property name="configuration">
|
||||
<bean
|
||||
class="org.springframework.security.authentication.jaas.memory.InMemoryConfiguration">
|
||||
<constructor-arg>
|
||||
<map>
|
||||
<entry key="SPRINGSECURITY">
|
||||
<array>
|
||||
<bean
|
||||
class="javax.security.auth.login.AppConfigurationEntry">
|
||||
<constructor-arg
|
||||
value="org.springframework.security.authentication.jaas.TestLoginModule" />
|
||||
<constructor-arg>
|
||||
<util:constant
|
||||
static-field="javax.security.auth.login.AppConfigurationEntry$LoginModuleControlFlag.REQUIRED" />
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<map></map>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</array>
|
||||
</entry>
|
||||
</map>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="authorityGranters">
|
||||
<list>
|
||||
<bean
|
||||
class="org.springframework.security.authentication.jaas.TestAuthorityGranter" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="jaasAuthProvider"
|
||||
class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider">
|
||||
<property name="configuration">
|
||||
<bean
|
||||
class="org.springframework.security.authentication.jaas.memory.InMemoryConfiguration">
|
||||
<constructor-arg>
|
||||
<map>
|
||||
<entry key="SPRINGSECURITY">
|
||||
<array>
|
||||
<bean
|
||||
class="javax.security.auth.login.AppConfigurationEntry">
|
||||
<constructor-arg
|
||||
value="org.springframework.security.authentication.jaas.TestLoginModule" />
|
||||
<constructor-arg>
|
||||
<util:constant
|
||||
static-field="javax.security.auth.login.AppConfigurationEntry$LoginModuleControlFlag.REQUIRED" />
|
||||
</constructor-arg>
|
||||
<constructor-arg>
|
||||
<map></map>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</array>
|
||||
</entry>
|
||||
</map>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="authorityGranters">
|
||||
<list>
|
||||
<bean
|
||||
class="org.springframework.security.authentication.jaas.TestAuthorityGranter" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
|
||||
<logger name="org.apache.directory" level="ERROR"/>
|
||||
|
||||
<root level="${root.level}:-WARN">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
|
||||
<bean id="userRepository" class="org.springframework.security.integration.StubUserRepository"/>
|
||||
<bean id="userRepository" class="org.springframework.security.integration.StubUserRepository"/>
|
||||
|
||||
<security:authentication-manager>
|
||||
<security:authentication-provider
|
||||
user-service-ref="userDetailsService" />
|
||||
</security:authentication-manager>
|
||||
<security:authentication-manager>
|
||||
<security:authentication-provider
|
||||
user-service-ref="userDetailsService" />
|
||||
</security:authentication-manager>
|
||||
|
||||
<bean id="userDetailsService" class="org.springframework.security.integration.UserDetailsServiceImpl">
|
||||
<property name="userRepository" ref="userRepository"/>
|
||||
</bean>
|
||||
<bean id="userDetailsService" class="org.springframework.security.integration.UserDetailsServiceImpl">
|
||||
<property name="userRepository" ref="userRepository"/>
|
||||
</bean>
|
||||
|
||||
<security:global-method-security>
|
||||
<security:protect-pointcut
|
||||
expression="execution(* org.springframework.security.integration.*Repository+.*(..))"
|
||||
access="ROLE_LOGGEDIN" />
|
||||
</security:global-method-security>
|
||||
<security:global-method-security>
|
||||
<security:protect-pointcut
|
||||
expression="execution(* org.springframework.security.integration.*Repository+.*(..))"
|
||||
access="ROLE_LOGGEDIN" />
|
||||
</security:global-method-security>
|
||||
|
||||
<aop:aspectj-autoproxy/>
|
||||
<aop:aspectj-autoproxy/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<security:authentication-manager alias="authenticationManager">
|
||||
<security:authentication-provider>
|
||||
<security:user-service>
|
||||
<security:user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B"/>
|
||||
</security:user-service>
|
||||
</security:authentication-provider>
|
||||
</security:authentication-manager>
|
||||
<security:authentication-manager alias="authenticationManager">
|
||||
<security:authentication-provider>
|
||||
<security:user-service>
|
||||
<security:user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B"/>
|
||||
</security:user-service>
|
||||
</security:authentication-provider>
|
||||
</security:authentication-manager>
|
||||
|
||||
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
|
||||
<constructor-arg>
|
||||
<util:list>
|
||||
<bean class="org.springframework.security.access.vote.RoleVoter" />
|
||||
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
|
||||
</util:list>
|
||||
</constructor-arg>
|
||||
<property name="allowIfAllAbstainDecisions" value="false"/>
|
||||
</bean>
|
||||
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
|
||||
<constructor-arg>
|
||||
<util:list>
|
||||
<bean class="org.springframework.security.access.vote.RoleVoter" />
|
||||
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
|
||||
</util:list>
|
||||
</constructor-arg>
|
||||
<property name="allowIfAllAbstainDecisions" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean id="securityInterceptor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
|
||||
<property name="validateConfigAttributes" value="true"/>
|
||||
<property name="rejectPublicInvocations" value="true"/>
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
<property name="accessDecisionManager" ref="accessDecisionManager"/>
|
||||
<property name="securityMetadataSource">
|
||||
<security:method-security-metadata-source>
|
||||
<security:protect method="org.springframework.security.core.session.SessionRegistry.get*" access="ROLE_C" />
|
||||
</security:method-security-metadata-source>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="securityInterceptor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
|
||||
<property name="validateConfigAttributes" value="true"/>
|
||||
<property name="rejectPublicInvocations" value="true"/>
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
<property name="accessDecisionManager" ref="accessDecisionManager"/>
|
||||
<property name="securityMetadataSource">
|
||||
<security:method-security-metadata-source>
|
||||
<security:protect method="org.springframework.security.core.session.SessionRegistry.get*" access="ROLE_C" />
|
||||
</security:method-security-metadata-source>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="httpRemoteService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces" value="org.springframework.security.core.session.SessionRegistry"/>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<value>securityInterceptor</value>
|
||||
<value>httpInvokerClientInterceptor</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="httpRemoteService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces" value="org.springframework.security.core.session.SessionRegistry"/>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<value>securityInterceptor</value>
|
||||
<value>httpInvokerClientInterceptor</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="httpInvokerClientInterceptor" class="org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor">
|
||||
<property name="serviceUrl" value="http://somehost/someUrl"/>
|
||||
</bean>
|
||||
<bean id="httpInvokerClientInterceptor" class="org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor">
|
||||
<property name="serviceUrl" value="http://somehost/someUrl"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
+150
-150
@@ -28,185 +28,185 @@ import java.util.Random;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class SessionRegistryImplMTTests extends TestCase {
|
||||
private static final Random rnd = new Random();
|
||||
private static boolean errorOccurred;
|
||||
private static final Random rnd = new Random();
|
||||
private static boolean errorOccurred;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
errorOccurred = false;
|
||||
}
|
||||
protected void setUp() throws Exception {
|
||||
errorOccurred = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reproduces the NPE mentioned in SEC-484 where a sessionId is removed from
|
||||
* the set of sessions before it is removed from the list of sessions for a principal.
|
||||
* getAllSessions(principal, false) then finds the sessionId in the principal's session list
|
||||
* but reads null for the SessionInformation with the same Id.
|
||||
* Note that this is not guaranteed to produce the error but is a good testing point. Increasing the number
|
||||
* of sessions makes a failure more likely, but slows the test considerably.
|
||||
* Inserting temporary sleep statements in SessionRegistryClassImpl will also help.
|
||||
*/
|
||||
public void testConcurrencyOfReadAndRemoveIsSafe() {
|
||||
Object principal = "Joe Principal";
|
||||
SessionRegistryImpl sessionregistry = new SessionRegistryImpl();
|
||||
Set sessions = Collections.synchronizedSet(new HashSet());
|
||||
// Register some sessions
|
||||
for (int i = 0; i < 50; i++) {
|
||||
String sessionId = Integer.toString(i);
|
||||
sessions.add(sessionId);
|
||||
sessionregistry.registerNewSession(sessionId, principal);
|
||||
}
|
||||
/**
|
||||
* Reproduces the NPE mentioned in SEC-484 where a sessionId is removed from
|
||||
* the set of sessions before it is removed from the list of sessions for a principal.
|
||||
* getAllSessions(principal, false) then finds the sessionId in the principal's session list
|
||||
* but reads null for the SessionInformation with the same Id.
|
||||
* Note that this is not guaranteed to produce the error but is a good testing point. Increasing the number
|
||||
* of sessions makes a failure more likely, but slows the test considerably.
|
||||
* Inserting temporary sleep statements in SessionRegistryClassImpl will also help.
|
||||
*/
|
||||
public void testConcurrencyOfReadAndRemoveIsSafe() {
|
||||
Object principal = "Joe Principal";
|
||||
SessionRegistryImpl sessionregistry = new SessionRegistryImpl();
|
||||
Set sessions = Collections.synchronizedSet(new HashSet());
|
||||
// Register some sessions
|
||||
for (int i = 0; i < 50; i++) {
|
||||
String sessionId = Integer.toString(i);
|
||||
sessions.add(sessionId);
|
||||
sessionregistry.registerNewSession(sessionId, principal);
|
||||
}
|
||||
|
||||
// Pile of readers to hammer the getAllSessions method.
|
||||
for (int i=0; i < 10; i++) {
|
||||
Thread reader = new Thread(new SessionRegistryReader(principal, sessionregistry));
|
||||
reader.start();
|
||||
}
|
||||
// Pile of readers to hammer the getAllSessions method.
|
||||
for (int i=0; i < 10; i++) {
|
||||
Thread reader = new Thread(new SessionRegistryReader(principal, sessionregistry));
|
||||
reader.start();
|
||||
}
|
||||
|
||||
Thread remover = new Thread(new SessionRemover("remover", sessionregistry, sessions));
|
||||
Thread remover = new Thread(new SessionRemover("remover", sessionregistry, sessions));
|
||||
|
||||
remover.start();
|
||||
remover.start();
|
||||
|
||||
while(remover.isAlive()) {
|
||||
pause(250);
|
||||
}
|
||||
while(remover.isAlive()) {
|
||||
pause(250);
|
||||
}
|
||||
|
||||
assertFalse("Thread errors detected; review log output for details", errorOccurred);
|
||||
}
|
||||
assertFalse("Thread errors detected; review log output for details", errorOccurred);
|
||||
}
|
||||
|
||||
public void testConcurrentRemovalIsSafe() {
|
||||
Object principal = "Some principal object";
|
||||
SessionRegistryImpl sessionregistry = new SessionRegistryImpl();
|
||||
// The session list (effectivelly the containers sessions).
|
||||
Set sessions = Collections.synchronizedSet(new HashSet());
|
||||
Thread registerer = new Thread(new SessionRegisterer(principal, sessionregistry, 100, sessions));
|
||||
public void testConcurrentRemovalIsSafe() {
|
||||
Object principal = "Some principal object";
|
||||
SessionRegistryImpl sessionregistry = new SessionRegistryImpl();
|
||||
// The session list (effectivelly the containers sessions).
|
||||
Set sessions = Collections.synchronizedSet(new HashSet());
|
||||
Thread registerer = new Thread(new SessionRegisterer(principal, sessionregistry, 100, sessions));
|
||||
|
||||
registerer.start();
|
||||
registerer.start();
|
||||
|
||||
int nRemovers = 4;
|
||||
int nRemovers = 4;
|
||||
|
||||
SessionRemover[] removers = new SessionRemover[nRemovers];
|
||||
Thread[] removerThreads = new Thread[nRemovers];
|
||||
SessionRemover[] removers = new SessionRemover[nRemovers];
|
||||
Thread[] removerThreads = new Thread[nRemovers];
|
||||
|
||||
for (int i = 0; i < removers.length; i++) {
|
||||
removers[i] = new SessionRemover("remover" + i, sessionregistry, sessions);
|
||||
removerThreads[i] = new Thread(removers[i], "remover" + i);
|
||||
removerThreads[i].start();
|
||||
}
|
||||
for (int i = 0; i < removers.length; i++) {
|
||||
removers[i] = new SessionRemover("remover" + i, sessionregistry, sessions);
|
||||
removerThreads[i] = new Thread(removers[i], "remover" + i);
|
||||
removerThreads[i].start();
|
||||
}
|
||||
|
||||
while (stillRunning(removerThreads)) {
|
||||
pause(500);
|
||||
}
|
||||
}
|
||||
while (stillRunning(removerThreads)) {
|
||||
pause(500);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean stillRunning(Thread[] threads) {
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if (threads[i].isAlive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private boolean stillRunning(Thread[] threads) {
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if (threads[i].isAlive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class SessionRegisterer implements Runnable {
|
||||
private SessionRegistry sessionregistry;
|
||||
private int nIterations;
|
||||
private Set sessionList;
|
||||
private Object principal;
|
||||
private static class SessionRegisterer implements Runnable {
|
||||
private SessionRegistry sessionregistry;
|
||||
private int nIterations;
|
||||
private Set sessionList;
|
||||
private Object principal;
|
||||
|
||||
public SessionRegisterer(Object principal, SessionRegistry sessionregistry, int nIterations, Set sessionList) {
|
||||
this.sessionregistry = sessionregistry;
|
||||
this.nIterations = nIterations;
|
||||
this.sessionList = sessionList;
|
||||
this.principal = principal;
|
||||
}
|
||||
public SessionRegisterer(Object principal, SessionRegistry sessionregistry, int nIterations, Set sessionList) {
|
||||
this.sessionregistry = sessionregistry;
|
||||
this.nIterations = nIterations;
|
||||
this.sessionList = sessionList;
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
for (int i=0; i < nIterations && !errorOccurred; i++) {
|
||||
String sessionId = Integer.toString(i);
|
||||
sessionList.add(sessionId);
|
||||
try {
|
||||
sessionregistry.registerNewSession(sessionId,principal);
|
||||
pause(20);
|
||||
Thread.yield();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void run() {
|
||||
for (int i=0; i < nIterations && !errorOccurred; i++) {
|
||||
String sessionId = Integer.toString(i);
|
||||
sessionList.add(sessionId);
|
||||
try {
|
||||
sessionregistry.registerNewSession(sessionId,principal);
|
||||
pause(20);
|
||||
Thread.yield();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SessionRegistryReader implements Runnable {
|
||||
private SessionRegistry sessionRegistry;
|
||||
private Object principal;
|
||||
private static class SessionRegistryReader implements Runnable {
|
||||
private SessionRegistry sessionRegistry;
|
||||
private Object principal;
|
||||
|
||||
public SessionRegistryReader(Object principal, SessionRegistry sessionregistry) {
|
||||
this.sessionRegistry = sessionregistry;
|
||||
this.principal = principal;
|
||||
}
|
||||
public SessionRegistryReader(Object principal, SessionRegistry sessionregistry) {
|
||||
this.sessionRegistry = sessionregistry;
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (!errorOccurred) {
|
||||
try {
|
||||
sessionRegistry.getAllSessions(principal, false);
|
||||
sessionRegistry.getAllPrincipals();
|
||||
sessionRegistry.getAllSessions(principal, true);
|
||||
Thread.yield();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void run() {
|
||||
while (!errorOccurred) {
|
||||
try {
|
||||
sessionRegistry.getAllSessions(principal, false);
|
||||
sessionRegistry.getAllPrincipals();
|
||||
sessionRegistry.getAllSessions(principal, true);
|
||||
Thread.yield();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SessionRemover implements Runnable {
|
||||
private SessionRegistry sessionregistry;
|
||||
private Set sessionList;
|
||||
private String name;
|
||||
private static class SessionRemover implements Runnable {
|
||||
private SessionRegistry sessionregistry;
|
||||
private Set sessionList;
|
||||
private String name;
|
||||
|
||||
public SessionRemover(String name, SessionRegistry sessionregistry, Set sessionList) {
|
||||
this.name = name;
|
||||
this.sessionregistry = sessionregistry;
|
||||
this.sessionList = sessionList;
|
||||
}
|
||||
public SessionRemover(String name, SessionRegistry sessionregistry, Set sessionList) {
|
||||
this.name = name;
|
||||
this.sessionregistry = sessionregistry;
|
||||
this.sessionList = sessionList;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
boolean finished = false;
|
||||
public void run() {
|
||||
boolean finished = false;
|
||||
|
||||
while (!finished && !errorOccurred) {
|
||||
if (sessionList.isEmpty()) {
|
||||
finished = true;
|
||||
// List of sessions appears to be empty but give it a chance to fill up again
|
||||
System.out.println(name + ": Session list empty. Waiting.");
|
||||
pause(500);
|
||||
}
|
||||
while (!finished && !errorOccurred) {
|
||||
if (sessionList.isEmpty()) {
|
||||
finished = true;
|
||||
// List of sessions appears to be empty but give it a chance to fill up again
|
||||
System.out.println(name + ": Session list empty. Waiting.");
|
||||
pause(500);
|
||||
}
|
||||
|
||||
Object[] sessions = sessionList.toArray();
|
||||
Object[] sessions = sessionList.toArray();
|
||||
|
||||
if (sessions.length > 0) {
|
||||
finished = false;
|
||||
String sessionId = (String) sessions[0];
|
||||
if (sessions.length > 0) {
|
||||
finished = false;
|
||||
String sessionId = (String) sessions[0];
|
||||
// System.out.println(name + ": removing " + sessionId);
|
||||
try {
|
||||
sessionregistry.removeSessionInformation(sessionId);
|
||||
try {
|
||||
sessionregistry.removeSessionInformation(sessionId);
|
||||
|
||||
pause(rnd.nextInt(100));
|
||||
pause(rnd.nextInt(100));
|
||||
|
||||
sessionList.remove(sessionId);
|
||||
Thread.yield();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sessionList.remove(sessionId);
|
||||
Thread.yield();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void pause(int length) {
|
||||
try {
|
||||
Thread.sleep(length);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
private static void pause(int length) {
|
||||
try {
|
||||
Thread.sleep(length);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
+172
-172
@@ -16,201 +16,201 @@ import org.springframework.security.providers.UsernamePasswordAuthenticationToke
|
||||
* @Author Luke Taylor
|
||||
*/
|
||||
public class SecurityContextHolderMTTests extends TestCase{
|
||||
private int errors = 0;
|
||||
private int errors = 0;
|
||||
|
||||
private static final int NUM_OPS = 25;
|
||||
private static final int NUM_THREADS = 25;
|
||||
private static final int NUM_OPS = 25;
|
||||
private static final int NUM_THREADS = 25;
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
||||
}
|
||||
public final void setUp() throws Exception {
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
||||
}
|
||||
|
||||
public void testSynchronizationCustomStrategyLoading() {
|
||||
SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
|
||||
assertTrue(new SecurityContextHolder().toString()
|
||||
.lastIndexOf("SecurityContextHolder[strategy='org.springframework.security.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
public void testSynchronizationCustomStrategyLoading() {
|
||||
SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
|
||||
assertTrue(new SecurityContextHolder().toString()
|
||||
.lastIndexOf("SecurityContextHolder[strategy='org.springframework.security.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
|
||||
public void testSynchronizationGlobal() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, true, false);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
public void testSynchronizationGlobal() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, true, false);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
|
||||
public void testSynchronizationInheritableThreadLocal()
|
||||
throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
public void testSynchronizationInheritableThreadLocal()
|
||||
throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
|
||||
public void testSynchronizationThreadLocal() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, false);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
public void testSynchronizationThreadLocal() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
|
||||
loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, false);
|
||||
assertEquals("Thread errors detected; review log output for details", 0, errors);
|
||||
}
|
||||
|
||||
private void startAndRun(Thread[] threads) {
|
||||
// Start them up
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
private void startAndRun(Thread[] threads) {
|
||||
// Start them up
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
// Wait for them to finish
|
||||
while (stillRunning(threads)) {
|
||||
try {
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
// Wait for them to finish
|
||||
while (stillRunning(threads)) {
|
||||
try {
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean stillRunning(Thread[] threads) {
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if (threads[i].isAlive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private boolean stillRunning(Thread[] threads) {
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if (threads[i].isAlive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void loadStartAndWaitForThreads(boolean topLevelThread, String prefix, int createThreads,
|
||||
boolean expectAllThreadsToUseIdenticalAuthentication, boolean expectChildrenToShareAuthenticationWithParent) {
|
||||
Thread[] threads = new Thread[createThreads];
|
||||
errors = 0;
|
||||
private void loadStartAndWaitForThreads(boolean topLevelThread, String prefix, int createThreads,
|
||||
boolean expectAllThreadsToUseIdenticalAuthentication, boolean expectChildrenToShareAuthenticationWithParent) {
|
||||
Thread[] threads = new Thread[createThreads];
|
||||
errors = 0;
|
||||
|
||||
if (topLevelThread) {
|
||||
// PARENT (TOP-LEVEL) THREAD CREATION
|
||||
if (expectChildrenToShareAuthenticationWithParent) {
|
||||
// An InheritableThreadLocal
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, true, null);
|
||||
} else {
|
||||
// Inject auth into current thread, but not child; current thread will have auth, child will also have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, true,
|
||||
prefix + "Auth_Parent_" + i);
|
||||
}
|
||||
}
|
||||
} else if (expectAllThreadsToUseIdenticalAuthentication) {
|
||||
// A global
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken("GLOBAL_USERNAME",
|
||||
"pass"));
|
||||
if (topLevelThread) {
|
||||
// PARENT (TOP-LEVEL) THREAD CREATION
|
||||
if (expectChildrenToShareAuthenticationWithParent) {
|
||||
// An InheritableThreadLocal
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, true, null);
|
||||
} else {
|
||||
// Inject auth into current thread, but not child; current thread will have auth, child will also have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, true,
|
||||
prefix + "Auth_Parent_" + i);
|
||||
}
|
||||
}
|
||||
} else if (expectAllThreadsToUseIdenticalAuthentication) {
|
||||
// A global
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken("GLOBAL_USERNAME",
|
||||
"pass"));
|
||||
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread;both current thread and child will have same authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, true, true,
|
||||
"GLOBAL_USERNAME");
|
||||
} else {
|
||||
// Inject auth into current thread; current thread will have auth, child will also have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, true, true, "GLOBAL_USERNAME");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// A standard ThreadLocal
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, false, null);
|
||||
} else {
|
||||
// Inject auth into current thread, but not child; current thread will have auth, child will not have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, false,
|
||||
prefix + "Auth_Parent_" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CHILD THREAD CREATION
|
||||
if (expectChildrenToShareAuthenticationWithParent || expectAllThreadsToUseIdenticalAuthentication) {
|
||||
// The children being created are all expected to have security (ie an InheritableThreadLocal/global AND auth was injected into parent)
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
String expectedUsername = prefix;
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread;both current thread and child will have same authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, true, true,
|
||||
"GLOBAL_USERNAME");
|
||||
} else {
|
||||
// Inject auth into current thread; current thread will have auth, child will also have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, true, true, "GLOBAL_USERNAME");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// A standard ThreadLocal
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, false, null);
|
||||
} else {
|
||||
// Inject auth into current thread, but not child; current thread will have auth, child will not have auth
|
||||
threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, false,
|
||||
prefix + "Auth_Parent_" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CHILD THREAD CREATION
|
||||
if (expectChildrenToShareAuthenticationWithParent || expectAllThreadsToUseIdenticalAuthentication) {
|
||||
// The children being created are all expected to have security (ie an InheritableThreadLocal/global AND auth was injected into parent)
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
String expectedUsername = prefix;
|
||||
|
||||
if (expectAllThreadsToUseIdenticalAuthentication) {
|
||||
expectedUsername = "GLOBAL_USERNAME";
|
||||
}
|
||||
if (expectAllThreadsToUseIdenticalAuthentication) {
|
||||
expectedUsername = "GLOBAL_USERNAME";
|
||||
}
|
||||
|
||||
// Don't inject auth into current thread; the current thread will obtain auth from its parent
|
||||
// NB: As topLevelThread = true, no further child threads will be created
|
||||
threads[i] = makeThread(prefix + "->child->Inherited_Auth_Child_" + i, false, false,
|
||||
expectAllThreadsToUseIdenticalAuthentication, false, expectedUsername);
|
||||
}
|
||||
} else {
|
||||
// The children being created are NOT expected to have security (ie not an InheritableThreadLocal OR auth was not injected into parent)
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
// NB: As topLevelThread = true, no further child threads will be created
|
||||
threads[i] = makeThread(prefix + "->child->Unauth_Child_" + i, false, false, false, false, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't inject auth into current thread; the current thread will obtain auth from its parent
|
||||
// NB: As topLevelThread = true, no further child threads will be created
|
||||
threads[i] = makeThread(prefix + "->child->Inherited_Auth_Child_" + i, false, false,
|
||||
expectAllThreadsToUseIdenticalAuthentication, false, expectedUsername);
|
||||
}
|
||||
} else {
|
||||
// The children being created are NOT expected to have security (ie not an InheritableThreadLocal OR auth was not injected into parent)
|
||||
for (int i = 0; i < threads.length; i++) {
|
||||
// Don't inject auth into current thread; neither current thread or child will have authentication
|
||||
// NB: As topLevelThread = true, no further child threads will be created
|
||||
threads[i] = makeThread(prefix + "->child->Unauth_Child_" + i, false, false, false, false, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start and execute the threads
|
||||
startAndRun(threads);
|
||||
}
|
||||
// Start and execute the threads
|
||||
startAndRun(threads);
|
||||
}
|
||||
|
||||
private Thread makeThread(final String threadIdentifier, final boolean topLevelThread,
|
||||
final boolean injectAuthIntoCurrentThread, final boolean expectAllThreadsToUseIdenticalAuthentication,
|
||||
final boolean expectChildrenToShareAuthenticationWithParent, final String expectedUsername) {
|
||||
final Random rnd = new Random();
|
||||
private Thread makeThread(final String threadIdentifier, final boolean topLevelThread,
|
||||
final boolean injectAuthIntoCurrentThread, final boolean expectAllThreadsToUseIdenticalAuthentication,
|
||||
final boolean expectChildrenToShareAuthenticationWithParent, final String expectedUsername) {
|
||||
final Random rnd = new Random();
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
if (injectAuthIntoCurrentThread) {
|
||||
// Set authentication in this thread
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
|
||||
expectedUsername, "pass"));
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
if (injectAuthIntoCurrentThread) {
|
||||
// Set authentication in this thread
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
|
||||
expectedUsername, "pass"));
|
||||
|
||||
//System.out.println(threadIdentifier + " - set to " + SecurityContextHolder.getContext().getAuthentication());
|
||||
} else {
|
||||
//System.out.println(threadIdentifier + " - not set (currently " + SecurityContextHolder.getContext().getAuthentication() + ")");
|
||||
}
|
||||
//System.out.println(threadIdentifier + " - set to " + SecurityContextHolder.getContext().getAuthentication());
|
||||
} else {
|
||||
//System.out.println(threadIdentifier + " - not set (currently " + SecurityContextHolder.getContext().getAuthentication() + ")");
|
||||
}
|
||||
|
||||
// Do some operations in current thread, checking authentication is as expected in the current thread (ie another thread doesn't change it)
|
||||
for (int i = 0; i < NUM_OPS; i++) {
|
||||
String currentUsername = (SecurityContextHolder.getContext().getAuthentication() == null)
|
||||
? null : SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
// Do some operations in current thread, checking authentication is as expected in the current thread (ie another thread doesn't change it)
|
||||
for (int i = 0; i < NUM_OPS; i++) {
|
||||
String currentUsername = (SecurityContextHolder.getContext().getAuthentication() == null)
|
||||
? null : SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
|
||||
if ((i % 7) == 0) {
|
||||
System.out.println(threadIdentifier + " at " + i + " username " + currentUsername);
|
||||
}
|
||||
if ((i % 7) == 0) {
|
||||
System.out.println(threadIdentifier + " at " + i + " username " + currentUsername);
|
||||
}
|
||||
|
||||
try {
|
||||
assertEquals("Failed on iteration " + i + "; Authentication was '"
|
||||
+ currentUsername + "' but principal was expected to contain username '"
|
||||
+ expectedUsername + "'", expectedUsername, currentUsername);
|
||||
} catch (ComparisonFailure err) {
|
||||
errors++;
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
assertEquals("Failed on iteration " + i + "; Authentication was '"
|
||||
+ currentUsername + "' but principal was expected to contain username '"
|
||||
+ expectedUsername + "'", expectedUsername, currentUsername);
|
||||
} catch (ComparisonFailure err) {
|
||||
errors++;
|
||||
throw err;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(rnd.nextInt(250));
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(rnd.nextInt(250));
|
||||
} catch (InterruptedException ignore) {}
|
||||
}
|
||||
|
||||
// Load some children threads, checking the authentication is as expected in the children (ie another thread doesn't change it)
|
||||
if (topLevelThread) {
|
||||
// Make four children, but we don't want the children to have any more children (so anti-nature, huh?)
|
||||
if (injectAuthIntoCurrentThread && expectChildrenToShareAuthenticationWithParent) {
|
||||
loadStartAndWaitForThreads(false, threadIdentifier, 4,
|
||||
expectAllThreadsToUseIdenticalAuthentication, true);
|
||||
} else {
|
||||
loadStartAndWaitForThreads(false, threadIdentifier, 4,
|
||||
expectAllThreadsToUseIdenticalAuthentication, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, threadIdentifier);
|
||||
// Load some children threads, checking the authentication is as expected in the children (ie another thread doesn't change it)
|
||||
if (topLevelThread) {
|
||||
// Make four children, but we don't want the children to have any more children (so anti-nature, huh?)
|
||||
if (injectAuthIntoCurrentThread && expectChildrenToShareAuthenticationWithParent) {
|
||||
loadStartAndWaitForThreads(false, threadIdentifier, 4,
|
||||
expectAllThreadsToUseIdenticalAuthentication, true);
|
||||
} else {
|
||||
loadStartAndWaitForThreads(false, threadIdentifier, 4,
|
||||
expectAllThreadsToUseIdenticalAuthentication, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, threadIdentifier);
|
||||
|
||||
return t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
|
||||
<logger name="org.apache.directory" level="ERROR"/>
|
||||
|
||||
<root level="${root.level}:-WARN">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<http use-expressions="false">
|
||||
<intercept-url pattern="/**" access="ROLE_DEVELOPER,ROLE_USER" />
|
||||
<http-basic />
|
||||
</http>
|
||||
<http use-expressions="false">
|
||||
<intercept-url pattern="/**" access="ROLE_DEVELOPER,ROLE_USER" />
|
||||
<http-basic />
|
||||
</http>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<debug />
|
||||
<debug />
|
||||
|
||||
<!--
|
||||
Http App Context to test form login, remember-me and concurrent session control.
|
||||
Needs to be supplemented with authentication provider(s)
|
||||
-->
|
||||
<http pattern="/login.jsp" security="none" />
|
||||
<!--
|
||||
Http App Context to test form login, remember-me and concurrent session control.
|
||||
Needs to be supplemented with authentication provider(s)
|
||||
-->
|
||||
<http pattern="/login.jsp" security="none" />
|
||||
|
||||
<http>
|
||||
<intercept-url pattern="/secure/**" access="hasAnyRole('ROLE_DEVELOPER','ROLE_USER')" />
|
||||
<intercept-url pattern="/**" access="hasAnyRole('ROLE_DEVELOPER','ROLE_USER')" />
|
||||
<http>
|
||||
<intercept-url pattern="/secure/**" access="hasAnyRole('ROLE_DEVELOPER','ROLE_USER')" />
|
||||
<intercept-url pattern="/**" access="hasAnyRole('ROLE_DEVELOPER','ROLE_USER')" />
|
||||
|
||||
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=true"/>
|
||||
<http-basic/>
|
||||
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=true"/>
|
||||
<http-basic/>
|
||||
|
||||
<!-- Default logout configuration -->
|
||||
<logout logout-url="/logout"/>
|
||||
<!-- Default logout configuration -->
|
||||
<logout logout-url="/logout"/>
|
||||
|
||||
<session-management>
|
||||
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
|
||||
</session-management>
|
||||
<session-management>
|
||||
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
|
||||
</session-management>
|
||||
|
||||
<csrf disabled="true"/>
|
||||
</http>
|
||||
<csrf disabled="true"/>
|
||||
</http>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<http pattern="/login.jsp" security="none" />
|
||||
<http pattern="/login.jsp" security="none" />
|
||||
|
||||
<http entry-point-ref="aep" use-expressions="false">
|
||||
<intercept-url pattern="/**" access="ROLE_DEVELOPER,ROLE_USER" />
|
||||
<http entry-point-ref="aep" use-expressions="false">
|
||||
<intercept-url pattern="/**" access="ROLE_DEVELOPER,ROLE_USER" />
|
||||
|
||||
<session-management session-authentication-strategy-ref="sas"/>
|
||||
<logout />
|
||||
<session-management session-authentication-strategy-ref="sas"/>
|
||||
<logout />
|
||||
|
||||
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
|
||||
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
|
||||
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
|
||||
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
|
||||
|
||||
<csrf disabled="true"/>
|
||||
</http>
|
||||
<csrf disabled="true"/>
|
||||
</http>
|
||||
|
||||
<beans:bean id="aep" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
|
||||
<beans:constructor-arg value="/login.jsp" />
|
||||
</beans:bean>
|
||||
<beans:bean id="aep" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
|
||||
<beans:constructor-arg value="/login.jsp" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="myAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
|
||||
<beans:property name="sessionAuthenticationStrategy" ref="sas" />
|
||||
<beans:property name="authenticationManager" ref="authenticationManager" />
|
||||
</beans:bean>
|
||||
<beans:bean id="myAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
|
||||
<beans:property name="sessionAuthenticationStrategy" ref="sas" />
|
||||
<beans:property name="authenticationManager" ref="authenticationManager" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
|
||||
<beans:constructor-arg ref="sessionRegistry" />
|
||||
<beans:constructor-arg value="/session-expired.htm" />
|
||||
</beans:bean>
|
||||
<beans:bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
|
||||
<beans:constructor-arg ref="sessionRegistry" />
|
||||
<beans:constructor-arg value="/session-expired.htm" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
|
||||
<beans:constructor-arg>
|
||||
<beans:list>
|
||||
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
|
||||
<beans:constructor-arg ref="sessionRegistry"/>
|
||||
<beans:property name="maximumSessions" value="1" />
|
||||
<beans:property name="exceptionIfMaximumExceeded" value="true" />
|
||||
</beans:bean>
|
||||
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
|
||||
</beans:bean>
|
||||
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
|
||||
<beans:constructor-arg ref="sessionRegistry"/>
|
||||
</beans:bean>
|
||||
</beans:list>
|
||||
</beans:constructor-arg>
|
||||
</beans:bean>
|
||||
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
|
||||
<beans:constructor-arg>
|
||||
<beans:list>
|
||||
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
|
||||
<beans:constructor-arg ref="sessionRegistry"/>
|
||||
<beans:property name="maximumSessions" value="1" />
|
||||
<beans:property name="exceptionIfMaximumExceeded" value="true" />
|
||||
</beans:bean>
|
||||
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
|
||||
</beans:bean>
|
||||
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
|
||||
<beans:constructor-arg ref="sessionRegistry"/>
|
||||
</beans:bean>
|
||||
</beans:list>
|
||||
</beans:constructor-arg>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
|
||||
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<authentication-manager alias="authenticationManager">
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="miles" password="milespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_TRUMPETER"/>
|
||||
<user name="johnc" password="johncspassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SAXOPHONIST"/>
|
||||
<user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ROCK,ROLE_GUITARIST"/>
|
||||
<user name="bessie" password="bessiespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SINGER"/>
|
||||
<user name="theescapist<>&." password="theescapistspassword" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
</authentication-manager>
|
||||
<authentication-manager alias="authenticationManager">
|
||||
<authentication-provider>
|
||||
<user-service>
|
||||
<user name="miles" password="milespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_TRUMPETER"/>
|
||||
<user name="johnc" password="johncspassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SAXOPHONIST"/>
|
||||
<user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ROCK,ROLE_GUITARIST"/>
|
||||
<user name="bessie" password="bessiespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SINGER"/>
|
||||
<user name="theescapist<>&." password="theescapistspassword" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
</authentication-manager>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
<?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:sec="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:sec="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<sec:global-method-security secured-annotations="enabled" mode="aspectj" />
|
||||
<sec:global-method-security secured-annotations="enabled" mode="aspectj" />
|
||||
<!--
|
||||
<bean id="aspectJSecurityInterceptor"
|
||||
class="org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
|
||||
<property name="authenticationManager" ref="authenticationManager" />
|
||||
<property name="accessDecisionManager" ref="accessDecisionManager" />
|
||||
<property name="securityMetadataSource">
|
||||
<bean
|
||||
class="org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource" />
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="aspectJSecurityInterceptor"
|
||||
class="org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
|
||||
<property name="authenticationManager" ref="authenticationManager" />
|
||||
<property name="accessDecisionManager" ref="accessDecisionManager" />
|
||||
<property name="securityMetadataSource">
|
||||
<bean
|
||||
class="org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager"
|
||||
class="org.springframework.security.authentication.ProviderManager">
|
||||
<property name="providers">
|
||||
<bean
|
||||
class="org.springframework.security.authentication.TestingAuthenticationProvider" />
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="authenticationManager"
|
||||
class="org.springframework.security.authentication.ProviderManager">
|
||||
<property name="providers">
|
||||
<bean
|
||||
class="org.springframework.security.authentication.TestingAuthenticationProvider" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="accessDecisionManager"
|
||||
class="org.springframework.security.access.vote.AffirmativeBased">
|
||||
<property name="decisionVoters">
|
||||
<list>
|
||||
<bean
|
||||
class="org.springframework.security.access.vote.RoleVoter" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="accessDecisionManager"
|
||||
class="org.springframework.security.access.vote.AffirmativeBased">
|
||||
<property name="decisionVoters">
|
||||
<list>
|
||||
<bean
|
||||
class="org.springframework.security.access.vote.RoleVoter" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean
|
||||
class="org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"
|
||||
factory-method="aspectOf">
|
||||
<property name="securityInterceptor" ref="aspectJSecurityInterceptor" />
|
||||
</bean>
|
||||
<bean
|
||||
class="org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"
|
||||
factory-method="aspectOf">
|
||||
<property name="securityInterceptor" ref="aspectJSecurityInterceptor" />
|
||||
</bean>
|
||||
-->
|
||||
<bean class="sample.aspectj.Service" />
|
||||
<bean class="sample.aspectj.Service" />
|
||||
|
||||
<bean class="sample.aspectj.SecuredService" />
|
||||
<bean class="sample.aspectj.SecuredService" />
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
|
||||
|
||||
<root level="${root.level}:-WARN">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
+77
-77
@@ -33,90 +33,90 @@ import spock.lang.*
|
||||
*/
|
||||
@Stepwise
|
||||
class CasSampleProxyTests extends AbstractCasTests {
|
||||
HttpClient client = new HttpClient()
|
||||
@Shared String casServerUrl = LoginPage.url.replaceFirst('/login','')
|
||||
@Shared JettyCasService service = new JettyCasService().init(casServerUrl)
|
||||
@Shared Cas20ProxyRetriever retriever = new Cas20ProxyRetriever(casServerUrl,'UTF-8')
|
||||
@Shared String pt
|
||||
HttpClient client = new HttpClient()
|
||||
@Shared String casServerUrl = LoginPage.url.replaceFirst('/login','')
|
||||
@Shared JettyCasService service = new JettyCasService().init(casServerUrl)
|
||||
@Shared Cas20ProxyRetriever retriever = new Cas20ProxyRetriever(casServerUrl,'UTF-8')
|
||||
@Shared String pt
|
||||
|
||||
def cleanupSpec() {
|
||||
service.stop()
|
||||
}
|
||||
def cleanupSpec() {
|
||||
service.stop()
|
||||
}
|
||||
|
||||
def 'access secure page succeeds with ROLE_USER'() {
|
||||
setup: 'Obtain a pgt for a user with ROLE_USER'
|
||||
driver.get LoginPage.url+"?service="+service.serviceUrl()
|
||||
at LoginPage
|
||||
login 'scott'
|
||||
when: 'User with ROLE_USER accesses the secure page'
|
||||
def content = getSecured(getBaseUrl()+SecurePage.url).responseBodyAsString
|
||||
then: 'The secure page is returned'
|
||||
content.contains('<h1>Secure Page</h1>')
|
||||
}
|
||||
def 'access secure page succeeds with ROLE_USER'() {
|
||||
setup: 'Obtain a pgt for a user with ROLE_USER'
|
||||
driver.get LoginPage.url+"?service="+service.serviceUrl()
|
||||
at LoginPage
|
||||
login 'scott'
|
||||
when: 'User with ROLE_USER accesses the secure page'
|
||||
def content = getSecured(getBaseUrl()+SecurePage.url).responseBodyAsString
|
||||
then: 'The secure page is returned'
|
||||
content.contains('<h1>Secure Page</h1>')
|
||||
}
|
||||
|
||||
def 'access proxy ticket sample succeeds with ROLE_USER'() {
|
||||
when: 'a proxy ticket is used to create another proxy ticket'
|
||||
def content = getSecured(getBaseUrl()+ProxyTicketSamplePage.url).responseBodyAsString
|
||||
then: 'The proxy ticket sample page is returned'
|
||||
content.contains('<h1>Secure Page using a Proxy Ticket</h1>')
|
||||
}
|
||||
def 'access proxy ticket sample succeeds with ROLE_USER'() {
|
||||
when: 'a proxy ticket is used to create another proxy ticket'
|
||||
def content = getSecured(getBaseUrl()+ProxyTicketSamplePage.url).responseBodyAsString
|
||||
then: 'The proxy ticket sample page is returned'
|
||||
content.contains('<h1>Secure Page using a Proxy Ticket</h1>')
|
||||
}
|
||||
|
||||
def 'access extremely secure page with ROLE_USER is denied'() {
|
||||
when: 'User with ROLE_USER accesses the extremely secure page'
|
||||
GetMethod method = getSecured(getBaseUrl()+ExtremelySecurePage.url)
|
||||
then: 'access is denied'
|
||||
assert method.responseBodyAsString =~ /(?i)403.*?Denied/
|
||||
assert 403 == method.statusCode
|
||||
}
|
||||
def 'access extremely secure page with ROLE_USER is denied'() {
|
||||
when: 'User with ROLE_USER accesses the extremely secure page'
|
||||
GetMethod method = getSecured(getBaseUrl()+ExtremelySecurePage.url)
|
||||
then: 'access is denied'
|
||||
assert method.responseBodyAsString =~ /(?i)403.*?Denied/
|
||||
assert 403 == method.statusCode
|
||||
}
|
||||
|
||||
def 'access secure page with ROLE_SUPERVISOR succeeds'() {
|
||||
setup: 'Obtain pgt for user with ROLE_SUPERVISOR'
|
||||
to LocalLogoutPage
|
||||
casServerLogout.click()
|
||||
driver.get(LoginPage.url+"?service="+service.serviceUrl())
|
||||
at LoginPage
|
||||
login 'rod'
|
||||
when: 'User with ROLE_SUPERVISOR accesses the secure page'
|
||||
def content = getSecured(getBaseUrl()+ExtremelySecurePage.url).responseBodyAsString
|
||||
then: 'The secure page is returned'
|
||||
content.contains('<h1>VERY Secure Page</h1>')
|
||||
}
|
||||
def 'access secure page with ROLE_SUPERVISOR succeeds'() {
|
||||
setup: 'Obtain pgt for user with ROLE_SUPERVISOR'
|
||||
to LocalLogoutPage
|
||||
casServerLogout.click()
|
||||
driver.get(LoginPage.url+"?service="+service.serviceUrl())
|
||||
at LoginPage
|
||||
login 'rod'
|
||||
when: 'User with ROLE_SUPERVISOR accesses the secure page'
|
||||
def content = getSecured(getBaseUrl()+ExtremelySecurePage.url).responseBodyAsString
|
||||
then: 'The secure page is returned'
|
||||
content.contains('<h1>VERY Secure Page</h1>')
|
||||
}
|
||||
|
||||
def 'access extremely secure page with ROLE_SUPERVISOR reusing pt succeeds (stateless mode works)'() {
|
||||
when: 'User with ROLE_SUPERVISOR accesses extremely secure page with used pt'
|
||||
def content = getSecured(getBaseUrl()+ExtremelySecurePage.url,pt).responseBodyAsString
|
||||
then: 'The extremely secure page is returned'
|
||||
content.contains('<h1>VERY Secure Page</h1>')
|
||||
}
|
||||
def 'access extremely secure page with ROLE_SUPERVISOR reusing pt succeeds (stateless mode works)'() {
|
||||
when: 'User with ROLE_SUPERVISOR accesses extremely secure page with used pt'
|
||||
def content = getSecured(getBaseUrl()+ExtremelySecurePage.url,pt).responseBodyAsString
|
||||
then: 'The extremely secure page is returned'
|
||||
content.contains('<h1>VERY Secure Page</h1>')
|
||||
}
|
||||
|
||||
def 'access secure page with invalid proxy ticket fails'() {
|
||||
when: 'Invalid ticket is used to access secure page'
|
||||
GetMethod method = getSecured(getBaseUrl()+SecurePage.url,'invalidticket')
|
||||
then: 'Authentication fails'
|
||||
method.statusCode == 401
|
||||
}
|
||||
def 'access secure page with invalid proxy ticket fails'() {
|
||||
when: 'Invalid ticket is used to access secure page'
|
||||
GetMethod method = getSecured(getBaseUrl()+SecurePage.url,'invalidticket')
|
||||
then: 'Authentication fails'
|
||||
method.statusCode == 401
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result of calling a url with a proxy ticket
|
||||
* @param targetUrl the absolute url to attempt to access
|
||||
* @param pt the proxy ticket to use. Defaults to {@link #getPt(String)} with targetUrl specified for the targetUrl.
|
||||
* @return the GetMethod after calling a url with a specified proxy ticket
|
||||
*/
|
||||
GetMethod getSecured(String targetUrl,String pt=getPt(targetUrl)) {
|
||||
assert pt != null
|
||||
GetMethod method = new GetMethod(targetUrl+"?ticket="+pt)
|
||||
int status = client.executeMethod(method)
|
||||
method
|
||||
}
|
||||
/**
|
||||
* Gets the result of calling a url with a proxy ticket
|
||||
* @param targetUrl the absolute url to attempt to access
|
||||
* @param pt the proxy ticket to use. Defaults to {@link #getPt(String)} with targetUrl specified for the targetUrl.
|
||||
* @return the GetMethod after calling a url with a specified proxy ticket
|
||||
*/
|
||||
GetMethod getSecured(String targetUrl,String pt=getPt(targetUrl)) {
|
||||
assert pt != null
|
||||
GetMethod method = new GetMethod(targetUrl+"?ticket="+pt)
|
||||
int status = client.executeMethod(method)
|
||||
method
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a proxy ticket using the pgt from the {@link #service}.
|
||||
* @param targetService the targetService that the proxy ticket will be valid for
|
||||
* @return a proxy ticket for targetService
|
||||
*/
|
||||
String getPt(String targetService) {
|
||||
assert service.pgt != null
|
||||
pt = retriever.getProxyTicketIdFor(service.pgt, targetService)
|
||||
pt
|
||||
}
|
||||
/**
|
||||
* Obtains a proxy ticket using the pgt from the {@link #service}.
|
||||
* @param targetService the targetService that the proxy ticket will be valid for
|
||||
* @return a proxy ticket for targetService
|
||||
*/
|
||||
String getPt(String targetService) {
|
||||
assert service.pgt != null
|
||||
pt = retriever.getProxyTicketIdFor(service.pgt, targetService)
|
||||
pt
|
||||
}
|
||||
}
|
||||
+86
-86
@@ -34,102 +34,102 @@ import spock.lang.Stepwise;
|
||||
*/
|
||||
@Stepwise
|
||||
class CasSampleTests extends AbstractCasTests {
|
||||
@Shared String casServerLogoutUrl = LoginPage.url.replaceFirst('/login','/logout')
|
||||
@Shared String casServerLogoutUrl = LoginPage.url.replaceFirst('/login','/logout')
|
||||
|
||||
def 'access home page with unauthenticated user succeeds'() {
|
||||
when: 'Unauthenticated user accesses the Home Page'
|
||||
to HomePage
|
||||
then: 'The home page succeeds'
|
||||
at HomePage
|
||||
}
|
||||
def 'access home page with unauthenticated user succeeds'() {
|
||||
when: 'Unauthenticated user accesses the Home Page'
|
||||
to HomePage
|
||||
then: 'The home page succeeds'
|
||||
at HomePage
|
||||
}
|
||||
|
||||
def 'access extremely secure page with unauthenitcated user requires login'() {
|
||||
when: 'Unauthenticated user accesses the extremely secure page'
|
||||
via ExtremelySecurePage
|
||||
then: 'The login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
def 'access extremely secure page with unauthenitcated user requires login'() {
|
||||
when: 'Unauthenticated user accesses the extremely secure page'
|
||||
via ExtremelySecurePage
|
||||
then: 'The login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
|
||||
def 'authenticate attempt with invaid ticket fails'() {
|
||||
when: 'present invalid ticket'
|
||||
go "login/cas?ticket=invalid"
|
||||
then: 'the login failed page is displayed'
|
||||
$("h2").text() == 'Login to CAS failed!'
|
||||
}
|
||||
def 'authenticate attempt with invaid ticket fails'() {
|
||||
when: 'present invalid ticket'
|
||||
go "login/cas?ticket=invalid"
|
||||
then: 'the login failed page is displayed'
|
||||
$("h2").text() == 'Login to CAS failed!'
|
||||
}
|
||||
|
||||
def 'access secure page with unauthenticated user requires login'() {
|
||||
when: 'Unauthenticated user accesses the secure page'
|
||||
via SecurePage
|
||||
then: 'The login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
def 'access secure page with unauthenticated user requires login'() {
|
||||
when: 'Unauthenticated user accesses the secure page'
|
||||
via SecurePage
|
||||
then: 'The login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
|
||||
def 'saved request is used for secure page'() {
|
||||
when: 'login with ROLE_USER after requesting the secure page'
|
||||
login 'scott'
|
||||
then: 'the secure page is displayed'
|
||||
at SecurePage
|
||||
}
|
||||
def 'saved request is used for secure page'() {
|
||||
when: 'login with ROLE_USER after requesting the secure page'
|
||||
login 'scott'
|
||||
then: 'the secure page is displayed'
|
||||
at SecurePage
|
||||
}
|
||||
|
||||
def 'access proxy ticket sample with ROLE_USER is allowed'() {
|
||||
when: 'user with ROLE_USER requests the proxy ticket sample page'
|
||||
to ProxyTicketSamplePage
|
||||
then: 'the proxy ticket sample page is displayed'
|
||||
at ProxyTicketSamplePage
|
||||
}
|
||||
def 'access proxy ticket sample with ROLE_USER is allowed'() {
|
||||
when: 'user with ROLE_USER requests the proxy ticket sample page'
|
||||
to ProxyTicketSamplePage
|
||||
then: 'the proxy ticket sample page is displayed'
|
||||
at ProxyTicketSamplePage
|
||||
}
|
||||
|
||||
def 'access extremely secure page with ROLE_USER is denied'() {
|
||||
when: 'User with ROLE_USER accesses extremely secure page'
|
||||
via ExtremelySecurePage
|
||||
then: 'the access denied page is displayed'
|
||||
at AccessDeniedPage
|
||||
}
|
||||
def 'access extremely secure page with ROLE_USER is denied'() {
|
||||
when: 'User with ROLE_USER accesses extremely secure page'
|
||||
via ExtremelySecurePage
|
||||
then: 'the access denied page is displayed'
|
||||
at AccessDeniedPage
|
||||
}
|
||||
|
||||
def 'clicking local logout link displays local logout page'() {
|
||||
setup: 'Navigate to page with logout link'
|
||||
to SecurePage
|
||||
when: 'Local logout link is clicked'
|
||||
navModule.logout.click()
|
||||
then: 'the local logout page is displayed'
|
||||
at LocalLogoutPage
|
||||
}
|
||||
def 'clicking local logout link displays local logout page'() {
|
||||
setup: 'Navigate to page with logout link'
|
||||
to SecurePage
|
||||
when: 'Local logout link is clicked'
|
||||
navModule.logout.click()
|
||||
then: 'the local logout page is displayed'
|
||||
at LocalLogoutPage
|
||||
}
|
||||
|
||||
def 'clicking cas server logout link successfully performs logout'() {
|
||||
when: 'the cas server logout link is clicked and the secure page is requested'
|
||||
casServerLogout.click()
|
||||
via SecurePage
|
||||
then: 'the login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
def 'clicking cas server logout link successfully performs logout'() {
|
||||
when: 'the cas server logout link is clicked and the secure page is requested'
|
||||
casServerLogout.click()
|
||||
via SecurePage
|
||||
then: 'the login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
|
||||
def 'access extremely secure page with ROLE_SUPERVISOR succeeds'() {
|
||||
setup: 'login with ROLE_SUPERVISOR'
|
||||
login 'rod'
|
||||
when: 'access extremely secure page'
|
||||
to ExtremelySecurePage
|
||||
then: 'extremely secure page is displayed'
|
||||
at ExtremelySecurePage
|
||||
}
|
||||
def 'access extremely secure page with ROLE_SUPERVISOR succeeds'() {
|
||||
setup: 'login with ROLE_SUPERVISOR'
|
||||
login 'rod'
|
||||
when: 'access extremely secure page'
|
||||
to ExtremelySecurePage
|
||||
then: 'extremely secure page is displayed'
|
||||
at ExtremelySecurePage
|
||||
}
|
||||
|
||||
def 'after logout extremely secure page requires login'() {
|
||||
when: 'logout and request extremely secure page'
|
||||
navModule.logout.click()
|
||||
casServerLogout.click()
|
||||
via ExtremelySecurePage
|
||||
then: 'login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
def 'after logout extremely secure page requires login'() {
|
||||
when: 'logout and request extremely secure page'
|
||||
navModule.logout.click()
|
||||
casServerLogout.click()
|
||||
via ExtremelySecurePage
|
||||
then: 'login page is displayed'
|
||||
at LoginPage
|
||||
}
|
||||
|
||||
def 'logging out of the cas server successfully logs out of the cas sample application'() {
|
||||
setup: 'login with ROLE_USER'
|
||||
via SecurePage
|
||||
at LoginPage
|
||||
login 'rod'
|
||||
at SecurePage
|
||||
when: 'logout of the CAS Server'
|
||||
go casServerLogoutUrl
|
||||
via SecurePage
|
||||
then: 'user is logged out of the CAS Service'
|
||||
at LoginPage
|
||||
}
|
||||
def 'logging out of the cas server successfully logs out of the cas sample application'() {
|
||||
setup: 'login with ROLE_USER'
|
||||
via SecurePage
|
||||
at LoginPage
|
||||
login 'rod'
|
||||
at SecurePage
|
||||
when: 'logout of the CAS Server'
|
||||
go casServerLogoutUrl
|
||||
via SecurePage
|
||||
then: 'user is logged out of the CAS Service'
|
||||
at LoginPage
|
||||
}
|
||||
}
|
||||
+77
-77
@@ -38,87 +38,87 @@ import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class JettyCasService extends Server {
|
||||
private Cas20ProxyTicketValidator validator
|
||||
private int port = availablePort()
|
||||
private Cas20ProxyTicketValidator validator
|
||||
private int port = availablePort()
|
||||
|
||||
/**
|
||||
* The Proxy Granting Ticket. To initialize pgt, authenticate to the CAS Server with the service parameter
|
||||
* equal to {@link #serviceUrl()}.
|
||||
*/
|
||||
String pgt
|
||||
/**
|
||||
* The Proxy Granting Ticket. To initialize pgt, authenticate to the CAS Server with the service parameter
|
||||
* equal to {@link #serviceUrl()}.
|
||||
*/
|
||||
String pgt
|
||||
|
||||
/**
|
||||
* Start the CAS Service which will be available at {@link #serviceUrl()}.
|
||||
*
|
||||
* @param casServerUrl
|
||||
* @return
|
||||
*/
|
||||
def init(String casServerUrl) {
|
||||
ProxyGrantingTicketStorage storage = new ProxyGrantingTicketStorageImpl()
|
||||
validator = new Cas20ProxyTicketValidator(casServerUrl)
|
||||
validator.setAcceptAnyProxy(true)
|
||||
validator.setProxyGrantingTicketStorage(storage)
|
||||
validator.setProxyCallbackUrl(absoluteUrl('callback'))
|
||||
/**
|
||||
* Start the CAS Service which will be available at {@link #serviceUrl()}.
|
||||
*
|
||||
* @param casServerUrl
|
||||
* @return
|
||||
*/
|
||||
def init(String casServerUrl) {
|
||||
ProxyGrantingTicketStorage storage = new ProxyGrantingTicketStorageImpl()
|
||||
validator = new Cas20ProxyTicketValidator(casServerUrl)
|
||||
validator.setAcceptAnyProxy(true)
|
||||
validator.setProxyGrantingTicketStorage(storage)
|
||||
validator.setProxyCallbackUrl(absoluteUrl('callback'))
|
||||
|
||||
String password = System.getProperty('javax.net.ssl.trustStorePassword','password')
|
||||
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector()
|
||||
ssl_connector.setPort(port)
|
||||
ssl_connector.setKeystore(getTrustStore())
|
||||
ssl_connector.setPassword(password)
|
||||
ssl_connector.setKeyPassword(password)
|
||||
addConnector(ssl_connector)
|
||||
setHandler(new AbstractHandler() {
|
||||
public void handle(String target, Request baseRequest,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
def st = request.getParameter('ticket')
|
||||
if(st) {
|
||||
JettyCasService.this.validator.validate(st, JettyCasService.this.serviceUrl())
|
||||
}
|
||||
def pgt = request.getParameter('pgtId')
|
||||
if(pgt) {
|
||||
JettyCasService.this.pgt = pgt
|
||||
}
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
})
|
||||
start()
|
||||
this
|
||||
}
|
||||
String password = System.getProperty('javax.net.ssl.trustStorePassword','password')
|
||||
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector()
|
||||
ssl_connector.setPort(port)
|
||||
ssl_connector.setKeystore(getTrustStore())
|
||||
ssl_connector.setPassword(password)
|
||||
ssl_connector.setKeyPassword(password)
|
||||
addConnector(ssl_connector)
|
||||
setHandler(new AbstractHandler() {
|
||||
public void handle(String target, Request baseRequest,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
def st = request.getParameter('ticket')
|
||||
if(st) {
|
||||
JettyCasService.this.validator.validate(st, JettyCasService.this.serviceUrl())
|
||||
}
|
||||
def pgt = request.getParameter('pgtId')
|
||||
if(pgt) {
|
||||
JettyCasService.this.pgt = pgt
|
||||
}
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
})
|
||||
start()
|
||||
this
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL that this CAS service is available at.
|
||||
* @return
|
||||
*/
|
||||
String serviceUrl() {
|
||||
absoluteUrl('service')
|
||||
}
|
||||
/**
|
||||
* Returns the absolute URL that this CAS service is available at.
|
||||
* @return
|
||||
*/
|
||||
String serviceUrl() {
|
||||
absoluteUrl('service')
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a relative url, will provide an absolute url for this CAS Service.
|
||||
* @param relativeUrl the relative url (i.e. service, callback, etc)
|
||||
* @return
|
||||
*/
|
||||
private String absoluteUrl(String relativeUrl) {
|
||||
"https://localhost:${port}/${relativeUrl}"
|
||||
}
|
||||
/**
|
||||
* Given a relative url, will provide an absolute url for this CAS Service.
|
||||
* @param relativeUrl the relative url (i.e. service, callback, etc)
|
||||
* @return
|
||||
*/
|
||||
private String absoluteUrl(String relativeUrl) {
|
||||
"https://localhost:${port}/${relativeUrl}"
|
||||
}
|
||||
|
||||
private static String getTrustStore() {
|
||||
String trustStoreLocation = System.getProperty('javax.net.ssl.trustStore')
|
||||
if(trustStoreLocation == null || !new File(trustStoreLocation).isFile()) {
|
||||
throw new IllegalStateException('Could not find the trust store at path "'+trustStoreLocation+'". Specify the location using the javax.net.ssl.trustStore system property.')
|
||||
}
|
||||
trustStoreLocation
|
||||
}
|
||||
/**
|
||||
* Obtains a random available port (i.e. one that is not in use)
|
||||
* @return
|
||||
*/
|
||||
private static int availablePort() {
|
||||
ServerSocket server = new ServerSocket(0)
|
||||
int port = server.localPort
|
||||
server.close()
|
||||
port
|
||||
}
|
||||
private static String getTrustStore() {
|
||||
String trustStoreLocation = System.getProperty('javax.net.ssl.trustStore')
|
||||
if(trustStoreLocation == null || !new File(trustStoreLocation).isFile()) {
|
||||
throw new IllegalStateException('Could not find the trust store at path "'+trustStoreLocation+'". Specify the location using the javax.net.ssl.trustStore system property.')
|
||||
}
|
||||
trustStoreLocation
|
||||
}
|
||||
/**
|
||||
* Obtains a random available port (i.e. one that is not in use)
|
||||
* @return
|
||||
*/
|
||||
private static int availablePort() {
|
||||
ServerSocket server = new ServerSocket(0)
|
||||
int port = server.localPort
|
||||
server.close()
|
||||
port
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -24,8 +24,8 @@ import org.springframework.security.samples.cas.pages.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class NavModule extends Module {
|
||||
static content = {
|
||||
home(to: HomePage) { $("a", text: "Home") }
|
||||
logout(to: LocalLogoutPage) { $("a", text: "Logout") }
|
||||
}
|
||||
static content = {
|
||||
home(to: HomePage) { $("a", text: "Home") }
|
||||
logout(to: LocalLogoutPage) { $("a", text: "Logout") }
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,5 +23,5 @@ import geb.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class AccessDeniedPage extends Page {
|
||||
static at = { $("*",text: iContains(~/.*?403.*/)) }
|
||||
static at = { $("*",text: iContains(~/.*?403.*/)) }
|
||||
}
|
||||
+5
-5
@@ -24,9 +24,9 @@ import org.springframework.security.samples.cas.modules.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class ExtremelySecurePage extends Page {
|
||||
static url = "secure/extreme/"
|
||||
static at = { assert $('h1').text() == 'VERY Secure Page'; true; }
|
||||
static content = {
|
||||
navModule { module NavModule }
|
||||
}
|
||||
static url = "secure/extreme/"
|
||||
static at = { assert $('h1').text() == 'VERY Secure Page'; true; }
|
||||
static content = {
|
||||
navModule { module NavModule }
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -23,10 +23,10 @@ import geb.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class HomePage extends Page {
|
||||
static at = { assert $('h1').text() == 'Home Page'; true}
|
||||
static url = ''
|
||||
static content = {
|
||||
securePage { $('a',text: 'Secure page') }
|
||||
extremelySecurePage { $('a',text: 'Extremely secure page') }
|
||||
}
|
||||
static at = { assert $('h1').text() == 'Home Page'; true}
|
||||
static url = ''
|
||||
static content = {
|
||||
securePage { $('a',text: 'Secure page') }
|
||||
extremelySecurePage { $('a',text: 'Extremely secure page') }
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -27,9 +27,9 @@ import geb.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class LocalLogoutPage extends Page {
|
||||
static url = 'cas-logout.jsp'
|
||||
static at = { assert driver.currentUrl.endsWith(url); true }
|
||||
static content = {
|
||||
casServerLogout { $('a',text: 'Logout of CAS') }
|
||||
}
|
||||
static url = 'cas-logout.jsp'
|
||||
static at = { assert driver.currentUrl.endsWith(url); true }
|
||||
static content = {
|
||||
casServerLogout { $('a',text: 'Logout of CAS') }
|
||||
}
|
||||
}
|
||||
|
||||
+19
-19
@@ -23,24 +23,24 @@ import geb.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class LoginPage extends Page {
|
||||
static url = loginUrl()
|
||||
static at = { assert driver.currentUrl.startsWith(loginUrl()); true}
|
||||
static content = {
|
||||
login(required:false) { user, password=user ->
|
||||
loginForm.username = user
|
||||
loginForm.password = password
|
||||
submit.click()
|
||||
}
|
||||
loginForm { $('#login') }
|
||||
submit { $('input', type: 'submit') }
|
||||
}
|
||||
static url = loginUrl()
|
||||
static at = { assert driver.currentUrl.startsWith(loginUrl()); true}
|
||||
static content = {
|
||||
login(required:false) { user, password=user ->
|
||||
loginForm.username = user
|
||||
loginForm.password = password
|
||||
submit.click()
|
||||
}
|
||||
loginForm { $('#login') }
|
||||
submit { $('input', type: 'submit') }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the login page url which might change based upon the system properties. This is to support using a randomly available port for CI.
|
||||
* @return
|
||||
*/
|
||||
private static String loginUrl() {
|
||||
def host = System.getProperty('cas.server.host', 'localhost:9443')
|
||||
"https://${host}/cas/login"
|
||||
}
|
||||
/**
|
||||
* Gets the login page url which might change based upon the system properties. This is to support using a randomly available port for CI.
|
||||
* @return
|
||||
*/
|
||||
private static String loginUrl() {
|
||||
def host = System.getProperty('cas.server.host', 'localhost:9443')
|
||||
"https://${host}/cas/login"
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -25,9 +25,9 @@ import org.springframework.security.samples.cas.modules.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class ProxyTicketSamplePage extends Page {
|
||||
static url = "secure/ptSample"
|
||||
static at = { assert $('h1').text() == 'Secure Page using a Proxy Ticket'; true}
|
||||
static content = {
|
||||
navModule { module NavModule }
|
||||
}
|
||||
static url = "secure/ptSample"
|
||||
static at = { assert $('h1').text() == 'Secure Page using a Proxy Ticket'; true}
|
||||
static content = {
|
||||
navModule { module NavModule }
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -25,9 +25,9 @@ import org.springframework.security.samples.cas.modules.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class SecurePage extends Page {
|
||||
static url = "secure/"
|
||||
static at = { assert $('h1').text() == 'Secure Page'; true}
|
||||
static content = {
|
||||
navModule { module NavModule }
|
||||
}
|
||||
static url = "secure/"
|
||||
static at = { assert $('h1').text() == 'Secure Page'; true}
|
||||
static content = {
|
||||
navModule { module NavModule }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="error">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -2,16 +2,16 @@
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
|
||||
<log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/">
|
||||
<appender name="console" class="org.apache.log4j.ConsoleAppender">
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d %p [%c] - <%m>%n"/>
|
||||
</layout>
|
||||
</appender>
|
||||
<logger name="org.jasig" additivity="true">
|
||||
<level value="@logLevel@" />
|
||||
</logger>
|
||||
<root>
|
||||
<level value="ERROR"/>
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
<appender name="console" class="org.apache.log4j.ConsoleAppender">
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d %p [%c] - <%m>%n"/>
|
||||
</layout>
|
||||
</appender>
|
||||
<logger name="org.jasig" additivity="true">
|
||||
<level value="@logLevel@" />
|
||||
</logger>
|
||||
<root>
|
||||
<level value="ERROR"/>
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
</log4j:configuration>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user