fix(auth): rotate session ID on login to prevent session fixation (CWE-384)
Inject Spring Security's SessionAuthenticationStrategy (ChangeSessionIdAuthenticationStrategy) into AuthSessionController and invoke onAuthentication at the credential boundary. The strategy calls HttpServletRequest.changeSessionId() to invalidate any pre-auth session ID an attacker may have planted and mint a fresh ID before the SecurityContext is attached. Addresses PR #612 / Nora B1. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -14,12 +14,14 @@ import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
@@ -33,6 +35,7 @@ class AuthSessionControllerTest {
|
||||
|
||||
@MockitoBean AuthService authService;
|
||||
@MockitoBean CustomUserDetailsService customUserDetailsService;
|
||||
@MockitoBean SessionAuthenticationStrategy sessionAuthenticationStrategy;
|
||||
|
||||
// ─── POST /api/auth/login ──────────────────────────────────────────────────
|
||||
|
||||
@@ -79,6 +82,24 @@ class AuthSessionControllerTest {
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_delegates_to_SessionAuthenticationStrategy_for_fixation_protection() throws Exception {
|
||||
UUID userId = UUID.randomUUID();
|
||||
AppUser appUser = AppUser.builder().id(userId).email("fix@test.de").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\":\"fix@test.de\",\"password\":\"pass\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
// Session-fixation defense (CWE-384): the controller must hand the new
|
||||
// Authentication to Spring Security's strategy, which rotates the session ID.
|
||||
verify(sessionAuthenticationStrategy).onAuthentication(eq(auth), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_does_not_set_cookie_on_failure() throws Exception {
|
||||
when(authService.login(anyString(), anyString(), anyString(), anyString()))
|
||||
|
||||
Reference in New Issue
Block a user