From c3d1bea6237793900444216a74e9aa230d939f4e Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 18 May 2026 13:39:14 +0200 Subject: [PATCH] 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 --- .../raddatz/familienarchiv/security/SecurityConfig.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/security/SecurityConfig.java b/backend/src/main/java/org/raddatz/familienarchiv/security/SecurityConfig.java index 1a5b904f..1c6382da 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/security/SecurityConfig.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/security/SecurityConfig.java @@ -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();