refactoring Gateway
This commit is contained in:
@@ -14,46 +14,26 @@ springBoot {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Platform BOM für zentrale Versionsverwaltung
|
||||
implementation(platform(projects.platform.platformBom))
|
||||
|
||||
// Core project dependencies (sind korrekt)
|
||||
// === Core Dependencies ===
|
||||
implementation(projects.core.coreUtils)
|
||||
implementation(projects.platform.platformDependencies)
|
||||
|
||||
// === BEREINIGTE ABHÄNGIGKEITEN ===
|
||||
|
||||
// 1. Spring Cloud Gateway & Service Discovery (dies ist die KERN-Abhängigkeit)
|
||||
implementation(libs.bundles.spring.cloud.gateway)
|
||||
|
||||
// 2. Spring Boot Security (ersetzt das "service.complete"-Bundle)
|
||||
// Dieses Bundle sollte spring-boot-starter-security, oauth2-client, oauth2-resource-server etc. enthalten
|
||||
// Temporär auskommentieren, um das Bundle als Fehlerquelle auszuschließen
|
||||
//implementation(libs.bundles.spring.boot.security)
|
||||
|
||||
// Stattdessen die Abhängigkeiten direkt hinzufügen:
|
||||
implementation(libs.spring.boot.starter.security)
|
||||
implementation(libs.spring.boot.starter.oauth2.resource.server)
|
||||
|
||||
|
||||
// 3. Resilience4j & AOP für Circuit Breaker
|
||||
implementation(libs.bundles.resilience)
|
||||
implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")
|
||||
|
||||
// 4. Monitoring-Client (ist korrekt)
|
||||
implementation(projects.infrastructure.auth.authClient)
|
||||
implementation(projects.infrastructure.monitoring.monitoringClient)
|
||||
|
||||
// 5. Auth-Client für JWT-Erstellung/Service (falls noch benötigt nach Schritt 2)
|
||||
implementation(projects.infrastructure.auth.authClient)
|
||||
|
||||
// 6. Logging & Jackson (sind korrekt)
|
||||
// === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN ===
|
||||
implementation(libs.bundles.spring.cloud.gateway)
|
||||
implementation(libs.bundles.spring.boot.security)
|
||||
implementation(libs.bundles.resilience)
|
||||
implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")
|
||||
implementation(libs.spring.boot.starter.actuator) // Wichtig für Health & Metrics
|
||||
implementation(libs.bundles.logging)
|
||||
implementation(libs.bundles.jackson.kotlin)
|
||||
implementation(project(":infrastructure:event-store:redis-event-store"))
|
||||
implementation(project(":infrastructure:event-store:redis-event-store"))
|
||||
|
||||
// FÜGEN SIE DIESE ZEILE HINZU, UM DIE FEHLER ZU BEHEBEN:
|
||||
implementation(libs.spring.boot.starter.actuator)
|
||||
|
||||
// Test-Abhängigkeiten (sind korrekt)
|
||||
// === Test Dependencies ===
|
||||
testImplementation(projects.platform.platformTesting)
|
||||
testImplementation(libs.bundles.testing.jvm)
|
||||
}
|
||||
|
||||
+9
-6
@@ -6,11 +6,12 @@ import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.config.web.server.authenticated
|
||||
|
||||
import org.springframework.security.config.web.server.invoke
|
||||
import org.springframework.security.config.web.server.pathMatchers
|
||||
import org.springframework.security.config.web.server.permitAll
|
||||
|
||||
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
import org.springframework.web.cors.reactive.CorsConfigurationSource
|
||||
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource
|
||||
@@ -41,10 +42,12 @@ class SecurityConfig(
|
||||
// 3. Routen-Berechtigungen definieren
|
||||
authorizeExchange {
|
||||
// Öffentlich zugängliche Pfade aus der .yml-Datei laden
|
||||
pathMatchers(*securityProperties.publicPaths.toTypedArray()).permitAll()
|
||||
|
||||
authorize(
|
||||
pathMatchers(*securityProperties.publicPaths.toTypedArray()),
|
||||
permitAll
|
||||
)
|
||||
// Alle anderen Pfade erfordern eine Authentifizierung
|
||||
anyExchange.authenticated()
|
||||
authorize(anyExchange, authenticated)
|
||||
}
|
||||
|
||||
// 4. JWT-Validierung via Keycloak aktivieren
|
||||
|
||||
+3
@@ -1,8 +1,10 @@
|
||||
package at.mocode.infrastructure.gateway
|
||||
|
||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
@@ -37,6 +39,7 @@ import org.springframework.test.web.reactive.server.WebTestClient
|
||||
]
|
||||
)
|
||||
@ActiveProfiles("test")
|
||||
@Import(TestSecurityConfig::class)
|
||||
class FallbackControllerTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
+3
@@ -1,7 +1,9 @@
|
||||
package at.mocode.infrastructure.gateway
|
||||
|
||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
|
||||
/**
|
||||
@@ -34,6 +36,7 @@ import org.springframework.test.context.ActiveProfiles
|
||||
]
|
||||
)
|
||||
@ActiveProfiles("test")
|
||||
@Import(TestSecurityConfig::class)
|
||||
class GatewayApplicationTests {
|
||||
|
||||
@Test
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package at.mocode.infrastructure.gateway
|
||||
|
||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
||||
@@ -46,7 +47,7 @@ import org.springframework.web.bind.annotation.RestController
|
||||
)
|
||||
@ActiveProfiles("dev") // Use dev profile to enable filters
|
||||
@AutoConfigureWebTestClient
|
||||
@Import(GatewayFiltersTests.TestFilterConfig::class)
|
||||
@Import(TestSecurityConfig::class, GatewayFiltersTests.TestFilterConfig::class)
|
||||
class GatewayFiltersTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -1,5 +1,6 @@
|
||||
package at.mocode.infrastructure.gateway
|
||||
|
||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
||||
@@ -9,7 +10,6 @@ import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
@@ -48,7 +48,7 @@ import org.springframework.web.bind.annotation.RestController
|
||||
)
|
||||
@ActiveProfiles("test")
|
||||
@AutoConfigureWebTestClient
|
||||
@Import(GatewayRoutingTests.TestRoutesConfig::class)
|
||||
@Import(TestSecurityConfig::class, GatewayRoutingTests.TestRoutesConfig::class)
|
||||
class GatewayRoutingTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package at.mocode.infrastructure.gateway
|
||||
|
||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@@ -46,7 +47,7 @@ import org.springframework.web.bind.annotation.*
|
||||
)
|
||||
@ActiveProfiles("test") // Use test profile to disable unrelated global filters; CORS config is present in application-test.yml
|
||||
@AutoConfigureWebTestClient
|
||||
@Import(GatewaySecurityTests.TestSecurityConfig::class)
|
||||
@Import(TestSecurityConfig::class, GatewaySecurityTests.TestSecurityConfig::class)
|
||||
class GatewaySecurityTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
-290
@@ -1,290 +0,0 @@
|
||||
package at.mocode.infrastructure.gateway
|
||||
|
||||
import at.mocode.infrastructure.auth.client.JwtService
|
||||
import at.mocode.infrastructure.auth.client.model.BerechtigungE
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.cloud.gateway.route.RouteLocator
|
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.web.bind.annotation.*
|
||||
|
||||
/**
|
||||
* Tests for JWT Authentication Filter functionality.
|
||||
* Tests public path exemptions, token validation, and user context injection.
|
||||
*/
|
||||
@SpringBootTest(
|
||||
classes = [GatewayApplication::class],
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = [
|
||||
// Disable external dependencies
|
||||
"spring.cloud.discovery.enabled=false",
|
||||
"spring.cloud.consul.enabled=false",
|
||||
"spring.cloud.consul.config.enabled=false",
|
||||
"spring.cloud.consul.discovery.register=false",
|
||||
"spring.cloud.loadbalancer.enabled=false",
|
||||
// Disable circuit breaker for JWT tests
|
||||
"resilience4j.circuitbreaker.configs.default.registerHealthIndicator=false",
|
||||
"management.health.circuitbreakers.enabled=false",
|
||||
// Disable Redis health indicator for tests (no Redis in the test environment)
|
||||
"management.health.redis.enabled=false",
|
||||
// Enable JWT authentication for testing
|
||||
"gateway.security.jwt.enabled=true",
|
||||
// Use reactive web application type
|
||||
"spring.main.web-application-type=reactive",
|
||||
// Disable gateway discovery - use explicit routes
|
||||
"spring.cloud.gateway.server.webflux.discovery.locator.enabled=false",
|
||||
// Disable actuator security
|
||||
"management.security.enabled=false",
|
||||
// Set random port
|
||||
"server.port=0"
|
||||
]
|
||||
)
|
||||
@ActiveProfiles("test") // Use test profile to disable unrelated global filters; JWT is enabled via properties above
|
||||
@AutoConfigureWebTestClient
|
||||
@Import(JwtAuthenticationTests.TestJwtConfig::class)
|
||||
class JwtAuthenticationTests {
|
||||
|
||||
@Autowired
|
||||
lateinit var webTestClient: WebTestClient
|
||||
|
||||
@Autowired
|
||||
lateinit var jwtService: JwtService
|
||||
|
||||
@Test
|
||||
fun `should allow access to public paths without authentication`() {
|
||||
listOf("/", "/health", "/actuator/health", "/api/auth/login", "/api/ping/health", "/fallback/test").forEach { path ->
|
||||
webTestClient.get()
|
||||
.uri(path)
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return 401 for protected paths without authorization header`() {
|
||||
webTestClient.get()
|
||||
.uri("/api/members/protected")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized
|
||||
.expectHeader().valueEquals("Content-Type", "application/json")
|
||||
.expectBody()
|
||||
.jsonPath("$.error").isEqualTo("UNAUTHORIZED")
|
||||
.jsonPath("$.message").isEqualTo("Missing or invalid Authorization header")
|
||||
.jsonPath("$.status").isEqualTo(401)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return 401 for protected paths with invalid authorization header`() {
|
||||
webTestClient.get()
|
||||
.uri("/api/members/protected")
|
||||
.header("Authorization", "InvalidHeader")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized
|
||||
.expectBody()
|
||||
.jsonPath("$.error").isEqualTo("UNAUTHORIZED")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return 401 for protected paths with invalid JWT token`() {
|
||||
webTestClient.get()
|
||||
.uri("/api/members/protected")
|
||||
.header("Authorization", "Bearer invalid")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized
|
||||
.expectBody()
|
||||
.jsonPath("$.error").isEqualTo("UNAUTHORIZED")
|
||||
.jsonPath("$.message").exists() // Auth-client provides detailed error messages
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should allow access with valid JWT token and inject user headers`() {
|
||||
// Generate a real JWT token using the JwtService with USER permissions
|
||||
val validToken = jwtService.generateToken(
|
||||
userId = "user-123",
|
||||
username = "testuser",
|
||||
permissions = listOf(BerechtigungE.PERSON_READ)
|
||||
)
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/members/protected")
|
||||
.header("Authorization", "Bearer $validToken")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
.expectBody(String::class.java)
|
||||
.consumeWith { result ->
|
||||
// The mock controller returns injected header values in the message
|
||||
val body = result.responseBody ?: ""
|
||||
assert(body.contains("User ID:"))
|
||||
assert(body.contains("Role:"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should extract admin role from JWT token`() {
|
||||
// Generate a real JWT token using the JwtService with admin-level permissions
|
||||
// Using DELETE permissions which map to an ADMIN role according to determineRoleFromPermissions logic
|
||||
val adminToken = jwtService.generateToken(
|
||||
userId = "admin-user-123",
|
||||
username = "adminuser",
|
||||
permissions = listOf(BerechtigungE.PERSON_DELETE, BerechtigungE.VEREIN_DELETE)
|
||||
)
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/members/protected")
|
||||
.header("Authorization", "Bearer $adminToken")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
.expectBody(String::class.java)
|
||||
.consumeWith { result ->
|
||||
val body = result.responseBody
|
||||
assert(body?.contains("ADMIN") == true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should extract user role from JWT token`() {
|
||||
// Generate a real JWT token using the JwtService with user-level permissions
|
||||
val userToken = jwtService.generateToken(
|
||||
userId = "user-456",
|
||||
username = "regularuser",
|
||||
permissions = listOf(BerechtigungE.PERSON_READ, BerechtigungE.PFERD_READ)
|
||||
)
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/members/protected")
|
||||
.header("Authorization", "Bearer $userToken")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
.expectBody(String::class.java)
|
||||
.consumeWith { result ->
|
||||
val body = result.responseBody
|
||||
assert(body?.contains("USER") == true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle POST requests to protected endpoints`() {
|
||||
// Generate a real JWT token using the JwtService for POST request test
|
||||
val validToken = jwtService.generateToken(
|
||||
userId = "user-789",
|
||||
username = "postuser",
|
||||
permissions = listOf(BerechtigungE.PERSON_CREATE, BerechtigungE.VEREIN_READ)
|
||||
)
|
||||
|
||||
webTestClient.post()
|
||||
.uri("/api/members/protected")
|
||||
.header("Authorization", "Bearer $validToken")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should allow access to swagger documentation paths`() {
|
||||
webTestClient.get()
|
||||
.uri("/docs/api-docs")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
}
|
||||
|
||||
/**
|
||||
* Test configuration that provides routes for JWT authentication testing.
|
||||
*/
|
||||
@Configuration
|
||||
class TestJwtConfig {
|
||||
|
||||
@Bean
|
||||
fun jwtTestRoutes(builder: RouteLocatorBuilder): RouteLocator = builder.routes()
|
||||
.route("test-protected") { r ->
|
||||
r.path("/api/members/**")
|
||||
.filters { f -> f.setPath("/mock/protected") }
|
||||
.uri("forward:/")
|
||||
}
|
||||
.route("test-public-health") { r ->
|
||||
r.path("/health")
|
||||
.uri("forward:/mock/health")
|
||||
}
|
||||
.route("test-public-ping") { r ->
|
||||
r.path("/api/ping/**")
|
||||
.filters { f -> f.setPath("/mock/ping") }
|
||||
.uri("forward:/")
|
||||
}
|
||||
.route("test-public-auth") { r ->
|
||||
r.path("/api/auth/**")
|
||||
.filters { f -> f.setPath("/mock/auth") }
|
||||
.uri("forward:/")
|
||||
}
|
||||
.route("test-public-fallback") { r ->
|
||||
r.path("/fallback/**")
|
||||
.uri("forward:/mock/fallback")
|
||||
}
|
||||
.route("test-public-docs") { r ->
|
||||
r.path("/docs/**")
|
||||
.uri("forward:/mock/docs")
|
||||
}
|
||||
.route("test-public-actuator") { r ->
|
||||
r.path("/actuator/**")
|
||||
.uri("forward:/mock/actuator")
|
||||
}
|
||||
.route("test-root") { r ->
|
||||
r.path("/")
|
||||
.filters { f -> f.setPath("/mock/root") }
|
||||
.uri("forward:/")
|
||||
}
|
||||
.build()
|
||||
|
||||
@Bean
|
||||
fun jwtTestController(): JwtTestController = JwtTestController()
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock controller for JWT authentication testing.
|
||||
* Returns information about injected user headers.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/mock")
|
||||
class JwtTestController {
|
||||
|
||||
@RequestMapping(
|
||||
value = ["/protected"],
|
||||
method = [RequestMethod.GET, RequestMethod.POST]
|
||||
)
|
||||
fun protectedEndpoint(
|
||||
@RequestHeader(value = "X-User-ID", required = false) userId: String?,
|
||||
@RequestHeader(value = "X-User-Role", required = false) userRole: String?
|
||||
): String {
|
||||
return "Protected endpoint accessed - User ID: $userId, Role: $userRole"
|
||||
}
|
||||
|
||||
@GetMapping("/health", "/health/**")
|
||||
fun healthEndpoint(): String = "Health OK"
|
||||
|
||||
@GetMapping("/ping", "/ping/**")
|
||||
fun pingEndpoint(): String = "Ping OK"
|
||||
|
||||
@GetMapping("/auth", "/auth/**")
|
||||
@PostMapping("/auth", "/auth/**")
|
||||
fun authEndpoint(): String = "Auth endpoint"
|
||||
|
||||
@GetMapping("/fallback", "/fallback/**")
|
||||
fun fallbackEndpoint(): String = "Fallback OK"
|
||||
|
||||
@GetMapping("/docs", "/docs/**")
|
||||
fun docsEndpoint(): String = "Documentation OK"
|
||||
|
||||
@GetMapping("/actuator", "/actuator/**")
|
||||
fun actuatorEndpoint(): String = "Actuator OK"
|
||||
|
||||
@GetMapping("/root")
|
||||
fun rootEndpoint(): Map<String, String> = mapOf(
|
||||
"service" to "api-gateway",
|
||||
"status" to "running"
|
||||
)
|
||||
}
|
||||
}
|
||||
+3
@@ -1,7 +1,9 @@
|
||||
package at.mocode.infrastructure.gateway
|
||||
|
||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
import org.springframework.test.context.TestPropertySource
|
||||
|
||||
@@ -24,6 +26,7 @@ import org.springframework.test.context.TestPropertySource
|
||||
"management.security.enabled=false"
|
||||
]
|
||||
)
|
||||
@Import(TestSecurityConfig::class)
|
||||
class KeycloakGatewayIntegrationTest {
|
||||
|
||||
@Test
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package at.mocode.infrastructure.gateway.config
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Primary
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.config.web.server.invoke
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
import reactor.core.publisher.Mono
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Test-Konfiguration für Security-Beans.
|
||||
* Stellt einen Mock ReactiveJwtDecoder und eine Security-Konfiguration bereit,
|
||||
* die alle Anfragen für Test-Zwecke erlaubt.
|
||||
*/
|
||||
@TestConfiguration
|
||||
class TestSecurityConfig {
|
||||
|
||||
/**
|
||||
* Mock ReactiveJwtDecoder für Tests.
|
||||
* Validiert keine echten JWTs, sondern akzeptiert alle Token für Test-Zwecke.
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
fun mockReactiveJwtDecoder(): ReactiveJwtDecoder {
|
||||
return ReactiveJwtDecoder { token ->
|
||||
// Erstelle ein Mock-JWT mit minimalen Claims
|
||||
val jwt = Jwt.withTokenValue(token)
|
||||
.header("alg", "none")
|
||||
.header("typ", "JWT")
|
||||
.claim("sub", "test-user")
|
||||
.claim("scope", "read write")
|
||||
.claim("preferred_username", "test-user")
|
||||
.issuedAt(Instant.now())
|
||||
.expiresAt(Instant.now().plusSeconds(3600))
|
||||
.build()
|
||||
|
||||
Mono.just(jwt)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Security Web Filter Chain, die alle Anfragen erlaubt.
|
||||
* Dies ermöglicht Tests von Routing, CORS und Filtern ohne Authentifizierung.
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
fun testSecurityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
return http {
|
||||
csrf { disable() }
|
||||
authorizeExchange {
|
||||
authorize(anyExchange, permitAll)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user