test(auth): login response never leaks the password field

Pin the @JsonProperty(WRITE_ONLY) invariant on AppUser.password. If the
annotation is ever dropped — or a new field aliases the hash — the CI run that
ships the regression flags it the next morning rather than waiting for a
security review. Addresses PR #612 / Nora concern (regression test).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-17 22:40:41 +02:00
parent ea65611690
commit c7782d554f

View File

@@ -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()))