fixing Keycloak JwtService entfernt

This commit is contained in:
2025-10-13 13:03:48 +02:00
parent 7921cc4b32
commit 212923ae8f
21 changed files with 31 additions and 2555 deletions
@@ -25,8 +25,6 @@ dependencies {
implementation(platform(projects.platform.platformBom))
// Stellt gemeinsame Abhängigkeiten bereit.
implementation(projects.platform.platformDependencies)
// Nutzt die Client-Logik für die Kommunikation mit Keycloak.
implementation(projects.infrastructure.auth.authClient)
// Spring Boot Starter für einen Web-Service.
// OPTIMIERUNG: Verwendung des `spring-boot-essentials`-Bundles.
implementation(libs.bundles.spring.boot.essentials)
@@ -1,55 +1,12 @@
package at.mocode.infrastructure.auth.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 das Auth-Server-Modul.
* Stellt die notwendigen Beans und Einstellungen für JWT-Verarbeitung und Authentifizierung bereit.
*
* Note: JWT handling is now fully delegated to Keycloak via OAuth2 Resource Server.
* This auth-server focuses on user management through Keycloak Admin Client.
*/
@Configuration
@EnableConfigurationProperties(AuthServerConfiguration.JwtProperties::class)
class AuthServerConfiguration {
/**
* Erstellt einen JwtService-Bean mit Konfiguration aus den Application Properties.
*/
@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("[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.
*/
@ConfigurationProperties(prefix = "auth.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
)
}
class AuthServerConfiguration
@@ -1,13 +1,16 @@
package at.mocode.infrastructure.auth
import at.mocode.infrastructure.auth.client.JwtService
import at.mocode.infrastructure.auth.config.AuthServerConfiguration
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
/**
* Basic tests for the Auth Server application and configuration.
* These tests verify the application structure and basic functionality without requiring full Spring context.
* These tests verify the application structure without requiring full Spring context.
*
* Note: Custom JWT handling has been removed. Authentication is now fully handled
* by Keycloak via OAuth2 Resource Server.
*/
class AuthServerApplicationTest {
@@ -30,43 +33,14 @@ class AuthServerApplicationTest {
}
@Test
fun `auth server configuration should create JWT service bean`() {
// Arrange
val config = AuthServerConfiguration()
val jwtProperties = AuthServerConfiguration.JwtProperties(
secret = "test-secret-for-testing-only-at-least-512-bits-long-for-hmac512",
issuer = "test-issuer",
audience = "test-audience",
expiration = 60
)
// Act
val jwtService = config.jwtService(jwtProperties)
// Assert
assertNotNull(jwtService)
assertInstanceOf(JwtService::class.java, jwtService)
// Test that the service can generate and validate tokens
val token = jwtService.generateToken("test-user", "testuser", emptyList())
assertNotNull(token)
assertTrue(token.isNotEmpty())
val validationResult = jwtService.validateToken(token)
assertTrue(validationResult.isSuccess)
assertEquals(true, validationResult.getOrNull())
}
@Test
fun `JWT properties should have sensible defaults`() {
fun `auth server configuration should be present`() {
// Arrange & Act
val defaultProperties = AuthServerConfiguration.JwtProperties()
val config = AuthServerConfiguration()
// Assert
assertNotNull(defaultProperties.secret)
assertTrue(defaultProperties.secret.isNotEmpty())
assertEquals("meldestelle-auth-server", defaultProperties.issuer)
assertEquals("meldestelle-services", defaultProperties.audience)
assertEquals(60L, defaultProperties.expiration)
assertNotNull(config)
assertTrue(config::class.java.isAnnotationPresent(org.springframework.context.annotation.Configuration::class.java)) {
"AuthServerConfiguration should be annotated with @Configuration"
}
}
}
@@ -1,10 +1,8 @@
package at.mocode.infrastructure.auth
import at.mocode.infrastructure.auth.client.JwtService
import at.mocode.infrastructure.auth.client.model.BerechtigungE
import at.mocode.infrastructure.auth.config.AuthServerConfiguration
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
@@ -13,21 +11,16 @@ import org.springframework.test.context.TestPropertySource
/**
* Minimal integration tests for the Auth Server.
* Tests essential functionality without full Spring Boot context complexity.
* Focuses on core service integration and configuration validation.
*
* This implements "Option 1: Minimale Integration Tests" focusing on essentials
* without vollständige Spring Boot Konfiguration.
* Note: Custom JWT handling has been removed. Authentication is now fully handled
* by Keycloak via OAuth2 Resource Server. This test verifies the basic Spring
* context loads correctly.
*/
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.NONE,
classes = [AuthServerConfiguration::class]
)
@TestPropertySource(properties = [
"auth.jwt.secret=test-secret-for-testing-only-at-least-512-bits-long-for-hmac512-algorithm",
"auth.jwt.issuer=test-issuer",
"auth.jwt.audience=test-audience",
"auth.jwt.expiration=60",
"spring.main.web-application-type=none",
"logging.level.org.springframework.security=WARN"
])
@@ -36,22 +29,6 @@ class AuthServerIntegrationTest {
@Autowired
private lateinit var applicationContext: ApplicationContext
@Autowired
private lateinit var jwtService: JwtService
private lateinit var testToken: String
@BeforeEach
fun setUp() {
testToken = jwtService.generateToken(
userId = "test-user-123",
username = "testuser",
permissions = listOf(BerechtigungE.PERSON_READ, BerechtigungE.VEREIN_READ)
)
}
// ========== Core Service Integration Tests ==========
@Test
fun `application context should load with minimal configuration`() {
// Verify that the Spring context loads successfully
@@ -63,138 +40,17 @@ class AuthServerIntegrationTest {
}
@Test
fun `JwtService should be properly configured as Spring bean`() {
// Verify that JwtService is available as a Spring bean
assertTrue(applicationContext.containsBean("jwtService"))
assertNotNull(jwtService)
assertInstanceOf(JwtService::class.java, jwtService)
println("[DEBUG_LOG] JwtService bean configured successfully")
}
@Test
fun `JWT service should generate valid tokens`() {
// Test token generation functionality
val token = jwtService.generateToken(
userId = "integration-test-user",
username = "inttest",
permissions = listOf(BerechtigungE.PERSON_CREATE, BerechtigungE.PFERD_READ)
)
assertNotNull(token)
assertTrue(token.isNotEmpty())
// Verify token can be validated
val validationResult = jwtService.validateToken(token)
assertTrue(validationResult.isSuccess)
assertEquals(true, validationResult.getOrNull())
println("[DEBUG_LOG] Token generated and validated successfully")
}
@Test
fun `JWT service should extract user information correctly`() {
// Test user ID extraction
val userIdResult = jwtService.getUserIdFromToken(testToken)
assertTrue(userIdResult.isSuccess)
assertEquals("test-user-123", userIdResult.getOrNull())
// Test permissions extraction
val permissionsResult = jwtService.getPermissionsFromToken(testToken)
assertTrue(permissionsResult.isSuccess)
val permissions = permissionsResult.getOrNull()!!
assertEquals(2, permissions.size)
assertTrue(permissions.contains(BerechtigungE.PERSON_READ))
assertTrue(permissions.contains(BerechtigungE.VEREIN_READ))
println("[DEBUG_LOG] User information extracted correctly")
println("[DEBUG_LOG] User ID: ${userIdResult.getOrNull()}")
println("[DEBUG_LOG] Permissions: $permissions")
}
@Test
fun `JWT service should handle invalid tokens properly`() {
val invalidToken = "invalid.jwt.token"
// Validation should fail
val validationResult = jwtService.validateToken(invalidToken)
assertTrue(validationResult.isFailure)
// User ID extraction should fail
val userIdResult = jwtService.getUserIdFromToken(invalidToken)
assertTrue(userIdResult.isFailure)
// Permissions extraction should fail
val permissionsResult = jwtService.getPermissionsFromToken(invalidToken)
assertTrue(permissionsResult.isFailure)
println("[DEBUG_LOG] Invalid token handling works correctly")
}
// ========== Configuration Validation Tests ==========
@Test
fun `configuration properties should be properly loaded`() {
// Test that JWT configuration is loaded correctly
val jwtProperties = applicationContext.getBean(AuthServerConfiguration.JwtProperties::class.java)
assertNotNull(jwtProperties)
assertEquals("test-issuer", jwtProperties.issuer)
assertEquals("test-audience", jwtProperties.audience)
assertEquals(60L, jwtProperties.expiration)
println("[DEBUG_LOG] Configuration properties loaded correctly")
println("[DEBUG_LOG] Issuer: ${jwtProperties.issuer}")
println("[DEBUG_LOG] Audience: ${jwtProperties.audience}")
println("[DEBUG_LOG] Expiration: ${jwtProperties.expiration}")
}
@Test
fun `essential beans should be properly configured`() {
// Verify that essential beans for auth functionality are available
fun `configuration bean should be present`() {
// Verify that essential beans are available
val beanNames = applicationContext.beanDefinitionNames.toList()
// Check for JWT service bean
assertTrue(applicationContext.containsBean("jwtService")) {
"JwtService bean should be configured"
}
// Check for configuration bean
assertTrue(beanNames.any { it.contains("authServerConfiguration") }) {
"AuthServerConfiguration bean should be configured"
}
println("[DEBUG_LOG] Essential beans configured successfully")
println("[DEBUG_LOG] Auth-related beans: ${beanNames.filter { it.contains("jwt") || it.contains("auth") }}")
}
@Test
fun `JWT configuration integration should work end-to-end`() {
// Test the complete flow from configuration to token operations
val userId = "end-to-end-test"
val username = "e2etest"
val permissions = listOf(BerechtigungE.PERSON_READ, BerechtigungE.PERSON_CREATE)
// Generate token
val token = jwtService.generateToken(userId, username, permissions)
assertNotNull(token)
assertTrue(token.isNotEmpty())
// Validate token
val isValid = jwtService.validateToken(token)
assertTrue(isValid.isSuccess)
// Extract and verify data
val extractedUserId = jwtService.getUserIdFromToken(token).getOrNull()
val extractedPermissions = jwtService.getPermissionsFromToken(token).getOrElse { emptyList() }
assertEquals(userId, extractedUserId)
assertEquals(2, extractedPermissions.size)
assertTrue(extractedPermissions.containsAll(permissions))
println("[DEBUG_LOG] End-to-end test completed successfully")
println("[DEBUG_LOG] Token validation: ${isValid.isSuccess}")
println("[DEBUG_LOG] Extracted user: $extractedUserId")
println("[DEBUG_LOG] Extracted permissions: $extractedPermissions")
println("[DEBUG_LOG] Auth-related beans: ${beanNames.filter { it.contains("auth") }}")
}
@Test
@@ -217,48 +73,4 @@ class AuthServerIntegrationTest {
println("[DEBUG_LOG] Total bean count: $beanCount")
println("[DEBUG_LOG] Web-related beans: $webBeans")
}
// ========== Service Functionality Tests ==========
@Test
fun `JWT service should handle different permission combinations`() {
// Test various permission combinations
val testCases = listOf(
emptyList(),
listOf(BerechtigungE.PERSON_READ),
listOf(BerechtigungE.PERSON_READ, BerechtigungE.PERSON_CREATE),
BerechtigungE.entries
)
testCases.forEach { permissions ->
val token = jwtService.generateToken("test-user", "test", permissions)
val validationResult = jwtService.validateToken(token)
val extractedPermissions = jwtService.getPermissionsFromToken(token).getOrElse { emptyList() }
assertTrue(validationResult.isSuccess)
assertEquals(permissions.size, extractedPermissions.size)
assertTrue(extractedPermissions.containsAll(permissions))
}
println("[DEBUG_LOG] Different permission combinations handled correctly")
}
@Test
fun `JWT service should be thread-safe for concurrent access`() {
// Test concurrent token operations
val threads = (1..5).map { threadIndex ->
Thread {
repeat(10) { iteration ->
val token = jwtService.generateToken("user-$threadIndex-$iteration", "test", listOf(BerechtigungE.PERSON_READ))
val isValid = jwtService.validateToken(token).isSuccess
assertTrue(isValid)
}
}
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println("[DEBUG_LOG] Concurrent access test completed successfully")
}
}
@@ -1,29 +1,13 @@
package at.mocode.infrastructure.auth.config
import at.mocode.infrastructure.auth.client.JwtService
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Primary
import kotlin.time.Duration.Companion.minutes
/**
* Test configuration for Auth Server integration tests.
* Provides minimal bean configuration needed for tests to run.
*
* Note: Custom JWT handling has been removed. Authentication is now fully handled
* by Keycloak via OAuth2 Resource Server. This configuration class is kept as a
* placeholder for future test-specific beans if needed.
*/
@TestConfiguration
class AuthServerTestConfiguration {
/**
* Provides a JwtService bean for testing with test-specific configuration.
*/
@Bean
@Primary
fun testJwtService(): JwtService {
return JwtService(
secret = "test-secret-for-testing-only-at-least-512-bits-long-for-hmac512-algorithm",
issuer = "test-issuer",
audience = "test-audience",
expiration = 60.minutes
)
}
}
class AuthServerTestConfiguration