diff --git a/spring-web-modules/spring-thymeleaf-4/README.md b/spring-web-modules/spring-thymeleaf-4/README.md
index 2ed70f1c49..f8dc4c8b4e 100644
--- a/spring-web-modules/spring-thymeleaf-4/README.md
+++ b/spring-web-modules/spring-thymeleaf-4/README.md
@@ -3,6 +3,7 @@
This module contains articles about Spring with Thymeleaf
### Relevant Articles:
+- [CSRF Protection with Spring MVC and Thymeleaf](https://www.baeldung.com/csrf-thymeleaf-with-spring-security)
- [Conditionals in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-conditionals)
- [Iteration in Thymeleaf](https://www.baeldung.com/thymeleaf-iteration)
- [Spring with Thymeleaf Pagination for a List](https://www.baeldung.com/spring-thymeleaf-pagination)
diff --git a/spring-web-modules/spring-thymeleaf-4/pom.xml b/spring-web-modules/spring-thymeleaf-4/pom.xml
index f307e6fc26..44577078b0 100644
--- a/spring-web-modules/spring-thymeleaf-4/pom.xml
+++ b/spring-web-modules/spring-thymeleaf-4/pom.xml
@@ -48,6 +48,17 @@
hibernate-validator
${hibernate-validator.version}
+
+
+ org.springframework.security
+ spring-security-web
+ ${spring-security.version}
+
+
+ org.springframework.security
+ spring-security-config
+ ${spring-security.version}
+
org.thymeleaf
@@ -83,6 +94,12 @@
${spring.version}
test
+
+ org.springframework.security
+ spring-security-test
+ ${spring-security.version}
+ test
+
diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/InitSecurity.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/InitSecurity.java
new file mode 100644
index 0000000000..956db4a0e5
--- /dev/null
+++ b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/InitSecurity.java
@@ -0,0 +1,11 @@
+package com.baeldung.thymeleaf.config;
+
+import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
+
+public class InitSecurity extends AbstractSecurityWebApplicationInitializer {
+
+ public InitSecurity() {
+ super(WebMVCSecurity.class);
+
+ }
+}
diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java
new file mode 100644
index 0000000000..ea51ca3cd9
--- /dev/null
+++ b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java
@@ -0,0 +1,43 @@
+package com.baeldung.thymeleaf.config;
+
+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;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+public class WebMVCSecurity extends WebSecurityConfigurerAdapter {
+
+ @Bean
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ public WebMVCSecurity() {
+ super();
+ }
+
+ @Override
+ protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
+ auth.inMemoryAuthentication().withUser("user1").password("{noop}user1Pass").authorities("ROLE_USER");
+ }
+
+ @Override
+ public void configure(final WebSecurity web) throws Exception {
+ web.ignoring().antMatchers("/resources/**");
+ }
+
+ @Override
+ protected void configure(final HttpSecurity http) throws Exception {
+ http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
+ }
+
+}
diff --git a/spring-web-modules/spring-thymeleaf/src/main/webapp/WEB-INF/views/csrfAttack.html b/spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/csrfAttack.html
similarity index 100%
rename from spring-web-modules/spring-thymeleaf/src/main/webapp/WEB-INF/views/csrfAttack.html
rename to spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/csrfAttack.html
diff --git a/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/controller/ControllerIntegrationTest.java b/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/controller/ControllerIntegrationTest.java
new file mode 100644
index 0000000000..cbbcdc0868
--- /dev/null
+++ b/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/controller/ControllerIntegrationTest.java
@@ -0,0 +1,63 @@
+package com.baeldung.thymeleaf.controller;
+
+import com.baeldung.thymeleaf.config.WebApp;
+import com.baeldung.thymeleaf.config.WebMVCConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.RequestPostProcessor;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import javax.servlet.Filter;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebApp.class, WebMVCConfig.class})
+public class ControllerIntegrationTest {
+
+ @Autowired
+ WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private RequestPostProcessor testUser() {
+ return user("user1").password("user1Pass").roles("USER");
+ }
+
+ @Before
+ public void setup() {
+ mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilters(springSecurityFilterChain).build();
+ }
+
+ @Test
+ public void testTeachers() throws Exception {
+ mockMvc.perform(get("/listTeachers").with(testUser()).with(csrf())).andExpect(status().isOk()).andExpect(view().name("listTeachers.html"));
+ }
+
+ @Test
+ public void addStudentWithoutCSRF() throws Exception {
+ mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON).param("id", "1234567").param("name", "Joe").param("gender", "M").with(testUser())).andExpect(status().isForbidden());
+ }
+
+ @Test
+ public void addStudentWithCSRF() throws Exception {
+ mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON).param("id", "1234567").param("name", "Joe").param("gender", "M").with(testUser()).with(csrf())).andExpect(status().isOk());
+ }
+}
diff --git a/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java b/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java
new file mode 100644
index 0000000000..08a31cfa83
--- /dev/null
+++ b/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java
@@ -0,0 +1,62 @@
+package com.baeldung.thymeleaf.security.csrf;
+
+import com.baeldung.thymeleaf.config.InitSecurity;
+import com.baeldung.thymeleaf.config.WebApp;
+import com.baeldung.thymeleaf.config.WebMVCConfig;
+import com.baeldung.thymeleaf.config.WebMVCSecurity;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockHttpSession;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.RequestPostProcessor;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import javax.servlet.Filter;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebApp.class, WebMVCConfig.class, WebMVCSecurity.class, InitSecurity.class })
+public class CsrfEnabledIntegrationTest {
+
+ @Autowired
+ WebApplicationContext wac;
+ @Autowired
+ MockHttpSession session;
+
+ private MockMvc mockMvc;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private RequestPostProcessor testUser() {
+ return user("user1").password("user1Pass").roles("USER");
+ }
+
+ @Before
+ public void setup() {
+ mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilters(springSecurityFilterChain).build();
+ }
+
+ @Test
+ public void addStudentWithoutCSRF() throws Exception {
+ mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON).param("id", "1234567").param("name", "Joe").param("gender", "M").with(testUser())).andExpect(status().isForbidden());
+ }
+
+ @Test
+ public void addStudentWithCSRF() throws Exception {
+ mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON).param("id", "1234567").param("name", "Joe").param("gender", "M").with(testUser()).with(csrf())).andExpect(status().isOk());
+ }
+
+}
diff --git a/spring-web-modules/spring-thymeleaf/README.md b/spring-web-modules/spring-thymeleaf/README.md
index e83ef332e0..12eb97b4a2 100644
--- a/spring-web-modules/spring-thymeleaf/README.md
+++ b/spring-web-modules/spring-thymeleaf/README.md
@@ -4,7 +4,6 @@ This module contains articles about Spring with Thymeleaf
### Relevant Articles:
- [Introduction to Using Thymeleaf in Spring](https://www.baeldung.com/thymeleaf-in-spring-mvc)
-- [CSRF Protection with Spring MVC and Thymeleaf](https://www.baeldung.com/csrf-thymeleaf-with-spring-security)
- [Thymeleaf: Custom Layout Dialect](https://www.baeldung.com/thymeleaf-spring-layouts)
- [Spring and Thymeleaf 3: Expressions](https://www.baeldung.com/spring-thymeleaf-3-expressions)
- [Spring MVC + Thymeleaf 3.0: New Features](https://www.baeldung.com/spring-thymeleaf-3)
diff --git a/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/controller/ExpressionUtilityObjectsControllerIntegrationTest.java b/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/controller/ExpressionUtilityObjectsControllerIntegrationTest.java
index 4a2a9974f1..462e9e8c21 100644
--- a/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/controller/ExpressionUtilityObjectsControllerIntegrationTest.java
+++ b/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/controller/ExpressionUtilityObjectsControllerIntegrationTest.java
@@ -59,10 +59,5 @@ public class ExpressionUtilityObjectsControllerIntegrationTest {
public void testDates() throws Exception {
mockMvc.perform(get("/dates").with(testUser()).with(csrf())).andExpect(status().isOk()).andExpect(view().name("dates.html"));
}
-
- @Test
- public void testTeachers() throws Exception {
- mockMvc.perform(get("/listTeachers").with(testUser()).with(csrf())).andExpect(status().isOk()).andExpect(view().name("listTeachers.html"));
- }
}
diff --git a/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java b/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java
index a7c9fb4ae4..1160250877 100644
--- a/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java
+++ b/spring-web-modules/spring-thymeleaf/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java
@@ -49,16 +49,6 @@ public class CsrfEnabledIntegrationTest {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilters(springSecurityFilterChain).build();
}
- @Test
- public void addStudentWithoutCSRF() throws Exception {
- mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON).param("id", "1234567").param("name", "Joe").param("gender", "M").with(testUser())).andExpect(status().isForbidden());
- }
-
- @Test
- public void addStudentWithCSRF() throws Exception {
- mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON).param("id", "1234567").param("name", "Joe").param("gender", "M").with(testUser()).with(csrf())).andExpect(status().isOk());
- }
-
@Test
public void htmlInliningTest() throws Exception {
mockMvc.perform(get("/html").with(testUser()).with(csrf())).andExpect(status().isOk()).andExpect(view().name("inliningExample.html"));