refactoring Gateway

This commit is contained in:
2025-10-10 12:31:53 +02:00
parent e8f4e9aef1
commit da7ea2c2da
9 changed files with 281 additions and 743 deletions
+7 -1
View File
@@ -79,7 +79,7 @@ subprojects {
includeTags("perf") includeTags("perf")
} }
shouldRunAfter("test") shouldRunAfter("test")
// Keep same JVM settings for consistency // Keep the same JVM settings for consistency
jvmArgs("-Xshare:auto", "-Djdk.instrument.traceUsage=false") jvmArgs("-Xshare:auto", "-Djdk.instrument.traceUsage=false")
maxHeapSize = "2g" maxHeapSize = "2g"
dependsOn("testClasses") dependsOn("testClasses")
@@ -100,6 +100,12 @@ subprojects {
environment("CHROMIUM_BIN", "/usr/bin/chromium") environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium") environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
} }
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
freeCompilerArgs.add("-Xannotation-default-target=param-property")
}
}
} }
// ################################################################## // ##################################################################
+2 -2
View File
@@ -251,7 +251,7 @@ flyway = [
] ]
spring-boot-essentials = [ spring-boot-essentials = [
"spring-boot-starter-web", # "spring-boot-starter-web",
"spring-boot-starter-validation", "spring-boot-starter-validation",
"spring-boot-starter-actuator" "spring-boot-starter-actuator"
] ]
@@ -426,7 +426,7 @@ ktor-server-complete = [
# Complete Spring Boot Service bundle - combines all Spring Boot bundles for full-featured services # Complete Spring Boot Service bundle - combines all Spring Boot bundles for full-featured services
spring-boot-service-complete = [ spring-boot-service-complete = [
"spring-boot-starter-web", # "spring-boot-starter-web",
"spring-boot-starter-validation", "spring-boot-starter-validation",
"spring-boot-starter-actuator", "spring-boot-starter-actuator",
"spring-boot-starter-security", "spring-boot-starter-security",
+25 -22
View File
@@ -17,42 +17,45 @@ dependencies {
// Platform BOM für zentrale Versionsverwaltung // Platform BOM für zentrale Versionsverwaltung
implementation(platform(projects.platform.platformBom)) implementation(platform(projects.platform.platformBom))
// Core project dependencies // Core project dependencies (sind korrekt)
implementation(projects.core.coreUtils) implementation(projects.core.coreUtils)
implementation(projects.platform.platformDependencies) implementation(projects.platform.platformDependencies)
// Spring Cloud Gateway und Service Discovery (Bundle) // === BEREINIGTE ABHÄNGIGKEITEN ===
// 1. Spring Cloud Gateway & Service Discovery (dies ist die KERN-Abhängigkeit)
implementation(libs.bundles.spring.cloud.gateway) implementation(libs.bundles.spring.cloud.gateway)
// Spring Boot Service Complete Bundle (Web, Security, Data, Observability) // 2. Spring Boot Security (ersetzt das "service.complete"-Bundle)
// Provides: spring-boot-starter-web, validation, actuator, security, // Dieses Bundle sollte spring-boot-starter-security, oauth2-client, oauth2-resource-server etc. enthalten
// oauth2-client, oauth2-resource-server, data-jpa, data-redis, // Temporär auskommentieren, um das Bundle als Fehlerquelle auszuschließen
// micrometer-prometheus, tracing-bridge-brave, zipkin-reporter-brave // implementation(libs.bundles.spring.boot.security)
implementation(libs.bundles.spring.boot.service.complete)
// Reactive WebFlux for Gateway // Stattdessen die Abhängigkeiten direkt hinzufügen:
implementation(libs.spring.boot.starter.webflux) implementation(libs.spring.boot.starter.security)
implementation(libs.spring.boot.starter.oauth2.resource.server)
// Resilience4j Bundle (Circuit Breaker support)
// 3. Resilience4j & AOP für Circuit Breaker
implementation(libs.bundles.resilience) implementation(libs.bundles.resilience)
// Spring Cloud CircuitBreaker for Gateway Filter Integration
implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j") implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")
// Jackson Kotlin support // 4. Monitoring-Client (ist korrekt)
implementation(libs.bundles.jackson.kotlin)
// Logging Bundle (kotlin-logging, logback-classic, logback-core, slf4j-api)
implementation(libs.bundles.logging)
// Infrastructure dependencies
implementation(projects.infrastructure.auth.authClient)
implementation(projects.infrastructure.monitoring.monitoringClient) implementation(projects.infrastructure.monitoring.monitoringClient)
// Test dependencies // 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)
implementation(libs.bundles.logging)
implementation(libs.bundles.jackson.kotlin)
// FÜGEN SIE DIESE ZEILE HINZU, UM DIE FEHLER ZU BEHEBEN:
implementation(libs.spring.boot.starter.actuator)
// Test-Abhängigkeiten (sind korrekt)
testImplementation(projects.platform.platformTesting) testImplementation(projects.platform.platformTesting)
testImplementation(libs.bundles.testing.jvm) testImplementation(libs.bundles.testing.jvm)
testImplementation(libs.bundles.logging)
} }
tasks.test { tasks.test {
@@ -1,55 +0,0 @@
package at.mocode.infrastructure.gateway.config
import at.mocode.infrastructure.auth.client.JwtService
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.validation.annotation.Validated
import jakarta.validation.constraints.Min
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.Size
import kotlin.time.Duration.Companion.minutes
/**
* Spring-Konfiguration für JWT-Verarbeitung im Gateway.
* Stellt den JwtService-Bean für die Token-Validierung bereit.
*/
@Configuration
@EnableConfigurationProperties(JwtConfiguration.JwtProperties::class)
class JwtConfiguration {
/**
* Erstellt einen JwtService-Bean für JWT-Token-Validierung im Gateway.
*/
@Bean
fun jwtService(jwtProperties: JwtProperties): JwtService {
// Basic safeguard: warn if default secret is used
if (jwtProperties.secret == "default-secret-for-development-only-please-change-in-production") {
System.err.println("[GATEWAY SECURITY WARNING] Using default JWT secret DO NOT use this in production!")
}
return JwtService(
secret = jwtProperties.secret,
issuer = jwtProperties.issuer,
audience = jwtProperties.audience,
expiration = jwtProperties.expiration.minutes
)
}
/**
* Konfigurationseigenschaften für JWT-Einstellungen im Gateway.
*/
@ConfigurationProperties(prefix = "gateway.security.jwt")
@Validated
data class JwtProperties(
@field:NotBlank
@field:Size(min = 32, message = "JWT secret must be at least 32 characters for HMAC512")
val secret: String = "default-secret-for-development-only-please-change-in-production",
@field:NotBlank
val issuer: String = "meldestelle-auth-server",
@field:NotBlank
val audience: String = "meldestelle-services",
@field:Min(1)
val expiration: Long = 60 // minutes
)
}
@@ -1,148 +0,0 @@
package at.mocode.infrastructure.gateway.security
import at.mocode.infrastructure.auth.client.JwtService
import at.mocode.infrastructure.auth.client.model.BerechtigungE
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.cloud.gateway.filter.GatewayFilterChain
import org.springframework.cloud.gateway.filter.GlobalFilter
import org.springframework.core.Ordered
import org.springframework.http.HttpStatus
import org.springframework.http.server.reactive.ServerHttpResponse
import org.springframework.stereotype.Component
import org.springframework.util.AntPathMatcher
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
/**
* JWT Authentication Filter für das Gateway.
* Validiert JWT-Tokens für alle geschützten Endpunkte.
*/
@Component
@ConditionalOnProperty(value = ["gateway.security.jwt.enabled"], havingValue = "true", matchIfMissing = true)
class JwtAuthenticationFilter(
private val jwtService: JwtService
) : GlobalFilter, Ordered {
private val pathMatcher = AntPathMatcher()
// Öffentliche Pfade, die keine Authentifizierung erfordern
private val publicPaths = listOf(
"/",
"/health",
"/actuator/**",
"/api/auth/login",
"/api/auth/register",
"/api/auth/refresh",
"/fallback/**",
"/docs/**",
"/swagger-ui/**",
"/api/ping/**" // Ping Service für Monitoring
)
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
val request = exchange.request
val path = request.path.value()
// Prüfe, ob der Pfad öffentlich zugänglich ist
if (isPublicPath(path)) {
return chain.filter(exchange)
}
// Extrahiere JWT aus Authorization Header
val authHeader = request.headers.getFirst("Authorization")
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
return handleUnauthorized(exchange, "Missing or invalid Authorization header")
}
val token = authHeader.substring(7)
// Hier würde normalerweise die JWT-Validierung mit dem auth-client erfolgen,
// für diese Implementation verwenden wir eine vereinfachte Validierung
return validateJwtToken(token, exchange, chain)
}
private fun isPublicPath(path: String): Boolean {
return publicPaths.any { publicPath ->
pathMatcher.match(publicPath, path)
}
}
private fun validateJwtToken(
token: String,
exchange: ServerWebExchange,
chain: GatewayFilterChain
): Mono<Void> {
// Use auth-client JwtService for comprehensive JWT validation
val validationResult = jwtService.validateToken(token)
if (validationResult.isFailure) {
return handleUnauthorized(exchange, "Invalid JWT token: ${validationResult.exceptionOrNull()?.message}")
}
try {
// Extract user ID using auth-client
val userIdResult = jwtService.getUserIdFromToken(token)
if (userIdResult.isFailure) {
return handleUnauthorized(exchange, "Failed to extract user ID from token")
}
val userId = userIdResult.getOrThrow()
// Extract permissions using auth-client
val permissionsResult = jwtService.getPermissionsFromToken(token)
val permissions = permissionsResult.getOrElse { emptyList() }
// Convert permissions to role for backward compatibility
val userRole = determineRoleFromPermissions(permissions)
val permissionsHeader = permissions.joinToString(",") { it.name }
val mutatedRequest = exchange.request.mutate()
.header("X-User-ID", userId)
.header("X-User-Role", userRole)
.header("X-User-Permissions", permissionsHeader)
.build()
val mutatedExchange = exchange.mutate()
.request(mutatedRequest)
.build()
return chain.filter(mutatedExchange)
} catch (e: Exception) {
return handleUnauthorized(exchange, "JWT processing failed: ${e.message}")
}
}
/**
* Determines the user role based on permissions for backward compatibility.
* Maps permissions to traditional role-based access control.
*/
private fun determineRoleFromPermissions(permissions: List<BerechtigungE>): String {
return when {
permissions.any { it.name.contains("ADMIN", ignoreCase = true) } -> "ADMIN"
permissions.any { it.name.contains("DELETE") } -> "ADMIN" // DELETE permissions indicate admin-level access
permissions.any { it.name.contains("WRITE") || it.name.contains("CREATE") } -> "USER"
permissions.isNotEmpty() -> "USER"
else -> "GUEST"
}
}
private fun handleUnauthorized(exchange: ServerWebExchange, message: String): Mono<Void> {
val response: ServerHttpResponse = exchange.response
response.statusCode = HttpStatus.UNAUTHORIZED
response.headers.add("Content-Type", "application/json")
val errorJson = """{
"error": "UNAUTHORIZED",
"message": "$message",
"timestamp": "${java.time.LocalDateTime.now()}",
"status": 401
}"""
val buffer = response.bufferFactory().wrap(errorJson.toByteArray())
return response.writeWith(Mono.just(buffer))
}
override fun getOrder(): Int = Ordered.HIGHEST_PRECEDENCE + 3
}
@@ -1,328 +1,100 @@
package at.mocode.infrastructure.gateway.security package at.mocode.infrastructure.gateway.security
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.ServerHttpSecurity import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder import org.springframework.security.config.web.server.invoke
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder
import org.springframework.security.web.server.SecurityWebFilterChain import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.web.cors.CorsConfiguration import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.reactive.CorsConfigurationSource import org.springframework.web.cors.reactive.CorsConfigurationSource
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource
import java.time.Duration import java.time.Duration
/**
* Erweiterte reaktive Sicherheitskonfiguration für das Gateway.
*
* ARCHITEKTUR-ÜBERBLICK:
* ======================
* Diese Konfiguration stellt die grundlegende Sicherheits-Schicht für das Spring Cloud Gateway bereit.
* Sie arbeitet zusammen mit mehreren weiteren Sicherheitskomponenten:
*
* 1. JwtAuthenticationFilter (GlobalFilter) Validiert JWT-Tokens und authentifiziert Benutzer
* 2. RateLimitingFilter (GlobalFilter) Bietet IP-basiertes Rate-Limiting mit benutzerbezogenen Limits
* 3. CorrelationIdFilter (GlobalFilter) Fügt Request-Tracing-Fähigkeiten hinzu
* 4. EnhancedLoggingFilter (GlobalFilter) Liefert strukturiertes Request/Response-Logging
*
* SICHERHEITSSTRATEGIE:
* =====================
* Das Gateway verwendet einen mehrschichtigen Sicherheitsansatz:
* - Diese SecurityWebFilterChain liefert grundlegende Einstellungen (CORS, CSRF, Basis-Header)
* - Der JwtAuthenticationFilter übernimmt die eigentliche Authentifizierung, wenn per Property aktiviert
* - Die SecurityWebFilterChain bleibt permissiv (permitAll), damit der JWT-Filter den Zugriff steuert
* - Rate-Limiting- und Logging-Filter liefern operative Sicherheit und Monitoring
*
* ENTWURFSBEGRÜNDUNG:
* ===================
* - Während Tests ist Spring Security auf dem Classpath (testImplementation), was
* die Auto-Konfiguration aktiviert und alle Endpunkte sperren kann, sofern keine SecurityWebFilterChain bereitgestellt wird
* - Das Gateway erzwingt Authentifizierung über den JwtAuthenticationFilter (falls per Property aktiviert),
* daher sollte die SecurityWebFilterChain permissiv bleiben und sich auf grundlegende Belange konzentrieren
* - Explizite CORS-Konfiguration stellt eine korrekte Behandlung von Cross-Origin-Anfragen aus Web-Clients sicher
* - Konfigurierbare Properties erlauben umgebungsspezifische Sicherheitseinstellungen ohne Codeänderungen
* - CSRF-Schutz ist deaktiviert, da er für zustandslose JWT-basierte Authentifizierung nicht benötigt wird
*
* CORS-INTEGRATION:
* =================
* Die CORS-Konfiguration arbeitet mit der bestehenden Filterkette zusammen:
* - Erlaubt Anfragen von konfigurierten Ursprüngen (Dev/Prod-Umgebungen)
* - Gibt benutzerdefinierte Header aus Gateway-Filtern frei (Korrelations-IDs, Rate-Limits)
* - Unterstützt Credentials für JWT-Authentifizierung
* - Cacht Preflight-Antworten für bessere Performance
*
* TESTHINWEISE:
* =============
* - Die Konfiguration ist so gestaltet, dass sie nahtlos mit bestehenden Sicherheitstests funktioniert
* - Das Test-Profil kann CORS-Einstellungen bei Bedarf überschreiben
* - Eine permissive Autorisierung stellt sicher, dass Tests sich auf die Sicherheit der Filterebene konzentrieren können
*/
@Configuration @Configuration
@EnableWebFluxSecurity @EnableWebFluxSecurity
@EnableConfigurationProperties(GatewaySecurityProperties::class) @EnableConfigurationProperties(GatewaySecurityProperties::class)
class SecurityConfig( class SecurityConfig(
private val securityProperties: GatewaySecurityProperties, private val securityProperties: GatewaySecurityProperties
@Value($$"${keycloak.issuer-uri:}") private val issuerUri: String,
@Value($$"${keycloak.jwk-set-uri:}") private val jwkSetUri: String
) { ) {
/** /**
* Hauptkonfiguration der Spring-Security-Filterkette. * Konfiguriert die zentrale Security-Filter-Kette für das Gateway.
* *
* Diese Methode konfiguriert die reaktive Sicherheits-Filterkette mit: * Diese Konfiguration nutzt den Standard-OAuth2-Resource-Server von Spring Security,
* - CSRF deaktiviert für zustandslosen API-Betrieb * um JWTs (z.B. von Keycloak) automatisch zu validieren.
* - Explizite CORS-Konfiguration für Cross-Origin-Unterstützung
* - Permissiver Autorisierung (Authentifizierung durch den JWT-Filter)
*
* Die Konfiguration bleibt kompatibel mit der bestehenden Filterarchitektur
* und bietet zugleich bessere CORS-Steuerung und Konfigurierbarkeit.
*/ */
@Bean @Bean
fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
val httpSecurity = http return http { // Start der modernen Kotlin-DSL
.cors { it.configurationSource(corsConfigurationSource()) } // 1. CORS-Konfiguration anwenden
.csrf { it.disable() } cors { }
.authorizeExchange { exchanges ->
exchanges // 2. CSRF deaktivieren (für zustandslose APIs)
// Public paths csrf { disable() }
.pathMatchers(
"/", // 3. Routen-Berechtigungen definieren
"/health/**", authorizeExchange {
"/actuator/**", // Öffentlich zugängliche Pfade aus der .yml-Datei laden
"/api/ping/**", pathMatchers(*securityProperties.publicPaths.toTypedArray()).permitAll()
"/api/auth/**", // All auth endpoints (includes test endpoints)
"/api/auth/login", // Alle anderen Pfade erfordern eine Authentifizierung
"/api/auth/register", anyExchange.authenticated()
"/api/auth/refresh",
"/fallback/**",
"/docs/**",
"/swagger-ui/**",
"/test/**", // Test paths for integration tests
"/mock/**" // Mock controller paths for tests
).permitAll()
.apply {
// Only enforce role-based authorization when oauth2ResourceServer is active
// In tests without oauth2, JwtAuthenticationFilter handles auth via GlobalFilter
if (jwkSetUri.isNotBlank()) {
// Admin paths
pathMatchers("/api/admin/**").hasRole("ADMIN")
// Monitoring paths
pathMatchers("/api/monitoring/**").hasAnyRole("ADMIN", "MONITORING")
// All other requests require authentication
anyExchange().authenticated()
} else {
// Permissive mode for tests - JwtAuthenticationFilter handles auth
anyExchange().permitAll()
}
}
} }
// Only configure oauth2ResourceServer if Keycloak JWK URI is configured // 4. JWT-Validierung via Keycloak aktivieren
// In tests, this will be empty, allowing JwtAuthenticationFilter to handle auth oauth2ResourceServer {
if (jwkSetUri.isNotBlank()) { jwt { }
httpSecurity.oauth2ResourceServer { oauth2 ->
oauth2.jwt { jwt ->
jwt.jwtDecoder(jwtDecoder())
}
} }
} }
return httpSecurity.build()
}
@Bean
@ConditionalOnProperty(name = ["keycloak.jwk-set-uri"])
fun jwtDecoder(): ReactiveJwtDecoder {
return NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri)
.build()
} }
/** /**
* Explizite CORS-Konfigurationsquelle. * Definiert die zentrale und einzige CORS-Konfiguration für das Gateway.
*
* Dieser Bean bietet eine detaillierte Steuerung der Cross-Origin-Resource-Sharing-Einstellungen
* und ersetzt die leere Standard-CORS-Konfiguration durch explizite, konfigurierbare Einstellungen.
*
* Schlüsselfunktionen:
* - Umgebungsspezifische erlaubte Ursprünge (Allowed Origins)
* - Umfassende Unterstützung für HTTP-Methoden
* - JWT-bewusste Header-Konfiguration
* - Integration mit Headern aus Gateway-Filtern
* - Performance-optimiertes Preflight-Caching
*
* Die Konfiguration ist darauf ausgelegt, mit typischen Webanwendungs-Architekturen zu funktionieren,
* bei denen ein JavaScript-Frontend API-Aufrufe an das Gateway sendet.
*/ */
@Bean @Bean
fun corsConfigurationSource(): CorsConfigurationSource { fun corsConfigurationSource(): CorsConfigurationSource {
val configuration = CorsConfiguration().apply { val configuration = CorsConfiguration().apply {
// Erlaubte Ursprünge pro Umgebung konfigurierbar allowedOriginPatterns = securityProperties.cors.allowedOriginPatterns.toList()
// Entwicklung: localhost-URLs für lokale Tests
// Produktion: domainspezifische URLs für ausgelieferte Anwendungen
allowedOrigins = securityProperties.cors.allowedOrigins.toList()
// Erlaubte HTTP-Methoden umfassende REST-API-Unterstützung
// Enthält alle Standardmethoden plus OPTIONS für Preflight-Anfragen
allowedMethods = securityProperties.cors.allowedMethods.toList() allowedMethods = securityProperties.cors.allowedMethods.toList()
// Erlaubte Request-Header beinhaltet JWT und benutzerdefinierte Header
// Authorization: für JWT Bearer Tokens
// X-Correlation-ID: für Request-Tracing
// Standard-Header: Content-Type, Accept, etc.
allowedHeaders = securityProperties.cors.allowedHeaders.toList() allowedHeaders = securityProperties.cors.allowedHeaders.toList()
// Sichtbare Response-Header ermöglicht Client-Zugriff auf benutzerdefinierte Header
// Beinhaltet Header, die von Gateway-Filtern hinzugefügt werden:
// - X-Correlation-ID vom CorrelationIdFilter
// - X-RateLimit-* vom RateLimitingFilter
exposedHeaders = securityProperties.cors.exposedHeaders.toList() exposedHeaders = securityProperties.cors.exposedHeaders.toList()
// Credentials erlauben erforderlich für JWT-Authentifizierung
// Aktiviert Cookies und Authorization-Header in Cross-Origin-Anfragen
allowCredentials = securityProperties.cors.allowCredentials allowCredentials = securityProperties.cors.allowCredentials
// Preflight-Cache-Dauer Performance-Optimierung
// Reduziert die Anzahl an OPTIONS-Anfragen für wiederholte API-Aufrufe
maxAge = securityProperties.cors.maxAge.seconds maxAge = securityProperties.cors.maxAge.seconds
} }
return UrlBasedCorsConfigurationSource().apply { return UrlBasedCorsConfigurationSource().apply {
// CORS-Konfiguration auf alle Gateway-Routen anwenden
registerCorsConfiguration("/**", configuration) registerCorsConfiguration("/**", configuration)
} }
} }
} }
/** /**
* Konfigurationseigenschaften für die Sicherheits-Einstellungen des Gateways. * Konfigurations-Properties für alle sicherheitsrelevanten Einstellungen des Gateways.
*
* Ermöglicht umgebungsspezifische Sicherheitskonfiguration über application.yml/-properties.
* Dieser Ansatz erlaubt unterschiedliche Sicherheitseinstellungen für Entwicklung, Test und
* Produktion, ohne Codeänderungen vornehmen zu müssen.
*
* Beispielkonfiguration in application.yml:
* ```yaml
* gateway:
* security:
* cors:
* allowed-origins:
* - http://localhost:3000
* - https://app.meldestelle.at
* allowed-methods:
* - GET
* - POST
* - PUT
* - DELETE
* allow-credentials: true
* max-age: PT2H
* ```
*/ */
@ConfigurationProperties(prefix = "gateway.security") @ConfigurationProperties(prefix = "gateway.security")
data class GatewaySecurityProperties( data class GatewaySecurityProperties(
val cors: CorsProperties = CorsProperties() val cors: CorsProperties = CorsProperties(),
val publicPaths: List<String> = listOf(
"/",
"/fallback/**",
"/actuator/**",
"/webjars/**",
"/v3/api-docs/**",
"/api/auth/**" // Alle Auth-Endpunkte
)
) )
/** /**
* CORS-spezifische Konfigurationseigenschaften mit sinnvollen Defaults. * DTO für CORS-Properties mit sinnvollen Standardwerten.
*
* Die Default-Werte sind so gewählt, dass sie mit typischen Entwicklungs- und Produktions-Setups funktionieren:
* - Übliche Entwicklungs-URLs (localhost mit Standardports)
* - Produktions-Domain-Muster
* - Volle Unterstützung der REST-API-Methoden
* - Unterstützung für JWT- und Gateway-Filter-Header
* - Sinnvolle Preflight-Cache-Dauer
*/ */
data class CorsProperties( data class CorsProperties(
/** val allowedOriginPatterns: Set<String> = setOf("http://localhost:[*]", "https://*.meldestelle.at"),
* Erlaubte Ursprünge (Allowed Origins) für CORS-Anfragen. val allowedMethods: Set<String> = setOf("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"),
* val allowedHeaders: Set<String> = setOf("*"),
* Defaults unterstützen gängige Entwicklungs- und Produktionsszenarien: val exposedHeaders: Set<String> = setOf("X-Correlation-ID", "X-RateLimit-Limit", "X-RateLimit-Remaining"),
* - localhost:3000 typischer React-Entwicklungsserver
* - localhost:8080 gängiger alternativer Entwicklungsport
* - localhost:4200 typischer Angular-Entwicklungsserver
* - Spezifische Subdomains von meldestelle.at für die Produktion
*
* Kann je Umgebung bei Bedarf überschrieben werden.
*/
val allowedOrigins: Set<String> = setOf(
"http://localhost:3000",
"http://localhost:8080",
"http://localhost:4200",
"https://app.meldestelle.at",
"https://frontend.meldestelle.at",
"https://www.meldestelle.at"
),
/**
* Erlaubte HTTP-Methoden für CORS-Anfragen.
*
* Enthält alle Standard-REST-API-Methoden sowie OPTIONS für Preflight-
* und HEAD für Metadaten-Anfragen.
*/
val allowedMethods: Set<String> = setOf(
"GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH"
),
/**
* Erlaubte Request-Header für CORS-Anfragen.
*
* Beinhaltet:
* - Standard-Header: Content-Type, Accept, etc.
* - JWT-Authentifizierung: Authorization
* - Gateway-Tracing: X-Correlation-ID
* - Cache-Steuerung: Cache-Control, Pragma
*/
val allowedHeaders: Set<String> = setOf(
"Authorization",
"Content-Type",
"X-Requested-With",
"X-Correlation-ID",
"Accept",
"Origin",
"Cache-Control",
"Pragma"
),
/**
* Sichtbare Response-Header für CORS-Anfragen.
*
* Header, auf die Client-JavaScript in Antworten zugreifen darf.
* Beinhaltet benutzerdefinierte Header, die von Gateway-Filtern hinzugefügt werden:
* - X-Correlation-ID: Request-Tracing (CorrelationIdFilter)
* - X-RateLimit-*: Informationen zum Rate-Limiting (RateLimitingFilter)
* - Standard-Header: Content-Length, Date
*/
val exposedHeaders: Set<String> = setOf(
"X-Correlation-ID",
"X-RateLimit-Limit",
"X-RateLimit-Remaining",
"X-RateLimit-Enabled",
"Content-Length",
"Date"
),
/**
* Credentials in CORS-Anfragen erlauben.
*
* Auf true setzen, um zu unterstützen:
* - JWT Bearer Tokens im Authorization-Header
* - Cookies (falls verwendet)
* - Client-Zertifikate (falls verwendet)
*/
val allowCredentials: Boolean = true, val allowCredentials: Boolean = true,
/**
* Maximales Alter für das Caching von Preflight-Anfragen.
*
* Dauer, für die Browser Preflight-Antworten cachen können, wodurch
* die Anzahl der OPTIONS-Anfragen für wiederholte API-Aufrufe reduziert wird.
* Default: 1 Stunde (guter Kompromiss zwischen Performance und Flexibilität)
*/
val maxAge: Duration = Duration.ofHours(1) val maxAge: Duration = Duration.ofHours(1)
) )
@@ -1,187 +0,0 @@
# ===================================================================
# Meldestelle API Gateway Configuration
# ===================================================================
server:
port: ${GATEWAY_PORT:8081}
spring:
application:
name: meldestelle-api-gateway
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev,keycloak}
# Security Configuration
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${KEYCLOAK_ISSUER_URI:http://keycloak:8080/realms/meldestelle}
jwk-set-uri: ${KEYCLOAK_JWK_SET_URI:http://keycloak:8080/realms/meldestelle/protocol/openid-connect/certs}
# Spring Cloud Gateway Configuration
cloud:
gateway:
routes:
# Ping Service Route
- id: ping-service
uri: lb://ping-service
predicates:
- Path=/api/ping/**
filters:
- StripPrefix=2
- name: CircuitBreaker
args:
name: ping-service-cb
fallbackUri: forward:/fallback/ping
# Auth Service Route
- id: auth-service
uri: lb://auth-server
predicates:
- Path=/api/auth/**
filters:
- StripPrefix=2
- name: CircuitBreaker
args:
name: auth-service-cb
fallbackUri: forward:/fallback/auth
# Global CORS Configuration
globalcors:
corsConfigurations:
'[/**]':
allowedOriginPatterns:
- "http://localhost:*"
- "http://127.0.0.1:*"
- "http://web-app:*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
- PATCH
allowedHeaders: "*"
allowCredentials: true
exposedHeaders:
- Authorization
- X-User-ID
- X-User-Name
- X-User-Role
# Keycloak Integration Settings
keycloak:
server-url: ${KEYCLOAK_SERVER_URL:http://keycloak:8080}
realm: ${KEYCLOAK_REALM:meldestelle}
client-id: ${KEYCLOAK_CLIENT_ID:api-gateway}
client-secret: ${KEYCLOAK_CLIENT_SECRET:api-gateway-secret-key-change-in-production}
issuer-uri: ${KEYCLOAK_ISSUER_URI:http://keycloak:8080/realms/meldestelle}
jwk-set-uri: ${KEYCLOAK_JWK_SET_URI:http://keycloak:8080/realms/meldestelle/protocol/openid-connect/certs}
# Gateway Security Settings
gateway:
security:
keycloak:
enabled: ${GATEWAY_SECURITY_KEYCLOAK_ENABLED:true}
public-paths: >
/,
/health/**,
/actuator/**,
/api/ping/health,
/api/auth/login,
/api/auth/register,
/api/auth/refresh,
/fallback/**,
/docs/**,
/swagger-ui/**
# Consul Service Discovery
consul:
host: ${CONSUL_HOST:consul}
port: ${CONSUL_PORT:8500}
enabled: ${CONSUL_ENABLED:true}
# Circuit Breaker Configuration
resilience4j:
circuitbreaker:
instances:
ping-service-cb:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 10s
failureRateThreshold: 50
auth-service-cb:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 10s
failureRateThreshold: 50
# Actuator Management
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
# Logging Configuration
logging:
level:
at.mocode.infrastructure.gateway: DEBUG
org.springframework.security: DEBUG
org.springframework.cloud.gateway: DEBUG
pattern:
console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
---
# Development Profile
spring:
config:
activate:
on-profile: dev
keycloak:
server-url: http://localhost:8180
issuer-uri: http://localhost:8180/realms/meldestelle
jwk-set-uri: http://localhost:8180/realms/meldestelle/protocol/openid-connect/certs
logging:
level:
root: INFO
at.mocode: DEBUG
---
# Production Profile
spring:
config:
activate:
on-profile: prod
keycloak:
server-url: ${KEYCLOAK_SERVER_URL}
issuer-uri: ${KEYCLOAK_ISSUER_URI}
jwk-set-uri: ${KEYCLOAK_JWK_SET_URI}
client-secret: ${KEYCLOAK_CLIENT_SECRET}
logging:
level:
root: WARN
at.mocode: INFO
gateway:
security:
public-paths: >
/,
/health,
/api/auth/login,
/api/auth/register
@@ -36,23 +36,6 @@ spring:
pool: pool:
max-idle-time: 15s max-idle-time: 15s
max-life-time: 60s max-life-time: 60s
globalcors:
cors-configurations:
'[/**]':
allowedOriginPatterns:
- "https://*.meldestelle.at"
- "http://localhost:*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
- PATCH
- OPTIONS
allowedHeaders:
- "*"
allowCredentials: true
maxAge: 3600
default-filters: default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
- name: CircuitBreaker - name: CircuitBreaker
@@ -282,20 +265,3 @@ logging:
max-file-size: 100MB max-file-size: 100MB
total-size-cap: 1GB total-size-cap: 1GB
max-history: 30 max-history: 30
# Gateway Security Configuration - JWT Authentication with auth-client
gateway:
security:
jwt:
# Enable JWT authentication via auth-client
enabled: ${GATEWAY_JWT_ENABLED:true}
# JWT secret key for token validation (must match auth-server secret)
secret: ${JWT_SECRET:default-secret-for-development-only-please-change-in-production}
# JWT issuer (must match auth-server issuer)
issuer: ${JWT_ISSUER:meldestelle-auth-server}
# JWT audience (must match auth-server audience)
audience: ${JWT_AUDIENCE:meldestelle-services}
# JWT expiration in minutes
expiration: ${JWT_EXPIRATION:60}
+208 -27
View File
@@ -1,27 +1,208 @@
2025-10-05 21:49:40.525 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final 2025-10-10 09:04:14.977 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-05 21:49:40.564 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 783949 (/home/stefan-mo/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan-mo in /home/stefan-mo/WsMeldestelle/Meldestelle) 2025-10-10 09:04:15.011 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 5959 (/home/stefan/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan in /home/stefan/WsMeldestelle/Meldestelle)
2025-10-05 21:49:40.565 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10 2025-10-10 09:04:15.011 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-05 21:49:40.565 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev" 2025-10-10 09:04:15.011 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-05 21:49:41.913 [main] INFO [] o.s.cloud.context.scope.GenericScope - BeanFactory id=548af07a-4d4c-30b3-8388-eaf5c0d95d23 2025-10-10 09:04:16.127 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-05 21:49:44.188 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [After] 2025-10-10 09:04:16.128 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-05 21:49:44.188 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Before] 2025-10-10 09:04:16.144 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 8 ms. Found 0 JPA repository interfaces.
2025-10-05 21:49:44.188 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Between] 2025-10-10 09:04:16.153 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Cookie] 2025-10-10 09:04:16.154 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Header] 2025-10-10 09:04:16.162 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Redis repository interfaces.
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Host] 2025-10-10 09:04:16.172 [main] WARN [] o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'conversionServicePostProcessor' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Cannot register bean definition [Root bean: class=org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]] for bean 'conversionServicePostProcessor' since there is already [Root bean: class=org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class]] bound.
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Method] 2025-10-10 09:04:16.183 [main] INFO [] o.s.b.a.l.ConditionEvaluationReportLogger -
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Path]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Query] Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [ReadBody] 2025-10-10 09:04:16.196 [main] ERROR [] o.s.b.d.LoggingFailureAnalysisReporter -
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [RemoteAddr]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [XForwardedRemoteAddr] ***************************
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Weight] APPLICATION FAILED TO START
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [CloudFoundryRouteService] ***************************
2025-10-05 21:49:44.880 [main] INFO [] o.s.b.a.e.web.EndpointLinksResolver - Exposing 6 endpoints beneath base path '/actuator'
2025-10-05 21:49:45.585 [main] WARN [] o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger - Spring Cloud LoadBalancer is currently working with the default cache. While this cache implementation is useful for development and tests, it's recommended to use Caffeine cache in production.You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath. Description:
2025-10-05 21:49:45.714 [main] INFO [] o.s.b.w.e.netty.NettyWebServer - Netty started on port 8080 (http)
2025-10-05 21:49:45.716 [main] INFO [] o.s.c.c.s.ConsulServiceRegistry - Registering service with consul: NewService{id='meldestelle-8080-2567c504-f48c-4f6e-918e-23b80c37675e', name='meldestelle', tags=[], address='10.0.0.18', meta={secure=false}, port=8080, enableTagOverride=null, check=Check{script='null', dockerContainerID='null', shell='null', interval='10s', ttl='null', http='http://10.0.0.18:8080/actuator/health', method='null', header={}, tcp='null', timeout='null', deregisterCriticalServiceAfter='null', tlsSkipVerify=null, status='null', grpc='null', grpcUseTLS=null}, checks=null} The bean 'conversionServicePostProcessor', defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class] and overriding is disabled.
2025-10-05 21:49:45.865 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Started GatewayApplicationKt in 5.753 seconds (process running for 6.365)
2025-10-05 21:53:53.365 [SpringApplicationShutdownHook] INFO [] o.s.b.w.e.netty.GracefulShutdown - Commencing graceful shutdown. Waiting for active requests to complete Action:
2025-10-05 21:53:53.367 [netty-shutdown] INFO [] o.s.b.w.e.netty.GracefulShutdown - Graceful shutdown complete
2025-10-05 21:53:55.378 [SpringApplicationShutdownHook] INFO [] o.s.c.c.s.ConsulServiceRegistry - Deregistering service with consul: meldestelle-8080-2567c504-f48c-4f6e-918e-23b80c37675e Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2025-10-10 09:06:36.886 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-10 09:06:36.993 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 6261 (/home/stefan/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan in /home/stefan/WsMeldestelle/Meldestelle)
2025-10-10 09:06:36.993 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-10 09:06:36.994 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-10 09:06:38.221 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:06:38.223 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-10 09:06:38.289 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 58 ms. Found 0 JPA repository interfaces.
2025-10-10 09:06:38.299 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:06:38.300 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-10 09:06:38.356 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 48 ms. Found 0 Redis repository interfaces.
2025-10-10 09:06:38.370 [main] WARN [] o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'conversionServicePostProcessor' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Cannot register bean definition [Root bean: class=org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]] for bean 'conversionServicePostProcessor' since there is already [Root bean: class=org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class]] bound.
2025-10-10 09:06:38.383 [main] INFO [] o.s.b.a.l.ConditionEvaluationReportLogger -
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-10-10 09:06:38.400 [main] ERROR [] o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'conversionServicePostProcessor', defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2025-10-10 09:52:44.759 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-10 09:52:44.795 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 11271 (/home/stefan/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan in /home/stefan/WsMeldestelle/Meldestelle)
2025-10-10 09:52:44.797 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-10 09:52:44.798 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-10 09:52:45.840 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:52:45.841 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-10 09:52:45.856 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 8 ms. Found 0 JPA repository interfaces.
2025-10-10 09:52:45.864 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:52:45.865 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-10 09:52:45.872 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Redis repository interfaces.
2025-10-10 09:52:45.881 [main] WARN [] o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'conversionServicePostProcessor' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Cannot register bean definition [Root bean: class=org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]] for bean 'conversionServicePostProcessor' since there is already [Root bean: class=org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class]] bound.
2025-10-10 09:52:45.893 [main] INFO [] o.s.b.a.l.ConditionEvaluationReportLogger -
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-10-10 09:52:45.905 [main] ERROR [] o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'conversionServicePostProcessor', defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2025-10-10 09:53:33.524 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-10 09:53:33.553 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 11704 (/home/stefan/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan in /home/stefan/WsMeldestelle/Meldestelle)
2025-10-10 09:53:33.553 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-10 09:53:33.554 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-10 09:53:34.618 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:53:34.619 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-10 09:53:34.634 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 8 ms. Found 0 JPA repository interfaces.
2025-10-10 09:53:34.642 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:53:34.643 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-10 09:53:34.650 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Redis repository interfaces.
2025-10-10 09:53:34.659 [main] WARN [] o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'conversionServicePostProcessor' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Cannot register bean definition [Root bean: class=org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]] for bean 'conversionServicePostProcessor' since there is already [Root bean: class=org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class]] bound.
2025-10-10 09:53:34.670 [main] INFO [] o.s.b.a.l.ConditionEvaluationReportLogger -
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-10-10 09:53:34.682 [main] ERROR [] o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'conversionServicePostProcessor', defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2025-10-10 09:54:30.831 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-10 09:54:30.929 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 11934 (/home/stefan/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan in /home/stefan/WsMeldestelle/Meldestelle)
2025-10-10 09:54:30.930 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-10 09:54:30.930 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-10 09:54:32.127 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:54:32.128 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-10 09:54:32.187 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 52 ms. Found 0 JPA repository interfaces.
2025-10-10 09:54:32.198 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 09:54:32.199 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-10 09:54:32.247 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 40 ms. Found 0 Redis repository interfaces.
2025-10-10 09:54:32.261 [main] WARN [] o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'conversionServicePostProcessor' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Cannot register bean definition [Root bean: class=org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]] for bean 'conversionServicePostProcessor' since there is already [Root bean: class=org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=conversionServicePostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class]] bound.
2025-10-10 09:54:32.274 [main] INFO [] o.s.b.a.l.ConditionEvaluationReportLogger -
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-10-10 09:54:32.290 [main] ERROR [] o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'conversionServicePostProcessor', defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2025-10-10 10:37:24.357 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-10 10:37:24.386 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 19202 (/home/stefan/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan in /home/stefan/WsMeldestelle/Meldestelle)
2025-10-10 10:37:24.387 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-10 10:37:24.387 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-10 10:37:25.381 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 10:37:25.382 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-10 10:37:25.397 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 9 ms. Found 0 JPA repository interfaces.
2025-10-10 10:37:25.406 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 10:37:25.406 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-10 10:37:25.414 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Redis repository interfaces.
2025-10-10 10:37:25.626 [main] INFO [] o.s.cloud.context.scope.GenericScope - BeanFactory id=3aaa65ed-d935-335c-a017-0d94f6536018
2025-10-10 10:37:26.129 [main] WARN [] o.s.b.w.r.c.AnnotationConfigReactiveWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Failed to initialize dependency 'flyway' of LoadTimeWeaverAware bean 'entityManagerFactory': Error creating bean with name 'flyway' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Failed to instantiate [org.flywaydb.core.Flyway]: Factory method 'flyway' threw exception with message: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class
2025-10-10 10:37:26.142 [main] INFO [] o.s.b.a.l.ConditionEvaluationReportLogger -
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-10-10 10:37:26.155 [main] ERROR [] o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active).
2025-10-10 10:51:40.233 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-10 10:51:40.328 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 29930 (/home/stefan/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan in /home/stefan/WsMeldestelle/Meldestelle)
2025-10-10 10:51:40.328 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-10 10:51:40.329 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-10 10:51:41.798 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 10:51:41.800 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-10-10 10:51:41.859 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 52 ms. Found 0 JPA repository interfaces.
2025-10-10 10:51:41.869 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-10 10:51:41.870 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-10 10:51:41.915 [main] INFO [] o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 39 ms. Found 0 Redis repository interfaces.
2025-10-10 10:51:42.198 [main] INFO [] o.s.cloud.context.scope.GenericScope - BeanFactory id=3aaa65ed-d935-335c-a017-0d94f6536018
2025-10-10 10:51:42.855 [main] WARN [] o.s.b.w.r.c.AnnotationConfigReactiveWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Failed to initialize dependency 'flyway' of LoadTimeWeaverAware bean 'entityManagerFactory': Error creating bean with name 'flyway' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Failed to instantiate [org.flywaydb.core.Flyway]: Factory method 'flyway' threw exception with message: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class
2025-10-10 10:51:42.870 [main] INFO [] o.s.b.a.l.ConditionEvaluationReportLogger -
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-10-10 10:51:42.887 [main] ERROR [] o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active).