Skip to content

Commit 9b728a6

Browse files
committed
fix(wallet): address final WAL-896 review feedback
1 parent 27e1557 commit 9b728a6

9 files changed

Lines changed: 104 additions & 84 deletions

File tree

waltid-applications/waltid-wallet-demo-ios/iosApp/iosAppTests/MobileWalletIntegrationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,15 @@ final class MobileWalletIntegrationTests: XCTestCase {
206206
func testReceiveAndPresentEudiEhicSdJwtAgainstEudi() async throws {
207207
try XCTSkipIf(
208208
true,
209-
"Upstream EUDI verifier request-object endpoint intermittently returns HTTP 400; OID4VP presentation is covered by the public demo tests"
209+
"Pending native iOS PKIX/x509_hash Request Object authentication and EUDI trust-anchor refresh; tracked by https://github.com/walt-id/waltid-identity/pull/1940"
210210
)
211211
try await receiveAndPresentEudiCredential(credentialID: Self.eudiEhicSdJwtCredentialID)
212212
}
213213

214214
func testPreviewAndSubmitEudiEhicSdJwtAgainstEudi() async throws {
215215
try XCTSkipIf(
216216
true,
217-
"Upstream EUDI verifier request-object endpoint intermittently returns HTTP 400; OID4VP presentation is covered by the public demo tests"
217+
"Pending native iOS PKIX/x509_hash Request Object authentication and EUDI trust-anchor refresh; tracked by https://github.com/walt-id/waltid-identity/pull/1940"
218218
)
219219
try await previewAndSubmitEudiCredential(credentialID: Self.eudiEhicSdJwtCredentialID)
220220
}

waltid-libraries/protocols/waltid-openid4vc-wallet-mobile/api/waltid-openid4vc-wallet-mobile.klib.api

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,6 @@ final class id.walt.wallet2.mobile/MobileWalletPresentationDisclosureSelection {
731731

732732
final class id.walt.wallet2.mobile/MobileWalletPresentationPreview { // id.walt.wallet2.mobile/MobileWalletPresentationPreview|null[0]
733733
constructor <init>(id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo, kotlin.collections/List<id.walt.wallet2.mobile/MobileWalletPresentationCredentialOption>, kotlin.collections/List<id.walt.wallet2.mobile/MobileWalletPresentationCredentialRequirement> = ..., id.walt.wallet2.mobile/MobileWalletEncryptionInfo = ...) // id.walt.wallet2.mobile/MobileWalletPresentationPreview.<init>|<init>(id.walt.wallet2.mobile.MobileWalletPresentationRequestInfo;kotlin.collections.List<id.walt.wallet2.mobile.MobileWalletPresentationCredentialOption>;kotlin.collections.List<id.walt.wallet2.mobile.MobileWalletPresentationCredentialRequirement>;id.walt.wallet2.mobile.MobileWalletEncryptionInfo){}[0]
734-
constructor <init>(id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo, kotlin.collections/List<id.walt.wallet2.mobile/MobileWalletPresentationCredentialOption>, kotlin.collections/List<id.walt.wallet2.mobile/MobileWalletPresentationCredentialRequirement>) // id.walt.wallet2.mobile/MobileWalletPresentationPreview.<init>|<init>(id.walt.wallet2.mobile.MobileWalletPresentationRequestInfo;kotlin.collections.List<id.walt.wallet2.mobile.MobileWalletPresentationCredentialOption>;kotlin.collections.List<id.walt.wallet2.mobile.MobileWalletPresentationCredentialRequirement>){}[0]
735734

736735
final val credentialOptions // id.walt.wallet2.mobile/MobileWalletPresentationPreview.credentialOptions|{}credentialOptions[0]
737736
final fun <get-credentialOptions>(): kotlin.collections/List<id.walt.wallet2.mobile/MobileWalletPresentationCredentialOption> // id.walt.wallet2.mobile/MobileWalletPresentationPreview.credentialOptions.<get-credentialOptions>|<get-credentialOptions>(){}[0]
@@ -754,7 +753,6 @@ final class id.walt.wallet2.mobile/MobileWalletPresentationPreview { // id.walt.
754753

755754
final class id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo { // id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo|null[0]
756755
constructor <init>(kotlin/String?, kotlin/String?, kotlin/String?, kotlin/String?, kotlin/String?, kotlin.collections/List<id.walt.wallet2.mobile/MobileWalletTransactionDataItem> = ..., kotlin/String? = ...) // id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo.<init>|<init>(kotlin.String?;kotlin.String?;kotlin.String?;kotlin.String?;kotlin.String?;kotlin.collections.List<id.walt.wallet2.mobile.MobileWalletTransactionDataItem>;kotlin.String?){}[0]
757-
constructor <init>(kotlin/String?, kotlin/String?, kotlin/String?, kotlin/String?, kotlin/String?, kotlin.collections/List<id.walt.wallet2.mobile/MobileWalletTransactionDataItem>) // id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo.<init>|<init>(kotlin.String?;kotlin.String?;kotlin.String?;kotlin.String?;kotlin.String?;kotlin.collections.List<id.walt.wallet2.mobile.MobileWalletTransactionDataItem>){}[0]
758756

759757
final val clientId // id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo.clientId|{}clientId[0]
760758
final fun <get-clientId>(): kotlin/String? // id.walt.wallet2.mobile/MobileWalletPresentationRequestInfo.clientId.<get-clientId>|<get-clientId>(){}[0]

waltid-libraries/protocols/waltid-openid4vc-wallet-mobile/src/androidDeviceTest/kotlin/id/walt/wallet2/mobile/test/MobileWalletIntegrationTest.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,11 @@ class MobileWalletIntegrationTest {
108108
receiveCredentialFromDemoIssuer2("iso-mdl")
109109
}
110110

111-
@Ignore("Upstream EUDI verifier request-object endpoint intermittently returns HTTP 400; OID4VP presentation is covered by the public demo tests")
112111
@Test
113112
fun receiveAndPresentEudiEhicSdJwtAgainstEudi() = runBlocking {
114113
receiveAndPresentEudiCredential(EUDI_EHIC_SD_JWT_CREDENTIAL_ID)
115114
}
116115

117-
@Ignore("Upstream EUDI verifier request-object endpoint intermittently returns HTTP 400; OID4VP presentation is covered by the public demo tests")
118116
@Test
119117
fun previewAndSubmitEudiEhicSdJwtAgainstEudi() = runBlocking {
120118
previewAndSubmitEudiCredential(EUDI_EHIC_SD_JWT_CREDENTIAL_ID)

waltid-libraries/protocols/waltid-openid4vc-wallet-mobile/src/commonMain/kotlin/id/walt/wallet2/mobile/MobileWalletPresentationModels.kt

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,7 @@ public data class MobileWalletPresentationPreview(
1313
public val credentialOptions: List<MobileWalletPresentationCredentialOption>,
1414
public val credentialRequirements: List<MobileWalletPresentationCredentialRequirement> = emptyList(),
1515
public val encryption: MobileWalletEncryptionInfo = MobileWalletEncryptionInfo.NotRequired,
16-
) {
17-
/** Binary/source compatibility constructor matching the pre-encryption API. */
18-
public constructor(
19-
request: MobileWalletPresentationRequestInfo,
20-
credentialOptions: List<MobileWalletPresentationCredentialOption>,
21-
credentialRequirements: List<MobileWalletPresentationCredentialRequirement>,
22-
) : this(request, credentialOptions, credentialRequirements, MobileWalletEncryptionInfo.NotRequired)
23-
}
16+
)
2417

2518
/** Authenticated encryption requirements for an OpenID4VP response (OID4VP 1.0 §8.3). */
2619
public sealed interface MobileWalletEncryptionInfo {
@@ -82,17 +75,7 @@ public data class MobileWalletPresentationRequestInfo(
8275
val nonce: String?,
8376
val transactionData: List<MobileWalletTransactionDataItem> = emptyList(),
8477
val responseMode: String? = null,
85-
) {
86-
/** Binary/source compatibility constructor matching the pre-response-mode API. */
87-
public constructor(
88-
clientId: String?,
89-
verifierName: String?,
90-
responseUri: String?,
91-
state: String?,
92-
nonce: String?,
93-
transactionData: List<MobileWalletTransactionDataItem>,
94-
) : this(clientId, verifierName, responseUri, state, nonce, transactionData, null)
95-
}
78+
)
9679

9780
/**
9881
* A wallet credential that satisfies one DCQL credential query in the presentation request.

waltid-libraries/protocols/waltid-openid4vp-wallet/src/commonMain/kotlin/id/waltid/openid4vp/wallet/request/AuthorizationRequestResolver.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,9 +497,7 @@ object AuthorizationRequestResolver {
497497
private fun requireHttpsRequestUri(requestUri: String) {
498498
val url = runCatching { Url(requestUri) }
499499
.getOrElse { error -> throw IllegalArgumentException("request_uri must be a valid HTTPS URL", error) }
500-
val isLoopbackHttp = url.protocol == URLProtocol.HTTP &&
501-
url.host.lowercase() in setOf("localhost", "127.0.0.1", "::1")
502-
require(url.protocol == URLProtocol.HTTPS || isLoopbackHttp) {
500+
require(url.protocol == URLProtocol.HTTPS) {
503501
"request_uri_method=post requires an HTTPS request_uri"
504502
}
505503
}

waltid-libraries/protocols/waltid-openid4vp-wallet/src/jvmTest/kotlin/id/waltid/openid4vp/wallet/request/AuthorizationRequestResolverJvmTest.kt

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -412,27 +412,36 @@ class AuthorizationRequestResolverJvmTest {
412412

413413
@Test
414414
fun `request uri post requires HTTPS before fetch and after redirects`() {
415-
val insecureRequest = URLBuilder("openid4vp://authorize").apply {
416-
parameters.append("client_id", "verifier2")
417-
parameters.append("request_uri", "http://verifier.example/request.jwt")
418-
parameters.append("request_uri_method", "post")
419-
}.build()
420-
var fetchCalled = false
421-
assertFailsWith<IllegalArgumentException> {
422-
runBlocking {
423-
AuthorizationRequestResolver.resolve(
424-
insecureRequest,
425-
AuthorizationRequestResolver.UnsignedRequestObjectPolicy.ALLOW_UNSIGNED,
426-
) { _, _ ->
427-
fetchCalled = true
428-
error("must not fetch")
415+
listOf(
416+
"http://verifier.example/request.jwt",
417+
"http://localhost/request.jwt",
418+
"http://127.0.0.1/request.jwt",
419+
"http://[::1]/request.jwt",
420+
).forEach { insecureRequestUri ->
421+
val insecureRequest = URLBuilder("openid4vp://authorize").apply {
422+
parameters.append("client_id", "verifier2")
423+
parameters.append("request_uri", insecureRequestUri)
424+
parameters.append("request_uri_method", "post")
425+
}.build()
426+
var fetchCalled = false
427+
assertFailsWith<IllegalArgumentException>(insecureRequestUri) {
428+
runBlocking {
429+
AuthorizationRequestResolver.resolve(
430+
insecureRequest,
431+
AuthorizationRequestResolver.UnsignedRequestObjectPolicy.ALLOW_UNSIGNED,
432+
) { _, _ ->
433+
fetchCalled = true
434+
error("must not fetch")
435+
}
429436
}
430437
}
438+
assertFalse(fetchCalled, insecureRequestUri)
431439
}
432-
assertFalse(fetchCalled)
433440

434-
val secureRequest = URLBuilder(insecureRequest).apply {
435-
parameters["request_uri"] = "https://verifier.example/request.jwt"
441+
val secureRequest = URLBuilder("openid4vp://authorize").apply {
442+
parameters.append("client_id", "verifier2")
443+
parameters.append("request_uri", "https://verifier.example/request.jwt")
444+
parameters.append("request_uri_method", "post")
436445
}.build()
437446
val failure = assertFailsWith<IllegalArgumentException> {
438447
runBlocking {

waltid-services/waltid-wallet-api/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ dependencies {
143143
testImplementation(identityLibs.junit.jupiter.params)
144144
testImplementation(kotlin("test"))
145145
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
146+
testImplementation(identityLibs.ktor.client.mock)
146147
testImplementation(identityLibs.ktor.server.test.host)
147148
testImplementation("io.mockk:mockk:1.14.9")
148149
testImplementation(identityLibs.klogging)

waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/exchange/OpenId4VpPresentationService.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class OpenId4VpPresentationService(
3939
private val credentialService: CredentialsService,
4040
private val unsignedRequestObjectPolicy: AuthorizationRequestResolver.UnsignedRequestObjectPolicy =
4141
AuthorizationRequestResolver.UnsignedRequestObjectPolicy.REQUIRE_SIGNED,
42+
private val requestUriDataFetcher: WebDataFetcher = defaultRequestUriDataFetcher,
4243
) {
4344
private val logger = KotlinLogging.logger { }
4445
private val json = Json {
@@ -59,7 +60,7 @@ class OpenId4VpPresentationService(
5960
enforceFinalRequestObject = false,
6061
) { requestUri, requestUriMethod ->
6162
AuthorizationRequestResolver.fetchRequestUriWithWebDataFetcher(
62-
webResolveAuthReq = webResolveAuthReq,
63+
webResolveAuthReq = requestUriDataFetcher,
6364
requestUri = requestUri,
6465
requestUriMethod = requestUriMethod,
6566
requestUriPostWalletMetadata = runtimeRequestUriPostWalletMetadata,
@@ -198,7 +199,8 @@ class OpenId4VpPresentationService(
198199
}
199200

200201
companion object {
201-
private val webResolveAuthReq = WebDataFetcher(WebDataFetcherId.OPENID4VP_WALLET_RESOLVE_AUTHORIZATIONREQUEST)
202+
private val defaultRequestUriDataFetcher =
203+
WebDataFetcher(WebDataFetcherId.OPENID4VP_WALLET_RESOLVE_AUTHORIZATIONREQUEST)
202204

203205
fun isOpenId4VpRequestCandidate(request: String): Boolean = runCatching {
204206
val parameters = Url(request).parameters

0 commit comments

Comments
 (0)