Skip to content

Commit

Permalink
Fix: Support for client_metadata_uri
Browse files Browse the repository at this point in the history
  • Loading branch information
josmilan committed Nov 4, 2024
1 parent c5150e0 commit 32ac087
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ data class PresentationRequest(
@SerializedName("response_uri") var responseUri: String? = null,
@SerializedName("presentation_definition") var presentationDefinition: Any? = null,
@SerializedName("presentation_definition_uri") var presentationDefinitionUri: String? = null,
@SerializedName("client_metadata") var clientMetaDetails: Any? = null
@SerializedName("client_metadata") var clientMetaDetails: Any? = null,
@SerializedName("client_metadata_uri") var clientMetadataUri: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ class IssueService : IssueServiceInterface {
location
} else if (location != null && (Uri.parse(location).getQueryParameter("code") != null
|| Uri.parse(location).getQueryParameter("presentation_definition") != null
|| Uri.parse(location).getQueryParameter("presentation_definition_uri") != null
|| (Uri.parse(location).getQueryParameter("request_uri") != null &&
Uri.parse(location).getQueryParameter("response_type") == null &&
Uri.parse(location).getQueryParameter("state") == null))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import com.ewc.eudi_wallet_oidc_android.models.AuthorisationServerWellKnownConfi
import com.ewc.eudi_wallet_oidc_android.models.CredentialRequest
import com.ewc.eudi_wallet_oidc_android.models.CredentialResponse
import com.ewc.eudi_wallet_oidc_android.models.DIDDocument
import com.ewc.eudi_wallet_oidc_android.models.IssuerWellKnownConfiguration
import com.ewc.eudi_wallet_oidc_android.models.ParResponse
import com.ewc.eudi_wallet_oidc_android.models.PresentationDefinition
import com.ewc.eudi_wallet_oidc_android.models.TokenResponse
import com.ewc.eudi_wallet_oidc_android.models.v2.DeferredCredentialRequestV2
import okhttp3.ResponseBody
Expand Down Expand Up @@ -84,7 +82,7 @@ interface ApiService {
suspend fun getPresentationDefinitionFromRequestUri(@Url url: String): Response<ResponseBody>

@GET
suspend fun getPresentationDefinitionFromPresentationDefinitionUri(@Url url: String): Response<ResponseBody>
suspend fun resolveUrl(@Url url: String): Response<ResponseBody>

@FormUrlEncoded
@POST("")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.ewc.eudi_wallet_oidc_android.services.utils

import com.nimbusds.jose.shaded.json.parser.ParseException
import com.nimbusds.jwt.SignedJWT

object JwtUtils {
fun isValidJWT(token: String?): Boolean {
if (token.isNullOrBlank())
return false
try {
// Parse the JWT token
val parsedJWT = SignedJWT.parse(token)
return parsedJWT.payload != null
} catch (e: Exception) {
println("JWT parsing failed: ${e.message}")
return false
}
}

@Throws(ParseException::class)
fun parseJWTForPayload(accessToken: String?): String {
if (accessToken.isNullOrBlank())
throw java.lang.Exception("Invalid token!")
try {
val decodedJWT = SignedJWT.parse(accessToken)
return decodedJWT.payload.toString()
} catch (e: ParseException) {
throw java.lang.Exception(e.message ?: "Invalid token!")
} catch (e: Exception){
throw java.lang.Exception("Invalid token!")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import com.ewc.eudi_wallet_oidc_android.services.issue.IssueService
import com.ewc.eudi_wallet_oidc_android.services.network.ApiManager
import com.ewc.eudi_wallet_oidc_android.services.sdjwt.SDJWTService
import com.ewc.eudi_wallet_oidc_android.services.utils.CborUtils
import com.ewc.eudi_wallet_oidc_android.services.utils.JwtUtils.isValidJWT
import com.ewc.eudi_wallet_oidc_android.services.utils.JwtUtils.parseJWTForPayload
import com.github.decentraliseddataexchange.presentationexchangesdk.PresentationExchange
import com.github.decentraliseddataexchange.presentationexchangesdk.models.MatchedCredential
import com.google.gson.Gson
Expand Down Expand Up @@ -56,6 +58,9 @@ class VerificationService : VerificationServiceInterface {
override suspend fun processAuthorisationRequest(data: String?): PresentationRequest? {
if (data.isNullOrBlank())
return null

val gson = Gson()

val clientId = Uri.parse(data).getQueryParameter("client_id")
val state = Uri.parse(data).getQueryParameter("state")
val redirectUri = Uri.parse(data).getQueryParameter("redirect_uri")
Expand All @@ -68,14 +73,15 @@ class VerificationService : VerificationServiceInterface {
val requestUri = Uri.parse(data).getQueryParameter("request_uri")
val responseUri = Uri.parse(data).getQueryParameter("response_uri")
val responseMode = Uri.parse(data).getQueryParameter("response_mode")
val clientMetadataUri = Uri.parse(data).getQueryParameter("client_metadata_uri")
val clientMetadataJson = Uri.parse(data).getQueryParameter("client_metadata")
val clientMetadetails: ClientMetaDetails? = if (!clientMetadataJson.isNullOrBlank()) {
Gson().fromJson(clientMetadataJson, ClientMetaDetails::class.java)
gson.fromJson(clientMetadataJson, ClientMetaDetails::class.java)
} else {
null
}
if (presentationDefinition != null) {
return PresentationRequest(
if (presentationDefinition != null || presentationDefinitionUri != null) {
val presentationRequest = PresentationRequest(
clientId = clientId,
state = state,
redirectUri = redirectUri,
Expand All @@ -89,30 +95,23 @@ class VerificationService : VerificationServiceInterface {
responseUri = responseUri,
clientMetaDetails = clientMetadetails
)
} else if (presentationDefinitionUri != null) {
val resolvedPresentationDefinition = getPresentationDefinitionFromDefinitionUri(presentationDefinitionUri)
return PresentationRequest(
clientId = clientId,
state = state,
redirectUri = redirectUri,
nonce = nonce,
presentationDefinition = resolvedPresentationDefinition,
presentationDefinitionUri = presentationDefinitionUri,
responseMode = responseMode,
responseType = responseType,
scope = scope,
requestUri = requestUri,
responseUri = responseUri,
clientMetaDetails = clientMetadetails
)
if (presentationDefinition.isNullOrBlank() && !presentationDefinitionUri.isNullOrBlank()){
val resolvedPresentationDefinition = getPresentationDefinitionFromDefinitionUri(presentationDefinitionUri)
presentationRequest.presentationDefinition = resolvedPresentationDefinition
}
if (clientMetadataJson.isNullOrBlank() && !clientMetadataUri.isNullOrBlank()){
val resolvedClientMetaData = getClientMetaDataFromClientMetaDataUri(clientMetadataUri)
presentationRequest.clientMetaDetails = resolvedClientMetaData
}
return presentationRequest
} else if (!requestUri.isNullOrBlank() || !responseUri.isNullOrBlank()) {
val response =
ApiManager.api.getService()
?.getPresentationDefinitionFromRequestUri(requestUri ?: responseUri ?: "")
if (response?.isSuccessful == true) {
val contentType = response.headers()["Content-Type"]
val responseString = response.body()?.string()
val gson = Gson()

if (contentType?.contains("application/json") == true) {
val json = gson.fromJson(
responseString,
Expand All @@ -122,6 +121,10 @@ class VerificationService : VerificationServiceInterface {
val resolvedPresentationDefinition = getPresentationDefinitionFromDefinitionUri(json.presentationDefinitionUri)
json.presentationDefinition = resolvedPresentationDefinition
}
if (json.clientMetaDetails == null && !json.clientMetadataUri.isNullOrBlank()){
val resolvedClientMetaDetails = getClientMetaDataFromClientMetaDataUri(json.clientMetadataUri)
json.clientMetaDetails = resolvedClientMetaDetails
}
return json
}else{
if (isValidJWT(responseString?:"")) {
Expand All @@ -133,6 +136,10 @@ class VerificationService : VerificationServiceInterface {
val resolvedPresentationDefinition = getPresentationDefinitionFromDefinitionUri(json.presentationDefinitionUri)
json.presentationDefinition = resolvedPresentationDefinition
}
if (json.clientMetaDetails == null && !json.clientMetadataUri.isNullOrBlank()){
val resolvedClientMetaDetails = getClientMetaDataFromClientMetaDataUri(json.clientMetadataUri)
json.clientMetaDetails = resolvedClientMetaDetails
}
return json
}else{
val json = gson.fromJson(
Expand All @@ -143,21 +150,30 @@ class VerificationService : VerificationServiceInterface {
val resolvedPresentationDefinition = getPresentationDefinitionFromDefinitionUri(json.presentationDefinitionUri)
json.presentationDefinition = resolvedPresentationDefinition
}
if (json.clientMetaDetails == null && !json.clientMetadataUri.isNullOrBlank()){
val resolvedClientMetaDetails = getClientMetaDataFromClientMetaDataUri(json.clientMetadataUri)
json.clientMetaDetails = resolvedClientMetaDetails
}
return json
}
}
} else {
return null
}
} else if (isValidJWT(data)) {
val split = data.split(".")
var payload: String? = null
if (split.size == 3) {
payload = split[1]
return Gson().fromJson(payload, PresentationRequest::class.java)
} else {
return null
val json = gson.fromJson(
parseJWTForPayload(data?:"{}"),
PresentationRequest::class.java
)
if (json.presentationDefinition == null && !json.presentationDefinitionUri.isNullOrBlank()){
val resolvedPresentationDefinition = getPresentationDefinitionFromDefinitionUri(json.presentationDefinitionUri)
json.presentationDefinition = resolvedPresentationDefinition
}
if (json.clientMetaDetails == null && !json.clientMetadataUri.isNullOrBlank()){
val resolvedClientMetaDetails = getClientMetaDataFromClientMetaDataUri(json.clientMetadataUri)
json.clientMetaDetails = resolvedClientMetaDetails
}
return json
} else {
return null
}
Expand All @@ -169,7 +185,7 @@ class VerificationService : VerificationServiceInterface {

val response =
ApiManager.api.getService()
?.getPresentationDefinitionFromPresentationDefinitionUri(presentationDefinitionUri ?: "")
?.resolveUrl(presentationDefinitionUri ?: "")
if (response?.isSuccessful == true) {
val contentType = response.headers()["Content-Type"]
val responseString = response.body()?.string()
Expand Down Expand Up @@ -200,24 +216,43 @@ class VerificationService : VerificationServiceInterface {
}
}

private fun isValidJWT(token: String): Boolean {
try {
// Parse the JWT token
val parsedJWT = SignedJWT.parse(token)
return parsedJWT.payload != null
} catch (e: Exception) {
println("JWT parsing failed: ${e.message}")
return false
}
}
private suspend fun getClientMetaDataFromClientMetaDataUri(clientMetadataUri:String?):ClientMetaDetails?{
if (clientMetadataUri.isNullOrBlank())
return null

@Throws(ParseException::class)
private fun parseJWTForPayload(accessToken: String): String {
try {
val decodedJWT = SignedJWT.parse(accessToken)
return decodedJWT.payload.toString()
} catch (e: ParseException) {
throw java.lang.Exception("Invalid token!")
val response =
ApiManager.api.getService()?.resolveUrl(clientMetadataUri ?: "")
if (response?.isSuccessful == true) {
try {
val contentType = response.headers()["Content-Type"]
val responseString = response.body()?.string()
val gson = Gson()
if (contentType?.contains("application/json") == true) {
val json = gson.fromJson(
responseString,
ClientMetaDetails::class.java
)
return json
}else{
if (isValidJWT(responseString?:"")) {
val json = gson.fromJson(
parseJWTForPayload(responseString?:"{}"),
ClientMetaDetails::class.java
)
return json
}else{
val json = gson.fromJson(
responseString?:"{}",
ClientMetaDetails::class.java
)
return json
}
}
} catch (e: Exception) {
return null
}
} else {
return null
}
}

Expand Down Expand Up @@ -336,6 +371,25 @@ class VerificationService : VerificationServiceInterface {
)

val tokenResponse = when {
response?.code() == 200 ->{
val redirectUri = response.body()?.string()
val gson = Gson()
try {
val vpTokenResponse =
gson.fromJson(redirectUri, VPTokenResponse::class.java)
return WrappedVpTokenResponse(
vpTokenResponse = VPTokenResponse(
location = vpTokenResponse.redirectUri ?: "https://www.example.com?code=1"
)
)
} catch (e: Exception) {
return WrappedVpTokenResponse(
vpTokenResponse = VPTokenResponse(
location ="https://www.example.com?code=1"
)
)
}
}
response?.code() == 302 || response?.code() == 200 -> {
val locationHeader = response.headers()["Location"]
if (locationHeader?.contains("error=") == true) {
Expand Down Expand Up @@ -619,7 +673,10 @@ class VerificationService : VerificationServiceInterface {
val descriptor = DescriptorMap(
id = inputDescriptors.id,
path = "$",
format = presentationDefinition.format?.keys?.firstOrNull() ?: "jwt_vp",
format =
presentationDefinition.format?.keys?.firstOrNull() ?:
inputDescriptors.format?.keys?.firstOrNull() ?:
"jwt_vp",
pathNested = PathNested(
id = inputDescriptors.id,
format = "jwt_vc",
Expand Down

0 comments on commit 32ac087

Please sign in to comment.