Skip to content

Commit a116895

Browse files
eleftheriaskostya05983
authored andcommitted
Allow configuration of csrf through nested builder
Issue: spring-projectsgh-5557
1 parent cf9f4d2 commit a116895

File tree

3 files changed

+175
-1
lines changed

3 files changed

+175
-1
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,35 @@ public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
771771
return getOrApply(new CsrfConfigurer<>(context));
772772
}
773773

774+
/**
775+
* Adds CSRF support. This is activated by default when using
776+
* {@link WebSecurityConfigurerAdapter}'s default constructor. You can disable it
777+
* using:
778+
*
779+
* <pre>
780+
* &#064;Configuration
781+
* &#064;EnableWebSecurity
782+
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
783+
*
784+
* &#064;Override
785+
* protected void configure(HttpSecurity http) throws Exception {
786+
* http
787+
* .csrf(csrf -> csrf.disable());
788+
* }
789+
* }
790+
* </pre>
791+
*
792+
* @param csrfCustomizer the {@link Customizer} to provide more options for
793+
* the {@link CsrfConfigurer}
794+
* @return the {@link HttpSecurity} for further customizations
795+
* @throws Exception
796+
*/
797+
public HttpSecurity csrf(Customizer<CsrfConfigurer<HttpSecurity>> csrfCustomizer) throws Exception {
798+
ApplicationContext context = getContext();
799+
csrfCustomizer.customize(getOrApply(new CsrfConfigurer<>(context)));
800+
return HttpSecurity.this;
801+
}
802+
774803
/**
775804
* Provides logout support. This is automatically applied when using
776805
* {@link WebSecurityConfigurerAdapter}. The default is that accessing the URL

config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -75,6 +75,36 @@ protected void configure(HttpSecurity http) throws Exception {
7575
}
7676
}
7777

78+
@Test
79+
public void requestWhenIgnoringRequestMatchersInLambdaThenAugmentedByConfiguredRequestMatcher()
80+
throws Exception {
81+
this.spring.register(IgnoringRequestInLambdaMatchers.class, BasicController.class).autowire();
82+
83+
this.mvc.perform(get("/path"))
84+
.andExpect(status().isForbidden());
85+
86+
this.mvc.perform(post("/path"))
87+
.andExpect(status().isOk());
88+
}
89+
90+
@EnableWebSecurity
91+
static class IgnoringRequestInLambdaMatchers extends WebSecurityConfigurerAdapter {
92+
RequestMatcher requestMatcher =
93+
request -> HttpMethod.POST.name().equals(request.getMethod());
94+
95+
@Override
96+
protected void configure(HttpSecurity http) throws Exception {
97+
// @formatter:off
98+
http
99+
.csrf(csrf ->
100+
csrf
101+
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
102+
.ignoringRequestMatchers(this.requestMatcher)
103+
);
104+
// @formatter:on
105+
}
106+
}
107+
78108
@Test
79109
public void requestWhenIgnoringRequestMatcherThenUnionsWithConfiguredIgnoringAntMatchers()
80110
throws Exception {
@@ -107,6 +137,40 @@ protected void configure(HttpSecurity http) throws Exception {
107137
}
108138
}
109139

140+
@Test
141+
public void requestWhenIgnoringRequestMatcherInLambdaThenUnionsWithConfiguredIgnoringAntMatchers()
142+
throws Exception {
143+
144+
this.spring.register(IgnoringPathsAndMatchersInLambdaConfig.class, BasicController.class).autowire();
145+
146+
this.mvc.perform(put("/csrf"))
147+
.andExpect(status().isForbidden());
148+
149+
this.mvc.perform(post("/csrf"))
150+
.andExpect(status().isOk());
151+
152+
this.mvc.perform(put("/no-csrf"))
153+
.andExpect(status().isOk());
154+
}
155+
156+
@EnableWebSecurity
157+
static class IgnoringPathsAndMatchersInLambdaConfig extends WebSecurityConfigurerAdapter {
158+
RequestMatcher requestMatcher =
159+
request -> HttpMethod.POST.name().equals(request.getMethod());
160+
161+
@Override
162+
protected void configure(HttpSecurity http) throws Exception {
163+
// @formatter:off
164+
http
165+
.csrf(csrf ->
166+
csrf
167+
.ignoringAntMatchers("/no-csrf")
168+
.ignoringRequestMatchers(this.requestMatcher)
169+
);
170+
// @formatter:on
171+
}
172+
}
173+
110174
@RestController
111175
public static class BasicController {
112176
@RequestMapping("/path")

config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,26 @@ protected void configure(HttpSecurity http) throws Exception {
210210
}
211211
}
212212

213+
@Test
214+
public void postWhenCsrfDisabledInLambdaThenRespondsWithOk() throws Exception {
215+
this.spring.register(DisableCsrfInLambdaConfig.class, BasicController.class).autowire();
216+
217+
this.mvc.perform(post("/"))
218+
.andExpect(status().isOk());
219+
}
220+
221+
@EnableWebSecurity
222+
static class DisableCsrfInLambdaConfig extends WebSecurityConfigurerAdapter {
223+
224+
@Override
225+
protected void configure(HttpSecurity http) throws Exception {
226+
// @formatter:off
227+
http
228+
.csrf(AbstractHttpConfigurer::disable);
229+
// @formatter:on
230+
}
231+
}
232+
213233
// SEC-2498
214234
@Test
215235
public void loginWhenCsrfDisabledThenRedirectsToPreviousPostRequest() throws Exception {
@@ -386,6 +406,40 @@ protected void configure(HttpSecurity http) throws Exception {
386406
}
387407
}
388408

409+
@Test
410+
public void requireCsrfProtectionMatcherInLambdaWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
411+
RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
412+
this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
413+
when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any()))
414+
.thenReturn(false);
415+
416+
this.mvc.perform(get("/"))
417+
.andExpect(status().isOk());
418+
}
419+
420+
@Test
421+
public void requireCsrfProtectionMatcherInLambdaWhenRequestMatchesThenRespondsWithForbidden() throws Exception {
422+
RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
423+
when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any())).thenReturn(true);
424+
this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
425+
426+
this.mvc.perform(get("/"))
427+
.andExpect(status().isForbidden());
428+
}
429+
430+
@EnableWebSecurity
431+
static class RequireCsrfProtectionMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
432+
static RequestMatcher MATCHER;
433+
434+
@Override
435+
protected void configure(HttpSecurity http) throws Exception {
436+
// @formatter:off
437+
http
438+
.csrf(csrf -> csrf.requireCsrfProtectionMatcher(MATCHER));
439+
// @formatter:on
440+
}
441+
}
442+
389443
@Test
390444
public void getWhenCustomCsrfTokenRepositoryThenRepositoryIsUsed() throws Exception {
391445
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
@@ -454,6 +508,33 @@ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
454508
}
455509
}
456510

511+
@Test
512+
public void getWhenCustomCsrfTokenRepositoryInLambdaThenRepositoryIsUsed() throws Exception {
513+
CsrfTokenRepositoryInLambdaConfig.REPO = mock(CsrfTokenRepository.class);
514+
when(CsrfTokenRepositoryInLambdaConfig.REPO.loadToken(any()))
515+
.thenReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
516+
this.spring.register(CsrfTokenRepositoryInLambdaConfig.class, BasicController.class).autowire();
517+
518+
this.mvc.perform(get("/"))
519+
.andExpect(status().isOk());
520+
verify(CsrfTokenRepositoryInLambdaConfig.REPO).loadToken(any(HttpServletRequest.class));
521+
}
522+
523+
@EnableWebSecurity
524+
static class CsrfTokenRepositoryInLambdaConfig extends WebSecurityConfigurerAdapter {
525+
static CsrfTokenRepository REPO;
526+
527+
@Override
528+
protected void configure(HttpSecurity http) throws Exception {
529+
// @formatter:off
530+
http
531+
.formLogin()
532+
.and()
533+
.csrf(csrf -> csrf.csrfTokenRepository(REPO));
534+
// @formatter:on
535+
}
536+
}
537+
457538
@Test
458539
public void getWhenCustomAccessDeniedHandlerThenHandlerIsUsed() throws Exception {
459540
AccessDeniedHandlerConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);

0 commit comments

Comments
 (0)