test(auth): add integration-level CSRF rejection test; fix SessionRevocationPort wiring
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;
|
package org.raddatz.familienarchiv.auth;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
|
||||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@ConditionalOnBean(JdbcIndexedSessionRepository.class)
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
class JdbcSessionRevocationAdapter implements SessionRevocationPort {
|
class JdbcSessionRevocationAdapter implements SessionRevocationPort {
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package org.raddatz.familienarchiv.auth;
|
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 {
|
class NoOpSessionRevocationAdapter implements SessionRevocationPort {
|
||||||
|
|
||||||
@Override
|
@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);
|
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 ─────────────────────────────────────────────────────────────
|
// ─── helpers ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user