2 Commits

Author SHA1 Message Date
stefan 28cd5d8afa Handle missing JWK Set URI gracefully and extend CORS allowed origins list
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Successful in 8m33s
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Successful in 7m21s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Successful in 1m55s
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Successful in 1m47s
2026-03-17 00:51:15 +01:00
stefan bafb63dc16 Remove deprecated isAuthenticated logic from PingViewModel and related UI components 2026-03-17 00:18:02 +01:00
5 changed files with 13 additions and 21 deletions
@@ -64,16 +64,18 @@ class SecurityConfig(
if (delegate == null) {
synchronized(this) {
if (delegate == null) {
if (jwkSetUri.isBlank()) {
logger.error("JWK Set URI is missing all authenticated requests will be rejected.")
return Mono.error(org.springframework.security.oauth2.jwt.BadJwtException("Identity Provider not configured"))
}
try {
if (jwkSetUri.isBlank()) {
throw IllegalArgumentException("JWK Set URI is missing")
}
logger.info("Attempting to initialize JWT Decoder with URI: {}", jwkSetUri)
delegate = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build()
logger.info("JWT Decoder successfully initialized.")
} catch (e: Exception) {
logger.warn("Could not initialize JWT Decoder: {}", e.message)
return Mono.error(IllegalStateException("Identity Provider unavailable"))
// Throw BadJwtException so Spring Security returns 401, not 500 or passthrough
return Mono.error(org.springframework.security.oauth2.jwt.BadJwtException("Identity Provider unavailable: ${e.message}"))
}
}
}
@@ -133,7 +135,7 @@ data class GatewaySecurityProperties(
)
data class CorsProperties(
val allowedOriginPatterns: Set<String> = setOf("http://localhost:*", "https://*.meldestelle.at"),
val allowedOriginPatterns: Set<String> = setOf("http://localhost:*", "https://*.meldestelle.at", "https://*.mo-code.at"),
val allowedMethods: Set<String> = setOf("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"),
val allowedHeaders: Set<String> = setOf("*"),
val exposedHeaders: Set<String> = setOf("X-Correlation-ID"),
@@ -46,7 +46,7 @@ Setze folgende Variablen in Postman (Environment "Local Docker"):
* `client_id`: `postman-client`
* `client_secret`: `postman-secret-123`
* `username`: `admin`
* `password`: `Change_Me_In_Production!`
* `password`: `Admin#1234`
---
@@ -22,10 +22,8 @@ import at.mocode.frontend.core.designsystem.theme.Dimens
@Composable
fun PingScreen(
viewModel: PingViewModel,
onBack: () -> Unit = {},
isAuthenticated: Boolean = false
onBack: () -> Unit = {}
) {
viewModel.isAuthenticated = isAuthenticated
val uiState = viewModel.uiState
// Wir nutzen jetzt das globale Theme (Hintergrund kommt vom Theme)
@@ -53,7 +51,7 @@ fun PingScreen(
.fillMaxHeight()
.padding(end = Dimens.SpacingS)
) {
ActionToolbar(viewModel, isAuthenticated)
ActionToolbar(viewModel)
Spacer(Modifier.height(Dimens.SpacingS))
StatusGrid(uiState)
}
@@ -133,7 +131,7 @@ private fun StatusBadge(text: String, color: Color) {
}
@Composable
private fun ActionToolbar(viewModel: PingViewModel, isAuthenticated: Boolean) {
private fun ActionToolbar(viewModel: PingViewModel) {
// Wrap buttons to avoid overflow on small screens
Row(
modifier = Modifier.fillMaxWidth(),
@@ -141,7 +139,7 @@ private fun ActionToolbar(viewModel: PingViewModel, isAuthenticated: Boolean) {
) {
DenseButton(text = "Simple", onClick = { viewModel.performSimplePing() })
DenseButton(text = "Enhanced", onClick = { viewModel.performEnhancedPing() })
DenseButton(text = "Secure", onClick = { viewModel.performSecurePing() }, enabled = isAuthenticated)
DenseButton(text = "Secure", onClick = { viewModel.performSecurePing() })
DenseButton(text = "Health", onClick = { viewModel.performHealthCheck() })
DenseButton(
text = "Sync",
@@ -41,8 +41,6 @@ class PingViewModel(
var uiState by mutableStateOf(PingUiState())
private set
var isAuthenticated: Boolean = false
private fun addLog(source: String, message: String, isError: Boolean = false) {
val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())
val timeString = "${now.hour.toString().padStart(2, '0')}:${now.minute.toString().padStart(2, '0')}:${
@@ -110,10 +108,6 @@ class PingViewModel(
}
fun performSecurePing() {
if (!isAuthenticated) {
addLog("SecurePing", "Not authenticated request blocked.", isError = true)
return
}
viewModelScope.launch {
uiState = uiState.copy(isLoading = true, errorMessage = null)
addLog("SecurePing", "Sending authenticated request...")
@@ -36,7 +36,6 @@ fun MainApp() {
// Delta-Sync blueprint: resolve the Ping feature view model via Koin.
val pingViewModel: PingViewModel = koinViewModel()
val loginViewModel: LoginViewModel = koinViewModel()
val authState by authTokenManager.authState.collectAsState()
when (currentScreen) {
is AppScreen.Landing -> LandingScreen(
@@ -59,8 +58,7 @@ fun MainApp() {
is AppScreen.Ping -> PingScreen(
viewModel = pingViewModel,
onBack = { navigationPort.navigateToScreen(AppScreen.Home) },
isAuthenticated = authState.isAuthenticated
onBack = { navigationPort.navigateToScreen(AppScreen.Home) } // Navigate back to Home
)
is AppScreen.Profile -> AuthStatusScreen(