mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 01:02:14 +00:00
Add Cross Site Tracing (XST) & HTTP Method Tampering Protection
Fixes: gh-5377
This commit is contained in:
parent
2c92496911
commit
73345e7434
@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.security.config.annotation.web.configurers
|
package org.springframework.security.config.annotation.web.configurers
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.security.core.userdetails.PasswordEncodedUser
|
import org.springframework.security.core.userdetails.PasswordEncodedUser
|
||||||
|
import org.springframework.security.web.firewall.StrictHttpFirewall
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse
|
import javax.servlet.http.HttpServletResponse
|
||||||
|
|
||||||
@ -44,7 +47,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
|
|||||||
@Unroll
|
@Unroll
|
||||||
def "csrf applied by default"() {
|
def "csrf applied by default"() {
|
||||||
setup:
|
setup:
|
||||||
loadConfig(CsrfAppliedDefaultConfig)
|
loadConfig(CsrfAppliedDefaultConfig, AllowHttpMethodsFirewallConfig)
|
||||||
request.method = httpMethod
|
request.method = httpMethod
|
||||||
clearCsrfToken()
|
clearCsrfToken()
|
||||||
when:
|
when:
|
||||||
@ -66,11 +69,21 @@ class CsrfConfigurerTests extends BaseSpringSpec {
|
|||||||
|
|
||||||
def "csrf default creates CsrfRequestDataValueProcessor"() {
|
def "csrf default creates CsrfRequestDataValueProcessor"() {
|
||||||
when:
|
when:
|
||||||
loadConfig(CsrfAppliedDefaultConfig)
|
loadConfig(CsrfAppliedDefaultConfig, AllowHttpMethodsFirewallConfig)
|
||||||
then:
|
then:
|
||||||
context.getBean(RequestDataValueProcessor)
|
context.getBean(RequestDataValueProcessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class AllowHttpMethodsFirewallConfig {
|
||||||
|
@Bean
|
||||||
|
StrictHttpFirewall strictHttpFirewall() {
|
||||||
|
StrictHttpFirewall result = new StrictHttpFirewall();
|
||||||
|
result.setAllowedHttpMethods(StrictHttpFirewall.ALLOW_ANY_HTTP_METHOD);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
|
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public class NamespaceHttpFirewallTests extends BaseSpringSpec {
|
|||||||
MockFilterChain chain
|
MockFilterChain chain
|
||||||
|
|
||||||
def setup() {
|
def setup() {
|
||||||
request = new MockHttpServletRequest()
|
request = new MockHttpServletRequest("GET", "")
|
||||||
response = new MockHttpServletResponse()
|
response = new MockHttpServletResponse()
|
||||||
chain = new MockFilterChain()
|
chain = new MockFilterChain()
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public class NamespaceHttpPortMappingsTests extends BaseSpringSpec {
|
|||||||
MockFilterChain chain
|
MockFilterChain chain
|
||||||
|
|
||||||
def setup() {
|
def setup() {
|
||||||
request = new MockHttpServletRequest()
|
request = new MockHttpServletRequest("GET", "")
|
||||||
request.setMethod("GET")
|
request.setMethod("GET")
|
||||||
response = new MockHttpServletResponse()
|
response = new MockHttpServletResponse()
|
||||||
chain = new MockFilterChain()
|
chain = new MockFilterChain()
|
||||||
|
@ -371,7 +371,7 @@ public class NamespaceRememberMeTests extends BaseSpringSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cookie createRememberMeCookie() {
|
Cookie createRememberMeCookie() {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "")
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
super.setupCsrf("CSRF_TOKEN", request, response)
|
super.setupCsrf("CSRF_TOKEN", request, response)
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cookie createRememberMeCookie() {
|
Cookie createRememberMeCookie() {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "")
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
super.setupCsrf("CSRF_TOKEN", request, response)
|
super.setupCsrf("CSRF_TOKEN", request, response)
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ abstract class AbstractHttpConfigTests extends AbstractXmlConfigTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FilterInvocation createFilterinvocation(String path, String method) {
|
FilterInvocation createFilterinvocation(String path, String method) {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.setMethod(method);
|
request.setMethod(method);
|
||||||
request.setRequestURI(null);
|
request.setRequestURI(null);
|
||||||
request.setServletPath(path);
|
request.setServletPath(path);
|
||||||
|
@ -69,7 +69,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, defaultHeaders)
|
assertHeaders(response, defaultHeaders)
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, defaultHeaders)
|
assertHeaders(response, defaultHeaders)
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
expectedHeaders['X-Frame-Options'] = 'SAMEORIGIN'
|
expectedHeaders['X-Frame-Options'] = 'SAMEORIGIN'
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
assertHeaders(response, ['X-Content-Type-Options':'nosniff'])
|
assertHeaders(response, ['X-Content-Type-Options':'nosniff'])
|
||||||
@ -147,7 +147,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
assertHeaders(response, ['X-Frame-Options':'DENY'])
|
assertHeaders(response, ['X-Frame-Options':'DENY'])
|
||||||
@ -163,7 +163,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
assertHeaders(response, ['X-Frame-Options':'DENY'])
|
assertHeaders(response, ['X-Frame-Options':'DENY'])
|
||||||
@ -179,7 +179,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
assertHeaders(response, ['X-Frame-Options':'SAMEORIGIN'])
|
assertHeaders(response, ['X-Frame-Options':'SAMEORIGIN'])
|
||||||
@ -228,7 +228,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['X-Frame-Options':'ALLOW-FROM https://example.com'])
|
assertHeaders(response, ['X-Frame-Options':'ALLOW-FROM https://example.com'])
|
||||||
@ -246,7 +246,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
|
|
||||||
def request = new MockHttpServletRequest()
|
def request = new MockHttpServletRequest("GET", "")
|
||||||
request.setParameter("from", "https://example.com");
|
request.setParameter("from", "https://example.com");
|
||||||
hf.doFilter(request, response, new MockFilterChain())
|
hf.doFilter(request, response, new MockFilterChain())
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['a':'b'])
|
assertHeaders(response, ['a':'b'])
|
||||||
@ -283,7 +283,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
then:
|
then:
|
||||||
assertHeaders(response , ['a':'b', 'c':'d'])
|
assertHeaders(response , ['a':'b', 'c':'d'])
|
||||||
@ -304,7 +304,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['abc':'def'])
|
assertHeaders(response, ['abc':'def'])
|
||||||
}
|
}
|
||||||
@ -346,7 +346,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['X-XSS-Protection':'1; mode=block'])
|
assertHeaders(response, ['X-XSS-Protection':'1; mode=block'])
|
||||||
@ -363,7 +363,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['X-XSS-Protection':'1; mode=block'])
|
assertHeaders(response, ['X-XSS-Protection':'1; mode=block'])
|
||||||
@ -380,7 +380,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
|
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
|
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['X-XSS-Protection':'0'])
|
assertHeaders(response, ['X-XSS-Protection':'0'])
|
||||||
@ -413,7 +413,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
assertHeaders(response, ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||||
'Expires' : '0',
|
'Expires' : '0',
|
||||||
@ -431,7 +431,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains'])
|
assertHeaders(response, ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains'])
|
||||||
}
|
}
|
||||||
@ -447,7 +447,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
response.headerNames.empty
|
response.headerNames.empty
|
||||||
}
|
}
|
||||||
@ -465,7 +465,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Strict-Transport-Security': 'max-age=1'])
|
assertHeaders(response, ['Strict-Transport-Security': 'max-age=1'])
|
||||||
}
|
}
|
||||||
@ -515,7 +515,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
|
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
|
||||||
}
|
}
|
||||||
@ -535,7 +535,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
|
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
|
||||||
}
|
}
|
||||||
@ -555,7 +555,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
response.headerNames.empty
|
response.headerNames.empty
|
||||||
}
|
}
|
||||||
@ -575,7 +575,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=604800 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
|
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=604800 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
|
||||||
}
|
}
|
||||||
@ -595,7 +595,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Public-Key-Pins': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="'])
|
assertHeaders(response, ['Public-Key-Pins': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="'])
|
||||||
}
|
}
|
||||||
@ -615,7 +615,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; includeSubDomains'])
|
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; includeSubDomains'])
|
||||||
}
|
}
|
||||||
@ -635,7 +635,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; report-uri="http://example.net/pkp-report"'])
|
assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; report-uri="http://example.net/pkp-report"'])
|
||||||
}
|
}
|
||||||
@ -657,7 +657,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
expectedHeaders.remove('Expires')
|
expectedHeaders.remove('Expires')
|
||||||
expectedHeaders.remove('Pragma')
|
expectedHeaders.remove('Pragma')
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, expectedHeaders)
|
assertHeaders(response, expectedHeaders)
|
||||||
}
|
}
|
||||||
@ -675,7 +675,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
expectedHeaders.remove('X-Content-Type-Options')
|
expectedHeaders.remove('X-Content-Type-Options')
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, expectedHeaders)
|
assertHeaders(response, expectedHeaders)
|
||||||
}
|
}
|
||||||
@ -693,7 +693,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
expectedHeaders.remove('Strict-Transport-Security')
|
expectedHeaders.remove('Strict-Transport-Security')
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, expectedHeaders)
|
assertHeaders(response, expectedHeaders)
|
||||||
}
|
}
|
||||||
@ -714,7 +714,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, expectedHeaders)
|
assertHeaders(response, expectedHeaders)
|
||||||
}
|
}
|
||||||
@ -732,7 +732,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
expectedHeaders.remove('X-Frame-Options')
|
expectedHeaders.remove('X-Frame-Options')
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, expectedHeaders)
|
assertHeaders(response, expectedHeaders)
|
||||||
}
|
}
|
||||||
@ -750,7 +750,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
expectedHeaders.remove('X-XSS-Protection')
|
expectedHeaders.remove('X-XSS-Protection')
|
||||||
when:
|
when:
|
||||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, expectedHeaders)
|
assertHeaders(response, expectedHeaders)
|
||||||
}
|
}
|
||||||
@ -853,7 +853,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
expectedHeaders['Content-Security-Policy'] = 'default-src \'self\''
|
expectedHeaders['Content-Security-Policy'] = 'default-src \'self\''
|
||||||
then:
|
then:
|
||||||
@ -885,7 +885,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Content-Security-Policy':'default-src \'self\''])
|
assertHeaders(response, ['Content-Security-Policy':'default-src \'self\''])
|
||||||
}
|
}
|
||||||
@ -913,7 +913,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest(secure:true, method: "GET"), response, new MockFilterChain())
|
||||||
def expectedHeaders = [:] << defaultHeaders
|
def expectedHeaders = [:] << defaultHeaders
|
||||||
expectedHeaders['Content-Security-Policy-Report-Only'] = 'default-src https:; report-uri https://example.com/'
|
expectedHeaders['Content-Security-Policy-Report-Only'] = 'default-src https:; report-uri https://example.com/'
|
||||||
then:
|
then:
|
||||||
@ -931,7 +931,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Referrer-Policy': 'no-referrer'])
|
assertHeaders(response, ['Referrer-Policy': 'no-referrer'])
|
||||||
}
|
}
|
||||||
@ -947,7 +947,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
|||||||
when:
|
when:
|
||||||
def hf = getFilter(HeaderWriterFilter)
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
hf.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain())
|
||||||
then:
|
then:
|
||||||
assertHeaders(response, ['Referrer-Policy': 'same-origin'])
|
assertHeaders(response, ['Referrer-Policy': 'same-origin'])
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
|||||||
createAppContext()
|
createAppContext()
|
||||||
then:
|
then:
|
||||||
Filter debugFilter = appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
Filter debugFilter = appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "")
|
||||||
request.setServletPath("/unprotected");
|
request.setServletPath("/unprotected");
|
||||||
debugFilter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
debugFilter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||||
request.setServletPath("/nomatch");
|
request.setServletPath("/nomatch");
|
||||||
|
@ -93,7 +93,7 @@ class MultiHttpBlockConfigTests extends AbstractHttpConfigTests {
|
|||||||
UserDetailsService uds = appContext.getBean('uds')
|
UserDetailsService uds = appContext.getBean('uds')
|
||||||
UserDetailsService uds2 = appContext.getBean('uds2')
|
UserDetailsService uds2 = appContext.getBean('uds2')
|
||||||
when:
|
when:
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "")
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
MockFilterChain chain = new MockFilterChain()
|
MockFilterChain chain = new MockFilterChain()
|
||||||
request.servletPath = "/first/login"
|
request.servletPath = "/first/login"
|
||||||
@ -104,7 +104,7 @@ class MultiHttpBlockConfigTests extends AbstractHttpConfigTests {
|
|||||||
verify(uds).loadUserByUsername(anyString()) || true
|
verify(uds).loadUserByUsername(anyString()) || true
|
||||||
verifyZeroInteractions(uds2) || true
|
verifyZeroInteractions(uds2) || true
|
||||||
when:
|
when:
|
||||||
MockHttpServletRequest request2 = new MockHttpServletRequest()
|
MockHttpServletRequest request2 = new MockHttpServletRequest("GET", "")
|
||||||
MockHttpServletResponse response2 = new MockHttpServletResponse()
|
MockHttpServletResponse response2 = new MockHttpServletResponse()
|
||||||
MockFilterChain chain2 = new MockFilterChain()
|
MockFilterChain chain2 = new MockFilterChain()
|
||||||
request2.servletPath = "/login"
|
request2.servletPath = "/login"
|
||||||
|
@ -115,7 +115,7 @@ class SessionManagementConfigTests extends AbstractHttpConfigTests {
|
|||||||
createAppContext()
|
createAppContext()
|
||||||
SessionRegistry registry = appContext.getBean(SessionRegistry)
|
SessionRegistry registry = appContext.getBean(SessionRegistry)
|
||||||
registry.registerNewSession("1", new User("user","password",AuthorityUtils.createAuthorityList("ROLE_USER")))
|
registry.registerNewSession("1", new User("user","password",AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "")
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
String credentials = "user:password"
|
String credentials = "user:password"
|
||||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||||
@ -134,7 +134,7 @@ class SessionManagementConfigTests extends AbstractHttpConfigTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
createAppContext()
|
createAppContext()
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "")
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
String originalSessionId = request.session.id
|
String originalSessionId = request.session.id
|
||||||
String credentials = "user:password"
|
String credentials = "user:password"
|
||||||
@ -282,7 +282,7 @@ class SessionManagementConfigTests extends AbstractHttpConfigTests {
|
|||||||
mockBean(SessionAuthenticationStrategy,'ss')
|
mockBean(SessionAuthenticationStrategy,'ss')
|
||||||
createAppContext()
|
createAppContext()
|
||||||
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.getSession();
|
request.getSession();
|
||||||
request.servletPath = "/login"
|
request.servletPath = "/login"
|
||||||
request.setMethod("POST");
|
request.setMethod("POST");
|
||||||
@ -343,15 +343,15 @@ class SessionManagementConfigTests extends AbstractHttpConfigTests {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
when: "First session is established"
|
when: "First session is established"
|
||||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
seshFilter.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain());
|
||||||
then: "ok"
|
then: "ok"
|
||||||
mockResponse.redirectedUrl == null
|
mockResponse.redirectedUrl == null
|
||||||
when: "Second session is established"
|
when: "Second session is established"
|
||||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
seshFilter.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain());
|
||||||
then: "ok"
|
then: "ok"
|
||||||
mockResponse.redirectedUrl == null
|
mockResponse.redirectedUrl == null
|
||||||
when: "Third session is established"
|
when: "Third session is established"
|
||||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
seshFilter.doFilter(new MockHttpServletRequest("GET", ""), response, new MockFilterChain());
|
||||||
then: "Rejected"
|
then: "Rejected"
|
||||||
mockResponse.redirectedUrl == "/max-exceeded";
|
mockResponse.redirectedUrl == "/max-exceeded";
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ public class FilterChainProxyConfigTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doNormalOperation(FilterChainProxy filterChainProxy) throws Exception {
|
private void doNormalOperation(FilterChainProxy filterChainProxy) throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.setServletPath("/foo/secure/super/somefile.html");
|
request.setServletPath("/foo/secure/super/somefile.html");
|
||||||
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
@ -54,7 +54,7 @@ public class WebSecurityTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setMethod("GET");
|
this.request.setMethod("GET");
|
||||||
this.response = new MockHttpServletResponse();
|
this.response = new MockHttpServletResponse();
|
||||||
this.chain = new MockFilterChain();
|
this.chain = new MockFilterChain();
|
||||||
|
@ -274,7 +274,7 @@ public class WebSecurityConfigurationTests {
|
|||||||
public void securityExpressionHandlerWhenPermissionEvaluatorBeanThenPermissionEvaluatorUsed() throws Exception {
|
public void securityExpressionHandlerWhenPermissionEvaluatorBeanThenPermissionEvaluatorUsed() throws Exception {
|
||||||
this.spring.register(WebSecurityExpressionHandlerPermissionEvaluatorBeanConfig.class).autowire();
|
this.spring.register(WebSecurityExpressionHandlerPermissionEvaluatorBeanConfig.class).autowire();
|
||||||
TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "notused");
|
TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "notused");
|
||||||
FilterInvocation invocation = new FilterInvocation(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain());
|
FilterInvocation invocation = new FilterInvocation(new MockHttpServletRequest("GET", ""), new MockHttpServletResponse(), new MockFilterChain());
|
||||||
|
|
||||||
AbstractSecurityExpressionHandler handler = this.spring.getContext().getBean(AbstractSecurityExpressionHandler.class);
|
AbstractSecurityExpressionHandler handler = this.spring.getContext().getBean(AbstractSecurityExpressionHandler.class);
|
||||||
EvaluationContext evaluationContext = handler.createEvaluationContext(authentication, invocation);
|
EvaluationContext evaluationContext = handler.createEvaluationContext(authentication, invocation);
|
||||||
|
@ -68,7 +68,7 @@ public class AuthorizeRequestsTests {
|
|||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.servletContext = spy(new MockServletContext());
|
this.servletContext = spy(new MockServletContext());
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setMethod("GET");
|
this.request.setMethod("GET");
|
||||||
this.response = new MockHttpServletResponse();
|
this.response = new MockHttpServletResponse();
|
||||||
this.chain = new MockFilterChain();
|
this.chain = new MockFilterChain();
|
||||||
|
@ -51,7 +51,7 @@ public class HttpSecurityAntMatchersTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = new MockFilterChain();
|
chain = new MockFilterChain();
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ public class HttpSecurityLogoutTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = new MockFilterChain();
|
chain = new MockFilterChain();
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ public class HttpSecurityRequestMatchersTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setMethod("GET");
|
this.request.setMethod("GET");
|
||||||
this.response = new MockHttpServletResponse();
|
this.response = new MockHttpServletResponse();
|
||||||
this.chain = new MockFilterChain();
|
this.chain = new MockFilterChain();
|
||||||
|
@ -72,7 +72,7 @@ public class SessionManagementConfigurerServlet31Tests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = new MockFilterChain();
|
chain = new MockFilterChain();
|
||||||
}
|
}
|
||||||
@ -88,7 +88,7 @@ public class SessionManagementConfigurerServlet31Tests {
|
|||||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||||
spy(ReflectionUtils.class);
|
spy(ReflectionUtils.class);
|
||||||
Method method = mock(Method.class);
|
Method method = mock(Method.class);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.getSession();
|
request.getSession();
|
||||||
request.setServletPath("/login");
|
request.setServletPath("/login");
|
||||||
request.setMethod("POST");
|
request.setMethod("POST");
|
||||||
|
@ -55,7 +55,7 @@ public class UrlAuthorizationConfigurerTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setMethod("GET");
|
this.request.setMethod("GET");
|
||||||
this.response = new MockHttpServletResponse();
|
this.response = new MockHttpServletResponse();
|
||||||
this.chain = new MockFilterChain();
|
this.chain = new MockFilterChain();
|
||||||
@ -211,4 +211,4 @@ public class UrlAuthorizationConfigurerTests {
|
|||||||
|
|
||||||
this.context.getAutowireCapableBeanFactory().autowireBean(this);
|
this.context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ public class OAuth2ClientConfigurerTests {
|
|||||||
|
|
||||||
AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
|
AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
|
||||||
new HttpSessionOAuth2AuthorizationRequestRepository();
|
new HttpSessionOAuth2AuthorizationRequestRepository();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
|
authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public class OAuth2LoginConfigurerTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.response = new MockHttpServletResponse();
|
this.response = new MockHttpServletResponse();
|
||||||
this.filterChain = new MockFilterChain();
|
this.filterChain = new MockFilterChain();
|
||||||
|
|
||||||
|
@ -493,7 +493,7 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MockHttpServletRequest sockjsHttpRequest(String mapping) {
|
private MockHttpServletRequest sockjsHttpRequest(String mapping) {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.setMethod("GET");
|
request.setMethod("GET");
|
||||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,
|
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,
|
||||||
"/289/tpyx6mde/websocket");
|
"/289/tpyx6mde/websocket");
|
||||||
|
@ -65,7 +65,7 @@ public class GrantedAuthorityDefaultsJcTests {
|
|||||||
public void setup() {
|
public void setup() {
|
||||||
setup("USER");
|
setup("USER");
|
||||||
|
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
request.setMethod("GET");
|
request.setMethod("GET");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = new MockFilterChain();
|
chain = new MockFilterChain();
|
||||||
|
@ -58,7 +58,7 @@ public class GrantedAuthorityDefaultsXmlTests {
|
|||||||
public void setup() {
|
public void setup() {
|
||||||
setup("USER");
|
setup("USER");
|
||||||
|
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
request.setMethod("GET");
|
request.setMethod("GET");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = new MockFilterChain();
|
chain = new MockFilterChain();
|
||||||
|
@ -123,7 +123,7 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private FilterInvocation createFilterInvocation(String path, String method) {
|
private FilterInvocation createFilterInvocation(String path, String method) {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.setRequestURI(null);
|
request.setRequestURI(null);
|
||||||
request.setMethod(method);
|
request.setMethod(method);
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ public class NamespaceHttpBasicTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setMethod("GET");
|
this.request.setMethod("GET");
|
||||||
this.response = new MockHttpServletResponse();
|
this.response = new MockHttpServletResponse();
|
||||||
this.chain = new MockFilterChain();
|
this.chain = new MockFilterChain();
|
||||||
|
@ -73,7 +73,7 @@ public class SessionManagementConfigServlet31Tests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = new MockFilterChain();
|
chain = new MockFilterChain();
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ public class SessionManagementConfigServlet31Tests {
|
|||||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||||
spy(ReflectionUtils.class);
|
spy(ReflectionUtils.class);
|
||||||
Method method = mock(Method.class);
|
Method method = mock(Method.class);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.getSession();
|
request.getSession();
|
||||||
request.setServletPath("/login");
|
request.setServletPath("/login");
|
||||||
request.setMethod("POST");
|
request.setMethod("POST");
|
||||||
@ -112,7 +112,7 @@ public class SessionManagementConfigServlet31Tests {
|
|||||||
public void changeSessionId() throws Exception {
|
public void changeSessionId() throws Exception {
|
||||||
spy(ReflectionUtils.class);
|
spy(ReflectionUtils.class);
|
||||||
Method method = mock(Method.class);
|
Method method = mock(Method.class);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.getSession();
|
request.getSession();
|
||||||
request.setServletPath("/login");
|
request.setServletPath("/login");
|
||||||
request.setMethod("POST");
|
request.setMethod("POST");
|
||||||
|
@ -55,7 +55,7 @@ public class CustomHttpSecurityConfigurerTests {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = new MockFilterChain();
|
chain = new MockFilterChain();
|
||||||
request.setMethod("GET");
|
request.setMethod("GET");
|
||||||
|
@ -18,10 +18,15 @@
|
|||||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns="http://www.springframework.org/schema/security"
|
xmlns="http://www.springframework.org/schema/security"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p"
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
|
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
|
||||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
|
||||||
|
<http-firewall ref="firewall"/>
|
||||||
<http auto-config="true"/>
|
<http auto-config="true"/>
|
||||||
|
|
||||||
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
||||||
|
|
||||||
|
<b:bean id="firewall" class="org.springframework.security.web.firewall.StrictHttpFirewall"
|
||||||
|
p:unsafeAllowAnyHttpMethod="true"/>
|
||||||
</b:beans>
|
</b:beans>
|
||||||
|
@ -18,13 +18,18 @@
|
|||||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns="http://www.springframework.org/schema/security"
|
xmlns="http://www.springframework.org/schema/security"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p"
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
|
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
|
||||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
|
||||||
|
<http-firewall ref="firewall"/>
|
||||||
<http auto-config="true">
|
<http auto-config="true">
|
||||||
<intercept-url pattern="/authenticated/**" access="authenticated"/>
|
<intercept-url pattern="/authenticated/**" access="authenticated"/>
|
||||||
<csrf/>
|
<csrf/>
|
||||||
</http>
|
</http>
|
||||||
|
|
||||||
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
||||||
|
|
||||||
|
<b:bean id="firewall" class="org.springframework.security.web.firewall.StrictHttpFirewall"
|
||||||
|
p:unsafeAllowAnyHttpMethod="true"/>
|
||||||
</b:beans>
|
</b:beans>
|
||||||
|
@ -179,6 +179,45 @@ public StrictHttpFirewall httpFirewall() {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
The `StrictHttpFirewall` provides a whitelist of valid HTTP methods that are allowed to protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering].
|
||||||
|
The default valid methods are "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", and "PUT".
|
||||||
|
If your application needs to modify the valid methods, you can configure a custom `StrictHttpFirewall` bean.
|
||||||
|
For example, the following will only allow HTTP "GET" and "POST" methods:
|
||||||
|
|
||||||
|
|
||||||
|
[source,xml]
|
||||||
|
----
|
||||||
|
<b:bean id="httpFirewall"
|
||||||
|
class="org.springframework.security.web.firewall.StrictHttpFirewall"
|
||||||
|
p:allowedHttpMethods="GET,HEAD"/>
|
||||||
|
|
||||||
|
<http-firewall ref="httpFirewall"/>
|
||||||
|
----
|
||||||
|
|
||||||
|
The same thing can be achieved with Java Configuration by exposing a `StrictHttpFirewall` bean.
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
public StrictHttpFirewall httpFirewall() {
|
||||||
|
StrictHttpFirewall firewall = new StrictHttpFirewall();
|
||||||
|
firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST"));
|
||||||
|
return firewall;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
If you are using `new MockHttpServletRequest()` it currently creates an HTTP method as an empty String "".
|
||||||
|
This is an invalid HTTP method and will be rejected by Spring Security.
|
||||||
|
You can resolve this by replacing it with `new MockHttpServletRequest("GET", "")`.
|
||||||
|
See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue requesting to improve this.
|
||||||
|
====
|
||||||
|
|
||||||
|
If you must allow any HTTP method (not recommended), you can use `StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`.
|
||||||
|
This will disable validation of the HTTP method entirely.
|
||||||
|
|
||||||
|
|
||||||
=== Use with other Filter-Based Frameworks
|
=== Use with other Filter-Based Frameworks
|
||||||
If you're using some other framework that is also filter-based, then you need to make sure that the Spring Security filters come first.
|
If you're using some other framework that is also filter-based, then you need to make sure that the Spring Security filters come first.
|
||||||
This enables the `SecurityContextHolder` to be populated in time for use by the other filters.
|
This enables the `SecurityContextHolder` to be populated in time for use by the other filters.
|
||||||
|
@ -238,7 +238,7 @@ public class FilterChainProxy extends GenericFilterBean {
|
|||||||
* @return matching filter list
|
* @return matching filter list
|
||||||
*/
|
*/
|
||||||
public List<Filter> getFilters(String url) {
|
public List<Filter> getFilters(String url) {
|
||||||
return getFilters(firewall.getFirewalledRequest((new FilterInvocation(url, null)
|
return getFilters(firewall.getFirewalledRequest((new FilterInvocation(url, "GET")
|
||||||
.getRequest())));
|
.getRequest())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.springframework.security.web.firewall;
|
package org.springframework.security.web.firewall;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -35,6 +37,11 @@ import java.util.Set;
|
|||||||
* </p>
|
* </p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>
|
* <li>
|
||||||
|
* Rejects HTTP methods that are not allowed. This specified to block
|
||||||
|
* <a href="https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)">HTTP Verb tampering and XST attacks</a>.
|
||||||
|
* See {@link #setAllowedHttpMethods(Collection)}
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
* Rejects URLs that are not normalized to avoid bypassing security constraints. There is
|
* Rejects URLs that are not normalized to avoid bypassing security constraints. There is
|
||||||
* no way to disable this as it is considered extremely risky to disable this constraint.
|
* no way to disable this as it is considered extremely risky to disable this constraint.
|
||||||
* A few options to allow this behavior is to normalize the request prior to the firewall
|
* A few options to allow this behavior is to normalize the request prior to the firewall
|
||||||
@ -66,6 +73,11 @@ import java.util.Set;
|
|||||||
* @since 4.2.4
|
* @since 4.2.4
|
||||||
*/
|
*/
|
||||||
public class StrictHttpFirewall implements HttpFirewall {
|
public class StrictHttpFirewall implements HttpFirewall {
|
||||||
|
/**
|
||||||
|
* Used to specify to {@link #setAllowedHttpMethods(Collection)} that any HTTP method should be allowed.
|
||||||
|
*/
|
||||||
|
private static final Set<String> ALLOW_ANY_HTTP_METHOD = Collections.unmodifiableSet(Collections.emptySet());
|
||||||
|
|
||||||
private static final String ENCODED_PERCENT = "%25";
|
private static final String ENCODED_PERCENT = "%25";
|
||||||
|
|
||||||
private static final String PERCENT = "%";
|
private static final String PERCENT = "%";
|
||||||
@ -82,6 +94,8 @@ public class StrictHttpFirewall implements HttpFirewall {
|
|||||||
|
|
||||||
private Set<String> decodedUrlBlacklist = new HashSet<String>();
|
private Set<String> decodedUrlBlacklist = new HashSet<String>();
|
||||||
|
|
||||||
|
private Set<String> allowedHttpMethods = createDefaultAllowedHttpMethods();
|
||||||
|
|
||||||
public StrictHttpFirewall() {
|
public StrictHttpFirewall() {
|
||||||
urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
|
urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
|
||||||
urlBlacklistsAddAll(FORBIDDEN_FORWARDSLASH);
|
urlBlacklistsAddAll(FORBIDDEN_FORWARDSLASH);
|
||||||
@ -92,6 +106,39 @@ public class StrictHttpFirewall implements HttpFirewall {
|
|||||||
this.decodedUrlBlacklist.add(PERCENT);
|
this.decodedUrlBlacklist.add(PERCENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if any HTTP method is allowed. If this set to true, then no validation on the HTTP method will be performed.
|
||||||
|
* This can open the application up to <a href="https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)">
|
||||||
|
* HTTP Verb tampering and XST attacks</a>
|
||||||
|
* @param unsafeAllowAnyHttpMethod if true, disables HTTP method validation, else resets back to the defaults. Default is false.
|
||||||
|
* @see #setAllowedHttpMethods(Collection)
|
||||||
|
* @since 5.1
|
||||||
|
*/
|
||||||
|
public void setUnsafeAllowAnyHttpMethod(boolean unsafeAllowAnyHttpMethod) {
|
||||||
|
this.allowedHttpMethods = unsafeAllowAnyHttpMethod ? ALLOW_ANY_HTTP_METHOD : createDefaultAllowedHttpMethods();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Determines which HTTP methods should be allowed. The default is to allow "DELETE", "GET", "HEAD", "OPTIONS",
|
||||||
|
* "PATCH", "POST", and "PUT".
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param allowedHttpMethods the case-sensitive collection of HTTP methods that are allowed.
|
||||||
|
* @see #setUnsafeAllowAnyHttpMethod(boolean)
|
||||||
|
* @since 5.1
|
||||||
|
*/
|
||||||
|
public void setAllowedHttpMethods(Collection<String> allowedHttpMethods) {
|
||||||
|
if (allowedHttpMethods == null) {
|
||||||
|
throw new IllegalArgumentException("allowedHttpMethods cannot be null");
|
||||||
|
}
|
||||||
|
if (allowedHttpMethods == ALLOW_ANY_HTTP_METHOD) {
|
||||||
|
this.allowedHttpMethods = ALLOW_ANY_HTTP_METHOD;
|
||||||
|
} else {
|
||||||
|
this.allowedHttpMethods = new HashSet<>(allowedHttpMethods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Determines if semicolon is allowed in the URL (i.e. matrix variables). The default
|
* Determines if semicolon is allowed in the URL (i.e. matrix variables). The default
|
||||||
@ -242,6 +289,7 @@ public class StrictHttpFirewall implements HttpFirewall {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
|
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
|
||||||
|
rejectForbiddenHttpMethod(request);
|
||||||
rejectedBlacklistedUrls(request);
|
rejectedBlacklistedUrls(request);
|
||||||
|
|
||||||
if (!isNormalized(request)) {
|
if (!isNormalized(request)) {
|
||||||
@ -259,6 +307,18 @@ public class StrictHttpFirewall implements HttpFirewall {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void rejectForbiddenHttpMethod(HttpServletRequest request) {
|
||||||
|
if (this.allowedHttpMethods == ALLOW_ANY_HTTP_METHOD) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.allowedHttpMethods.contains(request.getMethod())) {
|
||||||
|
throw new RequestRejectedException("The request was rejected because the HTTP method \"" +
|
||||||
|
request.getMethod() +
|
||||||
|
"\" was not included within the whitelist " +
|
||||||
|
this.allowedHttpMethods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void rejectedBlacklistedUrls(HttpServletRequest request) {
|
private void rejectedBlacklistedUrls(HttpServletRequest request) {
|
||||||
for (String forbidden : this.encodedUrlBlacklist) {
|
for (String forbidden : this.encodedUrlBlacklist) {
|
||||||
if (encodedUrlContains(request, forbidden)) {
|
if (encodedUrlContains(request, forbidden)) {
|
||||||
@ -277,6 +337,18 @@ public class StrictHttpFirewall implements HttpFirewall {
|
|||||||
return new FirewalledResponse(response);
|
return new FirewalledResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Set<String> createDefaultAllowedHttpMethods() {
|
||||||
|
Set<String> result = new HashSet<>();
|
||||||
|
result.add(HttpMethod.DELETE.name());
|
||||||
|
result.add(HttpMethod.GET.name());
|
||||||
|
result.add(HttpMethod.HEAD.name());
|
||||||
|
result.add(HttpMethod.OPTIONS.name());
|
||||||
|
result.add(HttpMethod.PATCH.name());
|
||||||
|
result.add(HttpMethod.POST.name());
|
||||||
|
result.add(HttpMethod.PUT.name());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isNormalized(HttpServletRequest request) {
|
private static boolean isNormalized(HttpServletRequest request) {
|
||||||
if (!isNormalized(request.getRequestURI())) {
|
if (!isNormalized(request.getRequestURI())) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -69,7 +69,7 @@ public class FilterChainProxyTests {
|
|||||||
fcp = new FilterChainProxy(new DefaultSecurityFilterChain(matcher,
|
fcp = new FilterChainProxy(new DefaultSecurityFilterChain(matcher,
|
||||||
Arrays.asList(filter)));
|
Arrays.asList(filter)));
|
||||||
fcp.setFilterChainValidator(mock(FilterChainProxy.FilterChainValidator.class));
|
fcp.setFilterChainValidator(mock(FilterChainProxy.FilterChainValidator.class));
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest("GET", "");
|
||||||
request.setServletPath("/path");
|
request.setServletPath("/path");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
chain = mock(FilterChain.class);
|
chain = mock(FilterChain.class);
|
||||||
|
@ -16,11 +16,17 @@
|
|||||||
|
|
||||||
package org.springframework.security.web.firewall;
|
package org.springframework.security.web.firewall;
|
||||||
|
|
||||||
import org.junit.Test;
|
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.fail;
|
import static org.assertj.core.api.Assertions.fail;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
*/
|
*/
|
||||||
@ -31,12 +37,61 @@ public class StrictHttpFirewallTests {
|
|||||||
|
|
||||||
private StrictHttpFirewall firewall = new StrictHttpFirewall();
|
private StrictHttpFirewall firewall = new StrictHttpFirewall();
|
||||||
|
|
||||||
private MockHttpServletRequest request = new MockHttpServletRequest();
|
private MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFirewalledRequestWhenInvalidMethodThenThrowsRequestRejectedException() {
|
||||||
|
this.request.setMethod("INVALID");
|
||||||
|
assertThatThrownBy(() -> this.firewall.getFirewalledRequest(this.request))
|
||||||
|
.isInstanceOf(RequestRejectedException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// blocks XST attacks
|
||||||
|
@Test
|
||||||
|
public void getFirewalledRequestWhenTraceMethodThenThrowsRequestRejectedException() {
|
||||||
|
this.request.setMethod(HttpMethod.TRACE.name());
|
||||||
|
assertThatThrownBy(() -> this.firewall.getFirewalledRequest(this.request))
|
||||||
|
.isInstanceOf(RequestRejectedException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// blocks XST attack if request is forwarded to a Microsoft IIS web server
|
||||||
|
public void getFirewalledRequestWhenTrackMethodThenThrowsRequestRejectedException() {
|
||||||
|
this.request.setMethod("TRACK");
|
||||||
|
assertThatThrownBy(() -> this.firewall.getFirewalledRequest(this.request))
|
||||||
|
.isInstanceOf(RequestRejectedException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// HTTP methods are case sensitive
|
||||||
|
public void getFirewalledRequestWhenLowercaseGetThenThrowsRequestRejectedException() {
|
||||||
|
this.request.setMethod("get");
|
||||||
|
assertThatThrownBy(() -> this.firewall.getFirewalledRequest(this.request))
|
||||||
|
.isInstanceOf(RequestRejectedException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFirewalledRequestWhenAllowedThenNoException() {
|
||||||
|
List<String> allowedMethods = Arrays.asList("DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT");
|
||||||
|
for (String allowedMethod : allowedMethods) {
|
||||||
|
this.request = new MockHttpServletRequest(allowedMethod, "");
|
||||||
|
assertThatCode(() -> this.firewall.getFirewalledRequest(this.request))
|
||||||
|
.doesNotThrowAnyException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFirewalledRequestWhenInvalidMethodAndAnyMethodThenNoException() {
|
||||||
|
this.firewall.setUnsafeAllowAnyHttpMethod(true);
|
||||||
|
this.request.setMethod("INVALID");
|
||||||
|
assertThatCode(() -> this.firewall.getFirewalledRequest(this.request))
|
||||||
|
.doesNotThrowAnyException();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFirewalledRequestWhenRequestURINotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
public void getFirewalledRequestWhenRequestURINotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
||||||
for (String path : this.unnormalizedPaths) {
|
for (String path : this.unnormalizedPaths) {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setRequestURI(path);
|
this.request.setRequestURI(path);
|
||||||
try {
|
try {
|
||||||
this.firewall.getFirewalledRequest(this.request);
|
this.firewall.getFirewalledRequest(this.request);
|
||||||
@ -49,7 +104,7 @@ public class StrictHttpFirewallTests {
|
|||||||
@Test
|
@Test
|
||||||
public void getFirewalledRequestWhenContextPathNotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
public void getFirewalledRequestWhenContextPathNotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
||||||
for (String path : this.unnormalizedPaths) {
|
for (String path : this.unnormalizedPaths) {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setContextPath(path);
|
this.request.setContextPath(path);
|
||||||
try {
|
try {
|
||||||
this.firewall.getFirewalledRequest(this.request);
|
this.firewall.getFirewalledRequest(this.request);
|
||||||
@ -62,7 +117,7 @@ public class StrictHttpFirewallTests {
|
|||||||
@Test
|
@Test
|
||||||
public void getFirewalledRequestWhenServletPathNotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
public void getFirewalledRequestWhenServletPathNotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
||||||
for (String path : this.unnormalizedPaths) {
|
for (String path : this.unnormalizedPaths) {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setServletPath(path);
|
this.request.setServletPath(path);
|
||||||
try {
|
try {
|
||||||
this.firewall.getFirewalledRequest(this.request);
|
this.firewall.getFirewalledRequest(this.request);
|
||||||
@ -75,7 +130,7 @@ public class StrictHttpFirewallTests {
|
|||||||
@Test
|
@Test
|
||||||
public void getFirewalledRequestWhenPathInfoNotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
public void getFirewalledRequestWhenPathInfoNotNormalizedThenThrowsRequestRejectedException() throws Exception {
|
||||||
for (String path : this.unnormalizedPaths) {
|
for (String path : this.unnormalizedPaths) {
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest("GET", "");
|
||||||
this.request.setPathInfo(path);
|
this.request.setPathInfo(path);
|
||||||
try {
|
try {
|
||||||
this.firewall.getFirewalledRequest(this.request);
|
this.firewall.getFirewalledRequest(this.request);
|
||||||
@ -352,7 +407,7 @@ public class StrictHttpFirewallTests {
|
|||||||
public void getFirewalledRequestWhenAllowUrlEncodedSlashAndLowercaseEncodedPathThenNoException() {
|
public void getFirewalledRequestWhenAllowUrlEncodedSlashAndLowercaseEncodedPathThenNoException() {
|
||||||
this.firewall.setAllowUrlEncodedSlash(true);
|
this.firewall.setAllowUrlEncodedSlash(true);
|
||||||
this.firewall.setAllowSemicolon(true);
|
this.firewall.setAllowSemicolon(true);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.setRequestURI("/context-root/a/b;%2f1/c");
|
request.setRequestURI("/context-root/a/b;%2f1/c");
|
||||||
request.setContextPath("/context-root");
|
request.setContextPath("/context-root");
|
||||||
request.setServletPath("");
|
request.setServletPath("");
|
||||||
@ -365,7 +420,7 @@ public class StrictHttpFirewallTests {
|
|||||||
public void getFirewalledRequestWhenAllowUrlEncodedSlashAndUppercaseEncodedPathThenNoException() {
|
public void getFirewalledRequestWhenAllowUrlEncodedSlashAndUppercaseEncodedPathThenNoException() {
|
||||||
this.firewall.setAllowUrlEncodedSlash(true);
|
this.firewall.setAllowUrlEncodedSlash(true);
|
||||||
this.firewall.setAllowSemicolon(true);
|
this.firewall.setAllowSemicolon(true);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||||
request.setRequestURI("/context-root/a/b;%2F1/c");
|
request.setRequestURI("/context-root/a/b;%2F1/c");
|
||||||
request.setContextPath("/context-root");
|
request.setContextPath("/context-root");
|
||||||
request.setServletPath("");
|
request.setServletPath("");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user