From 7b5f2a68de8986dd3c289fa32770e62212517b34 Mon Sep 17 00:00:00 2001 From: "Josep Milan K.A" Date: Mon, 21 Oct 2024 16:15:58 +0530 Subject: [PATCH] Fix: Support for presentation_defintion_uri and client_metadata_uri in OpenID4VP --- .../Model/PresentationRequest.swift | 10 ++- .../Service/IssueService.swift | 16 ++-- .../Service/VerificationService.swift | 74 +++++++++++++++++-- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/Sources/eudiWalletOidcIos/Model/PresentationRequest.swift b/Sources/eudiWalletOidcIos/Model/PresentationRequest.swift index a1a8c06..768945d 100644 --- a/Sources/eudiWalletOidcIos/Model/PresentationRequest.swift +++ b/Sources/eudiWalletOidcIos/Model/PresentationRequest.swift @@ -10,6 +10,8 @@ public struct PresentationRequest: Codable { public var responseUri: String? public var presentationDefinition: String? public var clientMetaData: String? + public var presentationDefinitionUri: String? + public var clientMetaDataUri: String? enum CodingKeys: String, CodingKey { case state = "state" case clientId = "client_id" @@ -22,8 +24,10 @@ public struct PresentationRequest: Codable { case requestUri = "request_uri" case presentationDefinition = "presentation_definition" case clientMetaData = "client_metadata" + case presentationDefinitionUri = "presentation_definition_uri" + case clientMetaDataUri = "client_metadata_uri" } - public init(state: String?, clientId: String?, redirectUri: String?, responseUri: String?, responseType: String?, responseMode: String?, scope: String?, nonce: String?, requestUri: String?, presentationDefinition: String?, clientMetaData: String?) { + public init(state: String?, clientId: String?, redirectUri: String?, responseUri: String?, responseType: String?, responseMode: String?, scope: String?, nonce: String?, requestUri: String?, presentationDefinition: String?, clientMetaData: String?, presentationDefinitionUri: String?, clientMetaDataUri: String?) { self.state = state self.clientId = clientId self.redirectUri = redirectUri @@ -35,6 +39,8 @@ public struct PresentationRequest: Codable { self.requestUri = requestUri self.presentationDefinition = presentationDefinition self.clientMetaData = clientMetaData + self.presentationDefinitionUri = presentationDefinitionUri + self.clientMetaDataUri = clientMetaDataUri } public init(from decoder: Decoder) throws { @@ -59,6 +65,8 @@ public struct PresentationRequest: Codable { if let clientMetaDataModel = try? container.decode(ClientMetaData.self, forKey: . clientMetaData) { clientMetaData = clientMetaDataModel.toJSONString() } + presentationDefinitionUri = try container.decodeIfPresent(String.self, forKey: .presentationDefinitionUri) + clientMetaDataUri = try container.decodeIfPresent(String.self, forKey: .clientMetaDataUri) } } public struct ClientMetaData: Codable { diff --git a/Sources/eudiWalletOidcIos/Service/IssueService.swift b/Sources/eudiWalletOidcIos/Service/IssueService.swift index a7e2956..e1bc633 100644 --- a/Sources/eudiWalletOidcIos/Service/IssueService.swift +++ b/Sources/eudiWalletOidcIos/Service/IssueService.swift @@ -319,7 +319,7 @@ public class IssueService: NSObject, IssueServiceProtocol { if responseUrl.contains("code=") || responseUrl.contains("error=") || - responseUrl.contains("presentation_definition=") || + responseUrl.contains("presentation_definition=") || responseUrl.contains("presentation_definition_uri=") || (responseUrl.contains("request_uri=") && !responseUrl.contains("response_type=") && !responseUrl.contains("state=")){ return responseUrl } else { @@ -542,7 +542,7 @@ public class IssueService: NSObject, IssueServiceProtocol { if types is String { params = [ "vct": types ?? "", - "format": format ?? "jwt_vc", + "format": formatT ?? "jwt_vc", "proof": [ "proof_type": "jwt", "jwt": idToken @@ -551,9 +551,9 @@ public class IssueService: NSObject, IssueServiceProtocol { }else{ params = [ "credential_definition": [ - "type": types + "type": types ?? [] ], - "format": format ?? "jwt_vc", + "format": formatT ?? "jwt_vc", "proof": [ "proof_type": "jwt", "jwt": idToken @@ -563,7 +563,7 @@ public class IssueService: NSObject, IssueServiceProtocol { if credentialOffer.credentials?[0].trustFramework != nil { params = [ "types": credentialTypes, - "format": formatT, + "format": formatT ?? "jwt_vc", "proof": [ "proof_type": "jwt", "jwt": idToken @@ -575,9 +575,9 @@ public class IssueService: NSObject, IssueServiceProtocol { if let dataArray = data as? [String] { params = [ "credential_definition": [ - "type": dataArray + "type": dataArray ?? [] ], - "format": formatT, + "format": formatT ?? "jwt_vc", "proof": [ "proof_type": "jwt", "jwt": idToken @@ -586,7 +586,7 @@ public class IssueService: NSObject, IssueServiceProtocol { } else if let dataString = data as? String { params = [ "vct": dataString, - "format": formatT, + "format": formatT ?? "jwt_vc", "proof": [ "proof_type": "jwt", "jwt": idToken diff --git a/Sources/eudiWalletOidcIos/Service/VerificationService.swift b/Sources/eudiWalletOidcIos/Service/VerificationService.swift index 1283993..652d460 100644 --- a/Sources/eudiWalletOidcIos/Service/VerificationService.swift +++ b/Sources/eudiWalletOidcIos/Service/VerificationService.swift @@ -72,21 +72,22 @@ public class VerificationService: NSObject, VerificationServiceProtocol { if let code = data { let state = URL(string: code)?.queryParameters?["state"] ?? "" let nonce = URL(string: code)?.queryParameters?["nonce"] ?? "" - let redirectUri = URL(string: code)?.queryParameters?["redirect_uri"] ?? "" + let responseUri = URL(string: code)?.queryParameters?["response_uri"] ?? "" + let redirectUri = URL(string: code)?.queryParameters?["redirect_uri"] ?? responseUri let clientID = URL(string: code)?.queryParameters?["client_id"] ?? "" let responseType = URL(string: code)?.queryParameters?["response_type"] ?? "" let scope = URL(string: code)?.queryParameters?["scope"] ?? "" let requestUri = URL(string: code)?.queryParameters?["request_uri"] ?? "" - let responseUri = URL(string: code)?.queryParameters?["response_uri"] ?? "" let responseMode = URL(string: code)?.queryParameters?["response_mode"] ?? "" var presentationDefinition = URL(string: code)?.queryParameters?["presentation_definition"] ?? "" var clientMetaData = URL(string: code)?.queryParameters?["client_metadata"] ?? "" + var presentationDefinitionUri = URL(string: code)?.queryParameters?["presentation_definition_uri"] ?? "" + var clientMetaDataUri = URL(string: code)?.queryParameters?["client_metadata_uri"] ?? "" - if presentationDefinition != "" { - - let presentationRequest = PresentationRequest(state: state, + if presentationDefinition != "" || presentationDefinitionUri != "" { + var presentationRequest = PresentationRequest(state: state, clientId: clientID, - redirectUri: redirectUri, + redirectUri: redirectUri ?? responseUri, responseUri: responseUri, responseType: responseType, responseMode: responseMode, @@ -94,8 +95,17 @@ public class VerificationService: NSObject, VerificationServiceProtocol { nonce: nonce, requestUri: requestUri, presentationDefinition: presentationDefinition, - clientMetaData: clientMetaData + clientMetaData: clientMetaData, + presentationDefinitionUri: presentationDefinitionUri, clientMetaDataUri: clientMetaDataUri ) + if presentationDefinition == "" && presentationDefinitionUri != "" { + let presentationDefinitionFromUri = await resolvePresentationDefinitionFromURI(url: presentationDefinitionUri) + presentationRequest.presentationDefinition = presentationDefinitionFromUri + } + if clientMetaData == "" && clientMetaDataUri != "" { + let clientMetaDataFromUri = await resolveClientMetaDataFromURI(url: clientMetaDataUri) + presentationRequest.clientMetaData = clientMetaDataFromUri + } return presentationRequest } else if requestUri != "" { @@ -105,7 +115,7 @@ public class VerificationService: NSObject, VerificationServiceProtocol { do { let (data, _) = try await URLSession.shared.data(for: request) let jsonDecoder = JSONDecoder() - let model = try? jsonDecoder.decode(PresentationRequest.self, from: data) + var model = try? jsonDecoder.decode(PresentationRequest.self, from: data) if model == nil { if let jwtString = String(data: data, encoding: .utf8) { do { @@ -126,6 +136,14 @@ public class VerificationService: NSObject, VerificationServiceProtocol { return nil } } + if model?.presentationDefinition == nil && model?.presentationDefinitionUri != "" { + let presentationDefinitionFromUri = await resolvePresentationDefinitionFromURI(url: model?.presentationDefinitionUri) + model?.presentationDefinition = presentationDefinitionFromUri + } + if model?.clientMetaData == nil && model?.clientMetaDataUri != "" { + let clientMetaDataFromUri = await resolveClientMetaDataFromURI(url: model?.clientMetaDataUri) + model?.clientMetaData = clientMetaDataFromUri + } return model } catch { debugPrint("Error:\(error)") @@ -136,6 +154,46 @@ public class VerificationService: NSObject, VerificationServiceProtocol { return nil } + func resolvePresentationDefinitionFromURI(url: String?) async -> String? { + if let uri = URL(string: url ?? "") { + var request = URLRequest(url: uri) + request.httpMethod = "GET" + do { + let (data, _) = try await URLSession.shared.data(for: request) + if let presentationDefinitionFromUri = String(data: data, encoding: .utf8) { + return presentationDefinitionFromUri + } else { + debugPrint("Error: Could not resolve presentation_definition from URI") + return nil + } + } catch { + debugPrint("Error while fetching presentation_definition from URI: \(error)") + return nil + } + } + return nil + } + + func resolveClientMetaDataFromURI(url: String?) async -> String? { + if let uri = URL(string: url ?? "") { + var request = URLRequest(url: uri) + request.httpMethod = "GET" + do { + let (data, _) = try await URLSession.shared.data(for: request) + if let clientMetaDataFromUri = String(data: data, encoding: .utf8) { + return clientMetaDataFromUri + } else { + debugPrint("Error: Could not resolve presentation_definition from URI") + return nil + } + } catch { + debugPrint("Error while fetching presentation_definition from URI: \(error)") + return nil + } + } + return nil + } + private func generateJWTHeader(jwk: [String: Any], did: String) -> String { let methodSpecificId = did.replacingOccurrences(of: "did:key:", with: "")