refactor(security): extract static ERROR_WRITER; update ADR ref to ADR-022

Replaces per-invocation new ObjectMapper() in the accessDeniedHandler
lambda with a static field (avoids repeated allocation). ObjectMapper
cannot be injected in SecurityConfig because @WebMvcTest slices exclude
JacksonAutoConfiguration; the static instance is safe since the response
only serialises fixed String keys.

Also corrects the ADR cross-reference in the CSRF comment from ADR-020
(Spring Session JDBC) to ADR-022 (CSRF + session revocation).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-18 13:39:14 +02:00
parent 97585a9cd4
commit c3d1bea623

View File

@@ -32,6 +32,11 @@ import java.util.Map;
@RequiredArgsConstructor
public class SecurityConfig {
// @WebMvcTest slices do not include JacksonAutoConfiguration, so ObjectMapper
// cannot be injected here. A static instance is safe because the response
// only serializes fixed String keys — no custom naming strategy or module needed.
private static final ObjectMapper ERROR_WRITER = new ObjectMapper();
private final CustomUserDetailsService userDetailsService;
private final Environment environment;
@@ -88,7 +93,7 @@ public class SecurityConfig {
// CSRF protection via CookieCsrfTokenRepository (NFR-SEC-103).
// The backend sets an XSRF-TOKEN cookie (not HttpOnly so JS can read it).
// All state-changing requests must include X-XSRF-TOKEN matching the cookie.
// See ADR-020 and issue #524 for the full security rationale.
// See ADR-022 and issue #524 for the full security rationale.
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()))
@@ -127,7 +132,7 @@ public class SecurityConfig {
ErrorCode code = (e instanceof CsrfException)
? ErrorCode.CSRF_TOKEN_MISSING
: ErrorCode.FORBIDDEN;
res.getWriter().write(new ObjectMapper().writeValueAsString(Map.of("code", code.name())));
res.getWriter().write(ERROR_WRITER.writeValueAsString(Map.of("code", code.name())));
}));
return http.build();