Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e412fb7ac0 | |||
| 28278eab89 | |||
| a93fb1e0e7 | |||
| dabcc5416a | |||
| 8a6d0cd16d | |||
| edb7ef567a | |||
| d002681bec | |||
| 6649d46896 | |||
| 1d97ee8dd6 | |||
| 7d1344fca8 | |||
| cc04392d9a | |||
| 919f000c80 | |||
| 310bb39a0d | |||
| 764a4d8414 | |||
| b17870ee07 | |||
| 8ad91ef6a5 | |||
| 5f6312c5be | |||
| 9d50944cb2 | |||
| e4c13e3c0e | |||
| 13bc70f693 | |||
| c935d857eb | |||
| 843ed3e437 | |||
| 7f3b3a8b59 | |||
| 261c932b8e | |||
| 1b4e20e97f | |||
| bd5f71bb0d | |||
| b76e3be822 | |||
| 26ad1cb4a5 | |||
| 87224f62e4 | |||
| 8f880aea0e | |||
| 5f658b3ffc | |||
| 77a478ba0d | |||
| a3c4a5fde7 | |||
| bbeb7f94d7 | |||
| a2a06d19c1 | |||
| 314828859e | |||
| 66858e22ad | |||
| 2a73f3cdf7 | |||
| dd9b59ba31 | |||
| 39ed7d0eca | |||
| a2ead4cf7a | |||
| 364db6762e | |||
| e8f4ee8a39 | |||
| d2b909e7c5 | |||
| 9fa2c64737 | |||
| 6b436ff409 | |||
| ca76e8d784 | |||
| 2d6051625f | |||
| 477573b3bc | |||
| fa1c484587 | |||
| 9e3d2e2d99 | |||
| e7fd6f6c3f | |||
| 208f898403 | |||
| a7369bf71b | |||
| cf78793f8f | |||
| 8aea83011d | |||
| fd65652bbe | |||
| 38e9f6a851 | |||
| cdb04c50e8 | |||
| 057ea4fb17 | |||
| 503828c994 | |||
| d3b3f8e004 | |||
| 9fcfeaf225 | |||
| 101190ad8b | |||
| 336de35874 | |||
| a53d022312 | |||
| 9f95bfdfc9 | |||
| ea2b5dd412 | |||
| 7b61a44929 | |||
| 602bb457b8 | |||
| f363c62afd | |||
| 66980e827c | |||
| c261975be0 | |||
| ede521dc8d | |||
| d4218c70f1 | |||
| 64f53620f8 |
@@ -1,6 +1,3 @@
|
||||
<!--
|
||||
Thanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with #).
|
||||
-->
|
||||
|
||||
<!-- Please also confirm that you have signed the CLA by put an [X] in the box below: -->
|
||||
- [] I have signed the CLA
|
||||
|
||||
+2
-10
@@ -32,17 +32,9 @@ Is there already an issue that addresses your concern? Do a bit of searching in
|
||||
If you're considering anything more than correcting a typo or fixing a minor bug , please discuss it on the [Spring Security Gitter](https://gitter.im/spring-projects/spring-security) before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
|
||||
|
||||
# Sign the Contributor License Agreement
|
||||
If you have not previously done so, please fill out and submit the [SpringSource CLA form](https://support.springsource.com/spring_committer_signup). You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
|
||||
|
||||
* For **Project** select _Spring Security_
|
||||
* For **Project Lead** enter _Rob Winch_
|
||||
* Note that emailing/postal mailing a signed copy is not necessary. Submission of the web form is all that is required.
|
||||
|
||||
When you've completed the web form, simply add the following in a comment on your pull request:
|
||||
|
||||
> I have signed and agree to the terms of the SpringSource Individual Contributor License Agreement.
|
||||
|
||||
You do not need to include your token/id. Please add the statement above to all future pull requests as well, simply so the Spring Security team knows immediately that this process is complete.
|
||||
If you have not previously done so, please fill out and
|
||||
submit the [Contributor License Agreement](https://cla.pivotal.io/sign/spring).
|
||||
|
||||
# Create your branch from master
|
||||
Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<name>spring-security-acl</name>
|
||||
<description>spring-security-acl</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.5.RELEASE</version>
|
||||
<version>4.3.1.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -51,7 +51,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
-2
@@ -16,12 +16,10 @@
|
||||
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.AfterInvocationProvider;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
|
||||
@@ -46,7 +46,7 @@ public interface AccessControlEntry extends Serializable {
|
||||
Sid getSid();
|
||||
|
||||
/**
|
||||
* Indicates the a Permission is being granted to the relevant Sid. If false,
|
||||
* Indicates the permission is being granted to the relevant Sid. If false,
|
||||
* indicates the permission is being revoked/blocked.
|
||||
*
|
||||
* @return true if being granted, false otherwise
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.security.acls;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
-4
@@ -18,17 +18,13 @@ package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.acls.model.*;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
-8
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
@@ -26,17 +25,12 @@ import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -48,12 +42,10 @@ import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link EhCacheBasedAclCache}
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -31,7 +29,6 @@ import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<name>spring-security-aspects</name>
|
||||
<description>spring-security-aspects</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.5.RELEASE</version>
|
||||
<version>4.3.1.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -45,7 +45,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ allprojects {
|
||||
|
||||
ext.releaseBuild = version.endsWith('RELEASE')
|
||||
ext.snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
ext.springVersion = '4.2.5.RELEASE'
|
||||
ext.springVersion = '4.3.1.RELEASE'
|
||||
ext.springLdapVersion = '2.0.2.RELEASE'
|
||||
|
||||
group = 'org.springframework.security'
|
||||
|
||||
+4
-4
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<name>spring-security-cas</name>
|
||||
<description>spring-security-cas</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.5.RELEASE</version>
|
||||
<version>4.3.1.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -51,13 +51,13 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+1
-9
@@ -17,14 +17,9 @@
|
||||
package org.springframework.security.cas.web;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
|
||||
import org.junit.After;
|
||||
@@ -40,11 +35,8 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.NullRememberMeServices;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link CasAuthenticationFilter}.
|
||||
|
||||
+9
-15
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<name>spring-security-config</name>
|
||||
<description>spring-security-config</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.5.RELEASE</version>
|
||||
<version>4.3.1.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -51,7 +51,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -97,28 +97,28 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-messaging</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-openid</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -248,12 +248,6 @@
|
||||
<version>4.1.0.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>3.6.10.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
@@ -371,13 +365,13 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+40
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,24 +15,17 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.authentication.ldap
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.LdapAuthenticationProviderConfig
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider
|
||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator
|
||||
import org.springframework.security.ldap.userdetails.PersonContextMapper
|
||||
import org.springframework.test.util.ReflectionTestUtils
|
||||
|
||||
import static org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.*
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Eddú Meléndez
|
||||
*
|
||||
*/
|
||||
class LdapAuthenticationProviderConfigurerTests extends BaseSpringSpec {
|
||||
@@ -44,17 +37,54 @@ class LdapAuthenticationProviderConfigurerTests extends BaseSpringSpec {
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
|
||||
}
|
||||
|
||||
def "authentication-manager support multiple ldap context with default role prefix" () {
|
||||
when:
|
||||
loadConfig(MultiLdapAuthenticationProvidersConfig)
|
||||
then:
|
||||
def authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob", "bobspassword"))
|
||||
authenticate.authorities.contains(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))
|
||||
}
|
||||
|
||||
def "authentication-manager support multiple ldap context with custom role prefix"() {
|
||||
when:
|
||||
loadConfig(MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig)
|
||||
then:
|
||||
def authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob", "bobspassword"))
|
||||
authenticate.authorities.contains(new SimpleGrantedAuthority("ROL_DEVELOPERS"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.and()
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.rolePrefix("ROL_")
|
||||
.and()
|
||||
.ldapAuthentication()
|
||||
.groupSearchBase("ou=groups")
|
||||
.groupSearchFilter("(member={0})")
|
||||
.userDnPatterns("uid={0},ou=people")
|
||||
.rolePrefix("RUOLO_")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ public abstract class Elements {
|
||||
public static final String DEBUG = "debug";
|
||||
public static final String HTTP_FIREWALL = "http-firewall";
|
||||
public static final String HEADERS = "headers";
|
||||
public static final String CORS = "cors";
|
||||
public static final String CSRF = "csrf";
|
||||
|
||||
public static final String WEBSOCKET_MESSAGE_BROKER = "websocket-message-broker";
|
||||
|
||||
+5
-4
@@ -25,6 +25,7 @@ import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
@@ -57,7 +58,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();
|
||||
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<SecurityConfigurer<O, B>>();
|
||||
|
||||
private final Map<Class<Object>, Object> sharedObjects = new HashMap<Class<Object>, Object>();
|
||||
private final Map<Class<? extends Object>, Object> sharedObjects = new HashMap<Class<? extends Object>, Object>();
|
||||
|
||||
private final boolean allowConfigurersOfSameType;
|
||||
|
||||
@@ -155,7 +156,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C> void setSharedObject(Class<C> sharedType, C object) {
|
||||
this.sharedObjects.put((Class<Object>) sharedType, object);
|
||||
this.sharedObjects.put(sharedType, object);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +174,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
* Gets the shared objects
|
||||
* @return
|
||||
*/
|
||||
public Map<Class<Object>, Object> getSharedObjects() {
|
||||
public Map<Class<? extends Object>, Object> getSharedObjects() {
|
||||
return Collections.unmodifiableMap(this.sharedObjects);
|
||||
}
|
||||
|
||||
@@ -300,7 +301,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
* @return the possibly modified Object to use
|
||||
*/
|
||||
protected <P> P postProcess(P object) {
|
||||
return (P) this.objectPostProcessor.postProcess(object);
|
||||
return this.objectPostProcessor.postProcess(object);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+54
-3
@@ -19,9 +19,11 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactoryBean;
|
||||
import org.springframework.aop.target.LazyInitTargetSource;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
@@ -34,6 +36,8 @@ import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -45,6 +49,9 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
@Configuration
|
||||
public class AuthenticationConfiguration {
|
||||
|
||||
private AtomicBoolean buildingAuthenticationManager = new AtomicBoolean();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
@@ -79,11 +86,15 @@ public class AuthenticationConfiguration {
|
||||
}
|
||||
|
||||
public AuthenticationManager getAuthenticationManager() throws Exception {
|
||||
if (authenticationManagerInitialized) {
|
||||
return authenticationManager;
|
||||
if (this.authenticationManagerInitialized) {
|
||||
return this.authenticationManager;
|
||||
}
|
||||
AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(
|
||||
this.objectPostProcessor);
|
||||
if (this.buildingAuthenticationManager.getAndSet(true)) {
|
||||
return new AuthenticationManagerDelegator(authBuilder);
|
||||
}
|
||||
|
||||
AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(objectPostProcessor);
|
||||
for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
|
||||
authBuilder.apply(config);
|
||||
}
|
||||
@@ -157,4 +168,44 @@ public class AuthenticationConfiguration {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents infinite recursion in the event that initializing the
|
||||
* AuthenticationManager.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 4.1.1
|
||||
*/
|
||||
static final class AuthenticationManagerDelegator implements AuthenticationManager {
|
||||
private AuthenticationManagerBuilder delegateBuilder;
|
||||
private AuthenticationManager delegate;
|
||||
private final Object delegateMonitor = new Object();
|
||||
|
||||
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {
|
||||
Assert.notNull(delegateBuilder, "delegateBuilder cannot be null");
|
||||
this.delegateBuilder = delegateBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
if (this.delegate != null) {
|
||||
return this.delegate.authenticate(authentication);
|
||||
}
|
||||
|
||||
synchronized (this.delegateMonitor) {
|
||||
if (this.delegate == null) {
|
||||
this.delegate = this.delegateBuilder.getObject();
|
||||
this.delegateBuilder = null;
|
||||
}
|
||||
}
|
||||
|
||||
return this.delegate.authenticate(authentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuthenticationManagerDelegator [delegate=" + this.delegate + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.authentication.AbstractLdapAuthenticator;
|
||||
@@ -51,6 +52,7 @@ import java.net.ServerSocket;
|
||||
* @param <B> the {@link ProviderManagerBuilder} type that this is configuring.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Eddú Meléndez
|
||||
* @since 3.2
|
||||
*/
|
||||
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>>
|
||||
@@ -68,6 +70,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
private Object passwordEncoder;
|
||||
private String passwordAttribute;
|
||||
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
|
||||
private GrantedAuthoritiesMapper authoritiesMapper;
|
||||
|
||||
private LdapAuthenticationProvider build() throws Exception {
|
||||
BaseLdapPathContextSource contextSource = getContextSource();
|
||||
@@ -77,10 +80,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
|
||||
LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(
|
||||
ldapAuthenticator, authoritiesPopulator);
|
||||
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
|
||||
simpleAuthorityMapper.setPrefix(rolePrefix);
|
||||
simpleAuthorityMapper.afterPropertiesSet();
|
||||
ldapAuthenticationProvider.setAuthoritiesMapper(simpleAuthorityMapper);
|
||||
ldapAuthenticationProvider.setAuthoritiesMapper(getAuthoritiesMapper());
|
||||
if (userDetailsContextMapper != null) {
|
||||
ldapAuthenticationProvider
|
||||
.setUserDetailsContextMapper(userDetailsContextMapper);
|
||||
@@ -128,11 +128,45 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
contextSource, groupSearchBase);
|
||||
defaultAuthoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
|
||||
defaultAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
|
||||
defaultAuthoritiesPopulator.setRolePrefix(rolePrefix);
|
||||
|
||||
this.ldapAuthoritiesPopulator = defaultAuthoritiesPopulator;
|
||||
return defaultAuthoritiesPopulator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specifies the {@link GrantedAuthoritiesMapper}.
|
||||
*
|
||||
* @param grantedAuthoritiesMapper the {@link GrantedAuthoritiesMapper} the default is {@link SimpleAuthorityMapper}
|
||||
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
|
||||
*
|
||||
* @author Tony Dalbrekt
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public LdapAuthenticationProviderConfigurer<B> authoritiesMapper(GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
|
||||
this.authoritiesMapper = grantedAuthoritiesMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link GrantedAuthoritiesMapper} and defaults to {@link SimpleAuthorityMapper}.
|
||||
*
|
||||
* @return the {@link GrantedAuthoritiesMapper}
|
||||
* @throws Exception if errors in {@link SimpleAuthorityMapper#afterPropertiesSet()}
|
||||
*/
|
||||
protected GrantedAuthoritiesMapper getAuthoritiesMapper() throws Exception {
|
||||
if(authoritiesMapper != null) {
|
||||
return authoritiesMapper;
|
||||
}
|
||||
|
||||
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
|
||||
simpleAuthorityMapper.setPrefix(rolePrefix);
|
||||
simpleAuthorityMapper.afterPropertiesSet();
|
||||
this.authoritiesMapper = simpleAuthorityMapper;
|
||||
return simpleAuthorityMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link LdapAuthenticator} to use
|
||||
*
|
||||
|
||||
-1
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.authentication.configurers.userdetails;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
+16
-1
@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -37,10 +38,11 @@ import org.springframework.util.Assert;
|
||||
* @since 3.2
|
||||
*/
|
||||
final class AutowireBeanFactoryObjectPostProcessor
|
||||
implements ObjectPostProcessor<Object>, DisposableBean {
|
||||
implements ObjectPostProcessor<Object>, DisposableBean, SmartInitializingSingleton {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private final AutowireCapableBeanFactory autowireBeanFactory;
|
||||
private final List<DisposableBean> disposableBeans = new ArrayList<DisposableBean>();
|
||||
private final List<SmartInitializingSingleton> smartSingletons = new ArrayList<SmartInitializingSingleton>();
|
||||
|
||||
public AutowireBeanFactoryObjectPostProcessor(
|
||||
AutowireCapableBeanFactory autowireBeanFactory) {
|
||||
@@ -74,9 +76,22 @@ final class AutowireBeanFactoryObjectPostProcessor
|
||||
if (result instanceof DisposableBean) {
|
||||
this.disposableBeans.add((DisposableBean) result);
|
||||
}
|
||||
if (result instanceof SmartInitializingSingleton) {
|
||||
this.smartSingletons.add((SmartInitializingSingleton) result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated()
|
||||
*/
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
for(SmartInitializingSingleton singleton : smartSingletons) {
|
||||
singleton.afterSingletonsInstantiated();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
+58
-24
@@ -22,6 +22,8 @@ import java.util.Map;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
@@ -76,7 +78,8 @@ import org.springframework.util.Assert;
|
||||
* @see EnableGlobalMethodSecurity
|
||||
*/
|
||||
@Configuration
|
||||
public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
public class GlobalMethodSecurityConfiguration
|
||||
implements ImportAware, SmartInitializingSingleton {
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(GlobalMethodSecurityConfiguration.class);
|
||||
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
|
||||
@@ -94,6 +97,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
private ApplicationContext context;
|
||||
private MethodSecurityExpressionHandler expressionHandler;
|
||||
private Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource;
|
||||
private MethodSecurityInterceptor methodSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* Creates the default MethodInterceptor which is a MethodSecurityInterceptor using
|
||||
@@ -117,18 +121,68 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
*/
|
||||
@Bean
|
||||
public MethodInterceptor methodSecurityInterceptor() throws Exception {
|
||||
MethodSecurityInterceptor methodSecurityInterceptor = isAspectJ() ? new AspectJMethodSecurityInterceptor()
|
||||
this.methodSecurityInterceptor = isAspectJ()
|
||||
? new AspectJMethodSecurityInterceptor()
|
||||
: new MethodSecurityInterceptor();
|
||||
methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
|
||||
methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
|
||||
methodSecurityInterceptor.setAuthenticationManager(authenticationManager());
|
||||
methodSecurityInterceptor
|
||||
.setSecurityMetadataSource(methodSecurityMetadataSource());
|
||||
RunAsManager runAsManager = runAsManager();
|
||||
if (runAsManager != null) {
|
||||
methodSecurityInterceptor.setRunAsManager(runAsManager);
|
||||
}
|
||||
return methodSecurityInterceptor;
|
||||
|
||||
return this.methodSecurityInterceptor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.beans.factory.SmartInitializingSingleton#
|
||||
* afterSingletonsInstantiated()
|
||||
*/
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
try {
|
||||
initializeMethodSecurityInterceptor();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
PermissionEvaluator permissionEvaluator = getSingleBeanOrNull(
|
||||
PermissionEvaluator.class);
|
||||
if (permissionEvaluator != null) {
|
||||
this.defaultMethodExpressionHandler
|
||||
.setPermissionEvaluator(permissionEvaluator);
|
||||
}
|
||||
|
||||
RoleHierarchy roleHierarchy = getSingleBeanOrNull(RoleHierarchy.class);
|
||||
if (roleHierarchy != null) {
|
||||
this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy);
|
||||
}
|
||||
|
||||
AuthenticationTrustResolver trustResolver = getSingleBeanOrNull(
|
||||
AuthenticationTrustResolver.class);
|
||||
if (trustResolver != null) {
|
||||
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T getSingleBeanOrNull(Class<T> type) {
|
||||
String[] beanNamesForType = this.context.getBeanNamesForType(type);
|
||||
if (beanNamesForType == null || beanNamesForType.length != 1) {
|
||||
return null;
|
||||
}
|
||||
return this.context.getBean(beanNamesForType[0], type);
|
||||
}
|
||||
|
||||
private void initializeMethodSecurityInterceptor() throws Exception {
|
||||
if(this.methodSecurityInterceptor == null) {
|
||||
return;
|
||||
}
|
||||
this.methodSecurityInterceptor.setAuthenticationManager(authenticationManager());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,16 +383,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
enableMethodSecurity = AnnotationAttributes.fromMap(annotationAttributes);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setAuthenticationTrustResolver(AuthenticationTrustResolver trustResolver) {
|
||||
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy){
|
||||
this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
@@ -352,16 +396,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||
this.jsr250MethodSecurityMetadataSource = jsr250MethodSecurityMetadataSource;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setPermissionEvaluator(List<PermissionEvaluator> permissionEvaluators) {
|
||||
if (permissionEvaluators.size() != 1) {
|
||||
logger.debug("Not autwiring PermissionEvaluator since size != 1. Got "
|
||||
+ permissionEvaluators);
|
||||
}
|
||||
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators
|
||||
.get(0));
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setMethodSecurityExpressionHandler(
|
||||
List<MethodSecurityExpressionHandler> handlers) {
|
||||
|
||||
+90
-5
@@ -15,17 +15,21 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for
|
||||
@@ -40,6 +44,21 @@ import org.springframework.util.ObjectUtils;
|
||||
public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
protected final void setApplicationContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link ApplicationContext}
|
||||
*
|
||||
* @return the {@link ApplicationContext}
|
||||
*/
|
||||
protected final ApplicationContext getApplicationContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps any request.
|
||||
*
|
||||
@@ -93,6 +112,71 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Maps an {@link MvcRequestMatcher} that does not care which {@link HttpMethod} is
|
||||
* used. This matcher will use the same rules that Spring MVC uses for matching. For
|
||||
* example, often times a mapping of the path "/path" will match on "/path", "/path/",
|
||||
* "/path.html", etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the current request will not be processed by Spring MVC, a reasonable default
|
||||
* using the pattern as a ant pattern will be used.
|
||||
* </p>
|
||||
*
|
||||
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
|
||||
* Spring MVC
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}.
|
||||
*/
|
||||
public abstract C mvcMatchers(String... mvcPatterns);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Maps an {@link MvcRequestMatcher} that also specifies a specific {@link HttpMethod}
|
||||
* to match on. This matcher will use the same rules that Spring MVC uses for
|
||||
* matching. For example, often times a mapping of the path "/path" will match on
|
||||
* "/path", "/path/", "/path.html", etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the current request will not be processed by Spring MVC, a reasonable default
|
||||
* using the pattern as a ant pattern will be used.
|
||||
* </p>
|
||||
*
|
||||
* @param method the HTTP method to match on
|
||||
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
|
||||
* Spring MVC
|
||||
* @return the object that is chained after creating the {@link RequestMatcher}.
|
||||
*/
|
||||
public abstract C mvcMatchers(HttpMethod method, String... mvcPatterns);
|
||||
|
||||
/**
|
||||
* Creates {@link MvcRequestMatcher} instances for the method and patterns passed in
|
||||
*
|
||||
* @param method the HTTP method to use or null if any should be used
|
||||
* @param mvcPatterns the Spring MVC patterns to match on
|
||||
* @return a List of {@link MvcRequestMatcher} instances
|
||||
*/
|
||||
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method,
|
||||
String... mvcPatterns) {
|
||||
boolean isServlet30 = ClassUtils.isPresent("javax.servlet.ServletRegistration", getClass().getClassLoader());
|
||||
ObjectPostProcessor<Object> opp = this.context.getBean(ObjectPostProcessor.class);
|
||||
HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(
|
||||
this.context);
|
||||
List<MvcRequestMatcher> matchers = new ArrayList<MvcRequestMatcher>(
|
||||
mvcPatterns.length);
|
||||
for (String mvcPattern : mvcPatterns) {
|
||||
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
|
||||
if (isServlet30) {
|
||||
opp.postProcess(matcher);
|
||||
}
|
||||
if (method != null) {
|
||||
matcher.setMethod(method);
|
||||
}
|
||||
matchers.add(matcher);
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher}
|
||||
@@ -222,4 +306,5 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||
private RequestMatchers() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ package org.springframework.security.config.annotation.web;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
|
||||
+3
@@ -44,6 +44,7 @@ import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* An internal use only {@link Comparator} that sorts the Security {@link Filter}
|
||||
@@ -70,6 +71,8 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
|
||||
order += STEP;
|
||||
put(HeaderWriterFilter.class, order);
|
||||
order += STEP;
|
||||
put(CorsFilter.class, order);
|
||||
order += STEP;
|
||||
put(CsrfFilter.class, order);
|
||||
order += STEP;
|
||||
put(LogoutFilter.class, order);
|
||||
|
||||
+127
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,8 @@ import java.util.Map;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||
@@ -38,6 +40,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.CorsConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||
@@ -61,7 +64,9 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.PortMapperImpl;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
@@ -69,6 +74,9 @@ import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the
|
||||
@@ -109,7 +117,7 @@ public final class HttpSecurity extends
|
||||
AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
|
||||
implements SecurityBuilder<DefaultSecurityFilterChain>,
|
||||
HttpSecurityBuilder<HttpSecurity> {
|
||||
private final RequestMatcherConfigurer requestMatcherConfigurer = new RequestMatcherConfigurer();
|
||||
private final RequestMatcherConfigurer requestMatcherConfigurer;
|
||||
private List<Filter> filters = new ArrayList<Filter>();
|
||||
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
|
||||
private FilterComparator comparator = new FilterComparator();
|
||||
@@ -122,15 +130,24 @@ public final class HttpSecurity extends
|
||||
* @param sharedObjects the shared Objects to initialize the {@link HttpSecurity} with
|
||||
* @see WebSecurityConfiguration
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor,
|
||||
AuthenticationManagerBuilder authenticationBuilder,
|
||||
Map<Class<Object>, Object> sharedObjects) {
|
||||
Map<Class<? extends Object>, Object> sharedObjects) {
|
||||
super(objectPostProcessor);
|
||||
Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
|
||||
setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
|
||||
for (Map.Entry<Class<Object>, Object> entry : sharedObjects.entrySet()) {
|
||||
setSharedObject(entry.getKey(), entry.getValue());
|
||||
for (Map.Entry<Class<? extends Object>, Object> entry : sharedObjects
|
||||
.entrySet()) {
|
||||
setSharedObject((Class<Object>) entry.getKey(), entry.getValue());
|
||||
}
|
||||
ApplicationContext context = (ApplicationContext) sharedObjects
|
||||
.get(ApplicationContext.class);
|
||||
this.requestMatcherConfigurer = new RequestMatcherConfigurer(context);
|
||||
}
|
||||
|
||||
private ApplicationContext getContext() {
|
||||
return getSharedObject(ApplicationContext.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,6 +334,19 @@ public final class HttpSecurity extends
|
||||
return getOrApply(new HeadersConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is
|
||||
* provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is
|
||||
* defined, then that {@link CorsConfiguration} is used. Otherwise, if Spring MVC is
|
||||
* on the classpath a {@link HandlerMappingIntrospector} is used.
|
||||
*
|
||||
* @return the {@link CorsConfigurer} for customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public CorsConfigurer<HttpSecurity> cors() throws Exception {
|
||||
return getOrApply(new CorsConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring of Session Management.
|
||||
*
|
||||
@@ -617,7 +647,8 @@ public final class HttpSecurity extends
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests()
|
||||
throws Exception {
|
||||
return getOrApply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>())
|
||||
ApplicationContext context = getContext();
|
||||
return getOrApply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>(context))
|
||||
.getRegistry();
|
||||
}
|
||||
|
||||
@@ -693,7 +724,8 @@ public final class HttpSecurity extends
|
||||
* @throws Exception
|
||||
*/
|
||||
public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
|
||||
return getOrApply(new CsrfConfigurer<HttpSecurity>());
|
||||
ApplicationContext context = getContext();
|
||||
return getOrApply(new CsrfConfigurer<HttpSecurity>(context));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -900,7 +932,9 @@ public final class HttpSecurity extends
|
||||
*/
|
||||
public ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry requiresChannel()
|
||||
throws Exception {
|
||||
return getOrApply(new ChannelSecurityConfigurer<HttpSecurity>()).getRegistry();
|
||||
ApplicationContext context = getContext();
|
||||
return getOrApply(new ChannelSecurityConfigurer<HttpSecurity>(context))
|
||||
.getRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1048,12 +1082,12 @@ public final class HttpSecurity extends
|
||||
* Allows specifying which {@link HttpServletRequest} instances this
|
||||
* {@link HttpSecurity} will be invoked on. This method allows for easily invoking the
|
||||
* {@link HttpSecurity} for multiple different {@link RequestMatcher} instances. If
|
||||
* only a single {@link RequestMatcher} is necessary consider using
|
||||
* only a single {@link RequestMatcher} is necessary consider using {@link #mvcMatcher(String)},
|
||||
* {@link #antMatcher(String)}, {@link #regexMatcher(String)}, or
|
||||
* {@link #requestMatcher(RequestMatcher)}.
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #requestMatchers()} will not override previous invocations of
|
||||
* Invoking {@link #requestMatchers()} will not override previous invocations of {@link #mvcMatcher(String)}},
|
||||
* {@link #requestMatchers()}, {@link #antMatcher(String)},
|
||||
* {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}.
|
||||
* </p>
|
||||
@@ -1162,7 +1196,7 @@ public final class HttpSecurity extends
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #requestMatcher(RequestMatcher)} will override previous invocations
|
||||
* of {@link #requestMatchers()}, {@link #antMatcher(String)},
|
||||
* of {@link #requestMatchers()}, {@link #mvcMatcher(String)}, {@link #antMatcher(String)},
|
||||
* {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}.
|
||||
* </p>
|
||||
*
|
||||
@@ -1184,7 +1218,7 @@ public final class HttpSecurity extends
|
||||
* {@link #requestMatchers()} or {@link #requestMatcher(RequestMatcher)}.
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #antMatcher(String)} will override previous invocations of
|
||||
* Invoking {@link #antMatcher(String)} will override previous invocations of {@link #mvcMatcher(String)}},
|
||||
* {@link #requestMatchers()}, {@link #antMatcher(String)},
|
||||
* {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}.
|
||||
* </p>
|
||||
@@ -1197,13 +1231,33 @@ public final class HttpSecurity extends
|
||||
return requestMatcher(new AntPathRequestMatcher(antPattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
|
||||
* provided Spring MVC pattern. If more advanced configuration is necessary, consider using
|
||||
* {@link #requestMatchers()} or {@link #requestMatcher(RequestMatcher)}.
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #mvcMatcher(String)} will override previous invocations of {@link #mvcMatcher(String)}},
|
||||
* {@link #requestMatchers()}, {@link #antMatcher(String)},
|
||||
* {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}.
|
||||
* </p>
|
||||
*
|
||||
* @param mvcPattern the Spring MVC Pattern to match on (i.e. "/admin/**")
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @see MvcRequestMatcher
|
||||
*/
|
||||
public HttpSecurity mvcMatcher(String mvcPattern) {
|
||||
HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(getContext());
|
||||
return requestMatcher(new MvcRequestMatcher(introspector, mvcPattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring the {@link HttpSecurity} to only be invoked when matching the
|
||||
* provided regex pattern. If more advanced configuration is necessary, consider using
|
||||
* {@link #requestMatchers()} or {@link #requestMatcher(RequestMatcher)}.
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #regexMatcher(String)} will override previous invocations of
|
||||
* Invoking {@link #regexMatcher(String)} will override previous invocations of {@link #mvcMatcher(String)}},
|
||||
* {@link #requestMatchers()}, {@link #antMatcher(String)},
|
||||
* {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}.
|
||||
* </p>
|
||||
@@ -1216,23 +1270,78 @@ public final class HttpSecurity extends
|
||||
return requestMatcher(new RegexRequestMatcher(pattern, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension to {@link RequestMatcherConfigurer} that allows optionally configuring
|
||||
* the servlet path.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class MvcMatchersRequestMatcherConfigurer extends RequestMatcherConfigurer {
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param context the {@link ApplicationContext} to use
|
||||
* @param matchers the {@link MvcRequestMatcher} instances to set the servlet path
|
||||
* on if {@link #servletPath(String)} is set.
|
||||
*/
|
||||
private MvcMatchersRequestMatcherConfigurer(ApplicationContext context,
|
||||
List<MvcRequestMatcher> matchers) {
|
||||
super(context);
|
||||
this.matchers = new ArrayList<RequestMatcher>(matchers);
|
||||
}
|
||||
|
||||
public RequestMatcherConfigurer servletPath(String servletPath) {
|
||||
for (RequestMatcher matcher : this.matchers) {
|
||||
((MvcRequestMatcher) matcher).setServletPath(servletPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows mapping HTTP requests that this {@link HttpSecurity} will be used for
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class RequestMatcherConfigurer extends
|
||||
AbstractRequestMatcherRegistry<RequestMatcherConfigurer> {
|
||||
private List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
public class RequestMatcherConfigurer
|
||||
extends AbstractRequestMatcherRegistry<RequestMatcherConfigurer> {
|
||||
|
||||
protected List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
|
||||
/**
|
||||
* @param context
|
||||
*/
|
||||
private RequestMatcherConfigurer(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersRequestMatcherConfigurer mvcMatchers(HttpMethod method,
|
||||
String... mvcPatterns) {
|
||||
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
|
||||
setMatchers(mvcMatchers);
|
||||
return new MvcMatchersRequestMatcherConfigurer(getContext(), mvcMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersRequestMatcherConfigurer mvcMatchers(String... patterns) {
|
||||
return mvcMatchers(null, patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RequestMatcherConfigurer chainRequestMatchers(
|
||||
List<RequestMatcher> requestMatchers) {
|
||||
matchers.addAll(requestMatchers);
|
||||
requestMatcher(new OrRequestMatcher(matchers));
|
||||
setMatchers(requestMatchers);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void setMatchers(List<? extends RequestMatcher> requestMatchers) {
|
||||
this.matchers.addAll(requestMatchers);
|
||||
requestMatcher(new OrRequestMatcher(this.matchers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link HttpSecurity} for further customizations
|
||||
*
|
||||
@@ -1242,8 +1351,6 @@ public final class HttpSecurity extends
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
|
||||
private RequestMatcherConfigurer() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+53
-8
@@ -23,9 +23,11 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
@@ -47,6 +49,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
||||
import org.springframework.security.web.debug.DebugFilter;
|
||||
import org.springframework.security.web.firewall.DefaultHttpFirewall;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
@@ -80,7 +83,7 @@ public final class WebSecurity extends
|
||||
|
||||
private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<SecurityBuilder<? extends SecurityFilterChain>>();
|
||||
|
||||
private final IgnoredRequestConfigurer ignoredRequestRegistry = new IgnoredRequestConfigurer();
|
||||
private IgnoredRequestConfigurer ignoredRequestRegistry;
|
||||
|
||||
private FilterSecurityInterceptor filterSecurityInterceptor;
|
||||
|
||||
@@ -306,6 +309,30 @@ public final class WebSecurity extends
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link IgnoredRequestConfigurer} that allows optionally configuring the
|
||||
* {@link MvcRequestMatcher#setMethod(HttpMethod)}
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class MvcMatchersIgnoredRequestConfigurer
|
||||
extends IgnoredRequestConfigurer {
|
||||
private final List<MvcRequestMatcher> mvcMatchers;
|
||||
|
||||
private MvcMatchersIgnoredRequestConfigurer(ApplicationContext context,
|
||||
List<MvcRequestMatcher> mvcMatchers) {
|
||||
super(context);
|
||||
this.mvcMatchers = mvcMatchers;
|
||||
}
|
||||
|
||||
public IgnoredRequestConfigurer servletPath(String servletPath) {
|
||||
for (MvcRequestMatcher matcher : this.mvcMatchers) {
|
||||
matcher.setServletPath(servletPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows registering {@link RequestMatcher} instances that should be ignored by
|
||||
* Spring Security.
|
||||
@@ -313,13 +340,31 @@ public final class WebSecurity extends
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class IgnoredRequestConfigurer extends
|
||||
AbstractRequestMatcherRegistry<IgnoredRequestConfigurer> {
|
||||
public class IgnoredRequestConfigurer
|
||||
extends AbstractRequestMatcherRegistry<IgnoredRequestConfigurer> {
|
||||
|
||||
private IgnoredRequestConfigurer(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersIgnoredRequestConfigurer mvcMatchers(HttpMethod method,
|
||||
String... mvcPatterns) {
|
||||
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
|
||||
WebSecurity.this.ignoredRequests.addAll(mvcMatchers);
|
||||
return new MvcMatchersIgnoredRequestConfigurer(getApplicationContext(),
|
||||
mvcMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersIgnoredRequestConfigurer mvcMatchers(String... mvcPatterns) {
|
||||
return mvcMatchers(null, mvcPatterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IgnoredRequestConfigurer chainRequestMatchers(
|
||||
List<RequestMatcher> requestMatchers) {
|
||||
ignoredRequests.addAll(requestMatchers);
|
||||
WebSecurity.this.ignoredRequests.addAll(requestMatchers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -329,13 +374,13 @@ public final class WebSecurity extends
|
||||
public WebSecurity and() {
|
||||
return WebSecurity.this;
|
||||
}
|
||||
|
||||
private IgnoredRequestConfigurer() {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
defaultWebSecurityExpressionHandler.setApplicationContext(applicationContext);
|
||||
this.defaultWebSecurityExpressionHandler
|
||||
.setApplicationContext(applicationContext);
|
||||
this.ignoredRequestRegistry = new IgnoredRequestConfigurer(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -38,7 +38,6 @@ import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.context.DelegatingApplicationListener;
|
||||
@@ -46,7 +45,7 @@ import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
|
||||
|
||||
+32
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,10 @@ package org.springframework.security.config.annotation.web.configuration;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -103,7 +105,7 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
* enabled. Disabling the default configuration should be considered more advanced
|
||||
* usage as it requires more understanding of how the framework is implemented.
|
||||
*
|
||||
* @param disableDefaults true if the default configuration should be enabled, else
|
||||
* @param disableDefaults true if the default configuration should be disabled, else
|
||||
* false
|
||||
*/
|
||||
protected WebSecurityConfigurerAdapter(boolean disableDefaults) {
|
||||
@@ -174,12 +176,10 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
|
||||
AuthenticationManager authenticationManager = authenticationManager();
|
||||
authenticationBuilder.parentAuthenticationManager(authenticationManager);
|
||||
Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
|
||||
|
||||
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
|
||||
localConfigureAuthenticationBldr.getSharedObjects());
|
||||
http.setSharedObject(UserDetailsService.class, userDetailsService());
|
||||
http.setSharedObject(ApplicationContext.class, context);
|
||||
http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy);
|
||||
http.setSharedObject(AuthenticationTrustResolver.class, trustResolver);
|
||||
sharedObjects);
|
||||
if (!disableDefaults) {
|
||||
// @formatter:off
|
||||
http
|
||||
@@ -329,6 +329,14 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
/**
|
||||
* Gets the ApplicationContext
|
||||
* @return the context
|
||||
*/
|
||||
protected final ApplicationContext getApplicationContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setApplicationContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
@@ -367,6 +375,21 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
this.authenticationConfiguration = authenticationConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the shared objects
|
||||
*
|
||||
* @return the shared Objects
|
||||
*/
|
||||
private Map<Class<? extends Object>, Object> createSharedObjects() {
|
||||
Map<Class<? extends Object>, Object> sharedObjects = new HashMap<Class<? extends Object>, Object>();
|
||||
sharedObjects.putAll(localConfigureAuthenticationBldr.getSharedObjects());
|
||||
sharedObjects.put(UserDetailsService.class, userDetailsService());
|
||||
sharedObjects.put(ApplicationContext.class, context);
|
||||
sharedObjects.put(ContentNegotiationStrategy.class, contentNegotiationStrategy);
|
||||
sharedObjects.put(AuthenticationTrustResolver.class, trustResolver);
|
||||
return sharedObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays the use of the {@link UserDetailsService} from the
|
||||
* {@link AuthenticationManagerBuilder} to ensure that it has been fully configured.
|
||||
@@ -481,4 +504,5 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-2
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -37,7 +38,10 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
|
||||
@@ -243,10 +247,17 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
if (contentNegotiationStrategy == null) {
|
||||
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
|
||||
}
|
||||
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(
|
||||
|
||||
MediaTypeRequestMatcher mediaMatcher = new MediaTypeRequestMatcher(
|
||||
contentNegotiationStrategy, MediaType.APPLICATION_XHTML_XML,
|
||||
new MediaType("image", "*"), MediaType.TEXT_HTML, MediaType.TEXT_PLAIN);
|
||||
preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
|
||||
mediaMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
|
||||
|
||||
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
|
||||
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
|
||||
|
||||
RequestMatcher preferredMatcher = new AndRequestMatcher(Arrays.asList(notXRequestedWith, mediaMatcher));
|
||||
|
||||
exceptionHandling.defaultAuthenticationEntryPointFor(
|
||||
postProcess(authenticationEntryPoint), preferredMatcher);
|
||||
}
|
||||
|
||||
+40
-9
@@ -20,6 +20,8 @@ import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
@@ -36,6 +38,7 @@ import org.springframework.security.web.access.channel.RetryWithHttpEntryPoint;
|
||||
import org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint;
|
||||
import org.springframework.security.web.access.channel.SecureChannelProcessor;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
/**
|
||||
@@ -80,13 +83,14 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
|
||||
private LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
|
||||
private List<ChannelProcessor> channelProcessors;
|
||||
|
||||
private final ChannelRequestMatcherRegistry REGISTRY = new ChannelRequestMatcherRegistry();
|
||||
private final ChannelRequestMatcherRegistry REGISTRY;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#requiresChannel()
|
||||
*/
|
||||
public ChannelSecurityConfigurer() {
|
||||
public ChannelSecurityConfigurer(ApplicationContext context) {
|
||||
this.REGISTRY = new ChannelRequestMatcherRegistry(context);
|
||||
}
|
||||
|
||||
public ChannelRequestMatcherRegistry getRegistry() {
|
||||
@@ -134,7 +138,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
|
||||
}
|
||||
|
||||
private ChannelRequestMatcherRegistry addAttribute(String attribute,
|
||||
List<RequestMatcher> matchers) {
|
||||
List<? extends RequestMatcher> matchers) {
|
||||
for (RequestMatcher matcher : matchers) {
|
||||
Collection<ConfigAttribute> attrs = Arrays
|
||||
.<ConfigAttribute> asList(new SecurityConfig(attribute));
|
||||
@@ -143,8 +147,24 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public final class ChannelRequestMatcherRegistry extends
|
||||
AbstractConfigAttributeRequestMatcherRegistry<RequiresChannelUrl> {
|
||||
public final class ChannelRequestMatcherRegistry
|
||||
extends AbstractConfigAttributeRequestMatcherRegistry<RequiresChannelUrl> {
|
||||
|
||||
private ChannelRequestMatcherRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersRequiresChannelUrl mvcMatchers(HttpMethod method,
|
||||
String... mvcPatterns) {
|
||||
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
|
||||
return new MvcMatchersRequiresChannelUrl(mvcMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersRequiresChannelUrl mvcMatchers(String... patterns) {
|
||||
return mvcMatchers(null, patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RequiresChannelUrl chainRequestMatchersInternal(
|
||||
@@ -185,15 +205,26 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
|
||||
public H and() {
|
||||
return ChannelSecurityConfigurer.this.and();
|
||||
}
|
||||
}
|
||||
|
||||
private ChannelRequestMatcherRegistry() {
|
||||
public final class MvcMatchersRequiresChannelUrl extends RequiresChannelUrl {
|
||||
|
||||
private MvcMatchersRequiresChannelUrl(List<MvcRequestMatcher> matchers) {
|
||||
super(matchers);
|
||||
}
|
||||
|
||||
public RequiresChannelUrl servletPath(String servletPath) {
|
||||
for (RequestMatcher matcher : this.requestMatchers) {
|
||||
((MvcRequestMatcher) matcher).setServletPath(servletPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public final class RequiresChannelUrl {
|
||||
private List<RequestMatcher> requestMatchers;
|
||||
public class RequiresChannelUrl {
|
||||
protected List<? extends RequestMatcher> requestMatchers;
|
||||
|
||||
private RequiresChannelUrl(List<RequestMatcher> requestMatchers) {
|
||||
private RequiresChannelUrl(List<? extends RequestMatcher> requestMatchers) {
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Adds {@link CorsFilter} to the Spring Security filter chain. If a bean by the name of
|
||||
* corsFilter is provided, that {@link CorsFilter} is used. Else if
|
||||
* corsConfigurationSource is defined, then that {@link CorsConfiguration} is used.
|
||||
* Otherwise, if Spring MVC is on the classpath a {@link HandlerMappingIntrospector} is
|
||||
* used.
|
||||
*
|
||||
* @param <H> the builder to return.
|
||||
* @author Rob Winch
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<CorsConfigurer<H>, H> {
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
private static final String CORS_CONFIGURATION_SOURCE_BEAN_NAME = "corsConfigurationSource";
|
||||
private static final String CORS_FILTER_BEAN_NAME = "corsFilter";
|
||||
|
||||
private CorsConfigurationSource configurationSource;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @see HttpSecurity#cors()
|
||||
*/
|
||||
public CorsConfigurer() {
|
||||
}
|
||||
|
||||
public CorsConfigurer<H> configurationSource(
|
||||
CorsConfigurationSource configurationSource) {
|
||||
this.configurationSource = configurationSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
|
||||
|
||||
CorsFilter corsFilter = getCorsFilter(context);
|
||||
if (corsFilter == null) {
|
||||
throw new IllegalStateException(
|
||||
"Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "
|
||||
+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");
|
||||
}
|
||||
http.addFilter(corsFilter);
|
||||
}
|
||||
|
||||
private CorsFilter getCorsFilter(ApplicationContext context) {
|
||||
if (this.configurationSource != null) {
|
||||
return new CorsFilter(this.configurationSource);
|
||||
}
|
||||
|
||||
boolean containsCorsFilter = context
|
||||
.containsBeanDefinition(CORS_FILTER_BEAN_NAME);
|
||||
if (containsCorsFilter) {
|
||||
return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);
|
||||
}
|
||||
|
||||
boolean containsCorsSource = context
|
||||
.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);
|
||||
if (containsCorsSource) {
|
||||
CorsConfigurationSource configurationSource = context.getBean(
|
||||
CORS_CONFIGURATION_SOURCE_BEAN_NAME, CorsConfigurationSource.class);
|
||||
return new CorsFilter(configurationSource);
|
||||
}
|
||||
|
||||
boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
|
||||
context.getClassLoader());
|
||||
if (mvcPresent) {
|
||||
return MvcCorsFilter.getMvcCorsFilter(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static class MvcCorsFilter {
|
||||
/**
|
||||
* This needs to be isolated into a separate class as Spring MVC is an optional
|
||||
* dependency and will potentially cause ClassLoading issues
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
private static CorsFilter getMvcCorsFilter(ApplicationContext context) {
|
||||
HandlerMappingIntrospector mappingIntrospector = new HandlerMappingIntrospector(
|
||||
context);
|
||||
return new CorsFilter(mappingIntrospector);
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
-2
@@ -21,6 +21,8 @@ import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
@@ -35,6 +37,7 @@ import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.LazyCsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
|
||||
import org.springframework.security.web.session.InvalidSessionStrategy;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
@@ -78,12 +81,14 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
new HttpSessionCsrfTokenRepository());
|
||||
private RequestMatcher requireCsrfProtectionMatcher = CsrfFilter.DEFAULT_CSRF_MATCHER;
|
||||
private List<RequestMatcher> ignoredCsrfProtectionMatchers = new ArrayList<RequestMatcher>();
|
||||
private final ApplicationContext context;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#csrf()
|
||||
*/
|
||||
public CsrfConfigurer() {
|
||||
public CsrfConfigurer(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +146,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @since 4.0
|
||||
*/
|
||||
public CsrfConfigurer<H> ignoringAntMatchers(String... antPatterns) {
|
||||
return new IgnoreCsrfProtectionRegistry().antMatchers(antPatterns).and();
|
||||
return new IgnoreCsrfProtectionRegistry(this.context).antMatchers(antPatterns)
|
||||
.and();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -265,6 +271,27 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
private class IgnoreCsrfProtectionRegistry
|
||||
extends AbstractRequestMatcherRegistry<IgnoreCsrfProtectionRegistry> {
|
||||
|
||||
/**
|
||||
* @param context
|
||||
*/
|
||||
private IgnoreCsrfProtectionRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersIgnoreCsrfProtectionRegistry mvcMatchers(HttpMethod method,
|
||||
String... mvcPatterns) {
|
||||
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
|
||||
CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(mvcMatchers);
|
||||
return new MvcMatchersIgnoreCsrfProtectionRegistry(getApplicationContext(),
|
||||
mvcMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersIgnoreCsrfProtectionRegistry mvcMatchers(String... mvcPatterns) {
|
||||
return mvcMatchers(null, mvcPatterns);
|
||||
}
|
||||
|
||||
public CsrfConfigurer<H> and() {
|
||||
return CsrfConfigurer.this;
|
||||
}
|
||||
@@ -276,4 +303,28 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link IgnoreCsrfProtectionRegistry} that allows optionally configuring the
|
||||
* {@link MvcRequestMatcher#setMethod(HttpMethod)}
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
private final class MvcMatchersIgnoreCsrfProtectionRegistry
|
||||
extends IgnoreCsrfProtectionRegistry {
|
||||
private final List<MvcRequestMatcher> mvcMatchers;
|
||||
|
||||
private MvcMatchersIgnoreCsrfProtectionRegistry(ApplicationContext context,
|
||||
List<MvcRequestMatcher> mvcMatchers) {
|
||||
super(context);
|
||||
this.mvcMatchers = mvcMatchers;
|
||||
}
|
||||
|
||||
public IgnoreCsrfProtectionRegistry servletPath(String servletPath) {
|
||||
for (MvcRequestMatcher matcher : this.mvcMatchers) {
|
||||
matcher.setServletPath(servletPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
-5
@@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
@@ -34,6 +35,7 @@ import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -84,7 +86,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
private static final String fullyAuthenticated = "fullyAuthenticated";
|
||||
private static final String rememberMe = "rememberMe";
|
||||
|
||||
private final ExpressionInterceptUrlRegistry REGISTRY = new ExpressionInterceptUrlRegistry();
|
||||
private final ExpressionInterceptUrlRegistry REGISTRY;
|
||||
|
||||
private SecurityExpressionHandler<FilterInvocation> expressionHandler;
|
||||
|
||||
@@ -92,7 +94,8 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#authorizeRequests()
|
||||
*/
|
||||
public ExpressionUrlAuthorizationConfigurer() {
|
||||
public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
|
||||
this.REGISTRY = new ExpressionInterceptUrlRegistry(context);
|
||||
}
|
||||
|
||||
public ExpressionInterceptUrlRegistry getRegistry() {
|
||||
@@ -103,6 +106,23 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
extends
|
||||
ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry, AuthorizedUrl> {
|
||||
|
||||
/**
|
||||
* @param context
|
||||
*/
|
||||
private ExpressionInterceptUrlRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
|
||||
return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) {
|
||||
return mvcMatchers(null, patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final AuthorizedUrl chainRequestMatchersInternal(
|
||||
List<RequestMatcher> requestMatchers) {
|
||||
@@ -233,8 +253,32 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
return "hasIpAddress('" + ipAddressExpression + "')";
|
||||
}
|
||||
|
||||
public final class AuthorizedUrl {
|
||||
private List<RequestMatcher> requestMatchers;
|
||||
/**
|
||||
* An {@link AuthorizedUrl} that allows optionally configuring the
|
||||
* {@link MvcRequestMatcher#setMethod(HttpMethod)}
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class MvcMatchersAuthorizedUrl extends AuthorizedUrl {
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map
|
||||
*/
|
||||
private MvcMatchersAuthorizedUrl(List<MvcRequestMatcher> requestMatchers) {
|
||||
super(requestMatchers);
|
||||
}
|
||||
|
||||
public AuthorizedUrl servletPath(String servletPath) {
|
||||
for (MvcRequestMatcher matcher : (List<MvcRequestMatcher>) getMatchers()) {
|
||||
matcher.setServletPath(servletPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AuthorizedUrl {
|
||||
private List<? extends RequestMatcher> requestMatchers;
|
||||
private boolean not;
|
||||
|
||||
/**
|
||||
@@ -242,10 +286,14 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map
|
||||
*/
|
||||
private AuthorizedUrl(List<RequestMatcher> requestMatchers) {
|
||||
private AuthorizedUrl(List<? extends RequestMatcher> requestMatchers) {
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
protected List<? extends RequestMatcher> getMatchers() {
|
||||
return this.requestMatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negates the following expression.
|
||||
*
|
||||
|
||||
+29
-14
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@@ -32,10 +33,12 @@ import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
@@ -76,6 +79,10 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
*/
|
||||
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
AbstractHttpConfigurer<HttpBasicConfigurer<B>, B> {
|
||||
|
||||
private static final RequestHeaderRequestMatcher X_REQUESTED_WITH = new RequestHeaderRequestMatcher("X-Requested-With",
|
||||
"XMLHttpRequest");
|
||||
|
||||
private static final String DEFAULT_REALM = "Realm";
|
||||
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
@@ -91,13 +98,12 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
realmName(DEFAULT_REALM);
|
||||
|
||||
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<RequestMatcher, AuthenticationEntryPoint>();
|
||||
entryPoints.put(new RequestHeaderRequestMatcher("X-Requested-With",
|
||||
"XMLHttpRequest"), new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
|
||||
entryPoints.put(X_REQUESTED_WITH, new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
|
||||
|
||||
DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(
|
||||
entryPoints);
|
||||
defaultEntryPoint.setDefaultEntryPoint(basicAuthEntryPoint);
|
||||
authenticationEntryPoint = defaultEntryPoint;
|
||||
defaultEntryPoint.setDefaultEntryPoint(this.basicAuthEntryPoint);
|
||||
this.authenticationEntryPoint = defaultEntryPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,8 +116,8 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
* @throws Exception
|
||||
*/
|
||||
public HttpBasicConfigurer<B> realmName(String realmName) throws Exception {
|
||||
basicAuthEntryPoint.setRealmName(realmName);
|
||||
basicAuthEntryPoint.afterPropertiesSet();
|
||||
this.basicAuthEntryPoint.setRealmName(realmName);
|
||||
this.basicAuthEntryPoint.afterPropertiesSet();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -144,23 +150,32 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(B http) throws Exception {
|
||||
registerDefaults(http);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerDefaults(B http) {
|
||||
ContentNegotiationStrategy contentNegotiationStrategy = http
|
||||
.getSharedObject(ContentNegotiationStrategy.class);
|
||||
if (contentNegotiationStrategy == null) {
|
||||
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
|
||||
}
|
||||
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(
|
||||
|
||||
MediaTypeRequestMatcher restMatcher = new MediaTypeRequestMatcher(
|
||||
contentNegotiationStrategy, MediaType.APPLICATION_ATOM_XML,
|
||||
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
|
||||
MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML,
|
||||
MediaType.MULTIPART_FORM_DATA, MediaType.TEXT_XML);
|
||||
preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
|
||||
restMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
|
||||
|
||||
RequestMatcher notHtmlMatcher = new NegatedRequestMatcher(
|
||||
new MediaTypeRequestMatcher(contentNegotiationStrategy,
|
||||
MediaType.TEXT_HTML));
|
||||
RequestMatcher restNotHtmlMatcher = new AndRequestMatcher(
|
||||
Arrays.<RequestMatcher>asList(notHtmlMatcher, restMatcher));
|
||||
|
||||
RequestMatcher preferredMatcher = new OrRequestMatcher(Arrays.asList(X_REQUESTED_WITH, restNotHtmlMatcher));
|
||||
|
||||
registerDefaultEntryPoint(http, preferredMatcher);
|
||||
registerDefaultLogoutSuccessHandler(http, preferredMatcher);
|
||||
@@ -173,7 +188,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
return;
|
||||
}
|
||||
exceptionHandling.defaultAuthenticationEntryPointFor(
|
||||
postProcess(authenticationEntryPoint), preferredMatcher);
|
||||
postProcess(this.authenticationEntryPoint), preferredMatcher);
|
||||
}
|
||||
|
||||
private void registerDefaultLogoutSuccessHandler(B http, RequestMatcher preferredMatcher) {
|
||||
@@ -191,10 +206,10 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
AuthenticationManager authenticationManager = http
|
||||
.getSharedObject(AuthenticationManager.class);
|
||||
BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(
|
||||
authenticationManager, authenticationEntryPoint);
|
||||
if (authenticationDetailsSource != null) {
|
||||
authenticationManager, this.authenticationEntryPoint);
|
||||
if (this.authenticationDetailsSource != null) {
|
||||
basicAuthenticationFilter
|
||||
.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
.setAuthenticationDetailsSource(this.authenticationDetailsSource);
|
||||
}
|
||||
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
|
||||
if(rememberMeServices != null) {
|
||||
|
||||
+7
-2
@@ -25,7 +25,6 @@ import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.DelegatingLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
@@ -35,6 +34,7 @@ import org.springframework.security.web.authentication.logout.SecurityContextLog
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -346,7 +346,12 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
|
||||
}
|
||||
else {
|
||||
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl);
|
||||
this.logoutRequestMatcher = new OrRequestMatcher(
|
||||
new AntPathRequestMatcher(this.logoutUrl, "GET"),
|
||||
new AntPathRequestMatcher(this.logoutUrl, "POST"),
|
||||
new AntPathRequestMatcher(this.logoutUrl, "PUT"),
|
||||
new AntPathRequestMatcher(this.logoutUrl, "DELETE")
|
||||
);
|
||||
}
|
||||
return this.logoutRequestMatcher;
|
||||
}
|
||||
|
||||
-2
@@ -18,10 +18,8 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.PortMapperImpl;
|
||||
|
||||
|
||||
+34
-2
@@ -79,12 +79,16 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
|
||||
*/
|
||||
public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<RememberMeConfigurer<H>, H> {
|
||||
/**
|
||||
* The default name for remember me parameter name and remember me cookie name
|
||||
*/
|
||||
private static final String DEFAULT_REMEMBER_ME_NAME = "remember-me";
|
||||
private AuthenticationSuccessHandler authenticationSuccessHandler;
|
||||
private String key;
|
||||
private RememberMeServices rememberMeServices;
|
||||
private LogoutHandler logoutHandler;
|
||||
private String rememberMeParameter = "remember-me";
|
||||
private String rememberMeCookieName = "remember-me";
|
||||
private String rememberMeParameter = DEFAULT_REMEMBER_ME_NAME;
|
||||
private String rememberMeCookieName = DEFAULT_REMEMBER_ME_NAME;
|
||||
private String rememberMeCookieDomain;
|
||||
private PersistentTokenRepository tokenRepository;
|
||||
private UserDetailsService userDetailsService;
|
||||
@@ -241,9 +245,26 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the cookie should always be created even if the remember-me parameter is
|
||||
* not set.
|
||||
* <p>
|
||||
* By default this will be set to {@code false}.
|
||||
*
|
||||
* @param alwaysRemember set to {@code true} to always trigger remember me,
|
||||
* {@code false} to use the remember-me parameter.
|
||||
* @return the {@link RememberMeConfigurer} for further customization
|
||||
* @see AbstractRememberMeServices#setAlwaysRemember(boolean)
|
||||
*/
|
||||
public RememberMeConfigurer<H> alwaysRemember(boolean alwaysRemember) {
|
||||
this.alwaysRemember = alwaysRemember;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
validateInput();
|
||||
String key = getKey();
|
||||
RememberMeServices rememberMeServices = getRememberMeServices(http, key);
|
||||
http.setSharedObject(RememberMeServices.class, rememberMeServices);
|
||||
@@ -273,6 +294,17 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
http.addFilter(rememberMeFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate rememberMeServices and rememberMeCookieName have not been set at
|
||||
* the same time.
|
||||
*/
|
||||
private void validateInput() {
|
||||
if (this.rememberMeServices != null && this.rememberMeCookieName != DEFAULT_REMEMBER_ME_NAME) {
|
||||
throw new IllegalArgumentException("Can not set rememberMeCookieName " +
|
||||
"and custom rememberMeServices.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP parameter used to indicate to remember the user at time of login.
|
||||
* @return the HTTP parameter used to indicate to remember the user
|
||||
|
||||
+59
-5
@@ -19,6 +19,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
@@ -27,9 +29,10 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer.AuthorizedUrl;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -87,7 +90,11 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
AbstractInterceptUrlConfigurer<UrlAuthorizationConfigurer<H>, H> {
|
||||
private final StandardInterceptUrlRegistry REGISTRY = new StandardInterceptUrlRegistry();
|
||||
private final StandardInterceptUrlRegistry REGISTRY;
|
||||
|
||||
public UrlAuthorizationConfigurer(ApplicationContext context) {
|
||||
this.REGISTRY = new StandardInterceptUrlRegistry(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* The StandardInterceptUrlRegistry is what users will interact with after applying
|
||||
@@ -115,6 +122,24 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends
|
||||
ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<StandardInterceptUrlRegistry, AuthorizedUrl> {
|
||||
|
||||
/**
|
||||
* @param context
|
||||
*/
|
||||
private StandardInterceptUrlRegistry(ApplicationContext context) {
|
||||
setApplicationContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method,
|
||||
String... mvcPatterns) {
|
||||
return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) {
|
||||
return mvcMatchers(null, patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final AuthorizedUrl chainRequestMatchersInternal(
|
||||
List<RequestMatcher> requestMatchers) {
|
||||
@@ -226,6 +251,31 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return authorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AuthorizedUrl} that allows optionally configuring the
|
||||
* {@link MvcRequestMatcher#setMethod(HttpMethod)}
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class MvcMatchersAuthorizedUrl extends AuthorizedUrl {
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map
|
||||
*/
|
||||
private MvcMatchersAuthorizedUrl(List<MvcRequestMatcher> requestMatchers) {
|
||||
super(requestMatchers);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public AuthorizedUrl servletPath(String servletPath) {
|
||||
for (MvcRequestMatcher matcher : (List<MvcRequestMatcher>) getMatchers()) {
|
||||
matcher.setServletPath(servletPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified {@link RequestMatcher} instances to {@link ConfigAttribute}
|
||||
* instances.
|
||||
@@ -233,15 +283,15 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class AuthorizedUrl {
|
||||
private final List<RequestMatcher> requestMatchers;
|
||||
public class AuthorizedUrl {
|
||||
private final List<? extends RequestMatcher> requestMatchers;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param requestMatchers the {@link RequestMatcher} instances to map to some
|
||||
* {@link ConfigAttribute} instances.
|
||||
*/
|
||||
private AuthorizedUrl(List<RequestMatcher> requestMatchers) {
|
||||
private AuthorizedUrl(List<? extends RequestMatcher> requestMatchers) {
|
||||
Assert.notEmpty(requestMatchers,
|
||||
"requestMatchers must contain at least one value");
|
||||
this.requestMatchers = requestMatchers;
|
||||
@@ -307,5 +357,9 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
addMapping(requestMatchers, SecurityConfig.createList(attributes));
|
||||
return UrlAuthorizationConfigurer.this.REGISTRY;
|
||||
}
|
||||
|
||||
protected List<? extends RequestMatcher> getMatchers() {
|
||||
return this.requestMatchers;
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.servlet.configuration
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
|
||||
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ import java.util.Arrays;
|
||||
public class AuthenticationManagerFactoryBean implements
|
||||
FactoryBean<AuthenticationManager>, BeanFactoryAware {
|
||||
private BeanFactory bf;
|
||||
public static final String MISSING_BEAN_ERROR_MESSAGE = "Did you forget to add a gobal <authentication-manager> element "
|
||||
public static final String MISSING_BEAN_ERROR_MESSAGE = "Did you forget to add a global <authentication-manager> element "
|
||||
+ "to your configuration (with child <authentication-provider> elements)? Alternatively you can use the "
|
||||
+ "authentication-manager-ref attribute on your <http> and <global-method-security> elements.";
|
||||
|
||||
|
||||
-1
@@ -30,7 +30,6 @@ import org.springframework.security.authentication.encoding.BaseDigestPasswordEn
|
||||
import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.Md4PasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.PasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
|
||||
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
|
||||
import org.springframework.security.config.Elements;
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ package org.springframework.security.config.authentication;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
|
||||
-2
@@ -22,8 +22,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* Parser for the {@code CorsFilter}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public class CorsBeanDefinitionParser {
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final String ATT_SOURCE = "configuration-source-ref";
|
||||
private static final String ATT_REF = "ref";
|
||||
|
||||
public BeanMetadataElement parse(Element element, ParserContext parserContext) {
|
||||
if(element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String filterRef = element.getAttribute(ATT_REF);
|
||||
if(StringUtils.hasText(filterRef)) {
|
||||
return new RuntimeBeanReference(filterRef);
|
||||
}
|
||||
|
||||
BeanMetadataElement configurationSource = getSource(element, parserContext);
|
||||
if(configurationSource == null) {
|
||||
throw new BeanCreationException("Could not create CorsFilter");
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterBldr = BeanDefinitionBuilder.rootBeanDefinition(CorsFilter.class);
|
||||
filterBldr.addConstructorArgValue(configurationSource);
|
||||
return filterBldr.getBeanDefinition();
|
||||
}
|
||||
|
||||
public BeanMetadataElement getSource(Element element, ParserContext parserContext) {
|
||||
String configurationSourceRef = element.getAttribute(ATT_SOURCE);
|
||||
if (StringUtils.hasText(configurationSourceRef)) {
|
||||
return new RuntimeBeanReference(configurationSourceRef);
|
||||
}
|
||||
|
||||
boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
|
||||
getClass().getClassLoader());
|
||||
if(!mvcPresent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder configurationSourceBldr = BeanDefinitionBuilder.rootBeanDefinition(HANDLER_MAPPING_INTROSPECTOR);
|
||||
configurationSourceBldr.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
|
||||
return configurationSourceBldr.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -19,11 +19,9 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -47,7 +45,7 @@ public class FilterChainBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
if (StringUtils.hasText(path)) {
|
||||
Assert.isTrue(!StringUtils.hasText(requestMatcher), "");
|
||||
builder.addConstructorArgValue(matcherType.createMatcher(path, null));
|
||||
builder.addConstructorArgValue(matcherType.createMatcher(pc, path, null));
|
||||
}
|
||||
else {
|
||||
Assert.isTrue(StringUtils.hasText(requestMatcher), "");
|
||||
|
||||
+1
-5
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -26,7 +23,6 @@ import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.config.Elements;
|
||||
@@ -75,7 +71,7 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
|
||||
+ "'must not be empty", elt);
|
||||
}
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, null);
|
||||
BeanDefinition matcher = matcherType.createMatcher(parserContext, path, null);
|
||||
|
||||
if (filters.equals(HttpSecurityBeanDefinitionParser.OPT_FILTERS_NONE)) {
|
||||
securityFilterChains.add(createSecurityFilterChain(matcher,
|
||||
|
||||
+22
-5
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -37,6 +35,8 @@ import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Allows for convenient creation of a {@link FilterInvocationSecurityMetadataSource} bean
|
||||
* for use with a FilterSecurityInterceptor.
|
||||
@@ -48,12 +48,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
private static final String ATT_HTTP_METHOD = "method";
|
||||
private static final String ATT_PATTERN = "pattern";
|
||||
private static final String ATT_ACCESS = "access";
|
||||
private static final String ATT_SERVLET_PATH = "servlet-path";
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(FilterInvocationSecurityMetadataSourceParser.class);
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
List<Element> interceptUrls = DomUtils.getChildElementsByTagName(element,
|
||||
"intercept-url");
|
||||
Elements.INTERCEPT_URL);
|
||||
|
||||
// Check for attributes that aren't allowed in this context
|
||||
for (Element elt : interceptUrls) {
|
||||
@@ -71,6 +72,12 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
"The attribute '" + HttpSecurityBeanDefinitionParser.ATT_FILTERS
|
||||
+ "' isn't allowed here.", elt);
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(elt.getAttribute(ATT_SERVLET_PATH))) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The attribute '" + ATT_SERVLET_PATH
|
||||
+ "' isn't allowed here.", elt);
|
||||
}
|
||||
}
|
||||
|
||||
BeanDefinition mds = createSecurityMetadataSource(interceptUrls, false, element,
|
||||
@@ -165,7 +172,16 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
method = null;
|
||||
}
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, method);
|
||||
String servletPath = urlElt.getAttribute(ATT_SERVLET_PATH);
|
||||
if (!StringUtils.hasText(servletPath)) {
|
||||
servletPath = null;
|
||||
} else if (!MatcherType.mvc.equals(matcherType)) {
|
||||
parserContext.getReaderContext().error(
|
||||
ATT_SERVLET_PATH + " is not applicable for request-matcher: '" + matcherType.name() + "'", urlElt);
|
||||
}
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher(parserContext, path,
|
||||
method, servletPath);
|
||||
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(SecurityConfig.class);
|
||||
|
||||
@@ -194,7 +210,8 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
|
||||
if (addAuthenticatedAll && filterInvocationDefinitionMap.isEmpty()) {
|
||||
|
||||
BeanDefinition matcher = matcherType.createMatcher("/**", null);
|
||||
BeanDefinition matcher = matcherType.createMatcher(parserContext, "/**",
|
||||
null);
|
||||
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(SecurityConfig.class);
|
||||
attributeBuilder.addConstructorArgValue(new String[] { "authenticated" });
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Used for creating an instance of {@link HandlerMappingIntrospector} and autowiring the
|
||||
* {@link ApplicationContext}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class HandlerMappingIntrospectorFactoryBean implements ApplicationContextAware {
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
HandlerMappingIntrospector createHandlerMappingIntrospector() {
|
||||
return new HandlerMappingIntrospector(this.context);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.
|
||||
* springframework.context.ApplicationContext)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.context = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
+12
-1
@@ -127,6 +127,7 @@ class HttpConfigurationBuilder {
|
||||
private BeanReference fsi;
|
||||
private BeanReference requestCache;
|
||||
private BeanDefinition addHeadersFilter;
|
||||
private BeanMetadataElement corsFilter;
|
||||
private BeanDefinition csrfFilter;
|
||||
private BeanMetadataElement csrfLogoutHandler;
|
||||
private BeanMetadataElement csrfAuthStrategy;
|
||||
@@ -176,6 +177,7 @@ class HttpConfigurationBuilder {
|
||||
createChannelProcessingFilter();
|
||||
createFilterSecurityInterceptor(authenticationManager);
|
||||
createAddHeadersFilter();
|
||||
createCorsFilter();
|
||||
}
|
||||
|
||||
private SessionCreationPolicy createPolicy(String createSession) {
|
||||
@@ -611,7 +613,7 @@ class HttpConfigurationBuilder {
|
||||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||
|
||||
if (StringUtils.hasText(requiredChannel)) {
|
||||
BeanDefinition matcher = matcherType.createMatcher(path, method);
|
||||
BeanDefinition matcher = matcherType.createMatcher(pc, path, method);
|
||||
|
||||
RootBeanDefinition channelAttributes = new RootBeanDefinition(
|
||||
ChannelAttributeFactory.class);
|
||||
@@ -737,6 +739,11 @@ class HttpConfigurationBuilder {
|
||||
private void createAddHeadersFilter() {
|
||||
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.HEADERS);
|
||||
this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, pc);
|
||||
}
|
||||
|
||||
private void createCorsFilter() {
|
||||
Element elmt = DomUtils.getChildElementByTagName(this.httpElt, Elements.CORS);
|
||||
this.corsFilter = new CorsBeanDefinitionParser().parse(elmt, this.pc);
|
||||
|
||||
}
|
||||
|
||||
@@ -808,6 +815,10 @@ class HttpConfigurationBuilder {
|
||||
filters.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
|
||||
}
|
||||
|
||||
if (this.corsFilter != null) {
|
||||
filters.add(new OrderDecorator(this.corsFilter, CORS_FILTER));
|
||||
}
|
||||
|
||||
if (addHeadersFilter != null) {
|
||||
filters.add(new OrderDecorator(addHeadersFilter, HEADERS_FILTER));
|
||||
}
|
||||
|
||||
+1
-1
@@ -198,7 +198,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
}
|
||||
else if (StringUtils.hasText(filterChainPattern)) {
|
||||
filterChainMatcher = MatcherType.fromElement(element).createMatcher(
|
||||
filterChainMatcher = MatcherType.fromElement(element).createMatcher(pc,
|
||||
filterChainPattern, null);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.security.config.http;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
@@ -33,17 +35,24 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
public enum MatcherType {
|
||||
ant(AntPathRequestMatcher.class), regex(RegexRequestMatcher.class), ciRegex(
|
||||
RegexRequestMatcher.class);
|
||||
RegexRequestMatcher.class), mvc(MvcRequestMatcher.class);
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR_FACTORY_BEAN_NAME = "org.springframework.security.config.http.HandlerMappingIntrospectorFactoryBean";
|
||||
|
||||
private static final String ATT_MATCHER_TYPE = "request-matcher";
|
||||
|
||||
private final Class<? extends RequestMatcher> type;
|
||||
final Class<? extends RequestMatcher> type;
|
||||
|
||||
MatcherType(Class<? extends RequestMatcher> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public BeanDefinition createMatcher(String path, String method) {
|
||||
public BeanDefinition createMatcher(ParserContext pc, String path, String method) {
|
||||
return createMatcher(pc, path, method, null);
|
||||
}
|
||||
|
||||
public BeanDefinition createMatcher(ParserContext pc, String path, String method, String servletPath) {
|
||||
if (("/**".equals(path) || "**".equals(path)) && method == null) {
|
||||
return new RootBeanDefinition(AnyRequestMatcher.class);
|
||||
}
|
||||
@@ -51,8 +60,29 @@ public enum MatcherType {
|
||||
BeanDefinitionBuilder matcherBldr = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(type);
|
||||
|
||||
if (this == mvc) {
|
||||
if (!pc.getRegistry().isBeanNameInUse(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder hmifb = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(HandlerMappingIntrospectorFactoryBean.class);
|
||||
pc.getRegistry().registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_FACTORY_BEAN_NAME,
|
||||
hmifb.getBeanDefinition());
|
||||
|
||||
RootBeanDefinition hmi = new RootBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME);
|
||||
hmi.setFactoryBeanName(HANDLER_MAPPING_INTROSPECTOR_FACTORY_BEAN_NAME);
|
||||
hmi.setFactoryMethodName("createHandlerMappingIntrospector");
|
||||
pc.getRegistry().registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, hmi);
|
||||
}
|
||||
matcherBldr.addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME);
|
||||
}
|
||||
|
||||
matcherBldr.addConstructorArgValue(path);
|
||||
matcherBldr.addConstructorArgValue(method);
|
||||
if (this == mvc) {
|
||||
matcherBldr.addPropertyValue("method", method);
|
||||
matcherBldr.addPropertyValue("servletPath", servletPath);
|
||||
}
|
||||
else {
|
||||
matcherBldr.addConstructorArgValue(method);
|
||||
}
|
||||
|
||||
if (this == ciRegex) {
|
||||
matcherBldr.addConstructorArgValue(true);
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.security.web.context.request.async.WebAsyncManagerInt
|
||||
enum SecurityFilters {
|
||||
FIRST(Integer.MIN_VALUE), CHANNEL_FILTER, SECURITY_CONTEXT_FILTER, CONCURRENT_SESSION_FILTER,
|
||||
/** {@link WebAsyncManagerIntegrationFilter} */
|
||||
WEB_ASYNC_MANAGER_FILTER, HEADERS_FILTER, CSRF_FILTER, LOGOUT_FILTER, X509_FILTER, PRE_AUTH_FILTER, CAS_FILTER, FORM_LOGIN_FILTER, OPENID_FILTER, LOGIN_PAGE_FILTER, DIGEST_AUTH_FILTER, BASIC_AUTH_FILTER, REQUEST_CACHE_FILTER, SERVLET_API_SUPPORT_FILTER, JAAS_API_SUPPORT_FILTER, REMEMBER_ME_FILTER, ANONYMOUS_FILTER, SESSION_MANAGEMENT_FILTER, EXCEPTION_TRANSLATION_FILTER, FILTER_SECURITY_INTERCEPTOR, SWITCH_USER_FILTER, LAST(
|
||||
WEB_ASYNC_MANAGER_FILTER, HEADERS_FILTER, CORS_FILTER, CSRF_FILTER, LOGOUT_FILTER, X509_FILTER, PRE_AUTH_FILTER, CAS_FILTER, FORM_LOGIN_FILTER, OPENID_FILTER, LOGIN_PAGE_FILTER, DIGEST_AUTH_FILTER, BASIC_AUTH_FILTER, REQUEST_CACHE_FILTER, SERVLET_API_SUPPORT_FILTER, JAAS_API_SUPPORT_FILTER, REMEMBER_ME_FILTER, ANONYMOUS_FILTER, SESSION_MANAGEMENT_FILTER, EXCEPTION_TRANSLATION_FILTER, FILTER_SECURITY_INTERCEPTOR, SWITCH_USER_FILTER, LAST(
|
||||
Integer.MAX_VALUE);
|
||||
|
||||
private static final int INTERVAL = 100;
|
||||
|
||||
-1
@@ -46,7 +46,6 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
|
||||
import org.springframework.security.access.annotation.Jsr250Voter;
|
||||
|
||||
+2
-2
@@ -759,10 +759,10 @@ frame-options.attlist &=
|
||||
## Specify the strategy to use when ALLOW-FROM is chosen.
|
||||
attribute strategy {"static","whitelist","regexp"}?
|
||||
frame-options.attlist &=
|
||||
## Specify the a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
## Specify a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
ref?
|
||||
frame-options.attlist &=
|
||||
## Specify the a value to use for the chosen strategy.
|
||||
## Specify a value to use for the chosen strategy.
|
||||
attribute value {xsd:string}?
|
||||
frame-options.attlist &=
|
||||
## Specify the request parameter to use for the origin when using a 'whitelist' or 'regexp' based strategy. Default is 'from'.
|
||||
|
||||
+1
-1
@@ -2365,7 +2365,7 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="value" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specify the a value to use for the chosen strategy.
|
||||
<xs:documentation>Specify a value to use for the chosen strategy.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
+2
-2
@@ -785,10 +785,10 @@ frame-options.attlist &=
|
||||
## Specify the strategy to use when ALLOW-FROM is chosen.
|
||||
attribute strategy {"static","whitelist","regexp"}?
|
||||
frame-options.attlist &=
|
||||
## Specify the a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
## Specify a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
ref?
|
||||
frame-options.attlist &=
|
||||
## Specify the a value to use for the chosen strategy.
|
||||
## Specify a value to use for the chosen strategy.
|
||||
attribute value {xsd:string}?
|
||||
frame-options.attlist &=
|
||||
## Specify the request parameter to use for the origin when using a 'whitelist' or 'regexp' based strategy. Default is 'from'.
|
||||
|
||||
+1
-1
@@ -2440,7 +2440,7 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="value" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specify the a value to use for the chosen strategy.
|
||||
<xs:documentation>Specify a value to use for the chosen strategy.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
+19
-7
@@ -12,8 +12,8 @@ base64 =
|
||||
## Whether a string should be base64 encoded
|
||||
attribute base64 {xsd:boolean}
|
||||
request-matcher =
|
||||
## Defines the strategy use for matching incoming requests. Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
|
||||
attribute request-matcher {"ant" | "regex" | "ciRegex"}
|
||||
## Defines the strategy use for matching incoming requests. Currently the options are 'mvc' (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
|
||||
attribute request-matcher {"mvc" | "ant" | "regex" | "ciRegex"}
|
||||
port =
|
||||
## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
|
||||
attribute port { xsd:positiveInteger }
|
||||
@@ -303,7 +303,7 @@ http-firewall =
|
||||
|
||||
http =
|
||||
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf?) }
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf? & cors?) }
|
||||
http.attlist &=
|
||||
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
|
||||
attribute pattern {xsd:token}?
|
||||
@@ -381,6 +381,9 @@ intercept-url.attlist &=
|
||||
intercept-url.attlist &=
|
||||
## Used to specify that a URL must be accessed over http or https, or that there is no preference. The value should be "http", "https" or "any", respectively.
|
||||
attribute requires-channel {xsd:token}?
|
||||
intercept-url.attlist &=
|
||||
## The path to the servlet. This attribute is only applicable when 'request-matcher' is 'mvc'. In addition, the value is only required in the following 2 use cases: 1) There are 2 or more HttpServlet's registered in the ServletContext that have mappings starting with '/' and are different; 2) The pattern starts with the same value of a registered HttpServlet path, excluding the default (root) HttpServlet '/'.
|
||||
attribute servlet-path {xsd:token}?
|
||||
|
||||
logout =
|
||||
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
|
||||
@@ -771,12 +774,21 @@ hsts-options.attlist &=
|
||||
## The RequestMatcher instance to be used to determine if the header should be set. Default is if HttpServletRequest.isSecure() is true.
|
||||
attribute request-matcher-ref { xsd:token }?
|
||||
|
||||
cors =
|
||||
## Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is specified a HandlerMappingIntrospector is used as the CorsConfigurationSource
|
||||
element cors { cors-options.attlist }
|
||||
cors-options.attlist &=
|
||||
ref?
|
||||
cors-options.attlist &=
|
||||
## Specifies a bean id that is a CorsConfigurationSource used to construct the CorsFilter to use
|
||||
attribute configuration-source-ref {xsd:token}?
|
||||
|
||||
hpkp =
|
||||
## Adds support for HTTP Public Key Pinning (HPKP).
|
||||
element hpkp {hpkp.pins,hpkp.attlist}
|
||||
hpkp.pins =
|
||||
## The list with pins
|
||||
element pins {hpkp.pin+}
|
||||
element pins {hpkp.pin+}
|
||||
hpkp.pin =
|
||||
## A pin is specified using the base64-encoded SPKI fingerprint as value and the cryptographic hash algorithm as attribute
|
||||
element pin {
|
||||
@@ -830,10 +842,10 @@ frame-options.attlist &=
|
||||
## Specify the strategy to use when ALLOW-FROM is chosen.
|
||||
attribute strategy {"static","whitelist","regexp"}?
|
||||
frame-options.attlist &=
|
||||
## Specify the a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
## Specify a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
ref?
|
||||
frame-options.attlist &=
|
||||
## Specify the a value to use for the chosen strategy.
|
||||
## Specify a value to use for the chosen strategy.
|
||||
attribute value {xsd:string}?
|
||||
frame-options.attlist &=
|
||||
## Specify the request parameter to use for the origin when using a 'whitelist' or 'regexp' based strategy. Default is 'from'.
|
||||
@@ -895,4 +907,4 @@ position =
|
||||
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
|
||||
attribute position {named-security-filter}
|
||||
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
|
||||
+54
-13
@@ -34,13 +34,14 @@
|
||||
<xs:attributeGroup name="request-matcher">
|
||||
<xs:attribute name="request-matcher" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'ant'
|
||||
(for ant path patterns), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
@@ -1111,6 +1112,7 @@
|
||||
</xs:element>
|
||||
<xs:element ref="security:headers"/>
|
||||
<xs:element ref="security:csrf"/>
|
||||
<xs:element ref="security:cors"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="security:http.attlist"/>
|
||||
</xs:complexType>
|
||||
@@ -1186,13 +1188,14 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="request-matcher">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'ant'
|
||||
(for ant path patterns), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
@@ -1342,6 +1345,16 @@
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="servlet-path" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The path to the servlet. This attribute is only applicable when 'request-matcher' is
|
||||
'mvc'. In addition, the value is only required in the following 2 use cases: 1) There are
|
||||
2 or more HttpServlet's registered in the ServletContext that have mappings starting with
|
||||
'/' and are different; 2) The pattern starts with the same value of a registered
|
||||
HttpServlet path, excluding the default (root) HttpServlet '/'.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:attributeGroup name="logout.attlist">
|
||||
@@ -1556,13 +1569,14 @@
|
||||
<xs:attributeGroup name="filter-chain-map.attlist">
|
||||
<xs:attribute name="request-matcher">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'ant'
|
||||
(for ant path patterns), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
@@ -1667,13 +1681,14 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="request-matcher">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'ant'
|
||||
(for ant path patterns), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
@@ -2385,6 +2400,31 @@
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="cors">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is
|
||||
specified a HandlerMappingIntrospector is used as the CorsConfigurationSource
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:cors-options.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="cors-options.attlist">
|
||||
<xs:attribute name="ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines a reference to a Spring bean Id.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="configuration-source-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies a bean id that is a CorsConfigurationSource used to construct the CorsFilter to
|
||||
use
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="hpkp">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Adds support for HTTP Public Key Pinning (HPKP).
|
||||
@@ -2555,7 +2595,7 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="value" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specify the a value to use for the chosen strategy.
|
||||
<xs:documentation>Specify a value to use for the chosen strategy.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
@@ -2716,6 +2756,7 @@
|
||||
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
|
||||
<xs:enumeration value="WEB_ASYNC_MANAGER_FILTER"/>
|
||||
<xs:enumeration value="HEADERS_FILTER"/>
|
||||
<xs:enumeration value="CORS_FILTER"/>
|
||||
<xs:enumeration value="CSRF_FILTER"/>
|
||||
<xs:enumeration value="LOGOUT_FILTER"/>
|
||||
<xs:enumeration value="X509_FILTER"/>
|
||||
|
||||
+33
-11
@@ -1,26 +1,25 @@
|
||||
package org.springframework.security.config
|
||||
|
||||
import groovy.xml.MarkupBuilder
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.context.ApplicationListener
|
||||
import org.springframework.context.support.AbstractRefreshableApplicationContext
|
||||
import org.springframework.mock.web.MockServletContext
|
||||
import org.springframework.security.CollectingAppListener
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext
|
||||
import org.springframework.security.config.util.InMemoryXmlWebApplicationContext
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import spock.lang.Specification
|
||||
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
import org.springframework.context.ApplicationListener
|
||||
import org.springframework.context.ApplicationEvent
|
||||
import org.springframework.security.authentication.event.AbstractAuthenticationEvent
|
||||
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent
|
||||
import org.springframework.security.access.event.AbstractAuthorizationEvent
|
||||
import org.springframework.security.CollectingAppListener
|
||||
|
||||
import javax.servlet.ServletContext
|
||||
|
||||
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
abstract class AbstractXmlConfigTests extends Specification {
|
||||
AbstractXmlApplicationContext appContext;
|
||||
AbstractRefreshableApplicationContext appContext;
|
||||
Writer writer;
|
||||
MarkupBuilder xml;
|
||||
ApplicationListener appListener;
|
||||
@@ -81,4 +80,27 @@ abstract class AbstractXmlConfigTests extends Specification {
|
||||
appContext = new InMemoryXmlApplicationContext(writer.toString() + extraXml);
|
||||
appContext.addApplicationListener(appListener);
|
||||
}
|
||||
|
||||
def createWebAppContext() {
|
||||
createWebAppContext(AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
def createWebAppContext(ServletContext servletContext) {
|
||||
createWebAppContext(AUTH_PROVIDER_XML, servletContext);
|
||||
}
|
||||
|
||||
def createWebAppContext(String extraXml) {
|
||||
createWebAppContext(extraXml, null);
|
||||
}
|
||||
|
||||
def createWebAppContext(String extraXml, ServletContext servletContext) {
|
||||
appContext = new InMemoryXmlWebApplicationContext(writer.toString() + extraXml);
|
||||
appContext.addApplicationListener(appListener);
|
||||
if (servletContext != null) {
|
||||
appContext.setServletContext(servletContext);
|
||||
} else {
|
||||
appContext.setServletContext(new MockServletContext());
|
||||
}
|
||||
appContext.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
+12
-9
@@ -17,20 +17,22 @@ package org.springframework.security.config.annotation;
|
||||
|
||||
import javax.servlet.Filter
|
||||
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.mock.web.MockServletContext
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
@@ -40,11 +42,9 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
import org.springframework.security.web.csrf.CsrfToken
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository
|
||||
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Specification
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -88,7 +88,10 @@ abstract class BaseSpringSpec extends Specification {
|
||||
}
|
||||
|
||||
def loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigApplicationContext(configs)
|
||||
context = new AnnotationConfigWebApplicationContext()
|
||||
context.register(configs)
|
||||
context.setServletContext(new MockServletContext())
|
||||
context.refresh()
|
||||
context
|
||||
}
|
||||
|
||||
|
||||
+4
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,28 +15,12 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.authentication
|
||||
|
||||
import static org.springframework.security.config.annotation.authentication.PasswordEncoderConfigurerConfigs.*
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.springframework.security.config.annotation.authentication.PasswordEncoderConfigurerConfigs.PasswordEncoderConfig
|
||||
import static org.springframework.security.config.annotation.authentication.PasswordEncoderConfigurerConfigs.PasswordEncoderNoAuthManagerLoadsConfig;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
+30
@@ -23,6 +23,7 @@ import org.springframework.context.annotation.Import
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.annotation.Order
|
||||
import org.springframework.security.access.annotation.Secured
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
@@ -485,4 +486,33 @@ class AuthenticationConfigurationTests extends BaseSpringSpec {
|
||||
UDS
|
||||
}
|
||||
}
|
||||
|
||||
def 'EnableGlobalMethodSecurity configuration uses PreAuthorize does not cause BeanCurrentlyInCreationException'() {
|
||||
when:
|
||||
loadConfig(UsesPreAuthorizeMethodSecurityConfig,AuthenticationManagerBeanConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class UsesPreAuthorizeMethodSecurityConfig {
|
||||
@PreAuthorize("denyAll")
|
||||
void run() {}
|
||||
}
|
||||
|
||||
|
||||
def 'EnableGlobalMethodSecurity uses method security service'() {
|
||||
when:
|
||||
loadConfig(ServicesConfig,UsesPreAuthorizeMethodSecurityConfig,AuthenticationManagerBeanConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
static class UsesServiceMethodSecurityConfig {
|
||||
@Autowired
|
||||
Service service
|
||||
}
|
||||
}
|
||||
+33
@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.configuration
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware
|
||||
import org.springframework.beans.factory.BeanFactoryAware
|
||||
import org.springframework.beans.factory.DisposableBean
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
@@ -138,4 +139,36 @@ class AutowireBeanFactoryObjectPostProcessorTests extends BaseSpringSpec {
|
||||
p.postProcess(new Object())
|
||||
}
|
||||
}
|
||||
|
||||
def "SmartInitializingSingleton"() {
|
||||
when:
|
||||
context = new AnnotationConfigWebApplicationContext([servletConfig:new MockServletConfig(),servletContext:new MockServletContext()])
|
||||
context.register(SmartConfig)
|
||||
context.refresh()
|
||||
context.start()
|
||||
then:
|
||||
context.getBean(SmartConfig).smart.instantiated
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SmartConfig {
|
||||
SmartInitializingSingleton smart = new SmartInitializingSingletonStub()
|
||||
|
||||
@Bean
|
||||
public static ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory)
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configure(ObjectPostProcessor<Object> p) {
|
||||
p.postProcess(smart)
|
||||
}
|
||||
}
|
||||
|
||||
static class SmartInitializingSingletonStub implements SmartInitializingSingleton {
|
||||
boolean instantiated
|
||||
void afterSingletonsInstantiated() {
|
||||
instantiated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class DisableUseExpressionsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// This config is also on UrlAuthorizationConfigurer javadoc
|
||||
http
|
||||
.apply(new UrlAuthorizationConfigurer<HttpSecurity>()).getRegistry()
|
||||
.apply(new UrlAuthorizationConfigurer<HttpSecurity>(getApplicationContext())).getRegistry()
|
||||
.antMatchers("/users**","/sessions/**").hasRole("USER")
|
||||
.antMatchers("/signup").hasRole("ANONYMOUS")
|
||||
.anyRequest().hasRole("USER");
|
||||
|
||||
-1
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configuration.sec2377.a;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
|
||||
-1
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configuration.sec2377.b;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
|
||||
+8
@@ -67,5 +67,13 @@ class AbstractConfigAttributeRequestMatcherRegistryTests extends Specification {
|
||||
List<RequestMatcher> chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
|
||||
return requestMatchers;
|
||||
}
|
||||
|
||||
List<RequestMatcher> mvcMatchers(String... mvcPatterns) {
|
||||
null
|
||||
}
|
||||
|
||||
List<RequestMatcher> mvcMatchers(HttpMethod method, String... mvcPatterns) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.http.*
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
import org.springframework.web.cors.CorsConfigurationSource
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
|
||||
import org.springframework.web.filter.CorsFilter
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class CorsConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "HandlerMappingIntrospector default"() {
|
||||
setup:
|
||||
loadConfig(DefaultCorsConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'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 DefaultCorsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
}
|
||||
|
||||
def "HandlerMappingIntrospector explicit"() {
|
||||
setup:
|
||||
loadConfig(MvcCorsConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setupWeb()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
static class MvcCorsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(methods = [
|
||||
RequestMethod.GET, RequestMethod.POST
|
||||
])
|
||||
static class CorsController {
|
||||
@RequestMapping("/")
|
||||
String hello() {
|
||||
"Hello"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "CorsConfigurationSource"() {
|
||||
setup:
|
||||
loadConfig(ConfigSourceConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setupWeb()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ConfigSourceConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
|
||||
@Bean
|
||||
CorsConfigurationSource corsConfigurationSource() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource()
|
||||
source.registerCorsConfiguration("/**", new CorsConfiguration(allowedOrigins : ['*'], allowedMethods : [
|
||||
RequestMethod.GET.name(),
|
||||
RequestMethod.POST.name()
|
||||
]))
|
||||
source
|
||||
}
|
||||
}
|
||||
|
||||
def "CorsFilter"() {
|
||||
setup:
|
||||
loadConfig(CorsFilterConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setupWeb()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CorsFilterConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
|
||||
@Bean
|
||||
CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource()
|
||||
source.registerCorsConfiguration("/**", new CorsConfiguration(allowedOrigins : ['*'], allowedMethods : [
|
||||
RequestMethod.GET.name(),
|
||||
RequestMethod.POST.name()
|
||||
]))
|
||||
new CorsFilter(source)
|
||||
}
|
||||
}
|
||||
|
||||
def addCors(boolean isPreflight=false) {
|
||||
request.addHeader(HttpHeaders.ORIGIN,"https://example.com")
|
||||
if(!isPreflight) {
|
||||
return
|
||||
}
|
||||
request.method = HttpMethod.OPTIONS.name()
|
||||
request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -91,7 +91,20 @@ class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
|
||||
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
|
||||
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
then:
|
||||
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy.class} == [HeaderContentNegotiationStrategy,HeaderContentNegotiationStrategy]
|
||||
def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
|
||||
entryPoints[0].requestMatchers[1].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
|
||||
entryPoints[1].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
|
||||
}
|
||||
|
||||
def "401 for text/plain and X-Requested-With:XMLHttpRequest"() {
|
||||
setup:
|
||||
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
|
||||
when:
|
||||
request.addHeader("Accept", MediaType.TEXT_PLAIN_VALUE)
|
||||
request.addHeader("X-Requested-With", "XMLHttpRequest")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@@ -123,7 +136,9 @@ class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
|
||||
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
|
||||
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||
then:
|
||||
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy} == [OverrideContentNegotiationStrategySharedObjectConfig.CNS,OverrideContentNegotiationStrategySharedObjectConfig.CNS]
|
||||
def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
|
||||
entryPoints[0].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||
entryPoints[1].requestMatchers[1].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||
}
|
||||
|
||||
def "Override ContentNegotiationStrategy with @Bean"() {
|
||||
|
||||
-1
@@ -19,7 +19,6 @@ import java.util.Arrays;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
|
||||
+66
-12
@@ -15,19 +15,15 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.security.config.annotation.AnyObjectPostProcessor
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurerTests.RememberMeNoLogoutHandler;
|
||||
import org.springframework.security.web.authentication.RememberMeServices
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
|
||||
/**
|
||||
@@ -91,14 +87,25 @@ class LogoutConfigurerTests extends BaseSpringSpec {
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2311: Logout allows other methods if CSRF is disabled"() {
|
||||
def "Logout allows other methods if CSRF is disabled"() {
|
||||
when:
|
||||
loadConfig(CsrfDisabledConfig)
|
||||
request.method = "GET"
|
||||
request.method = method
|
||||
request.servletPath = "/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
response.status == httpStatus.value()
|
||||
response.redirectedUrl == url
|
||||
where:
|
||||
method | httpStatus | url
|
||||
"GET" | HttpStatus.FOUND | "/login?logout"
|
||||
"POST" | HttpStatus.FOUND | "/login?logout"
|
||||
"PUT" | HttpStatus.FOUND | "/login?logout"
|
||||
"DELETE" | HttpStatus.FOUND | "/login?logout"
|
||||
"OPTIONS" | HttpStatus.OK | null
|
||||
"HEAD" | HttpStatus.OK | null
|
||||
"TRACE" | HttpStatus.OK | null
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@@ -113,14 +120,25 @@ class LogoutConfigurerTests extends BaseSpringSpec {
|
||||
}
|
||||
|
||||
|
||||
def "SEC-2311: Logout allows other methods if CSRF is disabled with custom logout URL"() {
|
||||
def "Logout allows other methods if CSRF is disabled with custom logout URL"() {
|
||||
when:
|
||||
loadConfig(CsrfDisabledCustomLogoutUrlConfig)
|
||||
request.method = "GET"
|
||||
request.method = method
|
||||
request.servletPath = "/custom/logout"
|
||||
findFilter(LogoutFilter).doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "/login?logout"
|
||||
response.status == httpStatus.value()
|
||||
response.redirectedUrl == url
|
||||
where:
|
||||
method | httpStatus | url
|
||||
"GET" | HttpStatus.FOUND | "/login?logout"
|
||||
"POST" | HttpStatus.FOUND | "/login?logout"
|
||||
"PUT" | HttpStatus.FOUND | "/login?logout"
|
||||
"DELETE" | HttpStatus.FOUND | "/login?logout"
|
||||
"OPTIONS" | HttpStatus.OK | null
|
||||
"HEAD" | HttpStatus.OK | null
|
||||
"TRACE" | HttpStatus.OK | null
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@@ -197,4 +215,40 @@ class LogoutConfigurerTests extends BaseSpringSpec {
|
||||
@EnableWebSecurity
|
||||
static class LogoutHandlerContentNegotiation extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
// gh-3902
|
||||
def "logout in chrome is 302"() {
|
||||
setup:
|
||||
loadConfig(LogoutHandlerContentNegotiationForChrome)
|
||||
when:
|
||||
login()
|
||||
request.method = 'POST'
|
||||
request.servletPath = '/logout'
|
||||
request.addHeader('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == 302
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class LogoutHandlerContentNegotiationForChrome extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
|
||||
// gh-3997
|
||||
def "LogoutConfigurer for XMLHttpRequest is 204"() {
|
||||
setup:
|
||||
loadConfig(LogoutXMLHttpRequestConfig)
|
||||
when:
|
||||
login()
|
||||
request.method = 'POST'
|
||||
request.servletPath = '/logout'
|
||||
request.addHeader('Accept', 'text/html,application/json')
|
||||
request.addHeader('X-Requested-With', 'XMLHttpRequest')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == 204
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class LogoutXMLHttpRequestConfig extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
+60
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,24 +17,27 @@ package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import javax.servlet.http.Cookie
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.mock.web.MockHttpSession
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
|
||||
import org.springframework.security.config.annotation.AnyObjectPostProcessor
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.core.context.SecurityContext
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.web.authentication.RememberMeServices
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
@@ -43,6 +46,7 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
|
||||
* Tests for RememberMeConfigurer that flex edge cases. {@link NamespaceRememberMeTests} demonstrate mapping of the XML namespace to Java Config.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class RememberMeConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
@@ -155,7 +159,7 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
}
|
||||
|
||||
def "http/remember-me with cookied domain"() {
|
||||
def "http/remember-me with cookie domain"() {
|
||||
setup:
|
||||
loadConfig(RememberMeCookieDomainConfig)
|
||||
when:
|
||||
@@ -172,6 +176,29 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
|
||||
rememberMeCookie.domain == "spring.io"
|
||||
}
|
||||
|
||||
def "http/remember-me with cookie name and custom rememberMeServices throws BeanCreationException"() {
|
||||
setup:
|
||||
RememberMeCookieDomainCustomRememberMeServicesConfig.REMEMBER_ME = Mock(RememberMeServices)
|
||||
when:
|
||||
loadConfig(RememberMeCookieDomainCustomRememberMeServicesConfig)
|
||||
then: "response contains remember me cookie"
|
||||
def ex = thrown(BeanCreationException)
|
||||
ex instanceof BeanCreationException
|
||||
}
|
||||
|
||||
def "http/remember-me with cookie name and custom rememberMeServices throws IllegalArgumentException"() {
|
||||
setup:
|
||||
def httpSec = new HttpSecurity(Mock(ObjectPostProcessor), Mock(AuthenticationManagerBuilder), [:])
|
||||
RememberMeConfigurer<HttpSecurity> config = new RememberMeConfigurer<HttpSecurity>();
|
||||
config.rememberMeCookieName("COOKIE_NAME")
|
||||
config.rememberMeServices(Mock(RememberMeServices))
|
||||
when:
|
||||
config.init(httpSec)
|
||||
then:
|
||||
IllegalArgumentException ex = thrown()
|
||||
ex.message == 'Can not set rememberMeCookieName and custom rememberMeServices.'
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RememberMeConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@@ -213,6 +240,33 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RememberMeCookieDomainCustomRememberMeServicesConfig extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
static RememberMeServices REMEMBER_ME
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeCookieName("SPRING_COOKIE_DOMAIN")
|
||||
.rememberMeCookieDomain("spring.io")
|
||||
.rememberMeServices(REMEMBER_ME);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Cookie createRememberMeCookie() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
|
||||
+1
-2
@@ -16,7 +16,6 @@
|
||||
package org.springframework.security.config.doc
|
||||
|
||||
import groovy.util.slurpersupport.GPathResult;
|
||||
import groovy.util.slurpersupport.NodeChild
|
||||
|
||||
import org.springframework.security.config.http.SecurityFilters
|
||||
|
||||
@@ -89,7 +88,7 @@ class XsdDocumentedTests extends Specification {
|
||||
def 'the latest schema is being validated'() {
|
||||
when: 'all the schemas are found'
|
||||
def schemas = schemaDocument.getParentFile().list().findAll { it.endsWith('.xsd') }
|
||||
then: 'the count is equal to 8, if not then schemaDocument needs updated'
|
||||
then: 'the count is equal to 10, if not then schemaDocument needs updated'
|
||||
schemas.size() == 10
|
||||
}
|
||||
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.http
|
||||
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.springframework.http.*
|
||||
import org.springframework.mock.web.*
|
||||
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.filter.CorsFilter
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Tim Ysewyn
|
||||
*/
|
||||
class HttpCorsConfigTests extends AbstractHttpConfigTests {
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest(method:"GET")
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
def "HandlerMappingIntrospector default"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'()
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
def "HandlerMappingIntrospector explicit"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'()
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
bean('controller', CorsController)
|
||||
xml.'mvc:annotation-driven'()
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setup()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def "CorsConfigurationSource"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'('configuration-source-ref':'ccs')
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
bean('ccs', MyCorsConfigurationSource)
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setup()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def "CorsFilter"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'('ref' : 'cf')
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
xml.'b:bean'(id: 'cf', 'class': CorsFilter.name) {
|
||||
'b:constructor-arg'(ref: 'ccs')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
bean('ccs', MyCorsConfigurationSource)
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setup()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def addCors(boolean isPreflight=false) {
|
||||
request.addHeader(HttpHeaders.ORIGIN,"https://example.com")
|
||||
if(!isPreflight) {
|
||||
return
|
||||
}
|
||||
request.method = HttpMethod.OPTIONS.name()
|
||||
request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
|
||||
}
|
||||
|
||||
def getResponseHeaders() {
|
||||
def headers = [:]
|
||||
response.headerNames.each { name ->
|
||||
headers.put(name, response.getHeaderValues(name).join(','))
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(methods = [
|
||||
RequestMethod.GET, RequestMethod.POST
|
||||
])
|
||||
static class CorsController {
|
||||
@RequestMapping("/")
|
||||
String hello() {
|
||||
"Hello"
|
||||
}
|
||||
}
|
||||
|
||||
static class MyCorsConfigurationSource extends UrlBasedCorsConfigurationSource {
|
||||
MyCorsConfigurationSource() {
|
||||
registerCorsConfiguration('/**', new CorsConfiguration(allowedOrigins : ['*'], allowedMethods : [
|
||||
RequestMethod.GET.name(),
|
||||
RequestMethod.POST.name()
|
||||
]))
|
||||
}
|
||||
}
|
||||
}
|
||||
+214
-4
@@ -15,17 +15,25 @@
|
||||
*/
|
||||
package org.springframework.security.config.http
|
||||
|
||||
import javax.servlet.Filter
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.mockito.invocation.InvocationOnMock
|
||||
import org.mockito.stubbing.Answer
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.mock.web.MockServletContext
|
||||
import org.springframework.security.access.SecurityConfig
|
||||
import org.springframework.security.crypto.codec.Base64
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
import javax.servlet.ServletContext
|
||||
import javax.servlet.ServletRegistration
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import static org.mockito.Mockito.*
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
@@ -197,14 +205,216 @@ class InterceptUrlConfigTests extends AbstractHttpConfigTests {
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "intercept-url supports mvc matchers"() {
|
||||
setup:
|
||||
MockServletContext servletContext = mockServletContext();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
xml.http('request-matcher':'mvc') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll")
|
||||
}
|
||||
bean('pathController',PathController)
|
||||
xml.'mvc:annotation-driven'()
|
||||
|
||||
createWebAppContext(servletContext)
|
||||
when:
|
||||
request.servletPath = "/path"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
request = new MockHttpServletRequest(method:'GET')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
request.servletPath = "/path.html"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
request = new MockHttpServletRequest(method:'GET')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
request.servletPath = "/path/"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
def "intercept-url mvc supports path variables"() {
|
||||
setup:
|
||||
MockServletContext servletContext = mockServletContext();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
xml.http('request-matcher':'mvc') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/user/{un}/**', access: "#un == 'user'")
|
||||
}
|
||||
createWebAppContext(servletContext)
|
||||
when: 'user can access'
|
||||
request.servletPath = '/user/user/abc'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is OK'
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: 'cannot access otheruser'
|
||||
request = new MockHttpServletRequest(method:'GET', servletPath : '/user/otheruser/abc')
|
||||
login(request, 'user', 'password')
|
||||
chain.reset()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is OK'
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when: 'user can access case insensitive URL'
|
||||
request = new MockHttpServletRequest(method:'GET', servletPath : '/USER/user/abc')
|
||||
login(request, 'user', 'password')
|
||||
chain.reset()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is OK'
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "intercept-url mvc matchers with servlet path"() {
|
||||
setup:
|
||||
MockServletContext servletContext = mockServletContext("/spring");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
xml.http('request-matcher':'mvc') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll", 'servlet-path': "/spring")
|
||||
}
|
||||
bean('pathController',PathController)
|
||||
xml.'mvc:annotation-driven'()
|
||||
createWebAppContext(servletContext)
|
||||
when:
|
||||
request.servletPath = "/spring"
|
||||
request.requestURI = "/spring/path"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
request = new MockHttpServletRequest(method:'GET')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
request.servletPath = "/spring"
|
||||
request.requestURI = "/spring/path.html"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
when:
|
||||
request = new MockHttpServletRequest(method:'GET')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
request.servletPath = "/spring"
|
||||
request.requestURI = "/spring/path/"
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
def "intercept-url mvc matchers servlet path required"() {
|
||||
when:
|
||||
MockServletContext servletContext = mockServletContext("/spring");
|
||||
xml.http('request-matcher':'mvc') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll")
|
||||
}
|
||||
createWebAppContext(servletContext)
|
||||
then:
|
||||
thrown(BeanCreationException)
|
||||
}
|
||||
|
||||
def "intercept-url mvc matchers servlet path NOT required"() {
|
||||
when:
|
||||
MockServletContext servletContext = mockServletContext();
|
||||
xml.http('request-matcher':'mvc') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll")
|
||||
}
|
||||
createWebAppContext(servletContext)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def "intercept-url ant matcher with servlet path fails"() {
|
||||
when:
|
||||
xml.http('request-matcher':'ant') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll", 'servlet-path': "/spring")
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
|
||||
def "intercept-url regex matcher with servlet path fails"() {
|
||||
when:
|
||||
xml.http('request-matcher':'regex') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll", 'servlet-path': "/spring")
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
|
||||
def "intercept-url ciRegex matcher with servlet path fails"() {
|
||||
when:
|
||||
xml.http('request-matcher':'ciRegex') {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll", 'servlet-path': "/spring")
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
|
||||
def "intercept-url default matcher with servlet path fails"() {
|
||||
when:
|
||||
xml.http() {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/path', access: "denyAll", 'servlet-path': "/spring")
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
|
||||
public static class Id {
|
||||
public boolean isOne(int i) {
|
||||
return i == 1;
|
||||
}
|
||||
}
|
||||
|
||||
private ServletContext mockServletContext() {
|
||||
return mockServletContext("/");
|
||||
}
|
||||
|
||||
private ServletContext mockServletContext(String servletPath) {
|
||||
MockServletContext servletContext = spy(new MockServletContext());
|
||||
final ServletRegistration registration = mock(ServletRegistration.class);
|
||||
when(registration.getMappings()).thenReturn(Collections.singleton(servletPath));
|
||||
Answer<Map<String, ? extends ServletRegistration>> answer = new Answer<Map<String, ? extends ServletRegistration>>() {
|
||||
@Override
|
||||
public Map<String, ? extends ServletRegistration> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return Collections.<String, ServletRegistration>singletonMap("spring", registration);
|
||||
}
|
||||
};
|
||||
when(servletContext.getServletRegistrations()).thenAnswer(answer);
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
def login(MockHttpServletRequest request, String username, String password) {
|
||||
String toEncode = username + ':' + password
|
||||
request.addHeader('Authorization','Basic ' + new String(Base64.encode(toEncode.getBytes('UTF-8'))))
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -17,7 +17,6 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -30,7 +29,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -42,7 +41,6 @@ import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
/**
|
||||
* Tests {@link FilterChainProxy}.
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.security.config;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.security.core.session.SessionCreationEvent;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.authentication.configurers.ldap;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class LdapAuthenticationProviderConfigurerTest {
|
||||
|
||||
private LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> configurer;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
configurer = new LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder>();
|
||||
}
|
||||
|
||||
// SEC-2557
|
||||
@Test
|
||||
public void getAuthoritiesMapper() throws Exception {
|
||||
assertThat(configurer.getAuthoritiesMapper()).isInstanceOf(SimpleAuthorityMapper.class);
|
||||
configurer.authoritiesMapper(new NullAuthoritiesMapper());
|
||||
assertThat(configurer.getAuthoritiesMapper()).isInstanceOf(NullAuthoritiesMapper.class);
|
||||
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRegistration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AbstractRequestMatcherRegistryTests {
|
||||
|
||||
@Mock
|
||||
HandlerMappingIntrospector introspector;
|
||||
|
||||
MvcRequestMatcher matcher;
|
||||
|
||||
ServletContext servletContext;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
servletContext = spy(new MockServletContext());
|
||||
matcher = new MvcRequestMatcher(introspector, "/foo");
|
||||
matcher.setServletContext(servletContext);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void servletPathValidatingMvcRequestMatcherAfterPropertiesSetFailsWithSpringServlet() throws Exception {
|
||||
setMappings("/spring");
|
||||
matcher.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void servletPathValidatingMvcRequestMatcherAfterPropertiesSetWithSpringServlet() throws Exception {
|
||||
matcher.setServletPath("/spring");
|
||||
setMappings("/spring");
|
||||
matcher.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void servletPathValidatingMvcRequestMatcherAfterPropertiesSetDefaultServlet() throws Exception {
|
||||
setMappings("/");
|
||||
matcher.afterPropertiesSet();
|
||||
}
|
||||
|
||||
private void setMappings(String... mappings) {
|
||||
final ServletRegistration registration = mock(ServletRegistration.class);
|
||||
when(registration.getMappings()).thenReturn(Arrays.asList(mappings));
|
||||
Answer<Map<String, ? extends ServletRegistration>> answer = new Answer<Map<String, ? extends ServletRegistration>>() {
|
||||
@Override
|
||||
public Map<String, ? extends ServletRegistration> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return Collections.<String, ServletRegistration>singletonMap("spring", registration);
|
||||
}
|
||||
};
|
||||
when(servletContext.getServletRegistrations()).thenAnswer(answer);
|
||||
}
|
||||
|
||||
}
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.builders;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class WebSecurityTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.request.setMethod("GET");
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoringMvcMatcher() throws Exception {
|
||||
loadConfig(MvcMatcherConfig.class);
|
||||
|
||||
this.request.setRequestURI("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setRequestURI("/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setRequestURI("/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setRequestURI("/other");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
// @formatter:off
|
||||
web
|
||||
.ignoring()
|
||||
.mvcMatchers("/path");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoringMvcMatcherServletPath() throws Exception {
|
||||
loadConfig(MvcMatcherServletPathConfig.class);
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/other");
|
||||
this.request.setRequestURI("/other/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherServletPathConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
// @formatter:off
|
||||
web
|
||||
.ignoring()
|
||||
.mvcMatchers("/path").servletPath("/spring")
|
||||
.mvcMatchers("/notused");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(Class<?>... configs) {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(configs);
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.refresh();
|
||||
|
||||
this.context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
|
||||
}
|
||||
-2
@@ -39,10 +39,8 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
+248
-1
@@ -15,12 +15,19 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletRegistration;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -28,6 +35,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
@@ -41,9 +49,15 @@ import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
@@ -55,12 +69,14 @@ public class AuthorizeRequestsTests {
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
MockServletContext servletContext;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.servletContext = spy(new MockServletContext());
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.request.setMethod("GET");
|
||||
this.response = new MockHttpServletResponse();
|
||||
@@ -249,11 +265,242 @@ public class AuthorizeRequestsTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatcher() throws Exception {
|
||||
loadConfig(MvcMatcherConfig.class);
|
||||
|
||||
this.request.setRequestURI("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setRequestURI("/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.mvcMatchers("/path").denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatcherServletPath() throws Exception {
|
||||
loadConfig(MvcMatcherServletPathConfig.class);
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/foo");
|
||||
this.request.setRequestURI("/foo/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/");
|
||||
this.request.setRequestURI("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherServletPathConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.mvcMatchers("/path").servletPath("/spring").denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatcherPathVariables() throws Exception {
|
||||
loadConfig(MvcMatcherPathVariablesConfig.class);
|
||||
|
||||
this.request.setRequestURI("/user/user");
|
||||
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
this.setup();
|
||||
this.request.setRequestURI("/user/deny");
|
||||
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherPathVariablesConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.mvcMatchers("/user/{userName}").access("#userName == 'user'");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void mvcMatcherServletPathRequired() throws Exception {
|
||||
final ServletRegistration registration = mock(ServletRegistration.class);
|
||||
when(registration.getMappings()).thenReturn(Collections.singleton("/spring"));
|
||||
Answer<Map<String, ? extends ServletRegistration>> answer = new Answer<Map<String, ? extends ServletRegistration>>() {
|
||||
@Override
|
||||
public Map<String, ? extends ServletRegistration> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return Collections.<String, ServletRegistration>singletonMap("spring", registration);
|
||||
}
|
||||
};
|
||||
when(servletContext.getServletRegistrations()).thenAnswer(answer);
|
||||
loadConfig(MvcMatcherPathServletPathRequiredConfig.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherPathServletPathRequiredConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.mvcMatchers("/user").denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(Class<?>... configs) {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(configs);
|
||||
this.context.setServletContext(this.servletContext);
|
||||
this.context.refresh();
|
||||
|
||||
this.context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -23,12 +23,11 @@ import org.junit.Test;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
|
||||
|
||||
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
|
||||
|
||||
-2
@@ -17,8 +17,6 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class HttpSecurityRequestMatchersTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.request.setMethod("GET");
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatcher() throws Exception {
|
||||
loadConfig(MvcMatcherConfig.class);
|
||||
|
||||
this.request.setServletPath("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatcherGetFiltersNoUnsupportedMethodExceptionFromDummyRequest() {
|
||||
loadConfig(MvcMatcherConfig.class);
|
||||
|
||||
assertThat(springSecurityFilterChain.getFilters("/path")).isNotEmpty();
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.mvcMatcher("/path")
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersMvcMatcher() throws Exception {
|
||||
loadConfig(RequestMatchersMvcMatcherConfig.class);
|
||||
|
||||
this.request.setServletPath("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class RequestMatchersMvcMatcherConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers()
|
||||
.mvcMatchers("/path")
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMatchersMvcMatcherServletPath() throws Exception {
|
||||
loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class);
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("");
|
||||
this.request.setRequestURI("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/other");
|
||||
this.request.setRequestURI("/other/path");
|
||||
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class RequestMatchersMvcMatcherServeltPathConfig
|
||||
extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers()
|
||||
.mvcMatchers("/path").servletPath("/spring")
|
||||
.mvcMatchers("/never-match")
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(Class<?>... configs) {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(configs);
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.refresh();
|
||||
|
||||
this.context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
}
|
||||
-1
@@ -36,7 +36,6 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class UrlAuthorizationConfigurerTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.request.setMethod("GET");
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatcher() throws Exception {
|
||||
loadConfig(MvcMatcherConfig.class);
|
||||
|
||||
this.request.setRequestURI("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setRequestURI("/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.apply(new UrlAuthorizationConfigurer(getApplicationContext())).getRegistry()
|
||||
.mvcMatchers("/path").hasRole("ADMIN");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatcherServletPath() throws Exception {
|
||||
loadConfig(MvcMatcherServletPathConfig.class);
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path.html");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/spring");
|
||||
this.request.setRequestURI("/spring/path/");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/foo");
|
||||
this.request.setRequestURI("/foo/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
setup();
|
||||
|
||||
this.request.setServletPath("/");
|
||||
this.request.setRequestURI("/path");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class MvcMatcherServletPathConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.httpBasic().and()
|
||||
.apply(new UrlAuthorizationConfigurer(getApplicationContext())).getRegistry()
|
||||
.mvcMatchers("/path").servletPath("/spring").hasRole("ADMIN");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// @formatter:off
|
||||
auth
|
||||
.inMemoryAuthentication();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PathController {
|
||||
@RequestMapping("/path")
|
||||
public String path() {
|
||||
return "path";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(Class<?>... configs) {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(configs);
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.refresh();
|
||||
|
||||
this.context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
}
|
||||
}
|
||||
+1
-19
@@ -20,23 +20,16 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageDeliveryException;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import static org.springframework.messaging.simp.SimpMessageType.*;
|
||||
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletConfig;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
@@ -44,25 +37,14 @@ import org.springframework.security.config.annotation.web.messaging.MessageSecur
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.server.HandshakeFailureException;
|
||||
import org.springframework.web.socket.server.HandshakeHandler;
|
||||
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
|
||||
import org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler;
|
||||
import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.authentication;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class AuthenticationConfigurationGh3935Tests {
|
||||
@Autowired
|
||||
FilterChainProxy springSecurityFilterChain;
|
||||
@Autowired
|
||||
UserDetailsService uds;
|
||||
@Autowired
|
||||
BootGlobalAuthenticationConfigurationAdapter adapter;
|
||||
|
||||
// gh-3935
|
||||
@Test
|
||||
public void loads() {
|
||||
assertThat(this.springSecurityFilterChain).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delegateUsesExisitingAuthentication() {
|
||||
String username = "user";
|
||||
String password = "password";
|
||||
User user = new User(username, password,
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
when(this.uds.loadUserByUsername(username)).thenReturn(user);
|
||||
|
||||
AuthenticationManager authenticationManager = this.adapter.authenticationManager;
|
||||
assertThat(authenticationManager).isNotNull();
|
||||
|
||||
Authentication auth = authenticationManager.authenticate(
|
||||
new UsernamePasswordAuthenticationToken(username, password));
|
||||
|
||||
verify(this.uds).loadUserByUsername(username);
|
||||
assertThat(auth.getPrincipal()).isEqualTo(user);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebSecurity extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
|
||||
static class BootGlobalAuthenticationConfigurationAdapter
|
||||
extends GlobalAuthenticationConfigurerAdapter {
|
||||
private final ApplicationContext context;
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
BootGlobalAuthenticationConfigurationAdapter(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
AuthenticationConfiguration configuration = this.context
|
||||
.getBean(AuthenticationConfiguration.class);
|
||||
this.authenticationManager = configuration.getAuthenticationManager();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AutoConfig {
|
||||
@Bean
|
||||
static BootGlobalAuthenticationConfigurationAdapter adapter(
|
||||
ApplicationContext context) {
|
||||
return new BootGlobalAuthenticationConfigurationAdapter(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() {
|
||||
return mock(UserDetailsService.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
@@ -33,6 +31,8 @@ import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
@@ -118,6 +118,13 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
|
||||
+ ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
public void parsingInterceptUrlServletPathFails() {
|
||||
setContext("<filter-security-metadata-source id='fids' use-expressions='false'>"
|
||||
+ " <intercept-url pattern='/secure' access='ROLE_USER' servlet-path='/spring' />"
|
||||
+ "</filter-security-metadata-source>");
|
||||
}
|
||||
|
||||
private FilterInvocation createFilterInvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI(null);
|
||||
|
||||
+2
-6
@@ -35,15 +35,11 @@ import org.mockito.Mock;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.method.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class Gh4020GlobalMethodSecurityConfigurationTests {
|
||||
@Autowired
|
||||
DenyAllService denyAll;
|
||||
|
||||
// gh-4020
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void denyAll() {
|
||||
this.denyAll.denyAll();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class SecurityConfig {
|
||||
@Bean
|
||||
PermissionEvaluator permissionEvaluator() {
|
||||
return mock(PermissionEvaluator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
RoleHierarchy RoleHierarchy() {
|
||||
return mock(RoleHierarchy.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationTrustResolver trustResolver() {
|
||||
return mock(AuthenticationTrustResolver.class);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
DenyAllService denyAll;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ServiceConfig {
|
||||
@Bean
|
||||
DenyAllService denyAllService() {
|
||||
return new DenyAllService();
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("denyAll")
|
||||
static class DenyAllService {
|
||||
void denyAll() {
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -25,27 +25,31 @@ import org.springframework.security.util.InMemoryResource;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext {
|
||||
private static final String BEANS_OPENING = "<b:beans xmlns='http://www.springframework.org/schema/security'\n"
|
||||
static final String BEANS_OPENING = "<b:beans xmlns='http://www.springframework.org/schema/security'\n"
|
||||
+ " xmlns:context='http://www.springframework.org/schema/context'\n"
|
||||
+ " xmlns:b='http://www.springframework.org/schema/beans'\n"
|
||||
+ " xmlns:aop='http://www.springframework.org/schema/aop'\n"
|
||||
+ " xmlns:mvc='http://www.springframework.org/schema/mvc'\n"
|
||||
+ " xmlns:websocket='http://www.springframework.org/schema/websocket'\n"
|
||||
+ " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"
|
||||
+ " xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n"
|
||||
+ "http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n"
|
||||
+ "http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd\n"
|
||||
+ "http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd\n"
|
||||
+ "http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\n"
|
||||
+ "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-";
|
||||
private static final String BEANS_CLOSE = "</b:beans>\n";
|
||||
static final String BEANS_CLOSE = "</b:beans>\n";
|
||||
|
||||
static final String SPRING_SECURITY_VERSION = "4.1";
|
||||
|
||||
Resource inMemoryXml;
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml) {
|
||||
this(xml, "4.1", null);
|
||||
this(xml, SPRING_SECURITY_VERSION, null);
|
||||
}
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
||||
this(xml, "4.1", parent);
|
||||
this(xml, SPRING_SECURITY_VERSION, parent);
|
||||
}
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml, String secVersion,
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.util;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.util.InMemoryResource;
|
||||
import org.springframework.web.context.support.AbstractRefreshableWebApplicationContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.springframework.security.config.util.InMemoryXmlApplicationContext.BEANS_CLOSE;
|
||||
import static org.springframework.security.config.util.InMemoryXmlApplicationContext.BEANS_OPENING;
|
||||
import static org.springframework.security.config.util.InMemoryXmlApplicationContext.SPRING_SECURITY_VERSION;
|
||||
|
||||
/**
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class InMemoryXmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
|
||||
private Resource inMemoryXml;
|
||||
|
||||
public InMemoryXmlWebApplicationContext(String xml) {
|
||||
this(xml, SPRING_SECURITY_VERSION, null);
|
||||
}
|
||||
|
||||
public InMemoryXmlWebApplicationContext(String xml, ApplicationContext parent) {
|
||||
this(xml, SPRING_SECURITY_VERSION, parent);
|
||||
}
|
||||
|
||||
public InMemoryXmlWebApplicationContext(String xml, String secVersion,
|
||||
ApplicationContext parent) {
|
||||
String fullXml = BEANS_OPENING + secVersion + ".xsd'>\n" + xml + BEANS_CLOSE;
|
||||
inMemoryXml = new InMemoryResource(fullXml);
|
||||
setAllowBeanDefinitionOverriding(true);
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
|
||||
reader.loadBeanDefinitions(new Resource[] { inMemoryXml });
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.1.0.RELEASE</version>
|
||||
<version>4.1.2.RELEASE</version>
|
||||
<name>spring-security-core</name>
|
||||
<description>spring-security-core</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.2.5.RELEASE</version>
|
||||
<version>4.3.1.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
-1
@@ -19,7 +19,6 @@ package org.springframework.security.access.intercept;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user