Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ POSTGRES_DB=${DATASOURCE_DB}
# Then just point the `OAUTH2_RESOURCE_SERVER_JWT_ISSUER_URI` value to the correct OIDC realm/issuer
# The keycloak admin user name that the server will be bootstrapped with. Change this value!
KC_BOOTSTRAP_ADMIN_USERNAME=admin

# The keycloak admin password that the server will be bootstrapped with. Change this value!
KC_BOOTSTRAP_ADMIN_PASSWORD=admin
# Whether to enable healt checks. Do not change normally!

# Whether to enable health checks. Do not change normally!
KC_HEALTH_ENABLED=true
# The JAVA memeory related options for the Keycloak docker image

# The JAVA memory related options for the Keycloak docker image
JAVA_OPTS=-XX:MaxRAMPercentage=75.0 -XX:InitialRAMPercentage=50.0 -XX:+UseG1GC

# The OIDC/OAUTH2 Isser. This is your OIDC issuer, provuding the trust/authentication. Defaults to the local KC instance deployed as docker container.
# The OIDC/OAUTH2 Issuer. This is your OIDC issuer, providing the trust/authentication. Defaults to the local KC instance deployed as docker container.
# Change to your OIDC environment if you have one, and then disable the keycloak deployment altogether
OAUTH2_RESOURCE_SERVER_JWT_ISSUER_URI=http://keycloak:8080/realms/openid-federation

Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ jobs:
POSTGRES_DB: "openid-federation-db"
NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
AWS_REGION: ${{ secrets.AWS_REGION }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
KMS_PROVIDER: memory
run: |
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fun getNpmVersion(): String {

allprojects {
group = "com.sphereon.oid.fed"
version = "0.22.0-SNAPSHOT"
version = "0.22.2-SNAPSHOT"
val npmVersion by extra { getNpmVersion() }

configurations {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ nimbusJoseJwt = "9.40"
node-gradle = "7.1.0"
npmPublish = "3.5.3"
openapi = "7.12.0"
sphereonKmp = "0.2.20-SNAPSHOT"
sphereonKmp = "0.2.24-SNAPSHOT"
springboot = "3.4.4"
springsecurity = "6.4.4"
springdoc = "2.8.5"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package com.sphereon.oid.fed.services


import com.sphereon.crypto.jose.JwaAlgorithm
import com.sphereon.crypto.kms.aws.AwsKmsCryptoProvider
import com.sphereon.crypto.kms.azure.AzureKeyVaultCryptoProvider
import com.sphereon.crypto.kms.ecdsa.EcDSACryptoProvider
import com.sphereon.oid.fed.client.crypto.cryptoService
import com.sphereon.oid.fed.openapi.models.JwtHeader
import com.sphereon.oid.fed.services.mappers.jsonSerialization
import com.sphereon.oid.fed.services.mappers.toJsonString
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertIs
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

class KmsServiceTest {

Expand Down Expand Up @@ -75,4 +83,77 @@ class KmsServiceTest {
KmsType.fromString("")
}
}


@Test
fun `create key with AWS KMS, sign JWT, map to Jwk model and verify signature`() = runTest {
// Create KmsService with AWS provider
val kmsService = KmsService.createAwsKms(
applicationId = "test-app-id",
region = System.getenv("AWS_REGION"),
accessKeyId = System.getenv("AWS_ACCESS_KEY_ID"),
secretAccessKey = System.getenv("AWS_SECRET_ACCESS_KEY")
)

// Get the KMS provider
val provider = kmsService.getKmsProvider()
assertIs<AwsKmsCryptoProvider>(provider)

// 1. Try to get an existing key or generate a new one
var generatedKey = provider.generateKeyAsync()

assertNotNull(generatedKey)
assertNotNull(generatedKey.kid)
assertNotNull(generatedKey.kmsKeyRef)

// 2. Create a JWT header and payload
val kid = requireNotNull(generatedKey.kid) { "Generated key must have a kid" }
val header = JwtHeader(
alg = JwaAlgorithm.ES256.value,
kid = kid,
typ = "JWT"
)

val payload = JsonObject(
mapOf(
"iss" to JsonPrimitive("test-issuer"),
"sub" to JsonPrimitive("test-subject"),
"iat" to JsonPrimitive((System.currentTimeMillis() / 1000).toInt()),
"exp" to JsonPrimitive((System.currentTimeMillis() / 1000 + 3600).toInt()),
"test-claim" to JsonPrimitive("test-value")
)
)

// 3. Sign the JWT using the JwtService
val jwtService = JwtService(provider)
val kmsKeyRef = requireNotNull(generatedKey.kmsKeyRef) { "Generated key must have a kmsKeyRef" }
val jwt = jwtService.sign(payload, header, kid, kmsKeyRef)

// Verify the JWT format
assertNotNull(jwt)
val jwtParts = jwt.split(".")
assertEquals(3, jwtParts.size, "JWT should have three parts separated by dots")

// Verify the JWT signature using the CryptoService
val cryptoSvc = cryptoService()
val jwkJson = generatedKey.jose.publicJwk.toJsonString()
val jwk: com.sphereon.oid.fed.openapi.models.Jwk = jsonSerialization.decodeFromString(jwkJson)
val isValid = cryptoSvc.verify(jwt, jwk)
if (!isValid) {
// Let's print the JWK and JWT for easy debugging in case it is not valid
println("JWK:\n${jwk.toJsonString()}\n\n")
println("JWT: $jwt")
}

assertTrue(isValid, "JWT signature should be valid")

// Verify the Jwk model properties
assertNotNull(jwk)
assertEquals(generatedKey.kid, jwk.kid)
assertEquals(JwaAlgorithm.ES256.value, jwk.alg)
assertEquals("EC", jwk.kty)
assertEquals("P-256", jwk.crv)
assertNotNull(jwk.x)
assertNotNull(jwk.y)
}
}