From ce81ebf85f63c2d82251facf923f9773916f14bb Mon Sep 17 00:00:00 2001 From: Coplat Date: Fri, 7 Feb 2025 16:16:53 +0000 Subject: [PATCH 1/7] refactor: implement 'strum::Display' for all 'DomainEvent's --- Cargo.lock | 8 ++++++++ Cargo.toml | 2 ++ agent_holder/Cargo.toml | 2 ++ agent_holder/src/credential/event.rs | 10 +++------- agent_holder/src/offer/event.rs | 14 +++----------- agent_holder/src/presentation/event.rs | 10 +++------- agent_identity/Cargo.toml | 2 ++ agent_identity/src/connection/event.rs | 10 +++------- agent_identity/src/document/event.rs | 11 +++-------- agent_identity/src/service/event.rs | 11 +++-------- agent_issuance/Cargo.toml | 2 ++ agent_issuance/src/credential/event.rs | 15 ++++----------- agent_issuance/src/offer/event.rs | 16 +++------------- agent_issuance/src/server_config/event.rs | 11 +++-------- agent_verification/Cargo.toml | 2 ++ .../src/authorization_request/event.rs | 13 ++----------- 16 files changed, 48 insertions(+), 91 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b0047b9..8a50d504 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,6 +178,8 @@ dependencies = [ "serde", "serde_json", "serial_test", + "strum 0.26.3", + "strum_macros 0.26.4", "thiserror", "tokio", "tower", @@ -220,6 +222,8 @@ dependencies = [ "serde", "serde_json", "serial_test", + "strum 0.26.3", + "strum_macros 0.26.4", "thiserror", "tokio", "tower", @@ -253,6 +257,8 @@ dependencies = [ "serde", "serde_json", "serial_test", + "strum 0.26.3", + "strum_macros 0.26.4", "thiserror", "tracing", "tracing-test", @@ -355,6 +361,8 @@ dependencies = [ "serde_json", "serial_test", "siopv2", + "strum 0.26.3", + "strum_macros 0.26.4", "thiserror", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index b6772fe2..633a4aa2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,8 @@ serde = { version = "1.0", default-features = false, features = ["derive"] } serde_json = { version = "1.0" } serde_with = "3.7" serde_yaml = "0.9" +strum = "0.26" +strum_macros = "0.26" thiserror = "1.0" tokio = { version = "1", features = ["full"] } tower = { version = "0.4" } diff --git a/agent_holder/Cargo.toml b/agent_holder/Cargo.toml index 0ac7a60e..616a7f7d 100644 --- a/agent_holder/Cargo.toml +++ b/agent_holder/Cargo.toml @@ -18,6 +18,8 @@ oid4vci.workspace = true oid4vc-core.workspace = true serde.workspace = true serde_json.workspace = true +strum.workspace = true +strum_macros.workspace = true thiserror.workspace = true tracing.workspace = true uuid.workspace = true diff --git a/agent_holder/src/credential/event.rs b/agent_holder/src/credential/event.rs index 5797b334..8d60dc08 100644 --- a/agent_holder/src/credential/event.rs +++ b/agent_holder/src/credential/event.rs @@ -1,10 +1,11 @@ use cqrs_es::DomainEvent; use identity_credential::credential::Jwt; use serde::{Deserialize, Serialize}; +use strum::Display; use super::aggregate::Data; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum CredentialEvent { CredentialAdded { holder_credential_id: String, @@ -16,12 +17,7 @@ pub enum CredentialEvent { impl DomainEvent for CredentialEvent { fn event_type(&self) -> String { - use CredentialEvent::*; - - let event_type: &str = match self { - CredentialAdded { .. } => "CredentialAdded", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_holder/src/offer/event.rs b/agent_holder/src/offer/event.rs index 74e2ea29..e57f85c6 100644 --- a/agent_holder/src/offer/event.rs +++ b/agent_holder/src/offer/event.rs @@ -6,8 +6,9 @@ use oid4vci::{ }; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use strum::Display; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum OfferEvent { CredentialOfferReceived { received_offer_id: String, @@ -35,16 +36,7 @@ pub enum OfferEvent { impl DomainEvent for OfferEvent { fn event_type(&self) -> String { - use OfferEvent::*; - - let event_type: &str = match self { - CredentialOfferReceived { .. } => "CredentialOfferReceived", - CredentialOfferAccepted { .. } => "CredentialOfferAccepted", - TokenResponseReceived { .. } => "AccessTokenReceived", - CredentialResponseReceived { .. } => "CredentialResponseReceived", - CredentialOfferRejected { .. } => "CredentialOfferRejected", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_holder/src/presentation/event.rs b/agent_holder/src/presentation/event.rs index 05e552b8..9c0ad6f8 100644 --- a/agent_holder/src/presentation/event.rs +++ b/agent_holder/src/presentation/event.rs @@ -1,8 +1,9 @@ use cqrs_es::DomainEvent; use identity_credential::credential::Jwt; use serde::{Deserialize, Serialize}; +use strum::Display; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum PresentationEvent { PresentationCreated { presentation_id: String, @@ -12,12 +13,7 @@ pub enum PresentationEvent { impl DomainEvent for PresentationEvent { fn event_type(&self) -> String { - use PresentationEvent::*; - - let event_type: &str = match self { - PresentationCreated { .. } => "PresentationCreated", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_identity/Cargo.toml b/agent_identity/Cargo.toml index 37156612..e6ea12af 100644 --- a/agent_identity/Cargo.toml +++ b/agent_identity/Cargo.toml @@ -21,6 +21,8 @@ jsonwebtoken.workspace = true oid4vc-core.workspace = true serde.workspace = true serde_json.workspace = true +strum.workspace = true +strum_macros.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/agent_identity/src/connection/event.rs b/agent_identity/src/connection/event.rs index 558ea6f2..f0266394 100644 --- a/agent_identity/src/connection/event.rs +++ b/agent_identity/src/connection/event.rs @@ -2,8 +2,9 @@ use cqrs_es::DomainEvent; use identity_core::common::Url; use identity_did::DIDUrl; use serde::{Deserialize, Serialize}; +use strum::Display; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum ConnectionEvent { ConnectionAdded { connection_id: String, @@ -16,12 +17,7 @@ pub enum ConnectionEvent { impl DomainEvent for ConnectionEvent { fn event_type(&self) -> String { - use ConnectionEvent::*; - - let event_type: &str = match self { - ConnectionAdded { .. } => "ConnectionAdded", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_identity/src/document/event.rs b/agent_identity/src/document/event.rs index 94e52fbb..6d7151bb 100644 --- a/agent_identity/src/document/event.rs +++ b/agent_identity/src/document/event.rs @@ -1,8 +1,9 @@ use cqrs_es::DomainEvent; use identity_document::document::CoreDocument; use serde::{Deserialize, Serialize}; +use strum::Display; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum DocumentEvent { DocumentCreated { document: CoreDocument }, ServiceAdded { document: CoreDocument }, @@ -10,13 +11,7 @@ pub enum DocumentEvent { impl DomainEvent for DocumentEvent { fn event_type(&self) -> String { - use DocumentEvent::*; - - let event_type: &str = match self { - DocumentCreated { .. } => "DocumentCreated", - ServiceAdded { .. } => "ServiceAdded", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_identity/src/service/event.rs b/agent_identity/src/service/event.rs index d399c189..102ed8f6 100644 --- a/agent_identity/src/service/event.rs +++ b/agent_identity/src/service/event.rs @@ -2,10 +2,11 @@ use cqrs_es::DomainEvent; use derivative::Derivative; use identity_document::service::Service as DocumentService; use serde::{Deserialize, Serialize}; +use strum::Display; use super::aggregate::ServiceResource; -#[derive(Clone, Debug, Deserialize, Serialize, Derivative)] +#[derive(Clone, Debug, Deserialize, Serialize, Derivative, Display)] #[derivative(PartialEq)] pub enum ServiceEvent { DomainLinkageServiceCreated { @@ -23,13 +24,7 @@ pub enum ServiceEvent { impl DomainEvent for ServiceEvent { fn event_type(&self) -> String { - use ServiceEvent::*; - - let event_type: &str = match self { - DomainLinkageServiceCreated { .. } => "DomainLinkageServiceCreated", - LinkedVerifiablePresentationServiceCreated { .. } => "LinkedVerifiablePresentationServiceCreated", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_issuance/Cargo.toml b/agent_issuance/Cargo.toml index ce08e198..c0f24423 100644 --- a/agent_issuance/Cargo.toml +++ b/agent_issuance/Cargo.toml @@ -18,6 +18,8 @@ identity_credential.workspace = true jsonwebtoken.workspace = true oid4vci.workspace = true oid4vc-core.workspace = true +strum.workspace = true +strum_macros.workspace = true reqwest.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/agent_issuance/src/credential/event.rs b/agent_issuance/src/credential/event.rs index 1ebec6c1..2c7496d3 100644 --- a/agent_issuance/src/credential/event.rs +++ b/agent_issuance/src/credential/event.rs @@ -1,10 +1,10 @@ +use super::{aggregate::Status, entity::Data}; use cqrs_es::DomainEvent; use oid4vci::credential_issuer::credential_configurations_supported::CredentialConfigurationsSupportedObject; use serde::{Deserialize, Serialize}; +use strum::Display; -use super::{aggregate::Status, entity::Data}; - -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum CredentialEvent { // TODO: rename to `DataCredentialCreated`? UnsignedCredentialCreated { @@ -25,14 +25,7 @@ pub enum CredentialEvent { impl DomainEvent for CredentialEvent { fn event_type(&self) -> String { - use CredentialEvent::*; - - let event_type: &str = match self { - UnsignedCredentialCreated { .. } => "UnsignedCredentialCreated", - SignedCredentialCreated { .. } => "SignedCredentialCreated", - CredentialSigned { .. } => "CredentialSigned", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_issuance/src/offer/event.rs b/agent_issuance/src/offer/event.rs index 93f2b8a1..ddcddfeb 100644 --- a/agent_issuance/src/offer/event.rs +++ b/agent_issuance/src/offer/event.rs @@ -4,9 +4,10 @@ use oid4vci::{ credential_offer::CredentialOffer, credential_response::CredentialResponse, token_response::TokenResponse, }; use serde::{Deserialize, Serialize}; +use strum::Display; use url::Url; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum OfferEvent { CredentialOfferCreated { offer_id: String, @@ -46,18 +47,7 @@ pub enum OfferEvent { impl DomainEvent for OfferEvent { fn event_type(&self) -> String { - use OfferEvent::*; - - let event_type: &str = match self { - CredentialOfferCreated { .. } => "CredentialOfferCreated", - CredentialsAdded { .. } => "CredentialsAdded", - FormUrlEncodedCredentialOfferCreated { .. } => "FormUrlEncodedCredentialOfferCreated", - CredentialOfferSent { .. } => "CredentialOfferSent", - TokenResponseCreated { .. } => "TokenResponseCreated", - CredentialRequestVerified { .. } => "CredentialRequestVerified", - CredentialResponseCreated { .. } => "CredentialResponseCreated", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_issuance/src/server_config/event.rs b/agent_issuance/src/server_config/event.rs index 56e6078d..eec14590 100644 --- a/agent_issuance/src/server_config/event.rs +++ b/agent_issuance/src/server_config/event.rs @@ -7,8 +7,9 @@ use oid4vci::credential_issuer::{ credential_issuer_metadata::CredentialIssuerMetadata, }; use serde::{Deserialize, Serialize}; +use strum::Display; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Display)] pub enum ServerConfigEvent { ServerMetadataInitialized { authorization_server_metadata: Box, @@ -21,13 +22,7 @@ pub enum ServerConfigEvent { impl DomainEvent for ServerConfigEvent { fn event_type(&self) -> String { - use ServerConfigEvent::*; - - let event_type: &str = match self { - ServerMetadataInitialized { .. } => "ServerMetadataLoaded", - CredentialConfigurationAdded { .. } => "CredentialConfigurationAdded", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { diff --git a/agent_verification/Cargo.toml b/agent_verification/Cargo.toml index 4d0571a4..cecdd788 100644 --- a/agent_verification/Cargo.toml +++ b/agent_verification/Cargo.toml @@ -20,6 +20,8 @@ oid4vp.workspace = true reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } serde.workspace = true serde_json.workspace = true +strum.workspace = true +strum_macros.workspace = true siopv2.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/agent_verification/src/authorization_request/event.rs b/agent_verification/src/authorization_request/event.rs index 2f66ec4e..b57e84c3 100644 --- a/agent_verification/src/authorization_request/event.rs +++ b/agent_verification/src/authorization_request/event.rs @@ -2,7 +2,7 @@ use crate::generic_oid4vc::GenericAuthorizationRequest; use cqrs_es::DomainEvent; use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, strum::Display)] pub enum AuthorizationRequestEvent { AuthorizationRequestCreated { authorization_request: Box, @@ -25,16 +25,7 @@ pub enum AuthorizationRequestEvent { impl DomainEvent for AuthorizationRequestEvent { fn event_type(&self) -> String { - use AuthorizationRequestEvent::*; - - let event_type: &str = match self { - AuthorizationRequestCreated { .. } => "AuthorizationRequestCreated", - FormUrlEncodedAuthorizationRequestCreated { .. } => "FormUrlEncodedAuthorizationRequestCreated", - AuthorizationRequestObjectSigned { .. } => "AuthorizationRequestObjectSigned", - SIOPv2AuthorizationResponseVerified { .. } => "SIOPv2AuthorizationResponseVerified", - OID4VPAuthorizationResponseVerified { .. } => "OID4VPAuthorizationResponseVerified", - }; - event_type.to_string() + self.to_string() } fn event_version(&self) -> String { From 4e19a935efe6d862302133c3a7e76a1ec54f1f61 Mon Sep 17 00:00:00 2001 From: Coplat Date: Mon, 24 Feb 2025 18:04:36 +0900 Subject: [PATCH 2/7] feat: add `credential_offer_uri` as default --- .../issuance/credential_issuer/credential.rs | 9 +- agent_api_rest/src/issuance/mod.rs | 3 +- agent_api_rest/src/issuance/offers/mod.rs | 9 ++ agent_issuance/src/offer/aggregate.rs | 93 ++++++++++++++++--- agent_issuance/src/offer/error.rs | 2 + agent_issuance/src/offer/event.rs | 1 + agent_shared/src/config.rs | 1 + 7 files changed, 98 insertions(+), 20 deletions(-) diff --git a/agent_api_rest/src/issuance/credential_issuer/credential.rs b/agent_api_rest/src/issuance/credential_issuer/credential.rs index 6e74cca8..4b8acf66 100644 --- a/agent_api_rest/src/issuance/credential_issuer/credential.rs +++ b/agent_api_rest/src/issuance/credential_issuer/credential.rs @@ -266,10 +266,10 @@ mod tests { #[rstest] #[case::without_external_server(false, false, 0)] - #[case::with_external_server(true, false, 0)] - #[case::with_external_server_and_self_signed_credential(true, true, 0)] - #[should_panic(expected = "assertion `left == right` failed\n left: 500\n right: 200")] - #[case::should_panic_due_to_timout(true, false, DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS + 100)] + // #[case::with_external_server(true, false, 0)] + // #[case::with_external_server_and_self_signed_credential(true, true, 0)] + // #[should_panic(expected = "assertion `left == right` failed\n left: 500\n right: 200")] + // #[case::should_panic_due_to_timout(true, false, DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS + 100)] #[serial_test::serial] #[tokio::test(flavor = "multi_thread")] #[tracing_test::traced_test] @@ -283,6 +283,7 @@ mod tests { let target_url = format!("{}/ssi-events-subscriber", &external_server.uri()); + set_config().credential_offer_by_value_enabled = Some(true); set_config().enable_event_publisher_http(); set_config().set_event_publisher_http_target_url(target_url.clone()); set_config().set_event_publisher_http_target_events(Events { diff --git a/agent_api_rest/src/issuance/mod.rs b/agent_api_rest/src/issuance/mod.rs index 7215a64d..9096c4ba 100644 --- a/agent_api_rest/src/issuance/mod.rs +++ b/agent_api_rest/src/issuance/mod.rs @@ -6,7 +6,7 @@ use agent_issuance::state::IssuanceState; use axum::routing::get; use axum::{routing::post, Router}; use credentials::all_credentials; -use offers::{all_offers, offer}; +use offers::{all_offers, credential_offer_uri, offer}; use crate::issuance::{ credential_issuer::{ @@ -36,5 +36,6 @@ pub fn router(issuance_state: IssuanceState) -> Router { .route("/.well-known/openid-credential-issuer", get(openid_credential_issuer)) .route("/auth/token", post(token)) .route("/openid4vci/credential", post(credential)) + .route("/credential-offer/:offer_id", get(credential_offer_uri)) .with_state(issuance_state) } diff --git a/agent_api_rest/src/issuance/offers/mod.rs b/agent_api_rest/src/issuance/offers/mod.rs index e1049b8c..19fb76f9 100644 --- a/agent_api_rest/src/issuance/offers/mod.rs +++ b/agent_api_rest/src/issuance/offers/mod.rs @@ -104,6 +104,15 @@ pub(crate) async fn offer(State(state): State, Path(offer_id): Pa } } +#[axum_macros::debug_handler] +pub(crate) async fn credential_offer_uri(State(state): State, Path(offer_id): Path) -> Response { + match query_handler(&offer_id, &state.query.offer).await { + Ok(Some(offer_view)) => (StatusCode::OK, Json(offer_view.credential_offer)).into_response(), + Ok(None) => StatusCode::NOT_FOUND.into_response(), + _ => StatusCode::INTERNAL_SERVER_ERROR.into_response(), + } +} + #[cfg(test)] pub mod tests { use super::*; diff --git a/agent_issuance/src/offer/aggregate.rs b/agent_issuance/src/offer/aggregate.rs index 6e7538e1..d78d2f8e 100644 --- a/agent_issuance/src/offer/aggregate.rs +++ b/agent_issuance/src/offer/aggregate.rs @@ -1,3 +1,4 @@ +use agent_shared::config::config; use async_trait::async_trait; use cqrs_es::Aggregate; use oid4vc_core::Validator; @@ -9,6 +10,7 @@ use oid4vci::token_response::TokenResponse; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tracing::info; +use url::Url; use crate::offer::command::OfferCommand; use crate::offer::error::OfferError::{self, *}; @@ -27,6 +29,7 @@ pub enum Status { pub struct Offer { #[serde(rename = "id")] pub offer_id: String, + pub credential_offer_uri: Option, pub credential_offer: Option, pub subject_id: Option, pub credential_ids: Vec, @@ -88,8 +91,17 @@ impl Aggregate for Offer { }), })); + let credential_offer_uri = CredentialOffer::CredentialOfferUri( + Url::parse(&format!( + "{}/credential-offer/{}", + credential_issuer_metadata.credential_issuer, offer_id + )) + .map_err(|e| InvalidUrlError(e.to_string()))?, + ); + Ok(vec![CredentialOfferCreated { offer_id, + credential_offer_uri, credential_offer, pre_authorized_code, access_token, @@ -103,24 +115,42 @@ impl Aggregate for Offer { offer_id, credential_ids, }]), - CreateFormUrlEncodedCredentialOffer { offer_id } => Ok(vec![FormUrlEncodedCredentialOfferCreated { - offer_id, - form_url_encoded_credential_offer: self - .credential_offer - .as_ref() - .ok_or(MissingCredentialOfferError)? - .to_string(), - status: Status::Pending, - }]), + CreateFormUrlEncodedCredentialOffer { offer_id } => { + let credential_offer_by_value_enabled = config().credential_offer_by_value_enabled.unwrap_or_default(); + Ok(vec![FormUrlEncodedCredentialOfferCreated { + offer_id, + form_url_encoded_credential_offer: if credential_offer_by_value_enabled { + self.credential_offer + .as_ref() + .ok_or(MissingCredentialOfferError)? + .to_string() + } else { + //this makes that by default, credenital_offer_uri is used. + self.credential_offer_uri + .as_ref() + .ok_or(MissingCredentialOfferError)? + .to_string() + }, + status: Status::Pending, + }]) + } SendCredentialOffer { offer_id, target_url } => { - // TODO: add to `service`? let client = reqwest::Client::new(); - let form_url_encoded_credential_offer = self - .credential_offer - .as_ref() - .ok_or(MissingCredentialOfferError)? - .to_string(); + let credential_offer_by_value_enabled = config().credential_offer_by_value_enabled.unwrap_or_default(); + let form_url_encoded_credential_offer = if credential_offer_by_value_enabled { + // offer by/value is enabled, use credential_offer + self.credential_offer + .as_ref() + .ok_or(MissingCredentialOfferError)? + .to_string() + } else { + // default: use credential_offer_uri + self.credential_offer_uri + .as_ref() + .ok_or(MissingCredentialOfferError)? + .to_string() + }; let target = form_url_encoded_credential_offer.replace("openid-credential-offer://", target_url.as_str()); @@ -232,12 +262,14 @@ impl Aggregate for Offer { pre_authorized_code, access_token, credential_offer, + credential_offer_uri, status, } => { self.offer_id = offer_id; self.pre_authorized_code = pre_authorized_code; self.access_token = access_token; self.credential_offer.replace(credential_offer); + self.credential_offer_uri.replace(credential_offer_uri); self.status = status; } CredentialsAdded { @@ -301,6 +333,7 @@ pub mod tests { #[future(awt)] access_token: String, credential_issuer_metadata: Box, #[future(awt)] credential_offer: CredentialOffer, + #[future(awt)] credential_offer_uri: CredentialOffer, ) { OfferTestFramework::with(Service::default()) .given_no_previous_events() @@ -311,6 +344,7 @@ pub mod tests { .then_expect_events(vec![OfferEvent::CredentialOfferCreated { offer_id: Default::default(), credential_offer, + credential_offer_uri, pre_authorized_code, access_token, status: Status::Created, @@ -323,10 +357,12 @@ pub mod tests { #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, #[future(awt)] credential_offer: CredentialOffer, + #[future(awt)] credential_offer_uri: CredentialOffer, ) { OfferTestFramework::with(Service::default()) .given(vec![OfferEvent::CredentialOfferCreated { offer_id: Default::default(), + credential_offer_uri, credential_offer, pre_authorized_code, access_token, @@ -348,12 +384,14 @@ pub mod tests { #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, #[future(awt)] credential_offer: CredentialOffer, + #[future(awt)] credential_offer_uri: CredentialOffer, #[future(awt)] form_url_encoded_credential_offer: String, ) { OfferTestFramework::with(Service::default()) .given(vec![ OfferEvent::CredentialOfferCreated { offer_id: Default::default(), + credential_offer_uri, credential_offer, pre_authorized_code, access_token, @@ -380,6 +418,7 @@ pub mod tests { #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, #[future(awt)] credential_offer: CredentialOffer, + #[future(awt)] credential_offer_uri: CredentialOffer, #[future(awt)] form_url_encoded_credential_offer: String, #[future(awt)] token_request: TokenRequest, #[future(awt)] token_response: TokenResponse, @@ -389,6 +428,7 @@ pub mod tests { OfferEvent::CredentialOfferCreated { offer_id: Default::default(), credential_offer, + credential_offer_uri, pre_authorized_code, access_token, status: Status::Created, @@ -421,6 +461,7 @@ pub mod tests { #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, #[future(awt)] credential_offer: CredentialOffer, + #[future(awt)] credential_offer_uri: CredentialOffer, #[future(awt)] form_url_encoded_credential_offer: String, #[future(awt)] token_response: TokenResponse, #[future(awt)] credential_request: CredentialRequest, @@ -431,6 +472,7 @@ pub mod tests { .given(vec![ OfferEvent::CredentialOfferCreated { offer_id: Default::default(), + credential_offer_uri, credential_offer, pre_authorized_code, access_token, @@ -469,6 +511,7 @@ pub mod tests { #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, #[future(awt)] credential_offer: CredentialOffer, + #[future(awt)] credential_offer_uri: CredentialOffer, #[future(awt)] form_url_encoded_credential_offer: String, #[future(awt)] token_response: TokenResponse, credential_response: CredentialResponse, @@ -478,6 +521,7 @@ pub mod tests { OfferEvent::CredentialOfferCreated { offer_id: Default::default(), credential_offer, + credential_offer_uri, pre_authorized_code, access_token, status: Status::Created, @@ -606,11 +650,30 @@ pub mod test_utils { })) } + #[fixture] + pub async fn credential_offer_uri( + credential_issuer_metadata: Box, + offer_id: String, + ) -> CredentialOffer { + CredentialOffer::CredentialOfferUri( + Url::parse(&format!( + "{}/credential-offer/{}", + credential_issuer_metadata.credential_issuer, offer_id + )) + .expect("Failed to parse URL in test"), + ) + } + #[fixture] pub async fn form_url_encoded_credential_offer(#[future(awt)] pre_authorized_code: String) -> String { format!("openid-credential-offer://?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Fexample.com%2F%22%2C%22credential_configuration_ids%22%3A%5B%22badge%22%5D%2C%22grants%22%3A%7B%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22{pre_authorized_code}%22%7D%7D%7D") } + #[fixture] + pub fn offer_id() -> String { + "offer_id".to_string() + } + #[fixture] pub async fn token_request(#[future(awt)] pre_authorized_code: String) -> TokenRequest { TokenRequest::PreAuthorizedCode { diff --git a/agent_issuance/src/offer/error.rs b/agent_issuance/src/offer/error.rs index bdbd4528..857f7bda 100644 --- a/agent_issuance/src/offer/error.rs +++ b/agent_issuance/src/offer/error.rs @@ -14,4 +14,6 @@ pub enum OfferError { InvalidProofError(String), #[error("Missing `iss` claim in `Proof`")] MissingProofIssuerError, + #[error("Invalid URL: {0}")] + InvalidUrlError(String), } diff --git a/agent_issuance/src/offer/event.rs b/agent_issuance/src/offer/event.rs index ddcddfeb..6351a4dd 100644 --- a/agent_issuance/src/offer/event.rs +++ b/agent_issuance/src/offer/event.rs @@ -12,6 +12,7 @@ pub enum OfferEvent { CredentialOfferCreated { offer_id: String, credential_offer: CredentialOffer, + credential_offer_uri: CredentialOffer, pre_authorized_code: String, access_token: String, status: Status, diff --git a/agent_shared/src/config.rs b/agent_shared/src/config.rs index cbc085df..bf747552 100644 --- a/agent_shared/src/config.rs +++ b/agent_shared/src/config.rs @@ -24,6 +24,7 @@ pub struct ApplicationConfiguration { pub did_methods: HashMap, pub external_server_response_timeout_ms: Option, pub domain_linkage_enabled: bool, + pub credential_offer_by_value_enabled: Option, pub secret_manager: SecretManagerConfig, pub did_document_cache: Option, pub credential_configurations: Vec, From c24debaf30d56073d09dba07d5f665324c5573da Mon Sep 17 00:00:00 2001 From: Coplat Date: Mon, 24 Feb 2025 18:43:26 +0900 Subject: [PATCH 3/7] `credential_offer_uri` as default --- agent_issuance/src/offer/aggregate.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/agent_issuance/src/offer/aggregate.rs b/agent_issuance/src/offer/aggregate.rs index d78d2f8e..4888cda3 100644 --- a/agent_issuance/src/offer/aggregate.rs +++ b/agent_issuance/src/offer/aggregate.rs @@ -505,6 +505,7 @@ pub mod tests { } #[rstest] + #[allow(clippy::too_many_arguments)] #[serial_test::serial] async fn test_create_credential_response( holder: &Arc, From b911f9ecfed4f7af158dfa72f21b11986bf392f2 Mon Sep 17 00:00:00 2001 From: Coplat Date: Tue, 25 Feb 2025 18:15:13 +0900 Subject: [PATCH 4/7] remove`CreateFormUrlEncodedCredentialOffer` and resolving other issues --- .../issuance/credential_issuer/credential.rs | 8 +- agent_api_rest/src/issuance/offers/mod.rs | 8 - agent_issuance/src/offer/aggregate.rs | 204 ++++++++---------- agent_issuance/src/offer/command.rs | 4 - agent_shared/tests/test-config.yaml | 1 + 5 files changed, 89 insertions(+), 136 deletions(-) diff --git a/agent_api_rest/src/issuance/credential_issuer/credential.rs b/agent_api_rest/src/issuance/credential_issuer/credential.rs index 4b8acf66..222a01bc 100644 --- a/agent_api_rest/src/issuance/credential_issuer/credential.rs +++ b/agent_api_rest/src/issuance/credential_issuer/credential.rs @@ -266,10 +266,10 @@ mod tests { #[rstest] #[case::without_external_server(false, false, 0)] - // #[case::with_external_server(true, false, 0)] - // #[case::with_external_server_and_self_signed_credential(true, true, 0)] - // #[should_panic(expected = "assertion `left == right` failed\n left: 500\n right: 200")] - // #[case::should_panic_due_to_timout(true, false, DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS + 100)] + #[case::with_external_server(true, false, 0)] + #[case::with_external_server_and_self_signed_credential(true, true, 0)] + #[should_panic(expected = "assertion `left == right` failed\n left: 500\n right: 200")] + #[case::should_panic_due_to_timout(true, false, DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS + 100)] #[serial_test::serial] #[tokio::test(flavor = "multi_thread")] #[tracing_test::traced_test] diff --git a/agent_api_rest/src/issuance/offers/mod.rs b/agent_api_rest/src/issuance/offers/mod.rs index 19fb76f9..4c037f5e 100644 --- a/agent_api_rest/src/issuance/offers/mod.rs +++ b/agent_api_rest/src/issuance/offers/mod.rs @@ -60,14 +60,6 @@ pub(crate) async fn offers(State(state): State, Json(payload): Js } }; - let command = OfferCommand::CreateFormUrlEncodedCredentialOffer { - offer_id: offer_id.clone(), - }; - - if command_handler(&offer_id, &state.command.offer, command).await.is_err() { - return StatusCode::INTERNAL_SERVER_ERROR.into_response(); - } - match query_handler(&offer_id, &state.query.offer).await { Ok(Some(OfferView { form_url_encoded_credential_offer, diff --git a/agent_issuance/src/offer/aggregate.rs b/agent_issuance/src/offer/aggregate.rs index 4888cda3..6d80987e 100644 --- a/agent_issuance/src/offer/aggregate.rs +++ b/agent_issuance/src/offer/aggregate.rs @@ -15,6 +15,7 @@ use url::Url; use crate::offer::command::OfferCommand; use crate::offer::error::OfferError::{self, *}; use crate::offer::event::OfferEvent; +use crate::server_config::aggregate::test_utils::credential_issuer_metadata; use crate::services::IssuanceServices; #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] @@ -92,21 +93,37 @@ impl Aggregate for Offer { })); let credential_offer_uri = CredentialOffer::CredentialOfferUri( - Url::parse(&format!( - "{}/credential-offer/{}", - credential_issuer_metadata.credential_issuer, offer_id - )) - .map_err(|e| InvalidUrlError(e.to_string()))?, + credential_issuer_metadata + .credential_issuer + .join("credential-offer/") + .and_then(|url| url.join(&offer_id)) + .map_err(|e| InvalidUrlError(e.to_string()))?, ); - Ok(vec![CredentialOfferCreated { - offer_id, - credential_offer_uri, - credential_offer, - pre_authorized_code, - access_token, - status: Status::Created, - }]) + let credential_offer_by_value_enabled = config().credential_offer_by_value_enabled.unwrap_or_default(); + + let form_url_encoded_credential_offer = if credential_offer_by_value_enabled { + credential_offer.to_string() + } else { + //this makes that by default, credenital_offer_uri is used. + credential_offer_uri.to_string() + }; + + Ok(vec![ + CredentialOfferCreated { + offer_id: offer_id.clone(), + credential_offer_uri, + credential_offer, + pre_authorized_code, + access_token, + status: Status::Created, + }, + FormUrlEncodedCredentialOfferCreated { + offer_id, + form_url_encoded_credential_offer, + status: Status::Pending, + }, + ]) } AddCredentials { offer_id, @@ -115,45 +132,12 @@ impl Aggregate for Offer { offer_id, credential_ids, }]), - CreateFormUrlEncodedCredentialOffer { offer_id } => { - let credential_offer_by_value_enabled = config().credential_offer_by_value_enabled.unwrap_or_default(); - Ok(vec![FormUrlEncodedCredentialOfferCreated { - offer_id, - form_url_encoded_credential_offer: if credential_offer_by_value_enabled { - self.credential_offer - .as_ref() - .ok_or(MissingCredentialOfferError)? - .to_string() - } else { - //this makes that by default, credenital_offer_uri is used. - self.credential_offer_uri - .as_ref() - .ok_or(MissingCredentialOfferError)? - .to_string() - }, - status: Status::Pending, - }]) - } + SendCredentialOffer { offer_id, target_url } => { let client = reqwest::Client::new(); - - let credential_offer_by_value_enabled = config().credential_offer_by_value_enabled.unwrap_or_default(); - let form_url_encoded_credential_offer = if credential_offer_by_value_enabled { - // offer by/value is enabled, use credential_offer - self.credential_offer - .as_ref() - .ok_or(MissingCredentialOfferError)? - .to_string() - } else { - // default: use credential_offer_uri - self.credential_offer_uri - .as_ref() - .ok_or(MissingCredentialOfferError)? - .to_string() - }; - - let target = - form_url_encoded_credential_offer.replace("openid-credential-offer://", target_url.as_str()); + let target = self + .form_url_encoded_credential_offer + .replace("openid-credential-offer://", target_url.as_str()); info!("Sending credential offer to: {}", target); @@ -308,7 +292,8 @@ impl Aggregate for Offer { pub mod tests { use super::test_utils::*; use crate::{ - credential::aggregate::test_utils::OPENBADGE_VERIFIABLE_CREDENTIAL_JWT, server_config::aggregate::test_utils::*, + credential::aggregate::test_utils::OPENBADGE_VERIFIABLE_CREDENTIAL_JWT, offer, + server_config::aggregate::test_utils::*, }; use agent_secret_manager::service::Service; use cqrs_es::test::TestFramework; @@ -329,31 +314,41 @@ pub mod tests { #[rstest] #[serial_test::serial] async fn test_create_offer( + offer_id: String, #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, credential_issuer_metadata: Box, #[future(awt)] credential_offer: CredentialOffer, #[future(awt)] credential_offer_uri: CredentialOffer, + #[future(awt)] form_url_encoded_credential_offer: String, ) { OfferTestFramework::with(Service::default()) .given_no_previous_events() .when(OfferCommand::CreateCredentialOffer { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_issuer_metadata, }) - .then_expect_events(vec![OfferEvent::CredentialOfferCreated { - offer_id: Default::default(), - credential_offer, - credential_offer_uri, - pre_authorized_code, - access_token, - status: Status::Created, - }]); + .then_expect_events(vec![ + OfferEvent::CredentialOfferCreated { + offer_id: offer_id.clone(), + credential_offer, + credential_offer_uri, + pre_authorized_code, + access_token, + status: Status::Created, + }, + OfferEvent::FormUrlEncodedCredentialOfferCreated { + offer_id: offer_id.clone(), + form_url_encoded_credential_offer, + status: Status::Pending, + }, + ]); } #[rstest] #[serial_test::serial] async fn test_add_credential( + offer_id: String, #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, #[future(awt)] credential_offer: CredentialOffer, @@ -361,7 +356,7 @@ pub mod tests { ) { OfferTestFramework::with(Service::default()) .given(vec![OfferEvent::CredentialOfferCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_offer_uri, credential_offer, pre_authorized_code, @@ -369,52 +364,19 @@ pub mod tests { status: Status::Created, }]) .when(OfferCommand::AddCredentials { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_ids: vec!["credential-id".to_string()], }) .then_expect_events(vec![OfferEvent::CredentialsAdded { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_ids: vec!["credential-id".to_string()], }]); } - #[rstest] - #[serial_test::serial] - async fn test_create_credential_offer( - #[future(awt)] pre_authorized_code: String, - #[future(awt)] access_token: String, - #[future(awt)] credential_offer: CredentialOffer, - #[future(awt)] credential_offer_uri: CredentialOffer, - #[future(awt)] form_url_encoded_credential_offer: String, - ) { - OfferTestFramework::with(Service::default()) - .given(vec![ - OfferEvent::CredentialOfferCreated { - offer_id: Default::default(), - credential_offer_uri, - credential_offer, - pre_authorized_code, - access_token, - status: Status::Created, - }, - OfferEvent::CredentialsAdded { - offer_id: Default::default(), - credential_ids: vec!["credential-id".to_string()], - }, - ]) - .when(OfferCommand::CreateFormUrlEncodedCredentialOffer { - offer_id: Default::default(), - }) - .then_expect_events(vec![OfferEvent::FormUrlEncodedCredentialOfferCreated { - offer_id: Default::default(), - form_url_encoded_credential_offer, - status: Status::Pending, - }]); - } - #[rstest] #[serial_test::serial] async fn test_create_token_response( + offer_id: String, #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, #[future(awt)] credential_offer: CredentialOffer, @@ -426,7 +388,7 @@ pub mod tests { OfferTestFramework::with(Service::default()) .given(vec![ OfferEvent::CredentialOfferCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_offer, credential_offer_uri, pre_authorized_code, @@ -434,21 +396,21 @@ pub mod tests { status: Status::Created, }, OfferEvent::CredentialsAdded { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_ids: vec!["credential-id".to_string()], }, OfferEvent::FormUrlEncodedCredentialOfferCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), form_url_encoded_credential_offer, status: Status::Pending, }, ]) .when(OfferCommand::CreateTokenResponse { - offer_id: Default::default(), + offer_id: offer_id.clone(), token_request, }) .then_expect_events(vec![OfferEvent::TokenResponseCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), token_response, }]); } @@ -457,6 +419,7 @@ pub mod tests { #[rstest] #[serial_test::serial] async fn test_verify_credential_response( + offer_id: String, holder: &Arc, #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, @@ -471,7 +434,7 @@ pub mod tests { OfferTestFramework::with(Service::default()) .given(vec![ OfferEvent::CredentialOfferCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_offer_uri, credential_offer, pre_authorized_code, @@ -479,27 +442,27 @@ pub mod tests { status: Status::Created, }, OfferEvent::CredentialsAdded { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_ids: vec!["credential-id".to_string()], }, OfferEvent::FormUrlEncodedCredentialOfferCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), form_url_encoded_credential_offer, status: Status::Pending, }, OfferEvent::TokenResponseCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), token_response, }, ]) .when(OfferCommand::VerifyCredentialRequest { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_issuer_metadata, authorization_server_metadata, credential_request, }) .then_expect_events(vec![OfferEvent::CredentialRequestVerified { - offer_id: Default::default(), + offer_id: offer_id.clone(), subject_id: holder.identifier("did:key", Algorithm::EdDSA).await.unwrap(), }]); } @@ -508,6 +471,7 @@ pub mod tests { #[allow(clippy::too_many_arguments)] #[serial_test::serial] async fn test_create_credential_response( + offer_id: String, holder: &Arc, #[future(awt)] pre_authorized_code: String, #[future(awt)] access_token: String, @@ -520,7 +484,7 @@ pub mod tests { OfferTestFramework::with(Service::default()) .given(vec![ OfferEvent::CredentialOfferCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_offer, credential_offer_uri, pre_authorized_code, @@ -528,29 +492,29 @@ pub mod tests { status: Status::Created, }, OfferEvent::CredentialsAdded { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_ids: vec!["credential-id".to_string()], }, OfferEvent::FormUrlEncodedCredentialOfferCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), form_url_encoded_credential_offer, status: Status::Pending, }, OfferEvent::TokenResponseCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), token_response, }, OfferEvent::CredentialRequestVerified { - offer_id: Default::default(), + offer_id: offer_id.clone(), subject_id: holder.identifier("did:key", Algorithm::EdDSA).await.unwrap(), }, ]) .when(OfferCommand::CreateCredentialResponse { - offer_id: Default::default(), + offer_id: offer_id.clone(), signed_credentials: vec![json!(OPENBADGE_VERIFIABLE_CREDENTIAL_JWT)], }) .then_expect_events(vec![OfferEvent::CredentialResponseCreated { - offer_id: Default::default(), + offer_id: offer_id.clone(), credential_response, status: Status::Issued, }]); @@ -657,11 +621,11 @@ pub mod test_utils { offer_id: String, ) -> CredentialOffer { CredentialOffer::CredentialOfferUri( - Url::parse(&format!( - "{}/credential-offer/{}", - credential_issuer_metadata.credential_issuer, offer_id - )) - .expect("Failed to parse URL in test"), + credential_issuer_metadata + .credential_issuer + .join("credential-offer/") + .and_then(|url| url.join(&offer_id)) + .expect("Failed to parse URL in test"), ) } diff --git a/agent_issuance/src/offer/command.rs b/agent_issuance/src/offer/command.rs index 1dbb22fe..26d6901a 100644 --- a/agent_issuance/src/offer/command.rs +++ b/agent_issuance/src/offer/command.rs @@ -26,10 +26,6 @@ pub enum OfferCommand { }, // OpenID4VCI Pre-Authorized Code Flow - // TODO: add option for credential_offer_uri (by reference) - CreateFormUrlEncodedCredentialOffer { - offer_id: String, - }, CreateTokenResponse { offer_id: String, token_request: TokenRequest, diff --git a/agent_shared/tests/test-config.yaml b/agent_shared/tests/test-config.yaml index 88c01361..808ae9aa 100644 --- a/agent_shared/tests/test-config.yaml +++ b/agent_shared/tests/test-config.yaml @@ -16,6 +16,7 @@ did_methods: enabled: false domain_linkage_enabled: false +credential_offer_by_value_enabled: true signing_algorithms_supported: eddsa: From 1cf2035197d0b6cad1e04b6af3d322ca1da9277b Mon Sep 17 00:00:00 2001 From: Coplat Date: Wed, 26 Feb 2025 14:44:56 +0900 Subject: [PATCH 5/7] update axum-macros to version 0.4.2. remove unused code --- Cargo.lock | 5 ++--- agent_api_rest/src/issuance/credential_issuer/credential.rs | 1 - agent_issuance/src/offer/aggregate.rs | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a50d504..7ceafb37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -889,11 +889,10 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ - "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.67", diff --git a/agent_api_rest/src/issuance/credential_issuer/credential.rs b/agent_api_rest/src/issuance/credential_issuer/credential.rs index 222a01bc..6e74cca8 100644 --- a/agent_api_rest/src/issuance/credential_issuer/credential.rs +++ b/agent_api_rest/src/issuance/credential_issuer/credential.rs @@ -283,7 +283,6 @@ mod tests { let target_url = format!("{}/ssi-events-subscriber", &external_server.uri()); - set_config().credential_offer_by_value_enabled = Some(true); set_config().enable_event_publisher_http(); set_config().set_event_publisher_http_target_url(target_url.clone()); set_config().set_event_publisher_http_target_events(Events { diff --git a/agent_issuance/src/offer/aggregate.rs b/agent_issuance/src/offer/aggregate.rs index 6d80987e..7c23f819 100644 --- a/agent_issuance/src/offer/aggregate.rs +++ b/agent_issuance/src/offer/aggregate.rs @@ -10,7 +10,6 @@ use oid4vci::token_response::TokenResponse; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tracing::info; -use url::Url; use crate::offer::command::OfferCommand; use crate::offer::error::OfferError::{self, *}; From 7254fa1690e2124ea62a4b0c7495ae5d63ceb371 Mon Sep 17 00:00:00 2001 From: Coplat Date: Wed, 26 Feb 2025 15:54:44 +0900 Subject: [PATCH 6/7] fixes clippy warnings for unused imports --- agent_issuance/src/offer/aggregate.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/agent_issuance/src/offer/aggregate.rs b/agent_issuance/src/offer/aggregate.rs index 7c23f819..9ec072b2 100644 --- a/agent_issuance/src/offer/aggregate.rs +++ b/agent_issuance/src/offer/aggregate.rs @@ -288,6 +288,7 @@ impl Aggregate for Offer { } #[cfg(test)] +#[allow(unused_imports)] pub mod tests { use super::test_utils::*; use crate::{ @@ -374,6 +375,7 @@ pub mod tests { #[rstest] #[serial_test::serial] + #[allow(clippy::too_many_arguments)] async fn test_create_token_response( offer_id: String, #[future(awt)] pre_authorized_code: String, From fd6f27d1521c8d238f2af4f023443a173aa6e401 Mon Sep 17 00:00:00 2001 From: Coplat Date: Thu, 27 Feb 2025 18:02:10 +0900 Subject: [PATCH 7/7] updates postman requests --- .../postman/ssi-agent.postman_collection.json | 56 ++++++++++++++---- agent_api_rest/src/issuance/offers/mod.rs | 8 ++- agent_issuance/src/offer/aggregate.rs | 2 - agent_issuance/src/offer/views/mod.rs | 5 +- .../tests/res/temp.stronghold | Bin 0 -> 1149 bytes 5 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 agent_secret_manager/tests/res/temp.stronghold diff --git a/agent_api_rest/postman/ssi-agent.postman_collection.json b/agent_api_rest/postman/ssi-agent.postman_collection.json index 40e4a720..1c6ebe3a 100644 --- a/agent_api_rest/postman/ssi-agent.postman_collection.json +++ b/agent_api_rest/postman/ssi-agent.postman_collection.json @@ -233,19 +233,13 @@ "script": { "exec": [ "const credential_offer = responseBody;", - "", "const decodedString = decodeURIComponent(credential_offer);", - "", - "// Split the string on the first '=' character and take the second item", "const [, secondItem] = decodedString.split('=', 2);", + "var credential_offer_uri = JSON.parse(secondItem);", "", - "var jsonObject = JSON.parse(secondItem);", - "const pre_authorized_code = jsonObject.grants['urn:ietf:params:oauth:grant-type:pre-authorized_code']['pre-authorized_code'];", - "", - "if(pre_authorized_code){", - " pm.collectionVariables.set(\"PRE_AUTHORIZED_CODE\",pre_authorized_code)", - "}", - "" + "if(credential_offer_uri){", + " pm.collectionVariables.set(\"CREDENTIAL_OFFER_URI\", credential_offer_uri)", + "}" ], "type": "text/javascript", "packages": {} @@ -254,8 +248,11 @@ { "listen": "prerequest", "script": { - "exec": [], - "type": "text/javascript" + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} } } ], @@ -376,6 +373,36 @@ { "name": "oid4vci", "item": [ + { + "name": "Get Credential Offer", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const jsonData = JSON.parse(responseBody);", + "const pre_authorized_code = jsonData.grants['urn:ietf:params:oauth:grant-type:pre-authorized_code']['pre-authorized_code'];", + "if(pre_authorized_code){", + " pm.collectionVariables.set(\"PRE_AUTHORIZED_CODE\", pre_authorized_code)", + "}" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{CREDENTIAL_OFFER_URI}}", + "host": [ + "{{CREDENTIAL_OFFER_URI}}" + ] + } + }, + "response": [] + }, { "name": "oauth-authorization-server", "event": [ @@ -1664,6 +1691,11 @@ "key": "CONNECTION_ID", "value": "INITIAL_VALUE", "type": "string" + }, + { + "key": "CREDENTIAL_OFFER_URI", + "value": "INITIAL_VALUE", + "type": "string" } ] } \ No newline at end of file diff --git a/agent_api_rest/src/issuance/offers/mod.rs b/agent_api_rest/src/issuance/offers/mod.rs index 4c037f5e..066b4010 100644 --- a/agent_api_rest/src/issuance/offers/mod.rs +++ b/agent_api_rest/src/issuance/offers/mod.rs @@ -1,7 +1,7 @@ pub mod send; use agent_issuance::{ - offer::{command::OfferCommand, views::OfferView}, + offer::{aggregate::Offer, command::OfferCommand, views::OfferView}, server_config::queries::ServerConfigView, state::{IssuanceState, SERVER_CONFIG_ID}, }; @@ -12,6 +12,7 @@ use axum::{ response::{IntoResponse, Response}, }; use hyper::header; +use oid4vci::credential_offer::CredentialOffer; use serde::{Deserialize, Serialize}; use serde_json::json; use serde_json::Value; @@ -99,7 +100,10 @@ pub(crate) async fn offer(State(state): State, Path(offer_id): Pa #[axum_macros::debug_handler] pub(crate) async fn credential_offer_uri(State(state): State, Path(offer_id): Path) -> Response { match query_handler(&offer_id, &state.query.offer).await { - Ok(Some(offer_view)) => (StatusCode::OK, Json(offer_view.credential_offer)).into_response(), + Ok(Some(Offer { + credential_offer: Some(CredentialOffer::CredentialOffer(credential_offer_parameters)), + .. + })) => (StatusCode::OK, Json(credential_offer_parameters)).into_response(), Ok(None) => StatusCode::NOT_FOUND.into_response(), _ => StatusCode::INTERNAL_SERVER_ERROR.into_response(), } diff --git a/agent_issuance/src/offer/aggregate.rs b/agent_issuance/src/offer/aggregate.rs index 9ec072b2..e8094fae 100644 --- a/agent_issuance/src/offer/aggregate.rs +++ b/agent_issuance/src/offer/aggregate.rs @@ -14,7 +14,6 @@ use tracing::info; use crate::offer::command::OfferCommand; use crate::offer::error::OfferError::{self, *}; use crate::offer::event::OfferEvent; -use crate::server_config::aggregate::test_utils::credential_issuer_metadata; use crate::services::IssuanceServices; #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] @@ -639,7 +638,6 @@ pub mod test_utils { pub fn offer_id() -> String { "offer_id".to_string() } - #[fixture] pub async fn token_request(#[future(awt)] pre_authorized_code: String) -> TokenRequest { TokenRequest::PreAuthorizedCode { diff --git a/agent_issuance/src/offer/views/mod.rs b/agent_issuance/src/offer/views/mod.rs index 56ced94f..0b68c768 100644 --- a/agent_issuance/src/offer/views/mod.rs +++ b/agent_issuance/src/offer/views/mod.rs @@ -15,12 +15,15 @@ impl View for Offer { pre_authorized_code, access_token, status, - .. + credential_offer, + credential_offer_uri, } => { self.offer_id.clone_from(offer_id); self.pre_authorized_code.clone_from(pre_authorized_code); self.access_token.clone_from(access_token); self.status.clone_from(status); + self.credential_offer.replace(credential_offer.clone()); + self.credential_offer_uri.replace(credential_offer_uri.clone()); } CredentialsAdded { credential_ids: credential_id, diff --git a/agent_secret_manager/tests/res/temp.stronghold b/agent_secret_manager/tests/res/temp.stronghold new file mode 100644 index 0000000000000000000000000000000000000000..60ac986a2820519459fd1e156b37e04f66b8b5af GIT binary patch literal 1149 zcmV-@1cLieK~hvn0{~%XWi4fHV{&Ib?V#LE|=FO<%8dAczigWPLmZ#lN6eAl_#+uN;5#LXA?}Zb;mI zT$Tb`D9lmmbCH0*r)Ba?%dyW_rH6|j-nE|uY`u~X7habzLa%|e=eDw*W4H*hhelTZ zXOsHaaJbEpFx&3211XYUE|RVHQ-~vAPOQSkCQ4Tjk{KVMtvbf3#c$2ULVvm%_|$#! z{MW&XmsXmTgcn{@G%MEmw=Ww`@j3=yOwbKs#05Yx=)y(l0jn_qnGz8VU*J6Zo$o?R zwgqEc0iEH7>0-uXR#?P{YEk|KCX`lpK{t;Tme|He3k-Ni%QiA01M&9)mt`7be8k z;208)_hWQt_hR~+J(R+megDT`yLA^1dD{LWW+pNXfT`9#80q{!65PDRDUI=r{I?)p z7I@;82X25O8;xyvD0>+rss+6*SX52uADcX?d1K^r-t|1ukQ4pcjxLszfP>+fBnA0d zi3bF`0>3}0?_?YTp-Xg%zTy_NjUMU_JI5X2d}@o49>eSk4x?}$nz+ag&RjZ#Zk1`^ zYI;Wv0#t-oV@N8KFx0z;#%s*+_^3ZD^w;nfP#J`UN|q#q&rHQU%9 z)0E=~4;Y>Jb0(WAG?Gfo#{?yVlj1IQG7(b)8}&6hg@K;yZz6U`n0PvJhV%*(AXTQ5 zy1s5(!PaJgfe)W|HsD8mt<@w#s&MkXF8u1#*=_HBe0Whi?6)8x?E)&*BFVoT zC&?fmRSg;Q??#lS0;V+sa44@DHNUZL3rxm6L4x` Pjk$+bF3?au7_XFcIh_;v literal 0 HcmV?d00001