Skip to content

Commit

Permalink
Refactor wallet code
Browse files Browse the repository at this point in the history
  • Loading branch information
cobward committed Jul 26, 2024
1 parent d9661e2 commit 321434a
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 263 deletions.
23 changes: 5 additions & 18 deletions src/core/authorization_request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use serde::{Deserialize, Serialize};
use serde_json::Value as Json;
use url::Url;

use crate::wallet::Wallet;

use self::{
parameters::{
ClientId, ClientIdScheme, Nonce, PresentationDefinition, PresentationDefinitionUri,
Expand All @@ -15,7 +17,6 @@ use self::{

use super::{
object::{ParsingErrorContext, UntypedObject},
profile::Wallet,
util::default_http_client,
};

Expand Down Expand Up @@ -64,9 +65,9 @@ impl AuthorizationRequest {
/// [RequestObject].
///
/// Custom wallet metadata can be provided, otherwise the default metadata for this profile is used.
pub async fn validate_with_http_client<WP: Wallet + ?Sized>(
pub async fn validate_with_http_client<W: Wallet + ?Sized>(
self,
wallet_profile: &WP,
wallet: &W,
http_client: &reqwest::Client,
) -> Result<AuthorizationRequestObject> {
let jwt = match self.request_indirection {
Expand All @@ -82,7 +83,7 @@ impl AuthorizationRequest {
.await
.context(format!("failed to parse data from {url}"))?,
};
let aro = verify_request(wallet_profile, jwt, http_client)
let aro = verify_request(wallet, jwt, http_client)
.await
.context("unable to validate Authorization Request")?;
if self.client_id.as_str() != aro.client_id().0.as_str() {
Expand All @@ -95,20 +96,6 @@ impl AuthorizationRequest {
Ok(aro)
}

/// Validate the [AuthorizationRequest] according to the client_id scheme and return the parsed
/// [RequestObject].
///
/// Custom wallet metadata can be provided, otherwise the default metadata for this profile is used.
///
/// This method uses the library default http client to fetch the request object if it is passed by reference.
pub async fn validate<WP: Wallet + ?Sized>(
self,
wallet_profile: &WP,
) -> Result<AuthorizationRequestObject> {
self.validate_with_http_client(wallet_profile, &default_http_client()?)
.await
}

/// Encode as [Url], using the `authorization_endpoint` as a base.
/// ```
/// # use oid4vp::core::authorization_request::AuthorizationRequest;
Expand Down
94 changes: 52 additions & 42 deletions src/core/authorization_request/verification/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use crate::core::{
metadata::{
parameters::{
verifier::{AuthorizationEncryptedResponseAlg, AuthorizationEncryptedResponseEnc},
wallet::{
AuthorizationEncryptionAlgValuesSupported,
AuthorizationEncryptionEncValuesSupported,
use crate::{
core::{
metadata::{
parameters::{
verifier::{AuthorizationEncryptedResponseAlg, AuthorizationEncryptedResponseEnc},
wallet::{
AuthorizationEncryptionAlgValuesSupported,
AuthorizationEncryptionEncValuesSupported,
},
},
WalletMetadata,
},
WalletMetadata,
object::{ParsingErrorContext, TypedParameter, UntypedObject},
},
object::{ParsingErrorContext, TypedParameter, UntypedObject},
profile::{Profile, Wallet},
wallet::Wallet,
};
use anyhow::{bail, Context, Error, Result};
use async_trait::async_trait;
Expand All @@ -25,103 +27,113 @@ pub mod x509_san_dns;
pub mod x509_san_uri;

/// Verifies Authorization Request Objects.
#[allow(unused_variables)]
#[async_trait]
pub trait RequestVerification {
pub trait RequestVerifier {
/// Performs verification on Authorization Request Objects when `client_id_scheme` is `did`.
async fn did(
&self,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'did' client verification not implemented")
}

/// Performs verification on Authorization Request Objects when `client_id_scheme` is `entity_id`.
async fn entity_id(
&self,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'entity' client verification not implemented")
}

/// Performs verification on Authorization Request Objects when `client_id_scheme` is `pre-registered`.
async fn preregistered(
&self,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'pre-registered' client verification not implemented")
}

/// Performs verification on Authorization Request Objects when `client_id_scheme` is `redirect_uri`.
async fn redirect_uri(
&self,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'redirect_uri' client verification not implemented")
}

/// Performs verification on Authorization Request Objects when `client_id_scheme` is `verifier_attestation`.
async fn verifier_attestation(
&self,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'verifier_attestation' client verification not implemented")
}

/// Performs verification on Authorization Request Objects when `client_id_scheme` is `x509_san_dns`.
async fn x509_san_dns(
&self,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'x509_san_dns' client verification not implemented")
}

/// Performs verification on Authorization Request Objects when `client_id_scheme` is `x509_san_uri`.
async fn x509_san_uri(
&self,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'x509_san_uri' client verification not implemented")
}

/// Performs verification on Authorization Request Objects when `client_id_scheme` is any other value.
async fn other(
&self,
client_id_scheme: &str,
decoded_request: &AuthorizationRequestObject,
request_jwt: String,
) -> Result<(), Error>;
) -> Result<(), Error> {
bail!("'{client_id_scheme}' client verification not implemented")
}
}

pub(crate) async fn verify_request<WP: Wallet + ?Sized>(
profile: &WP,
pub(crate) async fn verify_request<W: Wallet + ?Sized>(
wallet: &W,
jwt: String,
http_client: &reqwest::Client,
) -> Result<AuthorizationRequestObject> {
let request: AuthorizationRequestObject = ssi::jwt::decode_unverified::<UntypedObject>(&jwt)
.context("unable to decode Authorization Request Object JWT")?
.try_into()?;

validate_request_against_metadata::<WP>(
profile,
&request,
profile.wallet_metadata(),
http_client,
)
.await?;
validate_request_against_metadata(wallet.wallet_metadata(), &request, http_client).await?;

let client_id_scheme = request.client_id_scheme();

match client_id_scheme {
ClientIdScheme::Did => profile.did(&request, jwt).await?,
ClientIdScheme::EntityId => profile.entity_id(&request, jwt).await?,
ClientIdScheme::PreRegistered => profile.preregistered(&request, jwt).await?,
ClientIdScheme::RedirectUri => profile.redirect_uri(&request, jwt).await?,
ClientIdScheme::VerifierAttestation => profile.verifier_attestation(&request, jwt).await?,
ClientIdScheme::X509SanDns => profile.x509_san_dns(&request, jwt).await?,
ClientIdScheme::X509SanUri => profile.x509_san_uri(&request, jwt).await?,
ClientIdScheme::Other(scheme) => profile.other(scheme, &request, jwt).await?,
ClientIdScheme::Did => wallet.did(&request, jwt).await?,
ClientIdScheme::EntityId => wallet.entity_id(&request, jwt).await?,
ClientIdScheme::PreRegistered => wallet.preregistered(&request, jwt).await?,
ClientIdScheme::RedirectUri => wallet.redirect_uri(&request, jwt).await?,
ClientIdScheme::VerifierAttestation => wallet.verifier_attestation(&request, jwt).await?,
ClientIdScheme::X509SanDns => wallet.x509_san_dns(&request, jwt).await?,
ClientIdScheme::X509SanUri => wallet.x509_san_uri(&request, jwt).await?,
ClientIdScheme::Other(scheme) => wallet.other(scheme, &request, jwt).await?,
};

Ok(request)
}

pub(crate) async fn validate_request_against_metadata<P: Profile + ?Sized>(
profile: &P,
request: &AuthorizationRequestObject,
pub(crate) async fn validate_request_against_metadata(
wallet_metadata: &WalletMetadata,
request: &AuthorizationRequestObject,
http_client: &reqwest::Client,
) -> Result<(), Error> {
let client_id_scheme = request.client_id_scheme();
Expand Down Expand Up @@ -174,7 +186,5 @@ pub(crate) async fn validate_request_against_metadata<P: Profile + ?Sized>(
}
}

profile
.validate_request(wallet_metadata, request)
.context("unable to validate request according to profile-specific checks:")
Ok(())
}
1 change: 0 additions & 1 deletion src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ pub mod authorization_request;
pub mod credential_format;
pub mod metadata;
pub mod object;
pub mod profile;
pub mod response;
pub(crate) mod util;
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod core;
pub mod presentation_exchange;
pub mod utils;
mod utils;
pub mod verifier;
pub mod wallet;
16 changes: 8 additions & 8 deletions src/presentation_exchange.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::utils::NonEmptyVec;
pub use crate::utils::NonEmptyVec;
use serde::{Deserialize, Serialize};
use serde_json::Map;

Expand Down Expand Up @@ -101,10 +101,10 @@ pub struct DescriptorMap {

#[derive(Deserialize)]
pub struct SubmissionRequirementBaseBase {
_name: Option<String>,
_purpose: Option<String>,
pub name: Option<String>,
pub purpose: Option<String>,
#[serde(flatten)]
_property_set: Option<Map<String, serde_json::Value>>,
pub property_set: Option<Map<String, serde_json::Value>>,
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -132,10 +132,10 @@ pub enum SubmissionRequirement {
#[derive(Deserialize)]
pub struct SubmissionRequirementPick {
#[serde(flatten)]
_submission_requirement: SubmissionRequirementBase,
_count: Option<u64>,
_min: Option<u64>,
_max: Option<u64>,
pub submission_requirement: SubmissionRequirementBase,
pub count: Option<u64>,
pub min: Option<u64>,
pub max: Option<u64>,
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 321434a

Please sign in to comment.