diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f6a42e..c0262d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,6 @@ jobs: - name: Run integration tests uses: reactivecircus/android-emulator-runner@v2 env: - TEST_BASE_URL: ${{ vars.TEST_BASE_URL }} TEST_CUV_PROJECT_ID: ${{ vars.TEST_CUV_PROJECT_ID }} TEST_CUV_PROJECT_URL: ${{ vars.TEST_CUV_PROJECT_URL }} TEST_CUV_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TEST_CUV_SERVICE_ACCOUNT_TOKEN }} diff --git a/miracl-sdk/src/androidTest/java/com/miracl/trust/MIRACLTrustJavaTest.java b/miracl-sdk/src/androidTest/java/com/miracl/trust/MIRACLTrustJavaTest.java index 0b7b4d5..cb89061 100644 --- a/miracl-sdk/src/androidTest/java/com/miracl/trust/MIRACLTrustJavaTest.java +++ b/miracl-sdk/src/androidTest/java/com/miracl/trust/MIRACLTrustJavaTest.java @@ -4,6 +4,7 @@ import static com.miracl.trust.utilities.UtilitiesKt.USER_ID; import static com.miracl.trust.utilities.UtilitiesKt.USER_PIN_LENGTH; import static com.miracl.trust.utilities.UtilitiesKt.getUnixTime; +import static com.miracl.trust.utilities.UtilitiesKt.randomHash; import static com.miracl.trust.utilities.UtilitiesKt.randomNumericPin; import static com.miracl.trust.utilities.UtilitiesKt.randomUuidString; @@ -37,12 +38,14 @@ import com.miracl.trust.utilities.JwtHelper; import com.miracl.trust.utilities.MIRACLService; import com.miracl.trust.utilities.SigningSessionCreateResponse; +import com.miracl.trust.utilities.VerifySignatureResponse; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.util.HashMap; +import java.util.HexFormat; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -173,7 +176,9 @@ public void testAuthentication() { Assert.assertTrue(result instanceof MIRACLSuccess); String token = ((MIRACLSuccess) result).getValue(); - Jws claims = JwtHelper.INSTANCE.parseSignedClaims(token, projectUrl); + + String jwks = MIRACLService.INSTANCE.getJwkSet(projectUrl); + Jws claims = JwtHelper.INSTANCE.parseSignedClaims(token, jwks); Assert.assertTrue(claims.getPayload().getAudience().contains(projectId)); })); testCoroutineDispatcher.getScheduler().advanceUntilIdle(); @@ -231,14 +236,18 @@ public void testNotificationAuthentication() { @Test public void testSigning() { - createUser(user -> miraclTrust.sign("message".getBytes(), user, pinProvider, result -> { + byte[] hash = randomHash(); + createUser(user -> miraclTrust.sign(hash, user, pinProvider, result -> { Assert.assertTrue(result instanceof MIRACLSuccess); SigningResult signingResult = ((MIRACLSuccess) result).getValue(); Signature signature = signingResult.getSignature(); int timestamp = (int) (signingResult.getTimestamp().getTime() / 1000); - boolean signatureVerified = MIRACLService.INSTANCE.verifySignature(projectId, projectUrl, serviceAccountToken, signature, timestamp); - Assert.assertTrue(signatureVerified); + VerifySignatureResponse verifySignatureResponse = MIRACLService.INSTANCE.verifySignature(projectId, projectUrl, serviceAccountToken, signature, timestamp); + + String jwks = MIRACLService.INSTANCE.getDvsJwkSet(projectUrl); + Jws claims = JwtHelper.INSTANCE.parseSignedClaims(verifySignatureResponse.getCertificate(), jwks); + Assert.assertEquals(HexFormat.of().formatHex(hash), claims.getPayload().get("hash")); })); testCoroutineDispatcher.getScheduler().advanceUntilIdle(); } diff --git a/miracl-sdk/src/androidTest/java/com/miracl/trust/authentication/AuthenticationTest.kt b/miracl-sdk/src/androidTest/java/com/miracl/trust/authentication/AuthenticationTest.kt index e380664..ea258a4 100644 --- a/miracl-sdk/src/androidTest/java/com/miracl/trust/authentication/AuthenticationTest.kt +++ b/miracl-sdk/src/androidTest/java/com/miracl/trust/authentication/AuthenticationTest.kt @@ -80,7 +80,8 @@ class AuthenticationTest { Assert.assertTrue(result is MIRACLSuccess) val token = (result as MIRACLSuccess).value - val claims = JwtHelper.parseSignedClaims(token, projectUrl) + val jwks = MIRACLService.getJwkSet(projectUrl) + val claims = JwtHelper.parseSignedClaims(token, jwks) Assert.assertTrue(claims.payload.audience.contains(projectId)) } diff --git a/miracl-sdk/src/androidTest/java/com/miracl/trust/signing/DocumentSigningTest.kt b/miracl-sdk/src/androidTest/java/com/miracl/trust/signing/DocumentSigningTest.kt index e24f242..f17d5ba 100644 --- a/miracl-sdk/src/androidTest/java/com/miracl/trust/signing/DocumentSigningTest.kt +++ b/miracl-sdk/src/androidTest/java/com/miracl/trust/signing/DocumentSigningTest.kt @@ -34,11 +34,13 @@ import com.miracl.trust.util.json.KotlinxSerializationJsonUtil import com.miracl.trust.util.secondsSince1970 import com.miracl.trust.util.toHexString import com.miracl.trust.util.toUser +import com.miracl.trust.utilities.JwtHelper import com.miracl.trust.utilities.MIRACLService import com.miracl.trust.utilities.USER_ID import com.miracl.trust.utilities.USER_PIN_LENGTH import com.miracl.trust.utilities.WRONG_FORMAT_PIN import com.miracl.trust.utilities.generateWrongPin +import com.miracl.trust.utilities.randomHash import com.miracl.trust.utilities.randomNumericPin import com.miracl.trust.utilities.randomPinLength import com.miracl.trust.utilities.randomUuidString @@ -49,10 +51,6 @@ import org.junit.Test import kotlin.random.Random class DocumentSigningTest { - companion object { - private val HASH_RANGE = 1..10 - } - private val projectId = BuildConfig.CUV_PROJECT_ID private val projectUrl = BuildConfig.CUV_PROJECT_URL private val serviceAccountToken = BuildConfig.CUV_SERVICE_ACCOUNT_TOKEN @@ -129,8 +127,9 @@ class DocumentSigningTest { @Test fun testSuccessfulDocumentSigning() = runBlocking { // Sign + val message = randomHash() val result = documentSigner.sign( - message = randomHash(), + message = message, user = user, pinProvider = pinProvider, deviceName = Build.MODEL @@ -139,14 +138,17 @@ class DocumentSigningTest { // Verify the signature val signingResult = (result as MIRACLSuccess).value - val signatureVerified = MIRACLService.verifySignature( + val verifySignatureResponse = MIRACLService.verifySignature( projectId = projectId, projectUrl = projectUrl, serviceAccountToken = serviceAccountToken, signature = signingResult.signature, timestamp = signingResult.timestamp.secondsSince1970() ) - Assert.assertTrue(signatureVerified) + + val jwks = MIRACLService.getDvsJwkSet(projectUrl) + val claims = JwtHelper.parseSignedClaims(verifySignatureResponse.certificate, jwks) + Assert.assertEquals(message.toHexString(), claims.payload["hash"]) } @Test @@ -166,14 +168,17 @@ class DocumentSigningTest { val signingResult = (result as MIRACLSuccess).value Assert.assertEquals(signingSessionDetails.signingHash, signingResult.signature.hash) - val signatureVerified = MIRACLService.verifySignature( + val verifySignatureResponse = MIRACLService.verifySignature( projectId = projectId, projectUrl = projectUrl, serviceAccountToken = serviceAccountToken, signature = signingResult.signature, timestamp = signingResult.timestamp.secondsSince1970() ) - Assert.assertTrue(signatureVerified) + + val jwks = MIRACLService.getDvsJwkSet(projectUrl) + val claims = JwtHelper.parseSignedClaims(verifySignatureResponse.certificate, jwks) + Assert.assertEquals(signingSessionDetails.signingHash, claims.payload["hash"]) } @Test @@ -211,14 +216,17 @@ class DocumentSigningTest { val signature = KotlinxSerializationJsonUtil.fromJsonString(signatureJson) Assert.assertEquals(crossDeviceSession.signingHash, signature.hash) - val verified = MIRACLService.verifySignature( + val verifySignatureResponse = MIRACLService.verifySignature( projectId = projectId, projectUrl = projectUrl, serviceAccountToken = serviceAccountToken, signature = signature, timestamp = signature.timestamp ) - Assert.assertTrue(verified) + + val jwks = MIRACLService.getDvsJwkSet(projectUrl) + val claims = JwtHelper.parseSignedClaims(verifySignatureResponse.certificate, jwks) + Assert.assertEquals(crossDeviceSession.signingHash, claims.payload["hash"]) } @Test @@ -453,9 +461,4 @@ class DocumentSigningTest { return (getSigningSessionDetailsResult as MIRACLSuccess).value } - - private fun randomHash(): ByteArray = - (HASH_RANGE) - .map { Random.nextBytes(it) } - .reduce { acc, bytes -> acc + bytes } } \ No newline at end of file diff --git a/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/JwtHelper.kt b/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/JwtHelper.kt index 0fe1908..2d3ebb0 100644 --- a/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/JwtHelper.kt +++ b/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/JwtHelper.kt @@ -1,6 +1,5 @@ package com.miracl.trust.utilities -import com.miracl.trust.MIRACLSuccess import io.jsonwebtoken.Claims import io.jsonwebtoken.Jws import io.jsonwebtoken.JwtException @@ -10,26 +9,21 @@ import io.jsonwebtoken.LocatorAdapter import io.jsonwebtoken.ProtectedHeader import io.jsonwebtoken.security.JwkSet import io.jsonwebtoken.security.Jwks -import kotlinx.coroutines.runBlocking -import org.junit.Assert import java.security.Key object JwtHelper { - fun parseSignedClaims(token: String, projectUrl: String): Jws = runBlocking { - Jwts.parser() - .keyLocator(getKeyLocator(projectUrl)) + fun parseSignedClaims(token: String, jwks: String): Jws { + return Jwts.parser() + .keyLocator(getKeyLocator(jwks)) .build() .parseSignedClaims(token) } - private suspend fun getKeyLocator(projectUrl: String): Locator { - val result = MIRACLService.getJwkSet(projectUrl) - Assert.assertTrue(result is MIRACLSuccess) - val json = (result as MIRACLSuccess).value + private fun getKeyLocator(jwks: String): Locator { val jwkSet: JwkSet = Jwks.setParser() .build() - .parse(json) + .parse(jwks) val keyLocator = object : LocatorAdapter() { override fun locate(header: ProtectedHeader?): Key { diff --git a/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/MIRACLService.kt b/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/MIRACLService.kt index 34d08b4..72356fb 100644 --- a/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/MIRACLService.kt +++ b/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/MIRACLService.kt @@ -1,11 +1,9 @@ package com.miracl.trust.utilities import android.net.Uri -import com.miracl.trust.MIRACLResult import com.miracl.trust.MIRACLSuccess import com.miracl.trust.network.ApiRequest import com.miracl.trust.network.HttpMethod -import com.miracl.trust.network.HttpRequestExecutorException import com.miracl.trust.network.HttpsURLConnectionRequestExecutor import com.miracl.trust.signing.Signature import com.miracl.trust.test.BuildConfig @@ -74,6 +72,11 @@ data class VerifySignatureRequestBody( val timestamp: Int ) +@Serializable +data class VerifySignatureResponse( + val certificate: String +) + object MIRACLService { private val requestExecutor = HttpsURLConnectionRequestExecutor(10, 10) private val json = Json { @@ -168,7 +171,7 @@ object MIRACLService { activateInitiateResponse.actToken } - suspend fun getJwkSet(projectUrl: String): MIRACLResult { + fun getJwkSet(projectUrl: String): String = runBlocking { val apiRequest = ApiRequest( method = HttpMethod.GET, headers = null, @@ -177,7 +180,19 @@ object MIRACLService { url = "$projectUrl/.well-known/jwks" ) - return requestExecutor.execute(apiRequest) + (requestExecutor.execute(apiRequest) as MIRACLSuccess).value + } + + fun getDvsJwkSet(projectUrl: String): String = runBlocking { + val apiRequest = ApiRequest( + method = HttpMethod.GET, + headers = null, + body = null, + params = null, + url = "$projectUrl/dvs/jwks" + ) + + (requestExecutor.execute(apiRequest) as MIRACLSuccess).value } fun createSigningSession( @@ -212,7 +227,7 @@ object MIRACLService { serviceAccountToken: String, signature: Signature, timestamp: Int - ): Boolean = runBlocking { + ): VerifySignatureResponse = runBlocking { val apiRequest = ApiRequest( method = HttpMethod.POST, headers = mapOf("Authorization" to "Bearer $serviceAccountToken"), @@ -222,6 +237,6 @@ object MIRACLService { ) val result = requestExecutor.execute(apiRequest) - result is MIRACLSuccess + json.decodeFromString((result as MIRACLSuccess).value) } } \ No newline at end of file diff --git a/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/Utilities.kt b/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/Utilities.kt index c33ae92..59c7a1a 100644 --- a/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/Utilities.kt +++ b/miracl-sdk/src/androidTest/java/com/miracl/trust/utilities/Utilities.kt @@ -35,4 +35,9 @@ fun randomUuidString() = UUID.randomUUID().toString() fun randomByteArray(size: Int = 20) = Random.nextBytes(size) -fun randomPinLength() = Random.nextInt(4..6) \ No newline at end of file +fun randomPinLength() = Random.nextInt(4..6) + +fun randomHash(): ByteArray = + (1..10) + .map { Random.nextBytes(it) } + .reduce { acc, bytes -> acc + bytes } \ No newline at end of file diff --git a/run-instrumentation-tests.sh b/run-instrumentation-tests.sh old mode 100644 new mode 100755 index a8f5989..9e2c511 --- a/run-instrumentation-tests.sh +++ b/run-instrumentation-tests.sh @@ -7,7 +7,6 @@ echo $GMAIL_TOKEN > "${TEST_CREDENTIALS_DIR}/token.json" #Instrumentation tests ./gradlew connectedAndroidTest \ - -Pmiracltrust.baseUrl="$TEST_BASE_URL" \ -Pmiracltrust.cuvProjectId="$TEST_CUV_PROJECT_ID" \ -Pmiracltrust.cuvProjectUrl="$TEST_CUV_PROJECT_URL" \ -Pmiracltrust.cuvServiceAccountToken="$TEST_CUV_SERVICE_ACCOUNT_TOKEN" \