From 19aa6bf0d09f5d42658d48afe4bcd2cc00ba25ce Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 30 Sep 2026 16:16:10 +0000 Subject: [PATCH] COG-1159: add GET /api/csrf token-bootstrap endpoint (204) Co-Authored-By: patrick.bradley --- .../com/userFront/config/SecurityConfig.java | 3 +- .../com/userFront/resource/CsrfResource.java | 23 +++++++++++ .../userFront/resource/CsrfResourceTest.java | 38 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 UserFront/src/main/java/com/userFront/resource/CsrfResource.java create mode 100644 UserFront/src/test/java/com/userFront/resource/CsrfResourceTest.java diff --git a/UserFront/src/main/java/com/userFront/config/SecurityConfig.java b/UserFront/src/main/java/com/userFront/config/SecurityConfig.java index 40b10417..a26e6c38 100644 --- a/UserFront/src/main/java/com/userFront/config/SecurityConfig.java +++ b/UserFront/src/main/java/com/userFront/config/SecurityConfig.java @@ -45,7 +45,8 @@ public BCryptPasswordEncoder passwordEncoder() { "/contact/**", "/error/**/*", "/console/**", - "/signup" + "/signup", + "/api/csrf" }; @Override diff --git a/UserFront/src/main/java/com/userFront/resource/CsrfResource.java b/UserFront/src/main/java/com/userFront/resource/CsrfResource.java new file mode 100644 index 00000000..26c17c96 --- /dev/null +++ b/UserFront/src/main/java/com/userFront/resource/CsrfResource.java @@ -0,0 +1,23 @@ +package com.userFront.resource; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Safe, unauthenticated request a client can issue before its first state-changing call + * so that the CSRF token repository writes the XSRF-TOKEN cookie. While CSRF protection + * is disabled in SecurityConfig no token is bound to the request and no cookie is written. + */ +@RestController +public class CsrfResource { + + @GetMapping("/api/csrf") + public ResponseEntity csrf(CsrfToken token) { + if (token != null) { + token.getToken(); + } + return ResponseEntity.noContent().build(); + } +} diff --git a/UserFront/src/test/java/com/userFront/resource/CsrfResourceTest.java b/UserFront/src/test/java/com/userFront/resource/CsrfResourceTest.java new file mode 100644 index 00000000..4c7f0fff --- /dev/null +++ b/UserFront/src/test/java/com/userFront/resource/CsrfResourceTest.java @@ -0,0 +1,38 @@ +package com.userFront.resource; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import com.userFront.config.SecurityConfig; +import com.userFront.service.UserServiceImpl.UserSecurityService; + +@RunWith(SpringRunner.class) +@WebMvcTest(CsrfResource.class) +@Import(SecurityConfig.class) +public class CsrfResourceTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserSecurityService userSecurityService; + + /** + * Only the status is asserted: the XSRF-TOKEN cookie is written once CSRF protection + * is enabled with a cookie-based token repository, and is absent while it is disabled. + */ + @Test + public void csrfEndpointReturnsNoContentForAnonymousClient() throws Exception { + mockMvc.perform(get("/api/csrf")) + .andExpect(status().isNoContent()); + } +}