test(auth): add integration-level CSRF rejection test; fix SessionRevocationPort wiring
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m11s
CI / OCR Service Tests (pull_request) Successful in 20s
CI / Backend Unit Tests (pull_request) Successful in 3m21s
CI / fail2ban Regex (pull_request) Successful in 40s
CI / Semgrep Security Scan (pull_request) Successful in 19s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m0s
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m11s
CI / OCR Service Tests (pull_request) Successful in 20s
CI / Backend Unit Tests (pull_request) Successful in 3m21s
CI / fail2ban Regex (pull_request) Successful in 40s
CI / Semgrep Security Scan (pull_request) Successful in 19s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m0s
Integration test: - Adds post_without_csrf_token_returns_403_CSRF_TOKEN_MISSING to AuthSessionIntegrationTest, verifying CSRF is active end-to-end (not just in @WebMvcTest slices). SessionRevocationConfig (new): - Replaces fragile @ConditionalOnBean/@ConditionalOnMissingBean on @Service beans with a single @Configuration @Bean method that accepts JdbcIndexedSessionRepository as @Autowired(required=false). Spring resolves the optional parameter reliably after auto-configuration fires, choosing JdbcSessionRevocationAdapter when available and NoOpSessionRevocationAdapter otherwise. - JdbcSessionRevocationAdapter and NoOpSessionRevocationAdapter are now plain implementation classes (no @Service/@Conditional annotations). Addresses Sara Concern 2 from PR #617 review. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
package org.raddatz.familienarchiv.auth;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@ConditionalOnBean(JdbcIndexedSessionRepository.class)
|
||||
@RequiredArgsConstructor
|
||||
class JdbcSessionRevocationAdapter implements SessionRevocationPort {
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package org.raddatz.familienarchiv.auth;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@ConditionalOnMissingBean(SessionRevocationPort.class)
|
||||
class NoOpSessionRevocationAdapter implements SessionRevocationPort {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.raddatz.familienarchiv.auth;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
|
||||
@Configuration
|
||||
class SessionRevocationConfig {
|
||||
|
||||
@Bean
|
||||
SessionRevocationPort sessionRevocationPort(
|
||||
@Autowired(required = false) JdbcIndexedSessionRepository sessionRepository) {
|
||||
if (sessionRepository != null) {
|
||||
return new JdbcSessionRevocationAdapter(sessionRepository);
|
||||
}
|
||||
return new NoOpSessionRevocationAdapter();
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,21 @@ class AuthSessionIntegrationTest {
|
||||
assertThat(me.getStatusCode().value()).isEqualTo(401);
|
||||
}
|
||||
|
||||
// ─── Task: CSRF rejection at integration layer ────────────────────────────
|
||||
|
||||
@Test
|
||||
void post_without_csrf_token_returns_403_CSRF_TOKEN_MISSING() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
// Deliberately omit XSRF-TOKEN cookie and X-XSRF-TOKEN header
|
||||
ResponseEntity<String> response = http.postForEntity(
|
||||
baseUrl + "/api/auth/logout",
|
||||
new HttpEntity<>("{}", headers), String.class);
|
||||
|
||||
assertThat(response.getStatusCode().value()).isEqualTo(403);
|
||||
assertThat(response.getBody()).contains("CSRF_TOKEN_MISSING");
|
||||
}
|
||||
|
||||
// ─── helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user