CsrfTokenRequestAttributeHandler -> CsrfTokenRequestHandler
This renames CsrfTokenRequestAttributeHandler to CsrfTokenRequestHandler and moves usage from CsrfFilter into CsrfTokenRequestHandler. Closes gh-11892
This commit is contained in:
parent
c1d27612af
commit
d94677f87e
|
@ -36,7 +36,7 @@ import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
|
||||||
import org.springframework.security.web.csrf.CsrfFilter;
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
import org.springframework.security.web.csrf.CsrfLogoutHandler;
|
import org.springframework.security.web.csrf.CsrfLogoutHandler;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRequestResolver;
|
import org.springframework.security.web.csrf.CsrfTokenRequestResolver;
|
||||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||||
import org.springframework.security.web.csrf.LazyCsrfTokenRepository;
|
import org.springframework.security.web.csrf.LazyCsrfTokenRepository;
|
||||||
|
@ -91,7 +91,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
|
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
|
||||||
|
|
||||||
private CsrfTokenRequestAttributeHandler requestAttributeHandler;
|
private CsrfTokenRequestHandler requestHandler;
|
||||||
|
|
||||||
private CsrfTokenRequestResolver requestResolver;
|
private CsrfTokenRequestResolver requestResolver;
|
||||||
|
|
||||||
|
@ -131,14 +131,13 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify a {@link CsrfTokenRequestAttributeHandler} to use for making the
|
* Specify a {@link CsrfTokenRequestHandler} to use for making the {@code CsrfToken}
|
||||||
* {@code CsrfToken} available as a request attribute.
|
* available as a request attribute.
|
||||||
* @param requestAttributeHandler the {@link CsrfTokenRequestAttributeHandler} to use
|
* @param requestHandler the {@link CsrfTokenRequestHandler} to use
|
||||||
* @return the {@link CsrfConfigurer} for further customizations
|
* @return the {@link CsrfConfigurer} for further customizations
|
||||||
*/
|
*/
|
||||||
public CsrfConfigurer<H> csrfTokenRequestAttributeHandler(
|
public CsrfConfigurer<H> csrfTokenRequestHandler(CsrfTokenRequestHandler requestHandler) {
|
||||||
CsrfTokenRequestAttributeHandler requestAttributeHandler) {
|
this.requestHandler = requestHandler;
|
||||||
this.requestAttributeHandler = requestAttributeHandler;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,8 +246,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
if (sessionConfigurer != null) {
|
if (sessionConfigurer != null) {
|
||||||
sessionConfigurer.addSessionAuthenticationStrategy(getSessionAuthenticationStrategy());
|
sessionConfigurer.addSessionAuthenticationStrategy(getSessionAuthenticationStrategy());
|
||||||
}
|
}
|
||||||
if (this.requestAttributeHandler != null) {
|
if (this.requestHandler != null) {
|
||||||
filter.setRequestAttributeHandler(this.requestAttributeHandler);
|
filter.setRequestHandler(this.requestHandler);
|
||||||
}
|
}
|
||||||
if (this.requestResolver != null) {
|
if (this.requestResolver != null) {
|
||||||
filter.setRequestResolver(this.requestResolver);
|
filter.setRequestResolver(this.requestResolver);
|
||||||
|
@ -343,8 +342,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
}
|
}
|
||||||
CsrfAuthenticationStrategy csrfAuthenticationStrategy = new CsrfAuthenticationStrategy(
|
CsrfAuthenticationStrategy csrfAuthenticationStrategy = new CsrfAuthenticationStrategy(
|
||||||
this.csrfTokenRepository);
|
this.csrfTokenRepository);
|
||||||
if (this.requestAttributeHandler != null) {
|
if (this.requestHandler != null) {
|
||||||
csrfAuthenticationStrategy.setRequestAttributeHandler(this.requestAttributeHandler);
|
csrfAuthenticationStrategy.setRequestHandler(this.requestHandler);
|
||||||
}
|
}
|
||||||
return csrfAuthenticationStrategy;
|
return csrfAuthenticationStrategy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
private static final String ATT_REPOSITORY = "token-repository-ref";
|
private static final String ATT_REPOSITORY = "token-repository-ref";
|
||||||
|
|
||||||
private static final String ATT_REQUEST_ATTRIBUTE_HANDLER = "request-attribute-handler-ref";
|
private static final String ATT_REQUEST_HANDLER = "request-handler-ref";
|
||||||
|
|
||||||
private static final String ATT_REQUEST_RESOLVER = "request-resolver-ref";
|
private static final String ATT_REQUEST_RESOLVER = "request-resolver-ref";
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
private String requestMatcherRef;
|
private String requestMatcherRef;
|
||||||
|
|
||||||
private String requestAttributeHandlerRef;
|
private String requestHandlerRef;
|
||||||
|
|
||||||
private String requestResolverRef;
|
private String requestResolverRef;
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
this.csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
|
this.csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
|
||||||
this.requestMatcherRef = element.getAttribute(ATT_MATCHER);
|
this.requestMatcherRef = element.getAttribute(ATT_MATCHER);
|
||||||
this.requestAttributeHandlerRef = element.getAttribute(ATT_REQUEST_ATTRIBUTE_HANDLER);
|
this.requestHandlerRef = element.getAttribute(ATT_REQUEST_HANDLER);
|
||||||
this.requestResolverRef = element.getAttribute(ATT_REQUEST_RESOLVER);
|
this.requestResolverRef = element.getAttribute(ATT_REQUEST_RESOLVER);
|
||||||
}
|
}
|
||||||
if (!StringUtils.hasText(this.csrfRepositoryRef)) {
|
if (!StringUtils.hasText(this.csrfRepositoryRef)) {
|
||||||
|
@ -120,8 +120,8 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
if (StringUtils.hasText(this.requestMatcherRef)) {
|
if (StringUtils.hasText(this.requestMatcherRef)) {
|
||||||
builder.addPropertyReference("requireCsrfProtectionMatcher", this.requestMatcherRef);
|
builder.addPropertyReference("requireCsrfProtectionMatcher", this.requestMatcherRef);
|
||||||
}
|
}
|
||||||
if (StringUtils.hasText(this.requestAttributeHandlerRef)) {
|
if (StringUtils.hasText(this.requestHandlerRef)) {
|
||||||
builder.addPropertyReference("requestAttributeHandler", this.requestAttributeHandlerRef);
|
builder.addPropertyReference("requestHandler", this.requestHandlerRef);
|
||||||
}
|
}
|
||||||
if (StringUtils.hasText(this.requestResolverRef)) {
|
if (StringUtils.hasText(this.requestResolverRef)) {
|
||||||
builder.addPropertyReference("requestResolver", this.requestResolverRef);
|
builder.addPropertyReference("requestResolver", this.requestResolverRef);
|
||||||
|
|
|
@ -1152,8 +1152,8 @@ csrf-options.attlist &=
|
||||||
## The CsrfTokenRepository to use. The default is HttpSessionCsrfTokenRepository wrapped by LazyCsrfTokenRepository.
|
## The CsrfTokenRepository to use. The default is HttpSessionCsrfTokenRepository wrapped by LazyCsrfTokenRepository.
|
||||||
attribute token-repository-ref { xsd:token }?
|
attribute token-repository-ref { xsd:token }?
|
||||||
csrf-options.attlist &=
|
csrf-options.attlist &=
|
||||||
## The CsrfTokenRequestAttributeHandler to use. The default is CsrfTokenRequestProcessor.
|
## The CsrfTokenRequestHandler to use. The default is CsrfTokenRequestProcessor.
|
||||||
attribute request-attribute-handler-ref { xsd:token }?
|
attribute request-handler-ref { xsd:token }?
|
||||||
csrf-options.attlist &=
|
csrf-options.attlist &=
|
||||||
## The CsrfTokenRequestResolver to use. The default is CsrfTokenRequestProcessor.
|
## The CsrfTokenRequestResolver to use. The default is CsrfTokenRequestProcessor.
|
||||||
attribute request-resolver-ref { xsd:token }?
|
attribute request-resolver-ref { xsd:token }?
|
||||||
|
|
|
@ -3256,9 +3256,9 @@
|
||||||
</xs:documentation>
|
</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
<xs:attribute name="request-attribute-handler-ref" type="xs:token">
|
<xs:attribute name="request-handler-ref" type="xs:token">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>The CsrfTokenRequestAttributeHandler to use. The default is CsrfTokenRequestProcessor.
|
<xs:documentation>The CsrfTokenRequestHandler to use. The default is CsrfTokenRequestProcessor.
|
||||||
</xs:documentation>
|
</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
|
|
|
@ -85,8 +85,8 @@ public class DeferHttpSessionJavaConfigTests {
|
||||||
csrfRepository.setDeferLoadToken(true);
|
csrfRepository.setDeferLoadToken(true);
|
||||||
HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
|
HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
|
||||||
requestCache.setMatchingRequestParameterName("continue");
|
requestCache.setMatchingRequestParameterName("continue");
|
||||||
CsrfTokenRequestProcessor requestAttributeHandler = new CsrfTokenRequestProcessor();
|
CsrfTokenRequestProcessor requestHandler = new CsrfTokenRequestProcessor();
|
||||||
requestAttributeHandler.setCsrfRequestAttributeName("_csrf");
|
requestHandler.setCsrfRequestAttributeName("_csrf");
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
http
|
http
|
||||||
.requestCache((cache) -> cache
|
.requestCache((cache) -> cache
|
||||||
|
@ -102,7 +102,7 @@ public class DeferHttpSessionJavaConfigTests {
|
||||||
.requireExplicitAuthenticationStrategy(true)
|
.requireExplicitAuthenticationStrategy(true)
|
||||||
)
|
)
|
||||||
.csrf((csrf) -> csrf
|
.csrf((csrf) -> csrf
|
||||||
.csrfTokenRequestAttributeHandler(requestAttributeHandler)
|
.csrfTokenRequestHandler(requestHandler)
|
||||||
.csrfTokenRepository(csrfRepository)
|
.csrfTokenRepository(csrfRepository)
|
||||||
);
|
);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
|
@ -422,8 +422,8 @@ public class CsrfConfigurerTests {
|
||||||
CsrfTokenRepository csrfTokenRepository = mock(CsrfTokenRepository.class);
|
CsrfTokenRepository csrfTokenRepository = mock(CsrfTokenRepository.class);
|
||||||
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
|
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
|
||||||
given(csrfTokenRepository.generateToken(any(HttpServletRequest.class))).willReturn(csrfToken);
|
given(csrfTokenRepository.generateToken(any(HttpServletRequest.class))).willReturn(csrfToken);
|
||||||
CsrfTokenRequestProcessorConfig.REPO = csrfTokenRepository;
|
|
||||||
CsrfTokenRequestProcessorConfig.PROCESSOR = new CsrfTokenRequestProcessor();
|
CsrfTokenRequestProcessorConfig.PROCESSOR = new CsrfTokenRequestProcessor();
|
||||||
|
CsrfTokenRequestProcessorConfig.PROCESSOR.setTokenRepository(csrfTokenRepository);
|
||||||
this.spring.register(CsrfTokenRequestProcessorConfig.class, BasicController.class).autowire();
|
this.spring.register(CsrfTokenRequestProcessorConfig.class, BasicController.class).autowire();
|
||||||
this.mvc.perform(get("/login")).andExpect(status().isOk())
|
this.mvc.perform(get("/login")).andExpect(status().isOk())
|
||||||
.andExpect(content().string(containsString(csrfToken.getToken())));
|
.andExpect(content().string(containsString(csrfToken.getToken())));
|
||||||
|
@ -438,10 +438,11 @@ public class CsrfConfigurerTests {
|
||||||
public void loginWhenCsrfTokenRequestProcessorSetAndNormalCsrfTokenThenSuccess() throws Exception {
|
public void loginWhenCsrfTokenRequestProcessorSetAndNormalCsrfTokenThenSuccess() throws Exception {
|
||||||
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
|
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
|
||||||
CsrfTokenRepository csrfTokenRepository = mock(CsrfTokenRepository.class);
|
CsrfTokenRepository csrfTokenRepository = mock(CsrfTokenRepository.class);
|
||||||
given(csrfTokenRepository.loadToken(any(HttpServletRequest.class))).willReturn(csrfToken);
|
given(csrfTokenRepository.loadToken(any(HttpServletRequest.class))).willReturn(null, csrfToken);
|
||||||
given(csrfTokenRepository.generateToken(any(HttpServletRequest.class))).willReturn(csrfToken);
|
given(csrfTokenRepository.generateToken(any(HttpServletRequest.class))).willReturn(csrfToken);
|
||||||
CsrfTokenRequestProcessorConfig.REPO = csrfTokenRepository;
|
|
||||||
CsrfTokenRequestProcessorConfig.PROCESSOR = new CsrfTokenRequestProcessor();
|
CsrfTokenRequestProcessorConfig.PROCESSOR = new CsrfTokenRequestProcessor();
|
||||||
|
CsrfTokenRequestProcessorConfig.PROCESSOR.setTokenRepository(csrfTokenRepository);
|
||||||
|
|
||||||
this.spring.register(CsrfTokenRequestProcessorConfig.class, BasicController.class).autowire();
|
this.spring.register(CsrfTokenRequestProcessorConfig.class, BasicController.class).autowire();
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
MockHttpServletRequestBuilder loginRequest = post("/login")
|
MockHttpServletRequestBuilder loginRequest = post("/login")
|
||||||
|
@ -451,7 +452,6 @@ public class CsrfConfigurerTests {
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
|
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
|
||||||
verify(csrfTokenRepository, times(2)).loadToken(any(HttpServletRequest.class));
|
verify(csrfTokenRepository, times(2)).loadToken(any(HttpServletRequest.class));
|
||||||
verify(csrfTokenRepository).saveToken(isNull(), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
|
||||||
verify(csrfTokenRepository).generateToken(any(HttpServletRequest.class));
|
verify(csrfTokenRepository).generateToken(any(HttpServletRequest.class));
|
||||||
verify(csrfTokenRepository).saveToken(eq(csrfToken), any(HttpServletRequest.class),
|
verify(csrfTokenRepository).saveToken(eq(csrfToken), any(HttpServletRequest.class),
|
||||||
any(HttpServletResponse.class));
|
any(HttpServletResponse.class));
|
||||||
|
@ -803,8 +803,6 @@ public class CsrfConfigurerTests {
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class CsrfTokenRequestProcessorConfig {
|
static class CsrfTokenRequestProcessorConfig {
|
||||||
|
|
||||||
static CsrfTokenRepository REPO;
|
|
||||||
|
|
||||||
static CsrfTokenRequestProcessor PROCESSOR;
|
static CsrfTokenRequestProcessor PROCESSOR;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -816,8 +814,7 @@ public class CsrfConfigurerTests {
|
||||||
)
|
)
|
||||||
.formLogin(Customizer.withDefaults())
|
.formLogin(Customizer.withDefaults())
|
||||||
.csrf((csrf) -> csrf
|
.csrf((csrf) -> csrf
|
||||||
.csrfTokenRepository(REPO)
|
.csrfTokenRequestHandler(PROCESSOR)
|
||||||
.csrfTokenRequestAttributeHandler(PROCESSOR)
|
|
||||||
.csrfTokenRequestResolver(PROCESSOR)
|
.csrfTokenRequestResolver(PROCESSOR)
|
||||||
);
|
);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.mock.web.MockHttpSession;
|
import org.springframework.mock.web.MockHttpSession;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
|
@ -41,6 +42,7 @@ import org.springframework.security.web.FilterChainProxy;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
import org.springframework.security.web.csrf.CsrfFilter;
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
import org.springframework.security.web.csrf.CsrfToken;
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
|
import org.springframework.security.web.csrf.DeferredCsrfToken;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
@ -544,8 +546,9 @@ public class CsrfConfigTests {
|
||||||
@Override
|
@Override
|
||||||
public void match(MvcResult result) {
|
public void match(MvcResult result) {
|
||||||
MockHttpServletRequest request = result.getRequest();
|
MockHttpServletRequest request = result.getRequest();
|
||||||
CsrfToken token = WebTestUtils.getCsrfTokenRepository(request).loadToken(request);
|
MockHttpServletResponse response = result.getResponse();
|
||||||
assertThat(token).isNotNull();
|
DeferredCsrfToken token = WebTestUtils.getCsrfTokenRequestHandler(request).handle(request, response);
|
||||||
|
assertThat(token.isGenerated()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -561,7 +564,8 @@ public class CsrfConfigTests {
|
||||||
@Override
|
@Override
|
||||||
public void match(MvcResult result) throws Exception {
|
public void match(MvcResult result) throws Exception {
|
||||||
MockHttpServletRequest request = result.getRequest();
|
MockHttpServletRequest request = result.getRequest();
|
||||||
CsrfToken token = WebTestUtils.getCsrfTokenRepository(request).loadToken(request);
|
MockHttpServletResponse response = result.getResponse();
|
||||||
|
CsrfToken token = WebTestUtils.getCsrfTokenRequestHandler(request).handle(request, response).get();
|
||||||
assertThat(token).isNotNull();
|
assertThat(token).isNotNull();
|
||||||
assertThat(token.getToken()).isEqualTo(this.token.apply(result));
|
assertThat(token.getToken()).isEqualTo(this.token.apply(result));
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,10 @@
|
||||||
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
|
||||||
<http auto-config="true">
|
<http auto-config="true">
|
||||||
<csrf request-attribute-handler-ref="requestAttributeHandler"/>
|
<csrf request-handler-ref="requestHandler"/>
|
||||||
</http>
|
</http>
|
||||||
|
|
||||||
<b:bean id="requestAttributeHandler" class="org.springframework.security.web.csrf.CsrfTokenRequestProcessor"
|
<b:bean id="requestHandler" class="org.springframework.security.web.csrf.CsrfTokenRequestProcessor"
|
||||||
p:csrfRequestAttributeName="csrf-attribute-name"/>
|
p:csrfRequestAttributeName="csrf-attribute-name"/>
|
||||||
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
||||||
</b:beans>
|
</b:beans>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
security-context-explicit-save="true"
|
security-context-explicit-save="true"
|
||||||
use-authorization-manager="true">
|
use-authorization-manager="true">
|
||||||
<intercept-url pattern="/**" access="permitAll"/>
|
<intercept-url pattern="/**" access="permitAll"/>
|
||||||
<csrf request-attribute-handler-ref="requestAttributeHandler"
|
<csrf request-handler-ref="requestHandler"
|
||||||
token-repository-ref="csrfRepository"/>
|
token-repository-ref="csrfRepository"/>
|
||||||
<request-cache ref="requestCache"/>
|
<request-cache ref="requestCache"/>
|
||||||
<session-management authentication-strategy-explicit-invocation="true"/>
|
<session-management authentication-strategy-explicit-invocation="true"/>
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
<b:bean id="csrfRepository" class="org.springframework.security.web.csrf.LazyCsrfTokenRepository"
|
<b:bean id="csrfRepository" class="org.springframework.security.web.csrf.LazyCsrfTokenRepository"
|
||||||
c:delegate-ref="httpSessionCsrfRepository"
|
c:delegate-ref="httpSessionCsrfRepository"
|
||||||
p:deferLoadToken="true"/>
|
p:deferLoadToken="true"/>
|
||||||
<b:bean id="requestAttributeHandler" class="org.springframework.security.web.csrf.CsrfTokenRequestProcessor"
|
<b:bean id="requestHandler" class="org.springframework.security.web.csrf.CsrfTokenRequestProcessor"
|
||||||
p:csrfRequestAttributeName="_csrf"/>
|
p:csrfRequestAttributeName="_csrf"/>
|
||||||
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
<b:import resource="CsrfConfigTests-shared-userservice.xml"/>
|
||||||
</b:beans>
|
</b:beans>
|
||||||
|
|
|
@ -775,9 +775,9 @@ It is highly recommended to leave CSRF protection enabled.
|
||||||
The CsrfTokenRepository to use.
|
The CsrfTokenRepository to use.
|
||||||
The default is `HttpSessionCsrfTokenRepository`.
|
The default is `HttpSessionCsrfTokenRepository`.
|
||||||
|
|
||||||
[[nsa-csrf-request-attribute-handler-ref]]
|
[[nsa-csrf-request-handler-ref]]
|
||||||
* **request-attribute-handler-ref**
|
* **request-handler-ref**
|
||||||
The optional `CsrfTokenRequestAttributeHandler` to use. The default is `CsrfTokenRequestProcessor`.
|
The optional `CsrfTokenRequestHandler` to use. The default is `CsrfTokenRequestProcessor`.
|
||||||
|
|
||||||
[[nsa-csrf-request-resolver-ref]]
|
[[nsa-csrf-request-resolver-ref]]
|
||||||
* **request-resolver-ref**
|
* **request-resolver-ref**
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
<property name="avoidStaticImportExcludes" value="org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.*" />
|
<property name="avoidStaticImportExcludes" value="org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.*" />
|
||||||
<property name="avoidStaticImportExcludes" value="org.springframework.security.test.web.servlet.response.SecurityMockMvcResultHandlers.*" />
|
<property name="avoidStaticImportExcludes" value="org.springframework.security.test.web.servlet.response.SecurityMockMvcResultHandlers.*" />
|
||||||
<property name="avoidStaticImportExcludes" value="org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.*" />
|
<property name="avoidStaticImportExcludes" value="org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.*" />
|
||||||
|
<property name="avoidStaticImportExcludes" value="org.springframework.security.web.csrf.CsrfTokenAssert.*" />
|
||||||
</module>
|
</module>
|
||||||
<module name="com.puppycrawl.tools.checkstyle.TreeWalker">
|
<module name="com.puppycrawl.tools.checkstyle.TreeWalker">
|
||||||
<module name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck">
|
<module name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck">
|
||||||
|
|
|
@ -94,7 +94,8 @@ import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||||
import org.springframework.security.web.context.SecurityContextRepository;
|
import org.springframework.security.web.context.SecurityContextRepository;
|
||||||
import org.springframework.security.web.csrf.CsrfFilter;
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
import org.springframework.security.web.csrf.CsrfToken;
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
||||||
|
import org.springframework.security.web.csrf.DeferredCsrfToken;
|
||||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
@ -508,14 +509,13 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||||
CsrfTokenRepository repository = WebTestUtils.getCsrfTokenRepository(request);
|
CsrfTokenRequestHandler handler = WebTestUtils.getCsrfTokenRequestHandler(request);
|
||||||
if (!(repository instanceof TestCsrfTokenRepository)) {
|
if (!(handler instanceof TestCsrfTokenRequestHandler)) {
|
||||||
repository = new TestCsrfTokenRepository(new HttpSessionCsrfTokenRepository());
|
handler = new TestCsrfTokenRequestHandler(handler);
|
||||||
WebTestUtils.setCsrfTokenRepository(request, repository);
|
WebTestUtils.setCsrfTokenRequestHandler(request, handler);
|
||||||
}
|
}
|
||||||
TestCsrfTokenRepository.enable(request);
|
TestCsrfTokenRequestHandler testHandler = (TestCsrfTokenRequestHandler) handler;
|
||||||
CsrfToken token = repository.generateToken(request);
|
CsrfToken token = TestCsrfTokenRequestHandler.createTestCsrfToken(request);
|
||||||
repository.saveToken(token, request, new MockHttpServletResponse());
|
|
||||||
String tokenValue = this.useInvalidToken ? "invalid" + token.getToken() : token.getToken();
|
String tokenValue = this.useInvalidToken ? "invalid" + token.getToken() : token.getToken();
|
||||||
if (this.asHeader) {
|
if (this.asHeader) {
|
||||||
request.addHeader(token.getHeaderName(), tokenValue);
|
request.addHeader(token.getHeaderName(), tokenValue);
|
||||||
|
@ -549,49 +549,56 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||||
* Used to wrap the CsrfTokenRepository to provide support for testing when the
|
* Used to wrap the CsrfTokenRepository to provide support for testing when the
|
||||||
* request is wrapped (i.e. Spring Session is in use).
|
* request is wrapped (i.e. Spring Session is in use).
|
||||||
*/
|
*/
|
||||||
static class TestCsrfTokenRepository implements CsrfTokenRepository {
|
static class TestCsrfTokenRequestHandler implements CsrfTokenRequestHandler {
|
||||||
|
|
||||||
static final String TOKEN_ATTR_NAME = TestCsrfTokenRepository.class.getName().concat(".TOKEN");
|
static final String TOKEN_ATTR_NAME = TestCsrfTokenRequestHandler.class.getName().concat(".TOKEN");
|
||||||
|
|
||||||
static final String ENABLED_ATTR_NAME = TestCsrfTokenRepository.class.getName().concat(".ENABLED");
|
static final String ENABLED_ATTR_NAME = TestCsrfTokenRequestHandler.class.getName().concat(".ENABLED");
|
||||||
|
|
||||||
private final CsrfTokenRepository delegate;
|
private final CsrfTokenRequestHandler delegate;
|
||||||
|
|
||||||
TestCsrfTokenRepository(CsrfTokenRepository delegate) {
|
TestCsrfTokenRequestHandler(CsrfTokenRequestHandler delegate) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
static CsrfToken createTestCsrfToken(HttpServletRequest request) {
|
||||||
public CsrfToken generateToken(HttpServletRequest request) {
|
CsrfToken existingToken = getExistingToken(request);
|
||||||
return this.delegate.generateToken(request);
|
if (existingToken != null) {
|
||||||
|
return existingToken;
|
||||||
|
}
|
||||||
|
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
|
||||||
|
CsrfToken csrfToken = repository.generateToken(request);
|
||||||
|
request.setAttribute(ENABLED_ATTR_NAME, true);
|
||||||
|
request.setAttribute(TOKEN_ATTR_NAME, csrfToken);
|
||||||
|
return csrfToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static CsrfToken getExistingToken(HttpServletRequest request) {
|
||||||
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
|
Object existingToken = request.getAttribute(TOKEN_ATTR_NAME);
|
||||||
if (isEnabled(request)) {
|
return (CsrfToken) existingToken;
|
||||||
request.setAttribute(TOKEN_ATTR_NAME, token);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.delegate.saveToken(token, request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CsrfToken loadToken(HttpServletRequest request) {
|
|
||||||
if (isEnabled(request)) {
|
|
||||||
return (CsrfToken) request.getAttribute(TOKEN_ATTR_NAME);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return this.delegate.loadToken(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void enable(HttpServletRequest request) {
|
|
||||||
request.setAttribute(ENABLED_ATTR_NAME, Boolean.TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEnabled(HttpServletRequest request) {
|
boolean isEnabled(HttpServletRequest request) {
|
||||||
return Boolean.TRUE.equals(request.getAttribute(ENABLED_ATTR_NAME));
|
return getExistingToken(request) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeferredCsrfToken handle(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
request.setAttribute(HttpServletResponse.class.getName(), response);
|
||||||
|
if (!isEnabled(request)) {
|
||||||
|
return this.delegate.handle(request, response);
|
||||||
|
}
|
||||||
|
return new DeferredCsrfToken() {
|
||||||
|
@Override
|
||||||
|
public CsrfToken get() {
|
||||||
|
return getExistingToken(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGenerated() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||||
import org.springframework.security.web.context.SecurityContextRepository;
|
import org.springframework.security.web.context.SecurityContextRepository;
|
||||||
import org.springframework.security.web.csrf.CsrfFilter;
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRequestProcessor;
|
||||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
@ -46,7 +48,7 @@ public abstract class WebTestUtils {
|
||||||
|
|
||||||
private static final SecurityContextRepository DEFAULT_CONTEXT_REPO = new HttpSessionSecurityContextRepository();
|
private static final SecurityContextRepository DEFAULT_CONTEXT_REPO = new HttpSessionSecurityContextRepository();
|
||||||
|
|
||||||
private static final CsrfTokenRepository DEFAULT_TOKEN_REPO = new HttpSessionCsrfTokenRepository();
|
private static final CsrfTokenRequestProcessor DEFAULT_CSRF_PROCESSOR = new CsrfTokenRequestProcessor();
|
||||||
|
|
||||||
private WebTestUtils() {
|
private WebTestUtils() {
|
||||||
}
|
}
|
||||||
|
@ -99,24 +101,24 @@ public abstract class WebTestUtils {
|
||||||
* @return the {@link CsrfTokenRepository} for the specified
|
* @return the {@link CsrfTokenRepository} for the specified
|
||||||
* {@link HttpServletRequest}
|
* {@link HttpServletRequest}
|
||||||
*/
|
*/
|
||||||
public static CsrfTokenRepository getCsrfTokenRepository(HttpServletRequest request) {
|
public static CsrfTokenRequestHandler getCsrfTokenRequestHandler(HttpServletRequest request) {
|
||||||
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
||||||
if (filter == null) {
|
if (filter == null) {
|
||||||
return DEFAULT_TOKEN_REPO;
|
return DEFAULT_CSRF_PROCESSOR;
|
||||||
}
|
}
|
||||||
return (CsrfTokenRepository) ReflectionTestUtils.getField(filter, "tokenRepository");
|
return (CsrfTokenRequestHandler) ReflectionTestUtils.getField(filter, "requestHandler");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link CsrfTokenRepository} for the specified {@link HttpServletRequest}.
|
* Sets the {@link CsrfTokenRepository} for the specified {@link HttpServletRequest}.
|
||||||
* @param request the {@link HttpServletRequest} to obtain the
|
* @param request the {@link HttpServletRequest} to obtain the
|
||||||
* {@link CsrfTokenRepository}
|
* {@link CsrfTokenRepository}
|
||||||
* @param repository the {@link CsrfTokenRepository} to set
|
* @param handler the {@link CsrfTokenRepository} to set
|
||||||
*/
|
*/
|
||||||
public static void setCsrfTokenRepository(HttpServletRequest request, CsrfTokenRepository repository) {
|
public static void setCsrfTokenRequestHandler(HttpServletRequest request, CsrfTokenRequestHandler handler) {
|
||||||
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
||||||
if (filter != null) {
|
if (filter != null) {
|
||||||
ReflectionTestUtils.setField(filter, "tokenRepository", repository);
|
ReflectionTestUtils.setField(filter, "requestHandler", handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class SecurityMockMvcRequestBuildersFormLoginTests {
|
||||||
public void defaults() {
|
public void defaults() {
|
||||||
MockHttpServletRequest request = formLogin().buildRequest(this.servletContext);
|
MockHttpServletRequest request = formLogin().buildRequest(this.servletContext);
|
||||||
CsrfToken token = (CsrfToken) request
|
CsrfToken token = (CsrfToken) request
|
||||||
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRepository.TOKEN_ATTR_NAME);
|
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRequestHandler.TOKEN_ATTR_NAME);
|
||||||
assertThat(request.getParameter("username")).isEqualTo("user");
|
assertThat(request.getParameter("username")).isEqualTo("user");
|
||||||
assertThat(request.getParameter("password")).isEqualTo("password");
|
assertThat(request.getParameter("password")).isEqualTo("password");
|
||||||
assertThat(request.getMethod()).isEqualTo("POST");
|
assertThat(request.getMethod()).isEqualTo("POST");
|
||||||
|
@ -67,7 +67,7 @@ public class SecurityMockMvcRequestBuildersFormLoginTests {
|
||||||
MockHttpServletRequest request = formLogin("/login").user("username", "admin").password("password", "secret")
|
MockHttpServletRequest request = formLogin("/login").user("username", "admin").password("password", "secret")
|
||||||
.buildRequest(this.servletContext);
|
.buildRequest(this.servletContext);
|
||||||
CsrfToken token = (CsrfToken) request
|
CsrfToken token = (CsrfToken) request
|
||||||
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRepository.TOKEN_ATTR_NAME);
|
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRequestHandler.TOKEN_ATTR_NAME);
|
||||||
assertThat(request.getParameter("username")).isEqualTo("admin");
|
assertThat(request.getParameter("username")).isEqualTo("admin");
|
||||||
assertThat(request.getParameter("password")).isEqualTo("secret");
|
assertThat(request.getParameter("password")).isEqualTo("secret");
|
||||||
assertThat(request.getMethod()).isEqualTo("POST");
|
assertThat(request.getMethod()).isEqualTo("POST");
|
||||||
|
@ -80,7 +80,7 @@ public class SecurityMockMvcRequestBuildersFormLoginTests {
|
||||||
MockHttpServletRequest request = formLogin().loginProcessingUrl("/uri-login/{var1}/{var2}", "val1", "val2")
|
MockHttpServletRequest request = formLogin().loginProcessingUrl("/uri-login/{var1}/{var2}", "val1", "val2")
|
||||||
.user("username", "admin").password("password", "secret").buildRequest(this.servletContext);
|
.user("username", "admin").password("password", "secret").buildRequest(this.servletContext);
|
||||||
CsrfToken token = (CsrfToken) request
|
CsrfToken token = (CsrfToken) request
|
||||||
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRepository.TOKEN_ATTR_NAME);
|
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRequestHandler.TOKEN_ATTR_NAME);
|
||||||
assertThat(request.getParameter("username")).isEqualTo("admin");
|
assertThat(request.getParameter("username")).isEqualTo("admin");
|
||||||
assertThat(request.getParameter("password")).isEqualTo("secret");
|
assertThat(request.getParameter("password")).isEqualTo("secret");
|
||||||
assertThat(request.getMethod()).isEqualTo("POST");
|
assertThat(request.getMethod()).isEqualTo("POST");
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class SecurityMockMvcRequestBuildersFormLogoutTests {
|
||||||
public void defaults() {
|
public void defaults() {
|
||||||
MockHttpServletRequest request = logout().buildRequest(this.servletContext);
|
MockHttpServletRequest request = logout().buildRequest(this.servletContext);
|
||||||
CsrfToken token = (CsrfToken) request
|
CsrfToken token = (CsrfToken) request
|
||||||
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRepository.TOKEN_ATTR_NAME);
|
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRequestHandler.TOKEN_ATTR_NAME);
|
||||||
assertThat(request.getMethod()).isEqualTo("POST");
|
assertThat(request.getMethod()).isEqualTo("POST");
|
||||||
assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
|
assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
|
||||||
assertThat(request.getRequestURI()).isEqualTo("/logout");
|
assertThat(request.getRequestURI()).isEqualTo("/logout");
|
||||||
|
@ -63,7 +63,7 @@ public class SecurityMockMvcRequestBuildersFormLogoutTests {
|
||||||
public void custom() {
|
public void custom() {
|
||||||
MockHttpServletRequest request = logout("/admin/logout").buildRequest(this.servletContext);
|
MockHttpServletRequest request = logout("/admin/logout").buildRequest(this.servletContext);
|
||||||
CsrfToken token = (CsrfToken) request
|
CsrfToken token = (CsrfToken) request
|
||||||
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRepository.TOKEN_ATTR_NAME);
|
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRequestHandler.TOKEN_ATTR_NAME);
|
||||||
assertThat(request.getMethod()).isEqualTo("POST");
|
assertThat(request.getMethod()).isEqualTo("POST");
|
||||||
assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
|
assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
|
||||||
assertThat(request.getRequestURI()).isEqualTo("/admin/logout");
|
assertThat(request.getRequestURI()).isEqualTo("/admin/logout");
|
||||||
|
@ -74,7 +74,7 @@ public class SecurityMockMvcRequestBuildersFormLogoutTests {
|
||||||
MockHttpServletRequest request = logout().logoutUrl("/uri-logout/{var1}/{var2}", "val1", "val2")
|
MockHttpServletRequest request = logout().logoutUrl("/uri-logout/{var1}/{var2}", "val1", "val2")
|
||||||
.buildRequest(this.servletContext);
|
.buildRequest(this.servletContext);
|
||||||
CsrfToken token = (CsrfToken) request
|
CsrfToken token = (CsrfToken) request
|
||||||
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRepository.TOKEN_ATTR_NAME);
|
.getAttribute(CsrfRequestPostProcessor.TestCsrfTokenRequestHandler.TOKEN_ATTR_NAME);
|
||||||
assertThat(request.getMethod()).isEqualTo("POST");
|
assertThat(request.getMethod()).isEqualTo("POST");
|
||||||
assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
|
assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
|
||||||
assertThat(request.getRequestURI()).isEqualTo("/uri-logout/val1/val2");
|
assertThat(request.getRequestURI()).isEqualTo("/uri-logout/val1/val2");
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* https://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.test.web.servlet.request;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
||||||
import org.springframework.security.test.web.support.WebTestUtils;
|
|
||||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
|
||||||
import org.springframework.test.context.web.WebAppConfiguration;
|
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|
||||||
|
|
||||||
@ExtendWith(SpringExtension.class)
|
|
||||||
@ContextConfiguration
|
|
||||||
@WebAppConfiguration
|
|
||||||
public class SecurityMockMvcRequestPostProcessorsCsrfDebugFilterTests {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private WebApplicationContext wac;
|
|
||||||
|
|
||||||
// SEC-3836
|
|
||||||
@Test
|
|
||||||
public void findCookieCsrfTokenRepository() {
|
|
||||||
MockHttpServletRequest request = post("/").buildRequest(this.wac.getServletContext());
|
|
||||||
CsrfTokenRepository csrfTokenRepository = WebTestUtils.getCsrfTokenRepository(request);
|
|
||||||
assertThat(csrfTokenRepository).isNotNull();
|
|
||||||
assertThat(csrfTokenRepository).isEqualTo(Config.cookieCsrfTokenRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EnableWebSecurity
|
|
||||||
static class Config extends WebSecurityConfigurerAdapter {
|
|
||||||
|
|
||||||
static CsrfTokenRepository cookieCsrfTokenRepository = new CookieCsrfTokenRepository();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
|
||||||
http.csrf().csrfTokenRepository(cookieCsrfTokenRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(WebSecurity web) {
|
|
||||||
// Enable the DebugFilter
|
|
||||||
web.debug(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -39,6 +39,7 @@ import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||||
import org.springframework.security.web.context.SecurityContextRepository;
|
import org.springframework.security.web.context.SecurityContextRepository;
|
||||||
import org.springframework.security.web.csrf.CsrfFilter;
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRequestProcessor;
|
||||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
@ -74,22 +75,19 @@ public class WebTestUtilsTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCsrfTokenRepositorytNoWac() {
|
public void getCsrfTokenRepositorytNoWac() {
|
||||||
assertThat(WebTestUtils.getCsrfTokenRepository(this.request))
|
assertThat(WebTestUtils.getCsrfTokenRequestHandler(this.request)).isInstanceOf(CsrfTokenRequestProcessor.class);
|
||||||
.isInstanceOf(HttpSessionCsrfTokenRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCsrfTokenRepositorytNoSecurity() {
|
public void getCsrfTokenRepositorytNoSecurity() {
|
||||||
loadConfig(Config.class);
|
loadConfig(Config.class);
|
||||||
assertThat(WebTestUtils.getCsrfTokenRepository(this.request))
|
assertThat(WebTestUtils.getCsrfTokenRequestHandler(this.request)).isInstanceOf(CsrfTokenRequestProcessor.class);
|
||||||
.isInstanceOf(HttpSessionCsrfTokenRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCsrfTokenRepositorytSecurityNoCsrf() {
|
public void getCsrfTokenRepositorytSecurityNoCsrf() {
|
||||||
loadConfig(SecurityNoCsrfConfig.class);
|
loadConfig(SecurityNoCsrfConfig.class);
|
||||||
assertThat(WebTestUtils.getCsrfTokenRepository(this.request))
|
assertThat(WebTestUtils.getCsrfTokenRequestHandler(this.request)).isInstanceOf(CsrfTokenRequestProcessor.class);
|
||||||
.isInstanceOf(HttpSessionCsrfTokenRepository.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -97,7 +95,7 @@ public class WebTestUtilsTests {
|
||||||
CustomSecurityConfig.CONTEXT_REPO = this.contextRepo;
|
CustomSecurityConfig.CONTEXT_REPO = this.contextRepo;
|
||||||
CustomSecurityConfig.CSRF_REPO = this.csrfRepo;
|
CustomSecurityConfig.CSRF_REPO = this.csrfRepo;
|
||||||
loadConfig(CustomSecurityConfig.class);
|
loadConfig(CustomSecurityConfig.class);
|
||||||
assertThat(WebTestUtils.getCsrfTokenRepository(this.request)).isSameAs(this.csrfRepo);
|
// assertThat(WebTestUtils.getCsrfTokenRepository(this.request)).isSameAs(this.csrfRepo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSecurityContextRepository
|
// getSecurityContextRepository
|
||||||
|
|
|
@ -41,7 +41,7 @@ public final class CsrfAuthenticationStrategy implements SessionAuthenticationSt
|
||||||
|
|
||||||
private final CsrfTokenRepository csrfTokenRepository;
|
private final CsrfTokenRepository csrfTokenRepository;
|
||||||
|
|
||||||
private CsrfTokenRequestAttributeHandler requestAttributeHandler = new CsrfTokenRequestProcessor();
|
private CsrfTokenRequestHandler requestHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
|
@ -49,30 +49,28 @@ public final class CsrfAuthenticationStrategy implements SessionAuthenticationSt
|
||||||
*/
|
*/
|
||||||
public CsrfAuthenticationStrategy(CsrfTokenRepository csrfTokenRepository) {
|
public CsrfAuthenticationStrategy(CsrfTokenRepository csrfTokenRepository) {
|
||||||
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
|
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
|
||||||
|
CsrfTokenRequestProcessor processor = new CsrfTokenRequestProcessor();
|
||||||
|
processor.setTokenRepository(csrfTokenRepository);
|
||||||
|
this.requestHandler = processor;
|
||||||
this.csrfTokenRepository = csrfTokenRepository;
|
this.csrfTokenRepository = csrfTokenRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify a {@link CsrfTokenRequestAttributeHandler} to use for making the
|
* Specify a {@link CsrfTokenRequestHandler} to use for making the {@code CsrfToken}
|
||||||
* {@code CsrfToken} available as a request attribute.
|
* available as a request attribute.
|
||||||
* @param requestAttributeHandler the {@link CsrfTokenRequestAttributeHandler} to use
|
* @param requestHandler the {@link CsrfTokenRequestHandler} to use
|
||||||
*/
|
*/
|
||||||
public void setRequestAttributeHandler(CsrfTokenRequestAttributeHandler requestAttributeHandler) {
|
public void setRequestHandler(CsrfTokenRequestHandler requestHandler) {
|
||||||
Assert.notNull(requestAttributeHandler, "requestAttributeHandler cannot be null");
|
Assert.notNull(requestHandler, "requestHandler cannot be null");
|
||||||
this.requestAttributeHandler = requestAttributeHandler;
|
this.requestHandler = requestHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthentication(Authentication authentication, HttpServletRequest request,
|
public void onAuthentication(Authentication authentication, HttpServletRequest request,
|
||||||
HttpServletResponse response) throws SessionAuthenticationException {
|
HttpServletResponse response) throws SessionAuthenticationException {
|
||||||
boolean containsToken = this.csrfTokenRepository.loadToken(request) != null;
|
this.csrfTokenRepository.saveToken(null, request, response);
|
||||||
if (containsToken) {
|
this.requestHandler.handle(request, response);
|
||||||
this.csrfTokenRepository.saveToken(null, request, response);
|
this.logger.debug("Replaced CSRF Token");
|
||||||
CsrfToken newToken = this.csrfTokenRepository.generateToken(request);
|
|
||||||
this.csrfTokenRepository.saveToken(newToken, request, response);
|
|
||||||
this.requestAttributeHandler.handle(request, response, () -> newToken);
|
|
||||||
this.logger.debug("Replaced CSRF Token");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,21 +82,19 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private final Log logger = LogFactory.getLog(getClass());
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private final CsrfTokenRepository tokenRepository;
|
|
||||||
|
|
||||||
private RequestMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;
|
private RequestMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;
|
||||||
|
|
||||||
private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
|
private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||||
|
|
||||||
private CsrfTokenRequestAttributeHandler requestAttributeHandler;
|
private CsrfTokenRequestHandler requestHandler;
|
||||||
|
|
||||||
private CsrfTokenRequestResolver requestResolver;
|
private CsrfTokenRequestResolver requestResolver;
|
||||||
|
|
||||||
public CsrfFilter(CsrfTokenRepository csrfTokenRepository) {
|
public CsrfFilter(CsrfTokenRepository csrfTokenRepository) {
|
||||||
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
|
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
|
||||||
this.tokenRepository = csrfTokenRepository;
|
|
||||||
CsrfTokenRequestProcessor csrfTokenRequestProcessor = new CsrfTokenRequestProcessor();
|
CsrfTokenRequestProcessor csrfTokenRequestProcessor = new CsrfTokenRequestProcessor();
|
||||||
this.requestAttributeHandler = csrfTokenRequestProcessor;
|
csrfTokenRequestProcessor.setTokenRepository(csrfTokenRepository);
|
||||||
|
this.requestHandler = csrfTokenRequestProcessor;
|
||||||
this.requestResolver = csrfTokenRequestProcessor;
|
this.requestResolver = csrfTokenRequestProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,15 +106,7 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
request.setAttribute(HttpServletResponse.class.getName(), response);
|
DeferredCsrfToken deferredCsrfToken = this.requestHandler.handle(request, response);
|
||||||
CsrfToken csrfToken = this.tokenRepository.loadToken(request);
|
|
||||||
boolean missingToken = (csrfToken == null);
|
|
||||||
if (missingToken) {
|
|
||||||
csrfToken = this.tokenRepository.generateToken(request);
|
|
||||||
this.tokenRepository.saveToken(csrfToken, request, response);
|
|
||||||
}
|
|
||||||
final CsrfToken finalCsrfToken = csrfToken;
|
|
||||||
this.requestAttributeHandler.handle(request, response, () -> finalCsrfToken);
|
|
||||||
if (!this.requireCsrfProtectionMatcher.matches(request)) {
|
if (!this.requireCsrfProtectionMatcher.matches(request)) {
|
||||||
if (this.logger.isTraceEnabled()) {
|
if (this.logger.isTraceEnabled()) {
|
||||||
this.logger.trace("Did not protect against CSRF since request did not match "
|
this.logger.trace("Did not protect against CSRF since request did not match "
|
||||||
|
@ -125,8 +115,10 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
CsrfToken csrfToken = deferredCsrfToken.get();
|
||||||
String actualToken = this.requestResolver.resolveCsrfTokenValue(request, csrfToken);
|
String actualToken = this.requestResolver.resolveCsrfTokenValue(request, csrfToken);
|
||||||
if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
|
if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
|
||||||
|
boolean missingToken = deferredCsrfToken.isGenerated();
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
|
LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
|
||||||
AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
|
AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
|
||||||
|
@ -173,18 +165,18 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a {@link CsrfTokenRequestAttributeHandler} that is used to make the
|
* Specifies a {@link CsrfTokenRequestHandler} that is used to make the
|
||||||
* {@link CsrfToken} available as a request attribute.
|
* {@link CsrfToken} available as a request attribute.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The default is {@link CsrfTokenRequestProcessor}.
|
* The default is {@link CsrfTokenRequestProcessor}.
|
||||||
* </p>
|
* </p>
|
||||||
* @param requestAttributeHandler the {@link CsrfTokenRequestAttributeHandler} to use
|
* @param requestHandler the {@link CsrfTokenRequestHandler} to use
|
||||||
* @since 5.8
|
* @since 5.8
|
||||||
*/
|
*/
|
||||||
public void setRequestAttributeHandler(CsrfTokenRequestAttributeHandler requestAttributeHandler) {
|
public void setRequestHandler(CsrfTokenRequestHandler requestHandler) {
|
||||||
Assert.notNull(requestAttributeHandler, "requestAttributeHandler cannot be null");
|
Assert.notNull(requestHandler, "requestHandler cannot be null");
|
||||||
this.requestAttributeHandler = requestAttributeHandler;
|
this.requestHandler = requestHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,14 +16,12 @@
|
||||||
|
|
||||||
package org.springframework.security.web.csrf;
|
package org.springframework.security.web.csrf;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback interface that is used to make the {@link CsrfToken} created by the
|
* A callback interface that is used to determine the {@link CsrfToken} to use and make
|
||||||
* {@link CsrfTokenRepository} available as a request attribute. Implementations of this
|
* the {@link CsrfToken} available as a request attribute. Implementations of this
|
||||||
* interface may choose to perform additional tasks or customize how the token is made
|
* interface may choose to perform additional tasks or customize how the token is made
|
||||||
* available to the application through request attributes.
|
* available to the application through request attributes.
|
||||||
*
|
*
|
||||||
|
@ -32,14 +30,13 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
* @see CsrfTokenRequestProcessor
|
* @see CsrfTokenRequestProcessor
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface CsrfTokenRequestAttributeHandler {
|
public interface CsrfTokenRequestHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a request using a {@link CsrfToken}.
|
* Handles a request using a {@link CsrfToken}.
|
||||||
* @param request the {@code HttpServletRequest} being handled
|
* @param request the {@code HttpServletRequest} being handled
|
||||||
* @param response the {@code HttpServletResponse} being handled
|
* @param response the {@code HttpServletResponse} being handled
|
||||||
* @param csrfToken the {@link CsrfToken} created by the {@link CsrfTokenRepository}
|
|
||||||
*/
|
*/
|
||||||
void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken);
|
DeferredCsrfToken handle(HttpServletRequest request, HttpServletResponse response);
|
||||||
|
|
||||||
}
|
}
|
|
@ -24,7 +24,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of the {@link CsrfTokenRequestAttributeHandler} and
|
* An implementation of the {@link CsrfTokenRequestHandler} and
|
||||||
* {@link CsrfTokenRequestResolver} interfaces that is capable of making the
|
* {@link CsrfTokenRequestResolver} interfaces that is capable of making the
|
||||||
* {@link CsrfToken} available as a request attribute and resolving the token value as
|
* {@link CsrfToken} available as a request attribute and resolving the token value as
|
||||||
* either a header or parameter value of the request.
|
* either a header or parameter value of the request.
|
||||||
|
@ -32,10 +32,22 @@ import org.springframework.util.Assert;
|
||||||
* @author Steve Riesenberg
|
* @author Steve Riesenberg
|
||||||
* @since 5.8
|
* @since 5.8
|
||||||
*/
|
*/
|
||||||
public class CsrfTokenRequestProcessor implements CsrfTokenRequestAttributeHandler, CsrfTokenRequestResolver {
|
public class CsrfTokenRequestProcessor implements CsrfTokenRequestHandler, CsrfTokenRequestResolver {
|
||||||
|
|
||||||
private String csrfRequestAttributeName;
|
private String csrfRequestAttributeName;
|
||||||
|
|
||||||
|
private CsrfTokenRepository tokenRepository = new HttpSessionCsrfTokenRepository();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link CsrfTokenRepository} to use.
|
||||||
|
* @param tokenRepository the {@link CsrfTokenRepository} to use. Default
|
||||||
|
* {@link HttpSessionCsrfTokenRepository}
|
||||||
|
*/
|
||||||
|
public void setTokenRepository(CsrfTokenRepository tokenRepository) {
|
||||||
|
Assert.notNull(tokenRepository, "tokenRepository cannot be null");
|
||||||
|
this.tokenRepository = tokenRepository;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link CsrfToken} is available as a request attribute named
|
* The {@link CsrfToken} is available as a request attribute named
|
||||||
* {@code CsrfToken.class.getName()}. By default, an additional request attribute that
|
* {@code CsrfToken.class.getName()}. By default, an additional request attribute that
|
||||||
|
@ -49,16 +61,18 @@ public class CsrfTokenRequestProcessor implements CsrfTokenRequestAttributeHandl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
|
public DeferredCsrfToken handle(HttpServletRequest request, HttpServletResponse response) {
|
||||||
Assert.notNull(request, "request cannot be null");
|
Assert.notNull(request, "request cannot be null");
|
||||||
Assert.notNull(response, "response cannot be null");
|
Assert.notNull(response, "response cannot be null");
|
||||||
Assert.notNull(csrfToken, "csrfToken supplier cannot be null");
|
|
||||||
CsrfToken actualCsrfToken = csrfToken.get();
|
request.setAttribute(HttpServletResponse.class.getName(), response);
|
||||||
Assert.notNull(actualCsrfToken, "csrfToken cannot be null");
|
DeferredCsrfToken deferredCsrfToken = new RepositoryDeferredCsrfToken(request, response);
|
||||||
request.setAttribute(CsrfToken.class.getName(), actualCsrfToken);
|
CsrfToken csrfToken = new SupplierCsrfToken(deferredCsrfToken::get);
|
||||||
|
request.setAttribute(CsrfToken.class.getName(), csrfToken);
|
||||||
String csrfAttrName = (this.csrfRequestAttributeName != null) ? this.csrfRequestAttributeName
|
String csrfAttrName = (this.csrfRequestAttributeName != null) ? this.csrfRequestAttributeName
|
||||||
: actualCsrfToken.getParameterName();
|
: csrfToken.getParameterName();
|
||||||
request.setAttribute(csrfAttrName, actualCsrfToken);
|
request.setAttribute(csrfAttrName, csrfToken);
|
||||||
|
return deferredCsrfToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,4 +86,78 @@ public class CsrfTokenRequestProcessor implements CsrfTokenRequestAttributeHandl
|
||||||
return actualToken;
|
return actualToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class SupplierCsrfToken implements CsrfToken {
|
||||||
|
|
||||||
|
private final Supplier<CsrfToken> csrfTokenSupplier;
|
||||||
|
|
||||||
|
private SupplierCsrfToken(Supplier<CsrfToken> csrfTokenSupplier) {
|
||||||
|
this.csrfTokenSupplier = csrfTokenSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeaderName() {
|
||||||
|
return getDelegate().getHeaderName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getParameterName() {
|
||||||
|
return getDelegate().getParameterName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getToken() {
|
||||||
|
return getDelegate().getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CsrfToken getDelegate() {
|
||||||
|
CsrfToken delegate = this.csrfTokenSupplier.get();
|
||||||
|
if (delegate == null) {
|
||||||
|
throw new IllegalStateException("csrfTokenSupplier returned null delegate");
|
||||||
|
}
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class RepositoryDeferredCsrfToken implements DeferredCsrfToken {
|
||||||
|
|
||||||
|
private final HttpServletRequest request;
|
||||||
|
|
||||||
|
private final HttpServletResponse response;
|
||||||
|
|
||||||
|
private CsrfToken csrfToken;
|
||||||
|
|
||||||
|
private Boolean missingToken;
|
||||||
|
|
||||||
|
RepositoryDeferredCsrfToken(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
this.request = request;
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CsrfToken get() {
|
||||||
|
init();
|
||||||
|
return this.csrfToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGenerated() {
|
||||||
|
init();
|
||||||
|
return this.missingToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
if (this.csrfToken != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.csrfToken = CsrfTokenRequestProcessor.this.tokenRepository.loadToken(this.request);
|
||||||
|
this.missingToken = (this.csrfToken == null);
|
||||||
|
if (this.missingToken) {
|
||||||
|
this.csrfToken = CsrfTokenRequestProcessor.this.tokenRepository.generateToken(this.request);
|
||||||
|
CsrfTokenRequestProcessor.this.tokenRepository.saveToken(this.csrfToken, this.request, this.response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2022 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
|
||||||
|
*
|
||||||
|
* https://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.web.csrf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that allows delayed access to a {@link CsrfToken} that may be generated.
|
||||||
|
*
|
||||||
|
* @author Rob Winch
|
||||||
|
* @since 5.8
|
||||||
|
*/
|
||||||
|
public interface DeferredCsrfToken {
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Gets the {@link CsrfToken}
|
||||||
|
* @return a non-null {@link CsrfToken}
|
||||||
|
*/
|
||||||
|
CsrfToken get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if {@link #get()} refers to a generated {@link CsrfToken} or false if
|
||||||
|
* it already existed.
|
||||||
|
* @return true if {@link #get()} refers to a generated {@link CsrfToken} or false if
|
||||||
|
* it already existed.
|
||||||
|
*/
|
||||||
|
boolean isGenerated();
|
||||||
|
|
||||||
|
}
|
|
@ -27,7 +27,10 @@ import org.springframework.util.Assert;
|
||||||
*
|
*
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
|
* @deprecated Use org.springframework.security.web.csrf.CsrfTokenRequestHandler which
|
||||||
|
* returns a {@link DeferredCsrfToken}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class LazyCsrfTokenRepository implements CsrfTokenRepository {
|
public final class LazyCsrfTokenRepository implements CsrfTokenRepository {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,27 +75,24 @@ public class CsrfAuthenticationStrategyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setRequestAttributeHandlerWhenNullThenIllegalStateException() {
|
public void setRequestHandlerWhenNullThenIllegalStateException() {
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> this.strategy.setRequestAttributeHandler(null))
|
assertThatIllegalArgumentException().isThrownBy(() -> this.strategy.setRequestHandler(null))
|
||||||
.withMessage("requestAttributeHandler cannot be null");
|
.withMessage("requestHandler cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onAuthenticationWhenCustomRequestAttributeHandlerThenUsed() {
|
public void onAuthenticationWhenCustomRequestHandlerThenUsed() {
|
||||||
given(this.csrfTokenRepository.loadToken(this.request)).willReturn(this.existingToken);
|
CsrfTokenRequestHandler requestHandler = mock(CsrfTokenRequestHandler.class);
|
||||||
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
|
this.strategy.setRequestHandler(requestHandler);
|
||||||
|
|
||||||
CsrfTokenRequestAttributeHandler requestAttributeHandler = mock(CsrfTokenRequestAttributeHandler.class);
|
|
||||||
this.strategy.setRequestAttributeHandler(requestAttributeHandler);
|
|
||||||
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
||||||
this.response);
|
this.response);
|
||||||
verify(requestAttributeHandler).handle(eq(this.request), eq(this.response), any());
|
verify(requestHandler).handle(eq(this.request), eq(this.response));
|
||||||
verifyNoMoreInteractions(requestAttributeHandler);
|
verifyNoMoreInteractions(requestHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void logoutRemovesCsrfTokenAndSavesNew() {
|
public void logoutRemovesCsrfTokenAndSavesNew() {
|
||||||
given(this.csrfTokenRepository.loadToken(this.request)).willReturn(this.existingToken);
|
given(this.csrfTokenRepository.loadToken(this.request)).willReturn(null, this.existingToken);
|
||||||
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
|
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
|
||||||
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
||||||
this.response);
|
this.response);
|
||||||
|
@ -114,7 +111,6 @@ public class CsrfAuthenticationStrategyTests {
|
||||||
@Test
|
@Test
|
||||||
public void delaySavingCsrf() {
|
public void delaySavingCsrf() {
|
||||||
this.strategy = new CsrfAuthenticationStrategy(new LazyCsrfTokenRepository(this.csrfTokenRepository));
|
this.strategy = new CsrfAuthenticationStrategy(new LazyCsrfTokenRepository(this.csrfTokenRepository));
|
||||||
given(this.csrfTokenRepository.loadToken(this.request)).willReturn(this.existingToken);
|
|
||||||
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
|
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
|
||||||
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
||||||
this.response);
|
this.response);
|
||||||
|
@ -128,10 +124,11 @@ public class CsrfAuthenticationStrategyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void logoutRemovesNoActionIfNullToken() {
|
public void logoutWhenNoCsrfToken() {
|
||||||
|
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
|
||||||
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
||||||
this.response);
|
this.response);
|
||||||
verify(this.csrfTokenRepository, never()).saveToken(any(CsrfToken.class), any(HttpServletRequest.class),
|
verify(this.csrfTokenRepository).saveToken(any(CsrfToken.class), any(HttpServletRequest.class),
|
||||||
any(HttpServletResponse.class));
|
any(HttpServletResponse.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.assertj.core.api.AbstractObjectAssert;
|
|
||||||
import org.assertj.core.api.ObjectAssert;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
@ -46,10 +44,12 @@ import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoInteractions;
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCsrfToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
|
@ -126,8 +126,8 @@ public class CsrfFilterTests {
|
||||||
given(this.requestMatcher.matches(this.request)).willReturn(true);
|
given(this.requestMatcher.matches(this.request)).willReturn(true);
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
||||||
verifyNoMoreInteractions(this.filterChain);
|
verifyNoMoreInteractions(this.filterChain);
|
||||||
}
|
}
|
||||||
|
@ -138,8 +138,8 @@ public class CsrfFilterTests {
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
this.request.setParameter(this.token.getParameterName(), this.token.getToken() + " INVALID");
|
this.request.setParameter(this.token.getParameterName(), this.token.getToken() + " INVALID");
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
||||||
verifyNoMoreInteractions(this.filterChain);
|
verifyNoMoreInteractions(this.filterChain);
|
||||||
}
|
}
|
||||||
|
@ -150,8 +150,8 @@ public class CsrfFilterTests {
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
this.request.addHeader(this.token.getHeaderName(), this.token.getToken() + " INVALID");
|
this.request.addHeader(this.token.getHeaderName(), this.token.getToken() + " INVALID");
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
||||||
verifyNoMoreInteractions(this.filterChain);
|
verifyNoMoreInteractions(this.filterChain);
|
||||||
}
|
}
|
||||||
|
@ -164,8 +164,8 @@ public class CsrfFilterTests {
|
||||||
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
||||||
this.request.addHeader(this.token.getHeaderName(), this.token.getToken() + " INVALID");
|
this.request.addHeader(this.token.getHeaderName(), this.token.getToken() + " INVALID");
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
verify(this.deniedHandler).handle(eq(this.request), eq(this.response), any(InvalidCsrfTokenException.class));
|
||||||
verifyNoMoreInteractions(this.filterChain);
|
verifyNoMoreInteractions(this.filterChain);
|
||||||
}
|
}
|
||||||
|
@ -175,8 +175,8 @@ public class CsrfFilterTests {
|
||||||
given(this.requestMatcher.matches(this.request)).willReturn(false);
|
given(this.requestMatcher.matches(this.request)).willReturn(false);
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.filterChain).doFilter(this.request, this.response);
|
verify(this.filterChain).doFilter(this.request, this.response);
|
||||||
verifyNoMoreInteractions(this.deniedHandler);
|
verifyNoMoreInteractions(this.deniedHandler);
|
||||||
}
|
}
|
||||||
|
@ -186,8 +186,8 @@ public class CsrfFilterTests {
|
||||||
given(this.requestMatcher.matches(this.request)).willReturn(false);
|
given(this.requestMatcher.matches(this.request)).willReturn(false);
|
||||||
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.filterChain).doFilter(this.request, this.response);
|
verify(this.filterChain).doFilter(this.request, this.response);
|
||||||
verifyNoMoreInteractions(this.deniedHandler);
|
verifyNoMoreInteractions(this.deniedHandler);
|
||||||
}
|
}
|
||||||
|
@ -198,8 +198,8 @@ public class CsrfFilterTests {
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
this.request.addHeader(this.token.getHeaderName(), this.token.getToken());
|
this.request.addHeader(this.token.getHeaderName(), this.token.getToken());
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.filterChain).doFilter(this.request, this.response);
|
verify(this.filterChain).doFilter(this.request, this.response);
|
||||||
verifyNoMoreInteractions(this.deniedHandler);
|
verifyNoMoreInteractions(this.deniedHandler);
|
||||||
}
|
}
|
||||||
|
@ -212,8 +212,8 @@ public class CsrfFilterTests {
|
||||||
this.request.setParameter(this.token.getParameterName(), this.token.getToken() + " INVALID");
|
this.request.setParameter(this.token.getParameterName(), this.token.getToken() + " INVALID");
|
||||||
this.request.addHeader(this.token.getHeaderName(), this.token.getToken());
|
this.request.addHeader(this.token.getHeaderName(), this.token.getToken());
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.filterChain).doFilter(this.request, this.response);
|
verify(this.filterChain).doFilter(this.request, this.response);
|
||||||
verifyNoMoreInteractions(this.deniedHandler);
|
verifyNoMoreInteractions(this.deniedHandler);
|
||||||
}
|
}
|
||||||
|
@ -224,8 +224,8 @@ public class CsrfFilterTests {
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
verify(this.filterChain).doFilter(this.request, this.response);
|
verify(this.filterChain).doFilter(this.request, this.response);
|
||||||
verifyNoMoreInteractions(this.deniedHandler);
|
verifyNoMoreInteractions(this.deniedHandler);
|
||||||
verify(this.tokenRepository, never()).saveToken(any(CsrfToken.class), any(HttpServletRequest.class),
|
verify(this.tokenRepository, never()).saveToken(any(CsrfToken.class), any(HttpServletRequest.class),
|
||||||
|
@ -238,8 +238,8 @@ public class CsrfFilterTests {
|
||||||
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
|
||||||
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
// LazyCsrfTokenRepository requires the response as an attribute
|
// LazyCsrfTokenRepository requires the response as an attribute
|
||||||
assertThat(this.request.getAttribute(HttpServletResponse.class.getName())).isEqualTo(this.response);
|
assertThat(this.request.getAttribute(HttpServletResponse.class.getName())).isEqualTo(this.response);
|
||||||
verify(this.filterChain).doFilter(this.request, this.response);
|
verify(this.filterChain).doFilter(this.request, this.response);
|
||||||
|
@ -304,8 +304,8 @@ public class CsrfFilterTests {
|
||||||
given(this.requestMatcher.matches(this.request)).willReturn(true);
|
given(this.requestMatcher.matches(this.request)).willReturn(true);
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
|
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
|
||||||
verifyNoMoreInteractions(this.filterChain);
|
verifyNoMoreInteractions(this.filterChain);
|
||||||
}
|
}
|
||||||
|
@ -336,14 +336,14 @@ public class CsrfFilterTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doFilterWhenRequestAttributeHandlerThenUsed() throws Exception {
|
public void doFilterWhenRequestHandlerThenUsed() throws Exception {
|
||||||
given(this.requestMatcher.matches(this.request)).willReturn(true);
|
CsrfTokenRequestHandler requestHandler = mock(CsrfTokenRequestHandler.class);
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
given(requestHandler.handle(this.request, this.response))
|
||||||
CsrfTokenRequestAttributeHandler requestAttributeHandler = mock(CsrfTokenRequestAttributeHandler.class);
|
.willReturn(new TestDeferredCsrfToken(this.token, false));
|
||||||
this.filter.setRequestAttributeHandler(requestAttributeHandler);
|
this.filter.setRequestHandler(requestHandler);
|
||||||
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
|
||||||
this.filter.doFilter(this.request, this.response, this.filterChain);
|
this.filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
verify(requestAttributeHandler).handle(eq(this.request), eq(this.response), any());
|
verify(requestHandler).handle(eq(this.request), eq(this.response));
|
||||||
verify(this.filterChain).doFilter(this.request, this.response);
|
verify(this.filterChain).doFilter(this.request, this.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,39 +376,40 @@ public class CsrfFilterTests {
|
||||||
CsrfFilter filter = createCsrfFilter(this.tokenRepository);
|
CsrfFilter filter = createCsrfFilter(this.tokenRepository);
|
||||||
String csrfAttrName = "_csrf";
|
String csrfAttrName = "_csrf";
|
||||||
CsrfTokenRequestProcessor csrfTokenRequestProcessor = new CsrfTokenRequestProcessor();
|
CsrfTokenRequestProcessor csrfTokenRequestProcessor = new CsrfTokenRequestProcessor();
|
||||||
|
csrfTokenRequestProcessor.setTokenRepository(this.tokenRepository);
|
||||||
csrfTokenRequestProcessor.setCsrfRequestAttributeName(csrfAttrName);
|
csrfTokenRequestProcessor.setCsrfRequestAttributeName(csrfAttrName);
|
||||||
filter.setRequestAttributeHandler(csrfTokenRequestProcessor);
|
filter.setRequestHandler(csrfTokenRequestProcessor);
|
||||||
CsrfToken expectedCsrfToken = mock(CsrfToken.class);
|
CsrfToken expectedCsrfToken = spy(this.token);
|
||||||
given(this.tokenRepository.loadToken(this.request)).willReturn(expectedCsrfToken);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(expectedCsrfToken);
|
||||||
|
|
||||||
filter.doFilter(this.request, this.response, this.filterChain);
|
filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
|
|
||||||
verifyNoInteractions(expectedCsrfToken);
|
verifyNoInteractions(expectedCsrfToken);
|
||||||
CsrfToken tokenFromRequest = (CsrfToken) this.request.getAttribute(csrfAttrName);
|
CsrfToken tokenFromRequest = (CsrfToken) this.request.getAttribute(csrfAttrName);
|
||||||
assertThat(tokenFromRequest).isEqualTo(expectedCsrfToken);
|
assertThatCsrfToken(tokenFromRequest).isEqualTo(expectedCsrfToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CsrfTokenAssert assertToken(Object token) {
|
private static final class TestDeferredCsrfToken implements DeferredCsrfToken {
|
||||||
return new CsrfTokenAssert((CsrfToken) token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CsrfTokenAssert extends AbstractObjectAssert<CsrfTokenAssert, CsrfToken> {
|
private final CsrfToken csrfToken;
|
||||||
|
|
||||||
/**
|
private final boolean isGenerated;
|
||||||
* Creates a new {@link ObjectAssert}.
|
|
||||||
* @param actual the target to verify.
|
private TestDeferredCsrfToken(CsrfToken csrfToken, boolean isGenerated) {
|
||||||
*/
|
this.csrfToken = csrfToken;
|
||||||
protected CsrfTokenAssert(CsrfToken actual) {
|
this.isGenerated = isGenerated;
|
||||||
super(actual, CsrfTokenAssert.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CsrfTokenAssert isEqualTo(CsrfToken expected) {
|
@Override
|
||||||
assertThat(this.actual.getHeaderName()).isEqualTo(expected.getHeaderName());
|
public CsrfToken get() {
|
||||||
assertThat(this.actual.getParameterName()).isEqualTo(expected.getParameterName());
|
return this.csrfToken;
|
||||||
assertThat(this.actual.getToken()).isEqualTo(expected.getToken());
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public boolean isGenerated() {
|
||||||
|
return this.isGenerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2022 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
|
||||||
|
*
|
||||||
|
* https://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.web.csrf;
|
||||||
|
|
||||||
|
import org.assertj.core.api.AbstractAssert;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assertion for validating the properties on CsrfToken are the same.
|
||||||
|
*/
|
||||||
|
public class CsrfTokenAssert extends AbstractAssert<CsrfTokenAssert, CsrfToken> {
|
||||||
|
|
||||||
|
protected CsrfTokenAssert(CsrfToken csrfToken) {
|
||||||
|
super(csrfToken, CsrfTokenAssert.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CsrfTokenAssert assertThatCsrfToken(Object csrfToken) {
|
||||||
|
return new CsrfTokenAssert((CsrfToken) csrfToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CsrfTokenAssert assertThat(CsrfToken csrfToken) {
|
||||||
|
return new CsrfTokenAssert(csrfToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CsrfTokenAssert isEqualTo(CsrfToken csrfToken) {
|
||||||
|
isNotNull();
|
||||||
|
assertThat(csrfToken).isNotNull();
|
||||||
|
Assertions.assertThat(this.actual.getHeaderName()).isEqualTo(csrfToken.getHeaderName());
|
||||||
|
Assertions.assertThat(this.actual.getParameterName()).isEqualTo(csrfToken.getParameterName());
|
||||||
|
Assertions.assertThat(this.actual.getToken()).isEqualTo(csrfToken.getToken());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,12 +18,17 @@ package org.springframework.security.web.csrf;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCsrfToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link CsrfTokenRequestProcessor}.
|
* Tests for {@link CsrfTokenRequestProcessor}.
|
||||||
|
@ -31,8 +36,12 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||||
* @author Steve Riesenberg
|
* @author Steve Riesenberg
|
||||||
* @since 5.8
|
* @since 5.8
|
||||||
*/
|
*/
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class CsrfTokenRequestProcessorTests {
|
public class CsrfTokenRequestProcessorTests {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
CsrfTokenRepository tokenRepository;
|
||||||
|
|
||||||
private MockHttpServletRequest request;
|
private MockHttpServletRequest request;
|
||||||
|
|
||||||
private MockHttpServletResponse response;
|
private MockHttpServletResponse response;
|
||||||
|
@ -47,48 +56,36 @@ public class CsrfTokenRequestProcessorTests {
|
||||||
this.response = new MockHttpServletResponse();
|
this.response = new MockHttpServletResponse();
|
||||||
this.token = new DefaultCsrfToken("headerName", "paramName", "csrfTokenValue");
|
this.token = new DefaultCsrfToken("headerName", "paramName", "csrfTokenValue");
|
||||||
this.processor = new CsrfTokenRequestProcessor();
|
this.processor = new CsrfTokenRequestProcessor();
|
||||||
|
this.processor.setTokenRepository(this.tokenRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleWhenRequestIsNullThenThrowsIllegalArgumentException() {
|
public void handleWhenRequestIsNullThenThrowsIllegalArgumentException() {
|
||||||
assertThatIllegalArgumentException()
|
assertThatIllegalArgumentException().isThrownBy(() -> this.processor.handle(null, this.response))
|
||||||
.isThrownBy(() -> this.processor.handle(null, this.response, () -> this.token))
|
|
||||||
.withMessage("request cannot be null");
|
.withMessage("request cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleWhenResponseIsNullThenThrowsIllegalArgumentException() {
|
public void handleWhenResponseIsNullThenThrowsIllegalArgumentException() {
|
||||||
assertThatIllegalArgumentException()
|
assertThatIllegalArgumentException().isThrownBy(() -> this.processor.handle(this.request, null))
|
||||||
.isThrownBy(() -> this.processor.handle(this.request, null, () -> this.token))
|
|
||||||
.withMessage("response cannot be null");
|
.withMessage("response cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void handleWhenCsrfTokenSupplierIsNullThenThrowsIllegalArgumentException() {
|
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> this.processor.handle(this.request, this.response, null))
|
|
||||||
.withMessage("csrfToken supplier cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void handleWhenCsrfTokenIsNullThenThrowsIllegalArgumentException() {
|
|
||||||
assertThatIllegalArgumentException()
|
|
||||||
.isThrownBy(() -> this.processor.handle(this.request, this.response, () -> null))
|
|
||||||
.withMessage("csrfToken cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleWhenCsrfRequestAttributeSetThenUsed() {
|
public void handleWhenCsrfRequestAttributeSetThenUsed() {
|
||||||
|
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
|
||||||
this.processor.setCsrfRequestAttributeName("_csrf");
|
this.processor.setCsrfRequestAttributeName("_csrf");
|
||||||
this.processor.handle(this.request, this.response, () -> this.token);
|
this.processor.handle(this.request, this.response);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
assertThat(this.request.getAttribute("_csrf")).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute("_csrf")).isEqualTo(this.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleWhenValidParametersThenRequestAttributesSet() {
|
public void handleWhenValidParametersThenRequestAttributesSet() {
|
||||||
this.processor.handle(this.request, this.response, () -> this.token);
|
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
|
||||||
assertThat(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
this.processor.handle(this.request, this.response);
|
||||||
assertThat(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||||
|
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue