Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jcmelati committed Feb 18, 2025
1 parent 0a139cd commit f2bb3df
Show file tree
Hide file tree
Showing 26 changed files with 105 additions and 91 deletions.
2 changes: 1 addition & 1 deletion .docker/admin-server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ RUN microdnf install curl
WORKDIR /app

COPY --from=builder /app/modules/admin-server/build/libs/admin-server-*.jar ./admin-server.jar
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8080/status || exit 1
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8081/status || exit 1

# Create non-root user
RUN useradd -r -u 1002 -g root admin-server
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ fun getNpmVersion(): String {

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

// Common repository configuration for all projects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.sphereon.oid.fed.server.admin.controllers
import com.sphereon.oid.fed.common.Constants
import com.sphereon.oid.fed.openapi.models.Account
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.EntityJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import com.sphereon.oid.fed.services.JwkService
import jakarta.servlet.http.HttpServletRequest
Expand All @@ -16,13 +17,13 @@ class KeyController(
) {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(request: HttpServletRequest): Jwk {
fun create(request: HttpServletRequest): EntityJwk {
val account = request.getAttribute(Constants.ACCOUNT_ATTRIBUTE) as Account
return jwkService.createKey(account)
}

@GetMapping
fun getKeys(request: HttpServletRequest): Array<BaseJwk> {
fun getKeys(request: HttpServletRequest): Array<EntityJwk> {
val account = request.getAttribute(Constants.ACCOUNT_ATTRIBUTE) as Account
return jwkService.getKeys(account)
}
Expand All @@ -32,7 +33,7 @@ class KeyController(
request: HttpServletRequest,
@PathVariable keyId: Int,
@RequestParam reason: String?
): Jwk {
): EntityJwk {
val account = request.getAttribute(Constants.ACCOUNT_ATTRIBUTE) as Account
return jwkService.revokeKey(account, keyId, reason)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.sphereon.oid.fed.kms.local

import com.sphereon.oid.fed.kms.local.database.LocalKmsDatabase
import com.sphereon.oid.fed.kms.local.encryption.AesEncryption
import com.sphereon.oid.fed.kms.local.extensions.toJwk
import com.sphereon.oid.fed.kms.local.jwk.generateKeyPair
import com.sphereon.oid.fed.kms.local.jwt.sign
import com.sphereon.oid.fed.kms.local.jwt.verify
Expand All @@ -17,15 +16,15 @@ class LocalKms {
private val database: LocalKmsDatabase = LocalKmsDatabase()
private val aesEncryption: AesEncryption = AesEncryption()

fun generateKey(): Jwk {
fun generateKey(): JwkWithPrivateKey {
val jwk = generateKeyPair()

database.insertKey(
keyId = jwk.kid!!,
key = aesEncryption.encrypt(Json.encodeToString(JwkWithPrivateKey.serializer(), jwk))
)

return jwk.toJwk()
return jwk
}

fun sign(header: JwtHeader, payload: JsonObject, keyId: String): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/BaseJwk'
$ref: '#/components/schemas/Jwk'
responses:
'201':
description: Subordinate JWK created successfully
Expand Down Expand Up @@ -1645,7 +1645,7 @@ components:
- accountId
- admin

BaseJwk:
Jwk:
type: object
x-tags:
- federation
Expand Down Expand Up @@ -1752,7 +1752,7 @@ components:
keys:
type: array
items:
$ref: '#/components/schemas/BaseJwk'
$ref: '#/components/schemas/Jwk'
metadata:
additionalProperties: true
crit:
Expand Down Expand Up @@ -1996,7 +1996,7 @@ components:

HistoricalKey:
allOf:
- $ref: '#/components/schemas/BaseJwk'
- $ref: '#/components/schemas/Jwk'
- type: object
x-tags:
- federation
Expand All @@ -2014,9 +2014,9 @@ components:
revoked:
$ref: '#/components/schemas/JwkRevoked'

Jwk:
EntityJwk:
allOf:
- $ref: '#/components/schemas/BaseJwk'
- $ref: '#/components/schemas/Jwk'
- type: object
x-tags:
- federation
Expand Down Expand Up @@ -2067,7 +2067,7 @@ components:

JwkWithPrivateKey:
allOf:
- $ref: '#/components/schemas/BaseJwk'
- $ref: '#/components/schemas/Jwk'
- type: object
properties:
d:
Expand Down Expand Up @@ -2496,7 +2496,7 @@ components:
jwks:
type: array
items:
$ref: '#/components/schemas/BaseJwk'
$ref: '#/components/schemas/Jwk'
additionalProperties:
type: string

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.sphereon.oid.fed.client.helpers

import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import kotlinx.datetime.Clock
import kotlinx.serialization.json.Json

Expand All @@ -12,13 +12,13 @@ fun getSubordinateStatementEndpoint(fetchEndpoint: String, sub: String): String
return "${fetchEndpoint}?sub=$sub"
}

fun findKeyInJwks(keys: Array<BaseJwk>, kid: String, json: Json): BaseJwk? {
fun findKeyInJwks(keys: Array<Jwk>, kid: String, json: Json): Jwk? {
val key = keys.firstOrNull { it.kid?.trim() == kid.trim() }

return key
}

fun checkKidInJwks(keys: Array<BaseJwk>, kid: String): Boolean {
fun checkKidInJwks(keys: Array<Jwk>, kid: String): Boolean {
for (key in keys) {
if (key.kid == kid) {
return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package com.sphereon.oid.fed.client.services.jwtService
import com.sphereon.oid.fed.client.context.FederationContext
import com.sphereon.oid.fed.client.mapper.decodeJWTComponents
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import kotlinx.serialization.builtins.ArraySerializer
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject

class JwtService(private val context: FederationContext) {
suspend fun fetchAndVerifyJwt(endpoint: String, verifyWithKey: BaseJwk? = null): String {
suspend fun fetchAndVerifyJwt(endpoint: String, verifyWithKey: Jwk? = null): String {
context.logger.debug("Fetching JWT from endpoint: $endpoint")
val jwt = context.httpResolver.get(endpoint)

Expand All @@ -21,7 +22,7 @@ class JwtService(private val context: FederationContext) {
return jwt
}

suspend fun verifyJwt(jwt: String, key: BaseJwk) {
suspend fun verifyJwt(jwt: String, key: Jwk) {
context.logger.debug("Verifying JWT signature with key: ${key.kid}")
if (!context.cryptoService.verify(jwt, key)) {
throw IllegalStateException("JWT signature verification failed")
Expand All @@ -34,7 +35,7 @@ class JwtService(private val context: FederationContext) {
context.logger.debug("Verifying self-signed JWT with kid: ${decodedJwt.header.kid}")

val jwks = decodedJwt.payload["jwks"]?.jsonObject?.get("keys")?.jsonArray?.let { array ->
context.json.decodeFromJsonElement(ArraySerializer(BaseJwk.serializer()), array)
context.json.decodeFromJsonElement(ArraySerializer(Jwk.serializer()), array)
} ?: throw IllegalStateException("No JWKS found in JWT payload")

val key = jwks.find { it.kid == decodedJwt.header.kid }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import com.sphereon.oid.fed.client.mapper.mapEntityStatement
import com.sphereon.oid.fed.client.services.entityConfigurationStatementService.EntityConfigurationStatementService
import com.sphereon.oid.fed.client.types.TrustChainResolveResponse
import com.sphereon.oid.fed.client.types.VerifyTrustChainResponse
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.EntityConfigurationStatement
import com.sphereon.oid.fed.openapi.models.Jwt
import com.sphereon.oid.fed.openapi.models.SubordinateStatement
import com.sphereon.oid.fed.openapi.models.*
import kotlinx.serialization.builtins.ArraySerializer
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray
Expand Down Expand Up @@ -252,9 +249,6 @@ class TrustChainService(
} ?: run {
logger.debug("No JWKS found in entity configuration payload")
return null
} ?: run {
logger.debug("Could not find key with kid: ${decodedEntityConfiguration.header.kid} in JWKS")
return null
}

context.jwtService.verifyJwt(entityConfigurationJwt, key)
Expand Down Expand Up @@ -505,8 +499,8 @@ class TrustChainService(
return context.cryptoService.verify(jwt, key)
}

private fun decodeJwksArray(jsonArray: kotlinx.serialization.json.JsonArray): Array<BaseJwk> {
return context.json.decodeFromJsonElement(ArraySerializer(BaseJwk.serializer()), jsonArray)
private fun decodeJwksArray(jsonArray: kotlinx.serialization.json.JsonArray): Array<Jwk> {
return context.json.decodeFromJsonElement(ArraySerializer(Jwk.serializer()), jsonArray)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.sphereon.oid.fed.client.types

import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import kotlin.js.JsExport

@JsExport.Ignore
interface ICryptoService {
suspend fun verify(
jwt: String,
key: BaseJwk
key: Jwk
): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.sphereon.oid.fed.client.mapper.InvalidJwtException
import com.sphereon.oid.fed.client.mockResponses.mockResponses
import com.sphereon.oid.fed.client.types.ICryptoService
import com.sphereon.oid.fed.logger.Logger
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import io.ktor.client.plugins.*
Expand All @@ -16,7 +16,7 @@ import kotlin.test.*
import kotlin.time.Duration.Companion.seconds

object TestCryptoService : ICryptoService {
override suspend fun verify(jwt: String, key: BaseJwk): Boolean {
override suspend fun verify(jwt: String, key: Jwk): Boolean {
return true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.sphereon.oid.fed.client.FederationClient
import com.sphereon.oid.fed.client.mockResponses.mockResponses
import com.sphereon.oid.fed.client.types.ICryptoService
import com.sphereon.oid.fed.logger.Logger
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import io.ktor.client.plugins.*
Expand All @@ -16,7 +16,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertFalse

object CryptoService : ICryptoService {
override suspend fun verify(jwt: String, key: BaseJwk): Boolean {
override suspend fun verify(jwt: String, key: Jwk): Boolean {
return true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.sphereon.oid.fed.client.types.TrustMarkValidationResponse
import com.sphereon.oid.fed.client.types.VerifyTrustChainResponse
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.EntityConfigurationStatement
import com.sphereon.oid.fed.openapi.models.Jwk
import io.ktor.client.*
import io.ktor.client.engine.js.*
import io.ktor.client.plugins.*
Expand All @@ -25,7 +26,7 @@ import kotlin.js.Promise
external interface ICryptoServiceJS {
fun verify(
jwt: String,
key: BaseJwk
key: Jwk
): Promise<Boolean>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.sphereon.oid.fed.client.crypto
import ICryptoServiceJS
import com.sphereon.oid.fed.client.mapper.decodeJWTComponents
import com.sphereon.oid.fed.client.types.ICryptoService
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import kotlinx.coroutines.await
import kotlinx.serialization.encodeToString
Expand All @@ -18,13 +17,13 @@ external object Jose {
}

class CryptoServiceAdapter(private val jsCryptoService: ICryptoServiceJS) : ICryptoService {
override suspend fun verify(jwt: String, key: BaseJwk): Boolean {
override suspend fun verify(jwt: String, key: Jwk): Boolean {
return jsCryptoService.verify(jwt, key).await()
}
}

object CryptoServiceJS : ICryptoServiceJS {
override fun verify(jwt: String, key: BaseJwk): Promise<Boolean> {
override fun verify(jwt: String, key: Jwk): Promise<Boolean> {
return Promise { resolve, reject ->
try {
val decodedJwt = decodeJWTComponents(jwt)
Expand All @@ -51,7 +50,7 @@ object CryptoServiceJS : ICryptoServiceJS {
@JsExport.Ignore
actual fun cryptoService(): ICryptoService {
return object : ICryptoService {
override suspend fun verify(jwt: String, key: BaseJwk): Boolean {
override suspend fun verify(jwt: String, key: Jwk): Boolean {
return CryptoServiceJS.verify(jwt, key).await()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import com.nimbusds.jose.jwk.JWK
import com.nimbusds.jose.jwk.KeyType
import com.nimbusds.jwt.SignedJWT
import com.sphereon.oid.fed.client.types.ICryptoService
import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.Jwk
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.text.ParseException

actual fun cryptoService(): ICryptoService {
return object : ICryptoService {
override suspend fun verify(jwt: String, key: BaseJwk): Boolean {
override suspend fun verify(jwt: String, key: Jwk): Boolean {
return try {
val signedJWT = SignedJWT.parse(jwt)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package com.sphereon.oid.fed.common.builder

import com.sphereon.oid.fed.openapi.models.BaseJwk
import com.sphereon.oid.fed.openapi.models.BaseStatementJwks
import com.sphereon.oid.fed.openapi.models.EntityConfigurationStatement
import com.sphereon.oid.fed.openapi.models.TrustMark
import com.sphereon.oid.fed.openapi.models.*
import kotlinx.serialization.json.JsonObject

class EntityConfigurationStatementObjectBuilder {
private var iss: String? = null
private var exp: Int? = null
private var iat: Int? = null
private lateinit var jwks: List<BaseJwk>
private lateinit var jwks: List<Jwk>
private var metadata: MutableMap<String, JsonObject> = mutableMapOf()
private val authorityHints: MutableList<String> = mutableListOf()
private val trustMarkIssuers: MutableMap<String, List<String>> = mutableMapOf()
Expand All @@ -20,7 +17,7 @@ class EntityConfigurationStatementObjectBuilder {
fun iss(iss: String) = apply { this.iss = iss }
fun exp(exp: Int) = apply { this.exp = exp }
fun iat(iat: Int) = apply { this.iat = iat }
fun jwks(jwks: List<BaseJwk>) = apply { this.jwks = jwks }
fun jwks(jwks: List<Jwk>) = apply { this.jwks = jwks }


fun metadata(metadata: Pair<String, JsonObject>) = apply {
Expand All @@ -43,7 +40,7 @@ class EntityConfigurationStatementObjectBuilder {
this.trustMarks.add(trustMark)
}

private fun createJwks(jwks: List<BaseJwk>): BaseStatementJwks {
private fun createJwks(jwks: List<Jwk>): BaseStatementJwks {
return BaseStatementJwks(jwks.toTypedArray())
}

Expand All @@ -59,7 +56,6 @@ class EntityConfigurationStatementObjectBuilder {
crit = if (crit.isNotEmpty()) crit.toTypedArray() else null,
trustMarkIssuers = this.trustMarkIssuers.map { (k, v) -> k to v.toTypedArray() }.toMap(),
trustMarks = trustMarks.toTypedArray()

)
}
}
Loading

0 comments on commit f2bb3df

Please sign in to comment.