From d135c12fc2374a8e52d5fb4c4866279d8c1763ee Mon Sep 17 00:00:00 2001 From: Michael Avoyan Date: Tue, 6 Feb 2024 13:30:33 +0200 Subject: [PATCH 1/2] support both vnf protocols using didJwk --- VCL/build.gradle | 4 +-- .../java/io/velocitycareerlabs/api/VCL.kt | 7 ++--- .../api/entities/VCLJwtDescriptor.kt | 4 --- .../api/jwt/VCLJwtSignService.kt | 4 ++- .../io/velocitycareerlabs/impl/VCLImpl.kt | 8 +++--- .../repositories/JwtServiceRepositoryImpl.kt | 4 +-- .../usecases/FinalizeOffersUseCaseImpl.kt | 7 +++-- .../data/usecases/JwtServiceUseCaseImpl.kt | 4 +-- .../data/usecases/SubmissionUseCaseImpl.kt | 9 +++---- .../repositories/JwtServiceRepository.kt | 2 +- .../domain/usecases/FinalizeOffersUseCase.kt | 2 +- .../impl/domain/usecases/JwtServiceUseCase.kt | 2 +- .../impl/domain/usecases/SubmissionUseCase.kt | 2 +- .../jwt/local/VCLJwtSignServiceLocalImpl.kt | 9 ++++--- .../jwt/remote/VCLJwtSignServiceRemoteImpl.kt | 17 +++++++----- .../VCLFinalizeOffersDescriptorTest.kt | 13 +++++++++ .../jwt/local/JwtSignServiceLocalTest.kt | 22 ++++++++------- .../jwt/local/JwtVerifyServiceLocalTest.kt | 3 +-- .../jwt/remote/VCLJwtSignServiceTest.kt | 27 ++++++++++++++++--- .../resources/valid/VCLJwtSignServiceMock.kt | 3 ++- .../usecases/JwtServiceUseCaseTest.kt | 17 +++++++++--- .../main/java/com/vcl/wallet/MainActivity.kt | 11 +++++--- 22 files changed, 117 insertions(+), 64 deletions(-) diff --git a/VCL/build.gradle b/VCL/build.gradle index 893884c5..30951850 100644 --- a/VCL/build.gradle +++ b/VCL/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 24 targetSdk 33 - versionName "1.23.4" - versionCode 124 + versionName "2.0.0" + versionCode 125 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" } diff --git a/VCL/src/main/java/io/velocitycareerlabs/api/VCL.kt b/VCL/src/main/java/io/velocitycareerlabs/api/VCL.kt index 7a468b7d..6fe2d1df 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/api/VCL.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/api/VCL.kt @@ -33,7 +33,7 @@ interface VCL { fun submitPresentation( presentationSubmission: VCLPresentationSubmission, - didJwk: VCLDidJwk? = null, + didJwk: VCLDidJwk, remoteCryptoServicesToken: VCLToken? = null, successHandler: (VCLSubmissionResult) -> Unit, errorHandler: (VCLError) -> Unit @@ -60,7 +60,7 @@ interface VCL { fun generateOffers( generateOffersDescriptor: VCLGenerateOffersDescriptor, - didJwk: VCLDidJwk? = null, + didJwk: VCLDidJwk, remoteCryptoServicesToken: VCLToken? = null, successHandler: (VCLOffers) -> Unit, errorHandler: (VCLError) -> Unit @@ -75,7 +75,7 @@ interface VCL { fun finalizeOffers( finalizeOffersDescriptor: VCLFinalizeOffersDescriptor, - didJwk: VCLDidJwk? = null, + didJwk: VCLDidJwk, sessionToken: VCLToken, remoteCryptoServicesToken: VCLToken? = null, successHandler: (VCLJwtVerifiableCredentials) -> Unit, @@ -103,6 +103,7 @@ interface VCL { ) fun generateSignedJwt( + didJwk: VCLDidJwk, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken? = null, successHandler: (VCLJwt) -> Unit, diff --git a/VCL/src/main/java/io/velocitycareerlabs/api/entities/VCLJwtDescriptor.kt b/VCL/src/main/java/io/velocitycareerlabs/api/entities/VCLJwtDescriptor.kt index f6a4cd28..d62d87bd 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/api/entities/VCLJwtDescriptor.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/api/entities/VCLJwtDescriptor.kt @@ -11,10 +11,6 @@ import org.json.JSONObject import java.util.UUID data class VCLJwtDescriptor( - /** - * The Id of the existing private key to sign with - */ - val keyId: String? = null, /** * Json formatted payload */ diff --git a/VCL/src/main/java/io/velocitycareerlabs/api/jwt/VCLJwtSignService.kt b/VCL/src/main/java/io/velocitycareerlabs/api/jwt/VCLJwtSignService.kt index e4472742..7f16f838 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/api/jwt/VCLJwtSignService.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/api/jwt/VCLJwtSignService.kt @@ -7,14 +7,16 @@ package io.velocitycareerlabs.api.jwt +import io.velocitycareerlabs.api.entities.VCLDidJwk import io.velocitycareerlabs.api.entities.VCLJwt import io.velocitycareerlabs.api.entities.VCLJwtDescriptor +import io.velocitycareerlabs.api.entities.VCLPublicJwk import io.velocitycareerlabs.api.entities.VCLResult import io.velocitycareerlabs.api.entities.VCLToken interface VCLJwtSignService { fun sign( - kid: String? = null, + didJwk: VCLDidJwk, nonce: String? = null, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken? = null, diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/VCLImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/VCLImpl.kt index 76644bbe..8231bad0 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/VCLImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/VCLImpl.kt @@ -262,7 +262,7 @@ internal class VCLImpl: VCL { override fun submitPresentation( presentationSubmission: VCLPresentationSubmission, - didJwk: VCLDidJwk?, + didJwk: VCLDidJwk, remoteCryptoServicesToken: VCLToken?, successHandler: (VCLSubmissionResult) -> Unit, errorHandler: (VCLError) -> Unit @@ -363,7 +363,7 @@ internal class VCLImpl: VCL { override fun generateOffers( generateOffersDescriptor: VCLGenerateOffersDescriptor, - didJwk: VCLDidJwk?, + didJwk: VCLDidJwk, remoteCryptoServicesToken: VCLToken?, successHandler: (VCLOffers) -> Unit, errorHandler: (VCLError) -> Unit @@ -432,7 +432,7 @@ internal class VCLImpl: VCL { override fun finalizeOffers( finalizeOffersDescriptor: VCLFinalizeOffersDescriptor, - didJwk: VCLDidJwk?, + didJwk: VCLDidJwk, sessionToken: VCLToken, remoteCryptoServicesToken: VCLToken?, successHandler: (VCLJwtVerifiableCredentials) -> Unit, @@ -526,12 +526,14 @@ internal class VCLImpl: VCL { } override fun generateSignedJwt( + didJwk: VCLDidJwk, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken?, successHandler: (VCLJwt) -> Unit, errorHandler: (VCLError) -> Unit ) { jwtServiceUseCase.generateSignedJwt( + didJwk = didJwk, jwtDescriptor = jwtDescriptor, remoteCryptoServicesToken = remoteCryptoServicesToken ) { jwtResult -> diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/JwtServiceRepositoryImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/JwtServiceRepositoryImpl.kt index 1c6a1389..9f609895 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/JwtServiceRepositoryImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/JwtServiceRepositoryImpl.kt @@ -48,14 +48,14 @@ internal class JwtServiceRepositoryImpl( } override fun generateSignedJwt( - kid: String?, // did:jwk in case of person binding + didJwk: VCLDidJwk, nonce: String?, // nonce == challenge jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken?, completionBlock: (VCLResult) -> Unit ) { jwtSignService.sign( - kid = kid, + didJwk = didJwk, nonce = nonce, jwtDescriptor = jwtDescriptor, remoteCryptoServicesToken = remoteCryptoServicesToken, diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/FinalizeOffersUseCaseImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/FinalizeOffersUseCaseImpl.kt index 78c5fb8f..44a61ffd 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/FinalizeOffersUseCaseImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/FinalizeOffersUseCaseImpl.kt @@ -31,18 +31,17 @@ internal class FinalizeOffersUseCaseImpl( override fun finalizeOffers( finalizeOffersDescriptor: VCLFinalizeOffersDescriptor, - didJwk: VCLDidJwk?, + didJwk: VCLDidJwk, sessionToken: VCLToken, remoteCryptoServicesToken: VCLToken?, completionBlock: (VCLResult) -> Unit ) { executor.runOnBackground { this.jwtServiceRepository.generateSignedJwt( - kid = didJwk?.kid, + didJwk = didJwk, nonce = finalizeOffersDescriptor.offers.challenge, jwtDescriptor = VCLJwtDescriptor( - keyId = didJwk?.keyId, - iss = didJwk?.did ?: UUID.randomUUID().toString(), + iss = didJwk.did, aud = finalizeOffersDescriptor.aud ), remoteCryptoServicesToken = remoteCryptoServicesToken diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/JwtServiceUseCaseImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/JwtServiceUseCaseImpl.kt index 13059b36..12406647 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/JwtServiceUseCaseImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/JwtServiceUseCaseImpl.kt @@ -36,7 +36,7 @@ internal class JwtServiceUseCaseImpl( } override fun generateSignedJwt( - kid: String?, + didJwk: VCLDidJwk, nonce: String?, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken?, @@ -44,7 +44,7 @@ internal class JwtServiceUseCaseImpl( ) { executor.runOnBackground { jwtServiceRepository.generateSignedJwt( - kid = kid, + didJwk = didJwk, nonce = nonce, jwtDescriptor = jwtDescriptor, remoteCryptoServicesToken = remoteCryptoServicesToken diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/SubmissionUseCaseImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/SubmissionUseCaseImpl.kt index 1b84de05..c0b15d8b 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/SubmissionUseCaseImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/data/usecases/SubmissionUseCaseImpl.kt @@ -20,18 +20,17 @@ internal class SubmissionUseCaseImpl( ): SubmissionUseCase { override fun submit( submission: VCLSubmission, - didJwk: VCLDidJwk?, + didJwk: VCLDidJwk, remoteCryptoServicesToken: VCLToken?, completionBlock: (VCLResult) -> Unit ) { executor.runOnBackground { jwtServiceRepository.generateSignedJwt( - kid = didJwk?.kid, + didJwk = didJwk, jwtDescriptor = VCLJwtDescriptor( - keyId = didJwk?.keyId, - payload = submission.generatePayload(didJwk?.did), + payload = submission.generatePayload(didJwk.did), jti = submission.jti, - iss = didJwk?.did ?: "" + iss = didJwk.did ), remoteCryptoServicesToken = remoteCryptoServicesToken, completionBlock = { signedJwtResult -> diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/repositories/JwtServiceRepository.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/repositories/JwtServiceRepository.kt index a4dde68b..9ae04958 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/repositories/JwtServiceRepository.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/repositories/JwtServiceRepository.kt @@ -21,7 +21,7 @@ internal interface JwtServiceRepository { completionBlock: (VCLResult) -> Unit ) fun generateSignedJwt( - kid: String? = null, + didJwk: VCLDidJwk, nonce: String? = null, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken? = null, diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/FinalizeOffersUseCase.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/FinalizeOffersUseCase.kt index 7e03cf23..1fafe798 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/FinalizeOffersUseCase.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/FinalizeOffersUseCase.kt @@ -16,7 +16,7 @@ import io.velocitycareerlabs.api.entities.VCLFinalizeOffersDescriptor internal interface FinalizeOffersUseCase { fun finalizeOffers( finalizeOffersDescriptor: VCLFinalizeOffersDescriptor, - didJwk: VCLDidJwk? = null, + didJwk: VCLDidJwk, sessionToken: VCLToken, remoteCryptoServicesToken: VCLToken?, completionBlock: (VCLResult) -> Unit diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/JwtServiceUseCase.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/JwtServiceUseCase.kt index cc4a02e1..f8b69c1a 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/JwtServiceUseCase.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/JwtServiceUseCase.kt @@ -17,7 +17,7 @@ internal interface JwtServiceUseCase { completionBlock: (VCLResult) -> Unit ) fun generateSignedJwt( - kid: String? = null, + didJwk: VCLDidJwk, nonce: String? = null, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken?, diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/SubmissionUseCase.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/SubmissionUseCase.kt index 2736070d..29e25186 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/SubmissionUseCase.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/domain/usecases/SubmissionUseCase.kt @@ -16,7 +16,7 @@ import io.velocitycareerlabs.api.entities.VCLToken internal interface SubmissionUseCase { fun submit( submission: VCLSubmission, - didJwk: VCLDidJwk? = null, + didJwk: VCLDidJwk, remoteCryptoServicesToken: VCLToken?, completionBlock: (VCLResult) -> Unit ) diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/local/VCLJwtSignServiceLocalImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/local/VCLJwtSignServiceLocalImpl.kt index be2a5922..7a00796b 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/local/VCLJwtSignServiceLocalImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/local/VCLJwtSignServiceLocalImpl.kt @@ -14,8 +14,10 @@ import com.nimbusds.jose.crypto.ECDSASigner import com.nimbusds.jose.jwk.ECKey import com.nimbusds.jwt.JWTClaimsSet import com.nimbusds.jwt.SignedJWT +import io.velocitycareerlabs.api.entities.VCLDidJwk import io.velocitycareerlabs.api.entities.VCLJwt import io.velocitycareerlabs.api.entities.VCLJwtDescriptor +import io.velocitycareerlabs.api.entities.VCLPublicJwk import io.velocitycareerlabs.api.entities.VCLResult import io.velocitycareerlabs.api.entities.VCLToken import io.velocitycareerlabs.api.entities.error.VCLError @@ -33,19 +35,20 @@ class VCLJwtSignServiceLocalImpl( private val keyService: VCLKeyService ): VCLJwtSignService { override fun sign( - kid: String?, + didJwk: VCLDidJwk, nonce: String?, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken?, completionBlock: (VCLResult) -> Unit ) { - getSecretReference(jwtDescriptor.keyId) { ecKeyResult -> + getSecretReference(didJwk.keyId) { ecKeyResult -> ecKeyResult.handleResult( successHandler = { ecKey -> try { val header = JWSHeader.Builder(JWSAlgorithm.ES256K) .type(JOSEObjectType(GlobalConfig.TypeJwt)) - kid?.let { header.keyID(it) } ?: run { header.jwk(ecKey.toPublicJWK()) } + .jwk(ecKey.toPublicJWK()) // always provide + .keyID(didJwk.kid) // always provide val jwtHeader = header.build() val signedJWT = SignedJWT( diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt index a5e677cc..2290751d 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt @@ -7,8 +7,10 @@ package io.velocitycareerlabs.impl.jwt.remote +import io.velocitycareerlabs.api.entities.VCLDidJwk import io.velocitycareerlabs.api.entities.VCLJwt import io.velocitycareerlabs.api.entities.VCLJwtDescriptor +import io.velocitycareerlabs.api.entities.VCLPublicJwk import io.velocitycareerlabs.api.entities.VCLResult import io.velocitycareerlabs.api.entities.VCLToken import io.velocitycareerlabs.api.entities.error.VCLError @@ -27,7 +29,7 @@ internal class VCLJwtSignServiceRemoteImpl( private val jwtSignServiceUrl: String ): VCLJwtSignService { override fun sign( - kid: String?, + didJwk: VCLDidJwk, nonce: String?, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken?, @@ -35,7 +37,7 @@ internal class VCLJwtSignServiceRemoteImpl( ) { networkService.sendRequest( endpoint = jwtSignServiceUrl, - body = generateJwtPayloadToSign(kid, nonce, jwtDescriptor).toString(), + body = generateJwtPayloadToSign(didJwk, nonce, jwtDescriptor).toString(), contentType = Request.ContentTypeApplicationJson, method = Request.HttpMethod.POST, headers = listOf( @@ -64,7 +66,7 @@ internal class VCLJwtSignServiceRemoteImpl( } internal fun generateJwtPayloadToSign( - kid: String?, + didJwk: VCLDidJwk, nonce: String?, jwtDescriptor: VCLJwtDescriptor ): JSONObject { @@ -73,11 +75,11 @@ internal class VCLJwtSignServiceRemoteImpl( val options = JSONObject() val payload = jwtDescriptor.payload?.copy() ?: JSONObject() -// Base assumption: +// HeaderValues.XVnfProtocolVersion == VCLXVnfProtocolVersion.XVnfProtocolVersion1 + header.putOpt(KeyJwk, didJwk.publicJwk) // HeaderValues.XVnfProtocolVersion == VCLXVnfProtocolVersion.XVnfProtocolVersion2 - header.putOpt(KeyKid, kid) - - options.putOpt(KeyKeyId, jwtDescriptor.keyId) + header.putOpt(KeyKid, didJwk.kid) + options.putOpt(KeyKeyId, didJwk.keyId) payload.putOpt(KeyNonce, nonce) payload.putOpt(KeyAud, jwtDescriptor.aud) @@ -94,6 +96,7 @@ internal class VCLJwtSignServiceRemoteImpl( companion object CodingKeys { const val KeyKeyId = "keyId" const val KeyKid = "kid" + const val KeyJwk = "jwk" const val KeyIss = "iss" const val KeyAud = "aud" const val KeyJti = "jti" diff --git a/VCL/src/test/java/io/velocitycareerlabs/entities/VCLFinalizeOffersDescriptorTest.kt b/VCL/src/test/java/io/velocitycareerlabs/entities/VCLFinalizeOffersDescriptorTest.kt index d8b4adbd..9b1a50e8 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/entities/VCLFinalizeOffersDescriptorTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/entities/VCLFinalizeOffersDescriptorTest.kt @@ -9,6 +9,7 @@ package io.velocitycareerlabs.entities import android.os.Build import io.velocitycareerlabs.api.entities.VCLCredentialManifest +import io.velocitycareerlabs.api.entities.VCLDidJwk import io.velocitycareerlabs.api.entities.VCLFinalizeOffersDescriptor import io.velocitycareerlabs.api.entities.VCLJwt import io.velocitycareerlabs.api.entities.VCLJwtDescriptor @@ -36,6 +37,9 @@ import org.robolectric.annotation.Config class VCLFinalizeOffersDescriptorTest { lateinit var subject: VCLFinalizeOffersDescriptor + private lateinit var didJwk: VCLDidJwk + private val keyService = VCLKeyServiceLocalImpl(SecretStoreServiceMock.Instance) + private val offers = VCLOffers( payload = JSONObject(), all = listOf(), @@ -54,6 +58,14 @@ class VCLFinalizeOffersDescriptorTest { @Before fun setUp() { + keyService.generateDidJwk(null) { didJwkResult -> + didJwkResult.handleResult({ + didJwk = it + }, { + assert(false) { "Failed to generate did:jwk $it" } + }) + } + val credentialManifest = VCLCredentialManifest( jwt = VCLJwt(encodedJwt = CredentialManifestMocks.JwtCredentialManifest1), @@ -72,6 +84,7 @@ class VCLFinalizeOffersDescriptorTest { fun testGenerateRequestBody() { val payload = "{\"key1\": \"value1\"}".toJsonObject() VCLJwtSignServiceLocalImpl(VCLKeyServiceLocalImpl(SecretStoreServiceMock.Instance)).sign( + didJwk = didJwk, nonce = nonceMock, jwtDescriptor = VCLJwtDescriptor( payload = payload, diff --git a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtSignServiceLocalTest.kt b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtSignServiceLocalTest.kt index ff71db78..2b76a341 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtSignServiceLocalTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtSignServiceLocalTest.kt @@ -50,10 +50,9 @@ class JwtSignServiceLocalTest { @Test fun testSignFullParams() { subject.sign( - kid = didJwk.kid, + didJwk = didJwk, nonce = nonceMock, jwtDescriptor = VCLJwtDescriptor( - keyId = didJwk.keyId, payload = payloadMock, jti = jtiMock, iss = issMock, @@ -68,7 +67,7 @@ class JwtSignServiceLocalTest { assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyJti) == jtiMock) val iat = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyIat) as Long val nbf = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNbf) as Long - val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long +// val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long assert(iat == nbf) // assert(exp - iat == sevenDaysInSeconds) assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNonce) == nonceMock) @@ -81,9 +80,9 @@ class JwtSignServiceLocalTest { @Test fun testSignPartialParams1() { subject.sign( + didJwk = didJwk, nonce = nonceMock, jwtDescriptor = VCLJwtDescriptor( - keyId = didJwk.keyId, payload = payloadMock, jti = jtiMock, iss = issMock, @@ -98,7 +97,7 @@ class JwtSignServiceLocalTest { assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyJti) == jtiMock) val iat = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyIat) as Long val nbf = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNbf) as Long - val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long +// val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long assert(iat == nbf) // assert(exp - iat == sevenDaysInSeconds) assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNonce) == nonceMock) @@ -111,8 +110,8 @@ class JwtSignServiceLocalTest { @Test fun testSignPartialParams2() { subject.sign( + didJwk = didJwk, jwtDescriptor = VCLJwtDescriptor( - keyId = didJwk.keyId, payload = payloadMock, jti = jtiMock, iss = issMock, @@ -127,7 +126,7 @@ class JwtSignServiceLocalTest { assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyJti) == jtiMock) val iat = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyIat) as Long val nbf = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNbf) as Long - val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long +// val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long assert(iat == nbf) // assert(exp - iat == sevenDaysInSeconds) assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNonce) == null) @@ -140,6 +139,7 @@ class JwtSignServiceLocalTest { @Test fun testSignPartialParams3() { subject.sign( + didJwk = didJwk, jwtDescriptor = VCLJwtDescriptor( payload = payloadMock, iss = issMock, @@ -154,7 +154,7 @@ class JwtSignServiceLocalTest { assert((jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyJti) as? String)?.isBlank() == false) val iat = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyIat) as Long val nbf = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNbf) as Long - val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long +// val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long assert(iat == nbf) // assert(exp - iat == sevenDaysInSeconds) assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNonce) == null) @@ -167,6 +167,7 @@ class JwtSignServiceLocalTest { @Test fun testSignPartialParams4() { subject.sign( + didJwk = didJwk, jwtDescriptor = VCLJwtDescriptor( payload = payloadMock, iss = issMock @@ -180,7 +181,7 @@ class JwtSignServiceLocalTest { assert((jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyJti) as? String)?.isBlank() == false) val iat = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyIat) as Long val nbf = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNbf) as Long - val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long +// val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long assert(iat == nbf) // assert(exp - iat == sevenDaysInSeconds) assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNonce) == null) @@ -193,6 +194,7 @@ class JwtSignServiceLocalTest { @Test fun testSignPartParams5() { subject.sign( + didJwk = didJwk, jwtDescriptor = VCLJwtDescriptor( iss = issMock ) @@ -205,7 +207,7 @@ class JwtSignServiceLocalTest { assert((jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyJti) as? String)?.isBlank() == false) val iat = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyIat) as Long val nbf = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNbf) as Long - val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long +// val exp = jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyExp) as Long assert(iat == nbf) // assert(exp - iat == sevenDaysInSeconds) assert(jwt.payload?.toJSONObject()?.get(VCLJwtSignServiceLocalImpl.CodingKeys.KeyNonce) == null) diff --git a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtVerifyServiceLocalTest.kt b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtVerifyServiceLocalTest.kt index 616cb9bf..9d4f1dc2 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtVerifyServiceLocalTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/local/JwtVerifyServiceLocalTest.kt @@ -54,10 +54,9 @@ class JwtVerifyServiceLocalTest { @Test fun testSignAndVerify() { jwtSignServiceLocalImpl.sign( - kid = didJwk.kid, + didJwk = didJwk, nonce = nonceMock, jwtDescriptor = VCLJwtDescriptor( - keyId = didJwk.keyId, payload = payloadMock, jti = jtiMock, iss = issMock, diff --git a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt index ed39129e..c0ed0d41 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt @@ -7,19 +7,39 @@ package io.velocitycareerlabs.infrastructure.jwt.remote +import android.os.Build +import io.velocitycareerlabs.api.entities.VCLDidJwk import io.velocitycareerlabs.api.entities.VCLJwtDescriptor +import io.velocitycareerlabs.api.entities.handleResult import io.velocitycareerlabs.impl.extensions.toJsonObject import io.velocitycareerlabs.impl.jwt.remote.VCLJwtSignServiceRemoteImpl +import io.velocitycareerlabs.impl.keys.VCLKeyServiceLocalImpl +import io.velocitycareerlabs.infrastructure.db.SecretStoreServiceMock import io.velocitycareerlabs.infrastructure.network.NetworkServiceSuccess import org.json.JSONObject import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [Build.VERSION_CODES.O_MR1]) internal class VCLJwtSignServiceTest { lateinit var subject: VCLJwtSignServiceRemoteImpl + private lateinit var didJwk: VCLDidJwk + private val keyService = VCLKeyServiceLocalImpl(SecretStoreServiceMock.Instance) @Before fun setUp() { + keyService.generateDidJwk(null) { jwkResult -> + jwkResult.handleResult({ + didJwk = it + } ,{ + assert(false) { "Failed to generate did:jwk $it" } + }) + } + subject = VCLJwtSignServiceRemoteImpl( NetworkServiceSuccess(""), "" @@ -29,10 +49,9 @@ internal class VCLJwtSignServiceTest { @Test fun testGenerateJwtPayloadToSign() { val payloadToSign = subject.generateJwtPayloadToSign( - kid = "kid 1", + didJwk = didJwk, nonce = "nonce 1", VCLJwtDescriptor( - keyId = "keyId 1", payload = "{\"payload\": \"payload 1\"}".toJsonObject(), jti = "jti 1", iss = "iss 1", @@ -43,9 +62,9 @@ internal class VCLJwtSignServiceTest { val options = payloadToSign.optJSONObject("options") val payload = payloadToSign.optJSONObject("payload") - assert(header?.optString("kid") == "kid 1") + assert(header?.optString("kid") == didJwk.kid) - assert(options?.optString("keyId") == "keyId 1") + assert(options?.optString("keyId") == didJwk.keyId) assert(payload?.optString("nonce") == "nonce 1") assert(payload?.optString("aud") == "aud 1") diff --git a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/resources/valid/VCLJwtSignServiceMock.kt b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/resources/valid/VCLJwtSignServiceMock.kt index a22ff250..746fbb2b 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/resources/valid/VCLJwtSignServiceMock.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/resources/valid/VCLJwtSignServiceMock.kt @@ -7,6 +7,7 @@ package io.velocitycareerlabs.infrastructure.resources.valid +import io.velocitycareerlabs.api.entities.VCLDidJwk import io.velocitycareerlabs.api.entities.VCLJwt import io.velocitycareerlabs.api.entities.VCLJwtDescriptor import io.velocitycareerlabs.api.entities.VCLResult @@ -15,7 +16,7 @@ import io.velocitycareerlabs.api.jwt.VCLJwtSignService class VCLJwtSignServiceMock: VCLJwtSignService { override fun sign( - kid: String?, + didJwk: VCLDidJwk, nonce: String?, jwtDescriptor: VCLJwtDescriptor, remoteCryptoServicesToken: VCLToken?, diff --git a/VCL/src/test/java/io/velocitycareerlabs/usecases/JwtServiceUseCaseTest.kt b/VCL/src/test/java/io/velocitycareerlabs/usecases/JwtServiceUseCaseTest.kt index f483bb7c..2cb985ed 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/usecases/JwtServiceUseCaseTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/usecases/JwtServiceUseCaseTest.kt @@ -34,11 +34,19 @@ import org.robolectric.annotation.Config internal class JwtServiceUseCaseTest { lateinit var subject: JwtServiceUseCase - lateinit var keyService: VCLKeyService + private lateinit var didJwk: VCLDidJwk + private val keyService = VCLKeyServiceLocalImpl(SecretStoreServiceMock.Instance) @Before fun setUp() { - keyService = VCLKeyServiceLocalImpl(SecretStoreServiceMock.Instance) + keyService.generateDidJwk(null) { didJwkResult -> + didJwkResult.handleResult({ + didJwk = it + }, { + assert(false) { "Failed to generate did:jwk $it" } + }) + } + subject = JwtServiceUseCaseImpl( JwtServiceRepositoryImpl( VCLJwtSignServiceLocalImpl(keyService), @@ -51,6 +59,7 @@ internal class JwtServiceUseCaseTest { @Test fun testSign() { subject.generateSignedJwt( + didJwk = didJwk, jwtDescriptor = VCLJwtDescriptor( payload = JwtServiceMocks.Json.toJsonObject()!!, jti = "some jti", @@ -74,6 +83,7 @@ internal class JwtServiceUseCaseTest { @Test fun testSignVerify() { subject.generateSignedJwt( + didJwk = didJwk, jwtDescriptor = VCLJwtDescriptor( payload = JwtServiceMocks.Json.toJsonObject()!!, jti = "some jti", @@ -110,10 +120,9 @@ internal class JwtServiceUseCaseTest { keyService.generateDidJwk(null) { didJwkResult -> didJwkResult.handleResult({ didJwk -> subject.generateSignedJwt( - kid = didJwk.kid, + didJwk = didJwk, nonce = "some nonce", jwtDescriptor = VCLJwtDescriptor( - keyId = didJwk.keyId, payload = JwtServiceMocks.Json.toJsonObject()!!, jti = "some jti", iss = "some iss" diff --git a/app/src/main/java/com/vcl/wallet/MainActivity.kt b/app/src/main/java/com/vcl/wallet/MainActivity.kt index 6ec3975a..4baa01e1 100644 --- a/app/src/main/java/com/vcl/wallet/MainActivity.kt +++ b/app/src/main/java/com/vcl/wallet/MainActivity.kt @@ -12,12 +12,17 @@ import android.util.Log import androidx.core.view.isVisible import com.vcl.wallet.databinding.ActivityMainBinding import io.velocitycareerlabs.api.VCL +import io.velocitycareerlabs.api.VCLCryptoServiceType import io.velocitycareerlabs.api.VCLEnvironment import io.velocitycareerlabs.api.VCLProvider import io.velocitycareerlabs.api.VCLXVnfProtocolVersion import io.velocitycareerlabs.api.entities.* import io.velocitycareerlabs.api.entities.error.VCLError +import io.velocitycareerlabs.api.entities.initialization.VCLCryptoServicesDescriptor import io.velocitycareerlabs.api.entities.initialization.VCLInitializationDescriptor +import io.velocitycareerlabs.api.entities.initialization.VCLJwtServiceUrls +import io.velocitycareerlabs.api.entities.initialization.VCLKeyServiceUrls +import io.velocitycareerlabs.api.entities.initialization.VCLRemoteCryptoServicesUrlsDescriptor import org.json.JSONObject class MainActivity : AppCompatActivity() { @@ -28,7 +33,7 @@ class MainActivity : AppCompatActivity() { private val environment = VCLEnvironment.Dev private lateinit var vcl: VCL - private var didJwk: VCLDidJwk? = null + private lateinit var didJwk: VCLDidJwk override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -390,8 +395,8 @@ class MainActivity : AppCompatActivity() { private fun generateSignedJwt() { vcl.generateSignedJwt( - VCLJwtDescriptor( - keyId = didJwk?.keyId, + didJwk = didJwk, + jwtDescriptor = VCLJwtDescriptor( payload = Constants.SomePayload, iss = "iss123", jti = "jti123" From 5316bfe3d40328028ef0e4e833c657c6422ea848 Mon Sep 17 00:00:00 2001 From: Michael Avoyan Date: Tue, 6 Feb 2024 16:41:16 +0200 Subject: [PATCH 2/2] fix --- .../impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt | 3 ++- .../infrastructure/jwt/remote/VCLJwtSignServiceTest.kt | 2 ++ .../usecases/CredentialManifestUseCaseTest.kt | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt index 2290751d..a88a5eb2 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/jwt/remote/VCLJwtSignServiceRemoteImpl.kt @@ -76,9 +76,10 @@ internal class VCLJwtSignServiceRemoteImpl( val payload = jwtDescriptor.payload?.copy() ?: JSONObject() // HeaderValues.XVnfProtocolVersion == VCLXVnfProtocolVersion.XVnfProtocolVersion1 - header.putOpt(KeyJwk, didJwk.publicJwk) + header.putOpt(KeyJwk, didJwk.publicJwk.valueJson) // HeaderValues.XVnfProtocolVersion == VCLXVnfProtocolVersion.XVnfProtocolVersion2 header.putOpt(KeyKid, didJwk.kid) + options.putOpt(KeyKeyId, didJwk.keyId) payload.putOpt(KeyNonce, nonce) diff --git a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt index c0ed0d41..5fb826f3 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/infrastructure/jwt/remote/VCLJwtSignServiceTest.kt @@ -16,6 +16,7 @@ import io.velocitycareerlabs.impl.jwt.remote.VCLJwtSignServiceRemoteImpl import io.velocitycareerlabs.impl.keys.VCLKeyServiceLocalImpl import io.velocitycareerlabs.infrastructure.db.SecretStoreServiceMock import io.velocitycareerlabs.infrastructure.network.NetworkServiceSuccess +import junit.framework.TestCase.assertEquals import org.json.JSONObject import org.junit.Before import org.junit.Test @@ -63,6 +64,7 @@ internal class VCLJwtSignServiceTest { val payload = payloadToSign.optJSONObject("payload") assert(header?.optString("kid") == didJwk.kid) + assertEquals(header?.optJSONObject("jwk"), didJwk.publicJwk.valueJson) assert(options?.optString("keyId") == didJwk.keyId) diff --git a/VCL/src/test/java/io/velocitycareerlabs/usecases/CredentialManifestUseCaseTest.kt b/VCL/src/test/java/io/velocitycareerlabs/usecases/CredentialManifestUseCaseTest.kt index 453daefd..4363ed23 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/usecases/CredentialManifestUseCaseTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/usecases/CredentialManifestUseCaseTest.kt @@ -10,7 +10,6 @@ package io.velocitycareerlabs.usecases import android.os.Build import io.velocitycareerlabs.api.entities.* import io.velocitycareerlabs.api.entities.error.VCLErrorCode -import io.velocitycareerlabs.impl.data.infrastructure.executors.ExecutorImpl import io.velocitycareerlabs.impl.keys.VCLKeyServiceLocalImpl import io.velocitycareerlabs.impl.data.repositories.CredentialManifestRepositoryImpl import io.velocitycareerlabs.impl.data.repositories.JwtServiceRepositoryImpl