BAEL-5188 Add CSRF cookie protection + test (#11775)

* BAEL-5188 Add CSRF cookie protection + test

* BAEL-5188 Break long lines of code

* BAEL-5188 Remove line-breaks before semi-colons
This commit is contained in:
Benjamin Caure 2022-02-09 16:48:33 +01:00 committed by GitHub
parent b7fe8e8154
commit 437c050aee
6 changed files with 164 additions and 10 deletions

View File

@ -0,0 +1,41 @@
package com.baeldung.security.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.baeldung.security.spring.SecurityWithCsrfCookieConfig;
import com.baeldung.spring.MvcConfig;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = { SecurityWithCsrfCookieConfig.class, MvcConfig.class })
public class CsrfCookieEnabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test
public void givenNoCsrf_whenAddFoo_thenForbidden() throws Exception {
// @formatter:off
mvc
.perform(post("/auth/foos")
.contentType(MediaType.APPLICATION_JSON)
.content(createFoo())
.with(testUser()))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
public void givenCsrf_whenAddFoo_thenCreated() throws Exception {
// @formatter:off
mvc
.perform(post("/auth/foos")
.contentType(MediaType.APPLICATION_JSON)
.content(createFoo())
.with(testUser())
.with(csrf()))
.andExpect(status().isCreated());
// @formatter:on
}
}

View File

@ -14,12 +14,25 @@ public class CsrfDisabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test
public void givenNotAuth_whenAddFoo_thenUnauthorized() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo())).andExpect(status().isUnauthorized());
// @formatter:off
mvc
.perform(post("/auth/foos")
.contentType(MediaType.APPLICATION_JSON)
.content(createFoo()))
.andExpect(status().isUnauthorized());
// @formatter:on
}
@Test
public void givenAuth_whenAddFoo_thenCreated() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo()).with(testUser())).andExpect(status().isCreated());
// @formatter:off
mvc
.perform(post("/auth/foos")
.contentType(MediaType.APPLICATION_JSON)
.content(createFoo())
.with(testUser()))
.andExpect(status().isCreated());
// @formatter:on
}
}

View File

@ -15,12 +15,27 @@ public class CsrfEnabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test
public void givenNoCsrf_whenAddFoo_thenForbidden() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo()).with(testUser())).andExpect(status().isForbidden());
// @formatter:off
mvc
.perform(post("/auth/foos")
.contentType(MediaType.APPLICATION_JSON)
.content(createFoo())
.with(testUser()))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
public void givenCsrf_whenAddFoo_thenCreated() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo()).with(testUser()).with(csrf())).andExpect(status().isCreated());
// @formatter:off
mvc
.perform(post("/auth/foos")
.contentType(MediaType.APPLICATION_JSON)
.content(createFoo())
.with(testUser())
.with(csrf()))
.andExpect(status().isCreated());
// @formatter:on
}
}

View File

@ -27,7 +27,17 @@ public class SecurityWithCsrfConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user1").password("user1Pass").authorities("ROLE_USER").and().withUser("admin").password("adminPass").authorities("ROLE_ADMIN");
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user1")
.password("user1Pass")
.authorities("ROLE_USER")
.and()
.withUser("admin")
.password("adminPass")
.authorities("ROLE_ADMIN");
// @formatter:on
}
@Override
@ -45,8 +55,7 @@ public class SecurityWithCsrfConfig extends WebSecurityConfigurerAdapter {
.and()
.httpBasic()
.and()
.headers().cacheControl().disable()
;
.headers().cacheControl().disable();
// @formatter:on
}

View File

@ -0,0 +1,67 @@
package com.baeldung.security.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.web.csrf.CookieCsrfTokenRepository;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityWithCsrfCookieConfig extends WebSecurityConfigurerAdapter {
public SecurityWithCsrfCookieConfig() {
super();
}
@Bean("authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user1")
.password("user1Pass")
.authorities("ROLE_USER")
.and()
.withUser("admin")
.password("adminPass")
.authorities("ROLE_ADMIN");
// @formatter:on
}
@Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/auth/admin/*").hasAnyRole("ROLE_ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.headers().cacheControl().disable()
// Stateless API CSRF configuration
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// @formatter:on
}
}

View File

@ -27,7 +27,17 @@ public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user1").password("user1Pass").authorities("ROLE_USER").and().withUser("admin").password("adminPass").authorities("ROLE_ADMIN");
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user1")
.password("user1Pass")
.authorities("ROLE_USER")
.and()
.withUser("admin")
.password("adminPass")
.authorities("ROLE_ADMIN");
// @formatter:on
}
@Override
@ -47,8 +57,7 @@ public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
.and()
.headers().cacheControl().disable()
.and()
.csrf().disable()
;
.csrf().disable();
// @formatter:on
}