diff --git a/backend/src/test/java/org/raddatz/familienarchiv/auth/AuthSessionControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/auth/AuthSessionControllerTest.java index 45b96d11..7ace8c45 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/auth/AuthSessionControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/auth/AuthSessionControllerTest.java @@ -100,6 +100,31 @@ class AuthSessionControllerTest { verify(sessionAuthenticationStrategy).onAuthentication(eq(auth), any(), any()); } + @Test + void login_response_body_does_not_contain_password_field() throws Exception { + // Regression guard: AppUser.password is @JsonProperty(WRITE_ONLY). If anyone + // ever drops that annotation, this assertion catches the credential leak on + // the very next CI run. + UUID userId = UUID.randomUUID(); + AppUser appUser = AppUser.builder() + .id(userId) + .email("leak@test.de") + .password("$2a$10$shouldnotappearinresponse") + .build(); + Authentication auth = mock(Authentication.class); + when(authService.login(anyString(), anyString(), anyString(), anyString())) + .thenReturn(new LoginResult(appUser, auth)); + + mockMvc.perform(post("/api/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"email\":\"leak@test.de\",\"password\":\"pass\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.password").doesNotExist()) + .andExpect(jsonPath("$.pwd").doesNotExist()) + .andExpect(content().string(org.hamcrest.Matchers.not( + org.hamcrest.Matchers.containsString("$2a$10$shouldnotappearinresponse")))); + } + @Test void login_does_not_set_cookie_on_failure() throws Exception { when(authService.login(anyString(), anyString(), anyString(), anyString()))