From de82caad2954a9edef0d107742b667356f0e6135 Mon Sep 17 00:00:00 2001 From: Nander Stabel Date: Tue, 11 Feb 2025 00:33:14 +0100 Subject: [PATCH] test: add tests --- Cargo.lock | 16 + Cargo.toml | 1 + agent_identity/Cargo.toml | 2 +- agent_identity/src/document/aggregate.rs | 342 +++++++++++------- agent_identity/src/service/aggregate.rs | 67 ++-- agent_identity/src/state.rs | 44 +-- agent_issuance/Cargo.toml | 2 +- agent_secret_manager/Cargo.toml | 7 + agent_secret_manager/src/lib.rs | 43 +-- agent_secret_manager/src/subject.rs | 151 ++++++-- .../tests/res/selv.stronghold | Bin 1659 -> 1927 bytes agent_shared/src/config.rs | 27 ++ .../src/authorization_request/aggregate.rs | 26 +- 13 files changed, 473 insertions(+), 255 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddd42766..fe826d7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -276,16 +276,23 @@ dependencies = [ "async-trait", "base64 0.22.1", "consumer", + "did-jwk", + "did-method-key", "futures", "identity_iota", "identity_stronghold_ext", "iota-sdk", + "iota_stronghold", + "itertools 0.14.0", "jsonwebtoken", "lazy_static", "log", "oid4vc-core", "p256 0.13.2", "ring", + "serde_json", + "ssi-dids 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ssi-jwk 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio", "url", ] @@ -3829,6 +3836,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" diff --git a/Cargo.toml b/Cargo.toml index 95947074..09074621 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ axum = { version = "0.7", features = ["tracing"] } base64 = "0.22" chrono = { version = "0.4", features = ["serde"] } cqrs-es = "0.4.2" +derivative = "2.2" futures = "0.3" identity_core = "1.5" identity_credential = { version = "1.5", default-features = false, features = [ diff --git a/agent_identity/Cargo.toml b/agent_identity/Cargo.toml index fd8ccc5b..ba1da162 100644 --- a/agent_identity/Cargo.toml +++ b/agent_identity/Cargo.toml @@ -12,7 +12,7 @@ anyhow = "1.0" async-trait.workspace = true base64.workspace = true cqrs-es.workspace = true -derivative = "2.2" +derivative.workspace = true futures.workspace = true identity_credential.workspace = true identity_core.workspace = true diff --git a/agent_identity/src/document/aggregate.rs b/agent_identity/src/document/aggregate.rs index 63ee953d..c449bf58 100644 --- a/agent_identity/src/document/aggregate.rs +++ b/agent_identity/src/document/aggregate.rs @@ -1,9 +1,5 @@ use super::{command::DocumentCommand, error::DocumentError, event::DocumentEvent}; use crate::{services::IdentityServices, state::get_address}; -use agent_secret_manager::{ - subject::{Algorithms, DocumentData}, - ED25519_KEY_ID, ES256_KEY_ID, STRONGHOLD_PATH, -}; use agent_shared::config::SupportedDidMethod; use agent_shared::config::{config, get_all_enabled_signing_algorithms_supported, SecretManagerConfig}; use async_trait::async_trait; @@ -29,7 +25,7 @@ use jsonwebtoken::Algorithm; use reqwest::{header::HeaderMap, Method}; use serde::{Deserialize, Serialize}; use serde_json::json; -use std::{collections::BTreeMap, sync::Arc}; +use std::{collections::BTreeMap, str::FromStr as _, sync::Arc}; use tracing::info; #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] @@ -186,19 +182,10 @@ impl Aggregate for Document { } }; - did_methods.insert( - &did_method, - Algorithms { - es256: Some(DocumentData { - did: document.id().to_string(), - verification_method_id: None, - }), - eddsa: Some(DocumentData { - did: document.id().to_string(), - verification_method_id: None, - }), - }, - ); + let controller = document.id().to_string(); + + did_methods.insert_did(&did_method, Algorithm::ES256, controller.clone()); + did_methods.insert_did(&did_method, Algorithm::EdDSA, controller); let status = Status::SignAndValidate; @@ -225,20 +212,21 @@ impl Aggregate for Document { let mut public_key_jwks = vec![]; + let ed25519_key_id = KeyId::new(config().secret_manager.issuer_eddsa_key_id.clone()); + let es256_key_id = KeyId::new(config().secret_manager.issuer_es256_key_id.clone()); + for signing_algorithm in get_all_enabled_signing_algorithms_supported() { match signing_algorithm { Algorithm::EdDSA => { let public_key_jwk: Jwk = stronghold_storage - .get_ed25519_public_key(&KeyId::new(ED25519_KEY_ID)) + .get_ed25519_public_key(&ed25519_key_id) .await .unwrap(); public_key_jwks.push(public_key_jwk); } Algorithm::ES256 => { - let public_key_jwk: Jwk = stronghold_storage - .get_es256_public_key(&KeyId::new(ES256_KEY_ID)) - .await - .unwrap(); + let public_key_jwk: Jwk = + stronghold_storage.get_es256_public_key(&es256_key_id).await.unwrap(); public_key_jwks.push(public_key_jwk); } _ => return Err(UnsupportedSigningAlgorithmError(signing_algorithm)), @@ -278,7 +266,7 @@ impl Aggregate for Document { did_methods.insert_verification_method_id( &did_method, - &algorithm, + Algorithm::from_str(&algorithm).expect("FIX THIS"), &verification_method_id.to_string(), ); } @@ -292,19 +280,10 @@ impl Aggregate for Document { let mut did_methods = services.subject.did_methods.lock().await; if let Some(document) = &self.document { - did_methods.insert( - &did_method, - Algorithms { - es256: Some(DocumentData { - did: document.id().to_string(), - verification_method_id: None, - }), - eddsa: Some(DocumentData { - did: document.id().to_string(), - verification_method_id: None, - }), - }, - ); + let controller = document.id().to_string(); + + did_methods.insert_did(&did_method, Algorithm::ES256, controller.clone()); + did_methods.insert_did(&did_method, Algorithm::EdDSA, controller); } Ok(vec![StatusSet { @@ -397,11 +376,13 @@ impl Aggregate for Document { .finish() .map_err(|_| AliasOutputBuilderError)?; + let stronghold_path = config().secret_manager.stronghold_path.clone(); + // Create a new secret manager backed by a Stronghold. let secret_manager: SecretManager = SecretManager::Stronghold( StrongholdSecretManager::builder() .password(Password::from(password)) - .build(STRONGHOLD_PATH) + .build(stronghold_path) .map_err(|_| SecretManagerBuilderError)?, ); @@ -460,7 +441,7 @@ impl Aggregate for Document { } } -// For did:web +// TODO: Can we remove this? It does not seem to be required: https://w3c-ccg.github.io/did-method-web/#key-material-and-document-handling pub fn get_properties(method_type: MethodType) -> BTreeMap { let mut properties = BTreeMap::new(); properties.insert( @@ -482,6 +463,8 @@ pub fn get_properties(method_type: MethodType) -> BTreeMap; - // #[rstest] - // #[serial_test::serial] - // async fn test_create_document(document_id: String, #[future(awt)] document: CoreDocument) { - // DocumentTestFramework::with(IdentityServices::default()) - // .given_no_previous_events() - // .when(DocumentCommand::CreateDocument { - // document_id: document_id.clone(), - // }) - // .then_expect_events(vec![DocumentEvent::DocumentCreated { - // document, - // document_id, - // status: Status::SignAndValidate, - // }]) - // } - - // #[rstest] - // #[serial_test::serial] - // async fn test_add_service( - // document_id: String, - // #[future(awt)] document: CoreDocument, - // domain_linkage_service: Service, - // #[future(awt)] document_with_domain_linkage_service: CoreDocument, - // ) { - // DocumentTestFramework::with(IdentityServices::default()) - // .given(vec![DocumentEvent::DocumentCreated { - // document_id, - // document, - // status: Status::SignAndValidate, - // }]) - // .when(DocumentCommand::AddService { - // service: domain_linkage_service, - // service_id: "FIX THIS".to_string(), - // }) - // .then_expect_events(vec![DocumentEvent::ServiceAdded { - // document: document_with_domain_linkage_service, - // }]) - // } + #[rstest] + #[serial_test::serial] + async fn test_create_document(did_method: SupportedDidMethod, document: CoreDocument) { + DocumentTestFramework::with(IdentityServices::default()) + .given_no_previous_events() + .when(DocumentCommand::CreateDocument { + did_method: did_method.clone(), + }) + .then_expect_events(vec![DocumentEvent::DocumentCreated { + document, + document_id: did_method.to_string(), + status: Status::SignAndValidate, + }]) + } + + #[rstest] + #[serial_test::serial] + async fn test_set_public_key_jwks( + did_method: SupportedDidMethod, + document: CoreDocument, + document_with_verification_method: CoreDocument, + ) { + DocumentTestFramework::with(IdentityServices::default()) + .given(vec![DocumentEvent::DocumentCreated { + document, + document_id: did_method.to_string(), + status: Status::SignAndValidate, + }]) + .when(DocumentCommand::SetPublicKeyJwks { + did_method: did_method.clone(), + public_key_jwks: vec![], + }) + .then_expect_events(vec![DocumentEvent::PublicKeyJwksSet { + document_id: did_method.to_string(), + document: document_with_verification_method, + }]) + } + + #[rstest] + #[serial_test::serial] + async fn test_add_service( + did_method: SupportedDidMethod, + document: CoreDocument, + domain_linkage_service: Service, + document_with_verification_method: CoreDocument, + document_with_domain_linkage_service: CoreDocument, + ) { + DocumentTestFramework::with(IdentityServices::default()) + .given(vec![ + DocumentEvent::DocumentCreated { + document_id: did_method.to_string(), + document, + status: Status::SignAndValidate, + }, + DocumentEvent::PublicKeyJwksSet { + document_id: did_method.to_string(), + document: document_with_verification_method, + }, + ]) + .when(DocumentCommand::AddService { + service: domain_linkage_service, + service_id: DOMAIN_LINKAGE_SERVICE_ID.to_string(), + }) + .then_expect_events(vec![DocumentEvent::ServiceAdded { + document_id: did_method.to_string(), + document: document_with_domain_linkage_service, + }]) + } + + #[rstest] + #[serial_test::serial] + async fn test_remove_service( + did_method: SupportedDidMethod, + document: CoreDocument, + document_with_verification_method: CoreDocument, + document_with_domain_linkage_service: CoreDocument, + ) { + DocumentTestFramework::with(IdentityServices::default()) + .given(vec![ + DocumentEvent::DocumentCreated { + document_id: did_method.to_string(), + document, + status: Status::SignAndValidate, + }, + DocumentEvent::PublicKeyJwksSet { + document_id: did_method.to_string(), + document: document_with_verification_method.clone(), + }, + DocumentEvent::ServiceAdded { + document_id: did_method.to_string(), + document: document_with_domain_linkage_service, + }, + ]) + .when(DocumentCommand::RemoveService { + service_id: DOMAIN_LINKAGE_SERVICE_ID.to_string(), + }) + .then_expect_events(vec![DocumentEvent::ServiceRemoved { + document_id: did_method.to_string(), + document: document_with_verification_method, + }]) + } + + #[rstest] + #[serial_test::serial] + async fn test_set_status( + did_method: SupportedDidMethod, + document: CoreDocument, + document_with_verification_method: CoreDocument, + document_with_domain_linkage_service: CoreDocument, + ) { + DocumentTestFramework::with(IdentityServices::default()) + .given(vec![ + DocumentEvent::DocumentCreated { + document_id: did_method.to_string(), + document, + status: Status::SignAndValidate, + }, + DocumentEvent::PublicKeyJwksSet { + document_id: did_method.to_string(), + document: document_with_verification_method.clone(), + }, + DocumentEvent::ServiceAdded { + document_id: did_method.to_string(), + document: document_with_domain_linkage_service, + }, + DocumentEvent::ServiceRemoved { + document_id: did_method.to_string(), + document: document_with_verification_method, + }, + ]) + .when(DocumentCommand::SetStatus { + did_method: did_method.clone(), + status: Status::Disabled, + }) + .then_expect_events(vec![DocumentEvent::StatusSet { + document_id: did_method.to_string(), + status: Status::Disabled, + }]) + } } #[cfg(feature = "test_utils")] pub mod test_utils { + use super::get_properties; + use crate::state::DOMAIN_LINKAGE_SERVICE_ID; + use agent_shared::config::config; use agent_shared::config::SupportedDidMethod; - use agent_shared::{ - config::{config, get_preferred_signing_algorithm}, - from_jsonwebtoken_algorithm_to_jwsalgorithm, - }; use identity_core::convert::FromJson; + use identity_did::CoreDID; use identity_document::{ document::CoreDocument, service::{Service, ServiceEndpoint}, }; + use identity_iota::verification::jwk::Jwk; + use identity_iota::verification::{MethodData, MethodScope, MethodType, VerificationMethod}; use rstest::*; use serde_json::json; #[fixture] - pub fn document_id() -> String { - SupportedDidMethod::Web.to_string() + pub fn did_method() -> SupportedDidMethod { + SupportedDidMethod::Web } - // #[fixture] - // pub async fn document(did_method: DidMethod) -> CoreDocument { - // let mut secret_manager = secret_manager().await; + #[fixture] + pub fn document() -> CoreDocument { + let controller: CoreDID = "did:web:my-domain.example.org".parse().unwrap(); - // let method_specific_parameters = matches!(did_method, DidMethod::Web).then(|| MethodSpecificParameters::Web { - // origin: config().url.origin(), - // }); + CoreDocument::builder(get_properties(MethodType::JSON_WEB_KEY_2020)) + .id(controller.clone()) + .build() + .unwrap() + } + + #[fixture] + pub fn document_with_verification_method(mut document: CoreDocument) -> CoreDocument { + let verification_method = VerificationMethod::builder(Default::default()) + .id( + "did:web:my-domain.example.org#bQKQRzaop7CgEvqVq8UlgLGsdF-R-hnLFkKFZqW2VN0" + .parse() + .unwrap(), + ) + .controller("did:web:my-domain.example.org".parse().unwrap()) + .type_(MethodType::JSON_WEB_KEY_2020) + .data(MethodData::PublicKeyJwk( + Jwk::from_json_value(json!({ + "kty": "OKP", + "alg": "EdDSA", + "kid": "bQKQRzaop7CgEvqVq8UlgLGsdF-R-hnLFkKFZqW2VN0", + "crv": "Ed25519", + "x": "GlnK9ePs802XxAglROQzoGurm9Qpv0IFPEbdMCILN_U" + })) + .unwrap(), + )) + .build() + .unwrap(); + + document + .insert_method(verification_method, MethodScope::VerificationMethod) + .unwrap(); - // secret_manager - // .produce_document( - // did_method, - // method_specific_parameters, - // from_jsonwebtoken_algorithm_to_jwsalgorithm(&get_preferred_signing_algorithm()), - // ) - // .await - // .unwrap() - // } + document + } #[fixture] pub fn domain_linkage_service() -> Service { Service::builder(Default::default()) - .id("did:test:123#linked_domain-service".parse().unwrap()) + .id(format!("did:web:my-domain.example.org#{DOMAIN_LINKAGE_SERVICE_ID}") + .parse() + .unwrap()) .type_("LinkedDomains") .service_endpoint( ServiceEndpoint::from_json_value(json!({ @@ -582,28 +693,15 @@ pub mod test_utils { .unwrap() } - // #[fixture] - // pub async fn document_with_domain_linkage_service( - // did_method: DidMethod, - // domain_linkage_service: Service, - // ) -> CoreDocument { - // let mut secret_manager = secret_manager().await; - - // let method_specific_parameters = matches!(did_method, DidMethod::Web).then(|| MethodSpecificParameters::Web { - // origin: config().url.origin(), - // }); - - // let mut document = secret_manager - // .produce_document( - // did_method, - // method_specific_parameters, - // from_jsonwebtoken_algorithm_to_jwsalgorithm(&get_preferred_signing_algorithm()), - // ) - // .await - // .unwrap(); - - // document.insert_service(domain_linkage_service).unwrap(); - - // document - // } + #[fixture] + pub fn document_with_domain_linkage_service( + mut document_with_verification_method: CoreDocument, + domain_linkage_service: Service, + ) -> CoreDocument { + document_with_verification_method + .insert_service(domain_linkage_service) + .unwrap(); + + document_with_verification_method + } } diff --git a/agent_identity/src/service/aggregate.rs b/agent_identity/src/service/aggregate.rs index a74b9eaa..a0ae3302 100644 --- a/agent_identity/src/service/aggregate.rs +++ b/agent_identity/src/service/aggregate.rs @@ -265,12 +265,13 @@ impl Aggregate for Service { #[cfg(test)] pub mod service_tests { - use agent_shared::config::set_config; - use identity_document::service::Service as DocumentService; - use super::test_utils::*; use super::*; + use crate::document::aggregate::test_utils::document_with_domain_linkage_service; + use agent_shared::config::set_config; use cqrs_es::test::TestFramework; + use identity_document::service::Service as DocumentService; + use identity_iota::document::CoreDocument; use rstest::rstest; type ServiceTestFramework = TestFramework; @@ -281,6 +282,7 @@ pub mod service_tests { domain_linkage_service_id: String, domain_linkage_service: DocumentService, domain_linkage_resource: ServiceResource, + document_with_domain_linkage_service: CoreDocument, ) { set_config().set_preferred_did_method(agent_shared::config::SupportedDidMethod::Web); @@ -288,7 +290,7 @@ pub mod service_tests { .given_no_previous_events() .when(ServiceCommand::CreateDomainLinkageService { service_id: domain_linkage_service_id.clone(), - documents: vec![], + documents: vec![document_with_domain_linkage_service], }) .then_expect_events(vec![ServiceEvent::DomainLinkageServiceCreated { service_id: domain_linkage_service_id, @@ -298,14 +300,39 @@ pub mod service_tests { }]) } + #[rstest] + #[serial_test::serial] + async fn test_delete_domain_linkage_service( + domain_linkage_service_id: String, + domain_linkage_service: DocumentService, + domain_linkage_resource: ServiceResource, + ) { + set_config().set_preferred_did_method(agent_shared::config::SupportedDidMethod::Web); + + ServiceTestFramework::with(IdentityServices::default()) + .given(vec![ServiceEvent::DomainLinkageServiceCreated { + service_id: domain_linkage_service_id.clone(), + status: Status::Created, + service: domain_linkage_service.clone(), + resource: domain_linkage_resource.clone(), + }]) + .when(ServiceCommand::DeleteDomainLinkageService { + service_id: domain_linkage_service_id.clone(), + }) + .then_expect_events(vec![ServiceEvent::DomainLinkageServiceDeleted { + service_id: domain_linkage_service_id, + status: Status::Deleted, + service: None, + resource: None, + }]) + } + #[rstest] #[serial_test::serial] async fn test_create_linked_verifiable_presentation_service( linked_verifiable_presentation_service_id: String, linked_verifiable_presentation_service: DocumentService, ) { - set_config().set_preferred_did_method(agent_shared::config::SupportedDidMethod::Web); - ServiceTestFramework::with(IdentityServices::default()) .given_no_previous_events() .when(ServiceCommand::CreateLinkedVerifiablePresentationService { @@ -327,6 +354,7 @@ pub mod test_utils { use agent_shared::config::config; use identity_core::{common::Url, convert::FromJson}; use identity_document::service::{Service, ServiceEndpoint}; + use identity_iota::document::CoreDocument; use rstest::*; use serde_json::json; @@ -341,11 +369,14 @@ pub mod test_utils { } #[fixture] - pub fn domain_linkage_service(did_web_identifier: String, domain_linkage_service_id: String) -> DocumentService { + pub fn documents() -> Vec { + todo!(); + } + + #[fixture] + pub fn domain_linkage_service(domain_linkage_service_id: String) -> DocumentService { Service::builder(Default::default()) - .id(format!("{did_web_identifier}#{domain_linkage_service_id}") - .parse() - .unwrap()) + .id(format!("did:place:holder#{domain_linkage_service_id}").parse().unwrap()) .type_("LinkedDomains") .service_endpoint( ServiceEndpoint::from_json_value(json!({ @@ -359,17 +390,14 @@ pub mod test_utils { #[fixture] pub fn linked_verifiable_presentation_service( - did_web_identifier: String, linked_verifiable_presentation_service_id: String, ) -> DocumentService { let origin = config().url.origin().ascii_serialization(); Service::builder(Default::default()) - .id( - format!("{did_web_identifier}#{linked_verifiable_presentation_service_id}") - .parse() - .unwrap(), - ) + .id(format!("did:place:holder#{linked_verifiable_presentation_service_id}") + .parse() + .unwrap()) .type_("LinkedVerifiablePresentation") .service_endpoint(ServiceEndpoint::from(OrderedSet::from_iter(vec![format!( "{origin}/linked-verifiable-presentations/presentation-1" @@ -380,13 +408,6 @@ pub mod test_utils { .unwrap() } - #[fixture] - pub fn did_web_identifier() -> String { - let domain = config().url.domain().unwrap().to_string(); - - format!("did:web:{domain}") - } - #[fixture] pub fn domain_linkage_resource() -> ServiceResource { let domain_linkage_configuration = DomainLinkageConfiguration::new(vec![Jwt::from("eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDp3ZWI6bXktZG9tYWluLmV4YW1wbGUub3JnI2tleS0wIn0.eyJleHAiOjMxNTM2MDAwLCJpc3MiOiJkaWQ6d2ViOm15LWRvbWFpbi5leGFtcGxlLm9yZyIsIm5iZiI6MCwic3ViIjoiZGlkOndlYjpteS1kb21haW4uZXhhbXBsZS5vcmciLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vaWRlbnRpdHkuZm91bmRhdGlvbi8ud2VsbC1rbm93bi9kaWQtY29uZmlndXJhdGlvbi92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiRG9tYWluTGlua2FnZUNyZWRlbnRpYWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsib3JpZ2luIjoiaHR0cHM6Ly9teS1kb21haW4uZXhhbXBsZS5vcmcvIn19fQ.l7dEPioa-No5zBlDCthfXDcffRB7371OnLrrQQgeAdnvHhs5F8XqRtdAWKXB8z3Se00WtGxHrTepLKmH9OWJDQ".to_string())]); diff --git a/agent_identity/src/state.rs b/agent_identity/src/state.rs index 8e557c92..de7b651d 100644 --- a/agent_identity/src/state.rs +++ b/agent_identity/src/state.rs @@ -114,13 +114,7 @@ pub const VERIFIABLE_PRESENTATION_SERVICE_ID: &str = "linked-verifiable-presenta pub async fn initialize(state: &IdentityState) { info!("Initializing ..."); - // Only consider updateable DID methods. - let did_methods = config() - .did_methods - .clone() - .into_iter() - .filter(|(did_method, _)| did_method.is_updateable()) - .collect::>(); + let did_methods = config().did_methods.clone().into_iter().collect::>(); info!("DID Methods: {:?}", did_methods); @@ -135,6 +129,7 @@ pub async fn initialize(state: &IdentityState) { // Check whether the DID methods document already exists. let command = match query_handler(&document_id, &state.query.document).await { + // If the DID document exists, then the status needs to be updated. Ok(Some(_document_exists)) => { if *enabled { DocumentCommand::SetStatus { @@ -160,8 +155,6 @@ pub async fn initialize(state: &IdentityState) { } }; - info!("Executing command now: {:#?}", command); - if command_handler(&document_id, &state.command.document, command) .await .is_err() @@ -169,13 +162,9 @@ pub async fn initialize(state: &IdentityState) { warn!("5: Failed to Set status `{did_method}`"); } - info!("C: here"); - - let public_key_jwks = vec![]; - let command = DocumentCommand::SetPublicKeyJwks { did_method: did_method.clone(), - public_key_jwks, + public_key_jwks: vec![], }; if command_handler(&document_id, &state.command.document, command) @@ -185,8 +174,6 @@ pub async fn initialize(state: &IdentityState) { warn!("5: Failed to Set status `{did_method}`"); } - info!("D: here"); - match query_handler(&document_id, &state.query.document).await { Ok(Some(document)) => Ok(document), _ => Err(format!("DID Document for `{}` does not exist", did_method)), @@ -246,28 +233,19 @@ pub async fn initialize(state: &IdentityState) { .map(|document| async { // Clone the variables into the async closure. let document_id = document.document_id.clone(); - info!("document_id: {}", document_id); let did_method = SupportedDidMethod::from_str(&document_id).unwrap(); let service = service.clone(); let command = match document.status { - Status::Disabled => { - info!("I: Removing service: {document_id}"); - DocumentCommand::RemoveService { - service_id: DOMAIN_LINKAGE_SERVICE_ID.to_string(), - } - } - Status::SignAndValidate => { - info!("II: Adding service: {document_id}"); - DocumentCommand::AddService { - service_id: DOMAIN_LINKAGE_SERVICE_ID.to_string(), - service, - } - } + Status::Disabled => DocumentCommand::RemoveService { + service_id: DOMAIN_LINKAGE_SERVICE_ID.to_string(), + }, + Status::SignAndValidate => DocumentCommand::AddService { + service_id: DOMAIN_LINKAGE_SERVICE_ID.to_string(), + service, + }, }; - info!("III: here"); - if command_handler(&document_id, &state.command.document, command) .await .is_err() @@ -323,8 +301,6 @@ pub async fn initialize(state: &IdentityState) { .expect("FIX THISS"); } - info!("Publish all documents"); - try_join_all( // Loop through all DID methods. did_methods diff --git a/agent_issuance/Cargo.toml b/agent_issuance/Cargo.toml index ede082ec..29311d34 100644 --- a/agent_issuance/Cargo.toml +++ b/agent_issuance/Cargo.toml @@ -12,7 +12,7 @@ async-trait.workspace = true cqrs-es.workspace = true chrono.workspace = true types-ob-v3 = { git = "https://github.com/impierce/digital-credential-data-models.git", rev = "9f16c27" } -derivative = "2.2" +derivative.workspace = true identity_core.workspace = true identity_credential.workspace = true jsonwebtoken.workspace = true diff --git a/agent_secret_manager/Cargo.toml b/agent_secret_manager/Cargo.toml index ce588962..fbbe0bb0 100644 --- a/agent_secret_manager/Cargo.toml +++ b/agent_secret_manager/Cargo.toml @@ -19,13 +19,20 @@ did_manager_identity_stronghold_ext = { git = "https://git@github.com/impierce/d anyhow = "1.0" async-trait = "0.1" base64.workspace = true +did-jwk-extern = { version = "0.1.1", package = "did-jwk" } +did-key-extern = { version = "0.2.2", package = "did-method-key" } futures.workspace = true identity_iota.workspace = true iota-sdk.workspace = true +iota_stronghold = { version = "2.1" } +itertools = "0.14" jsonwebtoken = "9.3" log = "0.4" oid4vc-core.workspace = true p256 = { version = "0.13", features = ["jwk"] } +serde_json.workspace = true +ssi-dids = "0.1.1" +ssi-jwk = "0.1.2" tokio.workspace = true url.workspace = true diff --git a/agent_secret_manager/src/lib.rs b/agent_secret_manager/src/lib.rs index 1efa7b26..7272c6ed 100644 --- a/agent_secret_manager/src/lib.rs +++ b/agent_secret_manager/src/lib.rs @@ -10,60 +10,47 @@ use log::info; pub mod service; pub mod subject; -// TODO: Once we have a proper state implementation for `agent_secret_manager` we can make use of randomly generated Key -// IDs. For now we need to make use of these static variables. -pub static ED25519_KEY_ID: &str = "ed25519-0"; -pub static ES256_KEY_ID: &str = "es256-0"; - -// TODO: the stronghold path does not need to be configured through the config file anymore. Is this static variable for -// the stronghold path the right solution? -pub static STRONGHOLD_PATH: &str = "./app/res/stronghold"; - // TODO: find better solution for this pub async fn stronghold_storage() -> StrongholdExtStorage { + iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap(); + info!("Initializing Stronghold storage"); let stronghold_password = config().secret_manager.stronghold_password.clone(); + let stronghold_path = config().secret_manager.stronghold_path.clone(); let stronghold_adapter = StrongholdSecretManager::builder() .password(stronghold_password.clone()) - .build(STRONGHOLD_PATH) + .build(stronghold_path) .expect("Failed to initialize stronghold adapter"); let stronghold_storage = StrongholdExtStorage::new(stronghold_adapter); info!("Stronghold storage initialized"); + let ed25519_key_id = KeyId::new(config().secret_manager.issuer_eddsa_key_id.clone()); + let es256_key_id = KeyId::new(config().secret_manager.issuer_es256_key_id.clone()); + // Generate keys if they don't exist // TODO: currently `generate` will generate a 'static' key-ids for each keytype. In a future improvement we need to // make sure that the key-ids are generated dynamically and stored in some sort of key manager. if stronghold_storage - .get_ed25519_public_key(&identity_iota::storage::KeyId::new(ED25519_KEY_ID)) + .get_ed25519_public_key(&ed25519_key_id) .await .is_err() { - info!( - "Generating new key: {}", - identity_iota::storage::KeyId::new(ED25519_KEY_ID) - ); - let ed25519_key_id = generate(&stronghold_storage, KeyType::new("Ed25519"), JwsAlgorithm::EdDSA) + info!("Generating new key: {ed25519_key_id}",); + let key_id = generate(&stronghold_storage, KeyType::new("Ed25519"), JwsAlgorithm::EdDSA) .await .expect("Failed to generate Ed25519 key"); - assert_eq!(ed25519_key_id.as_str(), ED25519_KEY_ID); + assert_eq!(key_id, ed25519_key_id); } - if stronghold_storage - .get_es256_public_key(&identity_iota::storage::KeyId::new(ES256_KEY_ID)) - .await - .is_err() - { - info!( - "Generating new key: {}", - identity_iota::storage::KeyId::new(ES256_KEY_ID) - ); - let es256_key_id = generate(&stronghold_storage, KeyType::new("ES256"), JwsAlgorithm::ES256) + if stronghold_storage.get_es256_public_key(&es256_key_id).await.is_err() { + info!("Generating new key: {es256_key_id}",); + let key_id = generate(&stronghold_storage, KeyType::new("ES256"), JwsAlgorithm::ES256) .await .expect("Failed to generate ES256 key"); - assert_eq!(es256_key_id.as_str(), ES256_KEY_ID); + assert_eq!(key_id, es256_key_id); } stronghold_storage diff --git a/agent_secret_manager/src/subject.rs b/agent_secret_manager/src/subject.rs index 4fd14fe4..4e89a207 100644 --- a/agent_secret_manager/src/subject.rs +++ b/agent_secret_manager/src/subject.rs @@ -1,18 +1,27 @@ -use crate::{stronghold_storage, ED25519_KEY_ID, ES256_KEY_ID}; -use agent_shared::config::SupportedDidMethod; +use crate::stronghold_storage; +use agent_shared::config::{ + config, get_all_enabled_did_methods, get_all_enabled_signing_algorithms_supported, SupportedDidMethod, +}; use anyhow::anyhow; use async_trait::async_trait; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; use did_manager_consumer::resolver::Resolver; use did_manager_identity_stronghold_ext::StrongholdExtStorage; +use identity_iota::did::CoreDID; use identity_iota::storage::JwkStorage; use identity_iota::{did::DID, document::DIDUrlQuery, storage::KeyId, verification::jwk::JwkParams}; +use itertools::iproduct; use jsonwebtoken::Algorithm; use oid4vc_core::{authentication::sign::ExternalSign, Sign, Verify}; +use serde_json::json; +use ssi_dids::{DIDMethod, Source}; use std::str::FromStr; use std::sync::Arc; use tokio::sync::Mutex; +// See specification: "Since did:jwk only contains a single key, the DID URL fragment identifier is always a fixed #0 value." +const JWK_FRAGMENT: &str = "0"; + /// Reponsible for signing and verifying data. pub struct Subject { pub stronghold_storage: StrongholdExtStorage, @@ -21,9 +30,75 @@ pub struct Subject { impl Subject { pub async fn new() -> Self { + let stronghold_storage = stronghold_storage().await; + let mut did_methods = DidMethods::default(); + + let signing_algorithms = get_all_enabled_signing_algorithms_supported(); + let non_updateable_did_methods = get_all_enabled_did_methods() + .clone() + .into_iter() + .filter(|method| !method.is_updateable()) + .collect::>(); + + let cartesian_product = iproduct!(non_updateable_did_methods.into_iter(), signing_algorithms.into_iter()) + .map(|(did_method, signing_algorithm)| (did_method, signing_algorithm)) + .collect::>(); + + let ed25519_key_id = KeyId::new(config().secret_manager.issuer_eddsa_key_id.clone()); + let es256_key_id = KeyId::new(config().secret_manager.issuer_es256_key_id.clone()); + + for (did_method, signing_algorithm) in cartesian_product { + let public_key_jwk = match signing_algorithm { + Algorithm::EdDSA => { + let public_key_jwk = json!(stronghold_storage + .get_ed25519_public_key(&ed25519_key_id) + .await + .expect("FIX THIS")); + + public_key_jwk + } + Algorithm::ES256 => { + let public_key_jwk = json!(stronghold_storage + .get_es256_public_key(&es256_key_id) + .await + .expect("FIX THIS")); + + public_key_jwk + } + _ => { + todo!() + } + }; + + let jwk: ssi_jwk::JWK = serde_json::from_value(public_key_jwk.clone()).unwrap(); + + let (controller, verification_method_id) = match did_method { + SupportedDidMethod::Jwk => { + let controller = + CoreDID::parse(did_jwk_extern::DIDJWK.generate(&Source::Key(&jwk)).unwrap()).unwrap(); + let verification_method_id = format!("{controller}#{JWK_FRAGMENT}"); + + (controller, verification_method_id) + } + SupportedDidMethod::Key => { + let controller = + CoreDID::parse(did_key_extern::DIDKey.generate(&Source::Key(&jwk)).unwrap()).unwrap(); + let verification_method_id = format!("{controller}#{}", controller.method_id()); + + (controller, verification_method_id) + } + _ => { + todo!() + } + }; + + did_methods.insert_did(&did_method, signing_algorithm, controller.to_string()); + did_methods.insert_verification_method_id(&did_method, signing_algorithm, &verification_method_id); + } + Self { - stronghold_storage: stronghold_storage().await, - did_methods: Default::default(), + stronghold_storage, + did_methods: Arc::new(Mutex::new(did_methods)), } } } @@ -93,14 +168,14 @@ impl Sign for Subject { async fn sign(&self, message: &str, _subject_syntax_type: &str, algorithm: Algorithm) -> anyhow::Result> { let (key_id, public_key) = match algorithm { Algorithm::ES256 => { - let key_id = KeyId::new(ES256_KEY_ID); - let public_key = self.stronghold_storage.get_es256_public_key(&key_id).await?; - (key_id, public_key) + let es256_key_id = KeyId::new(config().secret_manager.issuer_es256_key_id.clone()); + let public_key = self.stronghold_storage.get_es256_public_key(&es256_key_id).await?; + (es256_key_id, public_key) } Algorithm::EdDSA => { - let key_id = KeyId::new(ED25519_KEY_ID); - let public_key = self.stronghold_storage.get_ed25519_public_key(&key_id).await?; - (key_id, public_key) + let ed25519_key_id = KeyId::new(config().secret_manager.issuer_eddsa_key_id.clone()); + let public_key = self.stronghold_storage.get_ed25519_public_key(&ed25519_key_id).await?; + (ed25519_key_id, public_key) } _ => return Err(anyhow!("Unsupported algorithm")), }; @@ -139,7 +214,7 @@ impl oid4vc_core::Subject for Subject { } /// Stores all the DIDs and their associated Verification Method IDs for each (enabled) DID method. -#[derive(Default)] +#[derive(Default, Debug)] pub struct DidMethods { pub did_iota: Algorithms, pub did_iota_smr: Algorithms, @@ -150,17 +225,6 @@ pub struct DidMethods { } impl DidMethods { - pub fn insert(&mut self, method: &SupportedDidMethod, algorithms: Algorithms) { - match method { - SupportedDidMethod::Iota => self.did_iota = algorithms, - SupportedDidMethod::IotaSmr => self.did_iota_smr = algorithms, - SupportedDidMethod::IotaRms => self.did_iota_rms = algorithms, - SupportedDidMethod::Jwk => self.did_jwk = algorithms, - SupportedDidMethod::Key => self.did_key = algorithms, - SupportedDidMethod::Web => self.did_web = algorithms, - } - } - pub fn get(&self, method: &SupportedDidMethod) -> &Algorithms { match method { SupportedDidMethod::Iota => &self.did_iota, @@ -172,10 +236,37 @@ impl DidMethods { } } + pub fn insert_did(&mut self, method: &SupportedDidMethod, algorithm: Algorithm, did: String) { + let algorithms = match method { + SupportedDidMethod::Iota => &mut self.did_iota, + SupportedDidMethod::IotaSmr => &mut self.did_iota_smr, + SupportedDidMethod::IotaRms => &mut self.did_iota_rms, + SupportedDidMethod::Jwk => &mut self.did_jwk, + SupportedDidMethod::Key => &mut self.did_key, + SupportedDidMethod::Web => &mut self.did_web, + }; + + match algorithm { + Algorithm::ES256 => { + let _ = algorithms.es256.insert(DocumentData { + did, + verification_method_id: None, + }); + } + Algorithm::EdDSA => { + let _ = algorithms.eddsa.insert(DocumentData { + did, + verification_method_id: None, + }); + } + _ => {} + } + } + pub fn insert_verification_method_id( &mut self, method: &SupportedDidMethod, - algorithm: &str, + algorithm: Algorithm, verification_method_id: &str, ) { let algorithms = match method { @@ -188,12 +279,12 @@ impl DidMethods { }; match algorithm { - "ES256" => { + Algorithm::ES256 => { if let Some(document_data) = &mut algorithms.es256 { document_data.verification_method_id = Some(verification_method_id.to_string()); } } - "EdDSA" => { + Algorithm::EdDSA => { if let Some(document_data) = &mut algorithms.eddsa { document_data.verification_method_id = Some(verification_method_id.to_string()); } @@ -203,7 +294,7 @@ impl DidMethods { } } -#[derive(Default)] +#[derive(Default, Debug)] pub struct Algorithms { pub es256: Option, pub eddsa: Option, @@ -219,6 +310,7 @@ impl Algorithms { } } +#[derive(Debug)] pub struct DocumentData { pub did: String, pub verification_method_id: Option, @@ -227,7 +319,9 @@ pub struct DocumentData { #[cfg(test)] mod tests { use super::*; - use agent_shared::config::{set_config, SecretManagerConfig}; + use agent_shared::config::{ + default_issuer_eddsa_key_id, default_issuer_es256_key_id, set_config, SecretManagerConfig, + }; use ring::signature::{UnparsedPublicKey, ECDSA_P256_SHA256_FIXED, ED25519}; const ES256_SIGNED_JWT: &str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDpqd2s6ZXlKaGJHY2lPaUpGVXpJMU5pSXNJbU55ZGlJNklsQXRNalUySWl3aWEybGtJam9pTkVGMVdXaFNRMk5HYkc0eWJuUm5VMTlxT1hCRlFtUkxkekl3VUhRdGJHRnFXVWh0V1RkQk1FMUdUU0lzSW10MGVTSTZJa1ZESWl3aWVDSTZJakpNV0dwT1JFOTZWM1J3WlZOWk0ydGlUbEkyWm14YVRVUjRZV2gxYXpKMlVXMWpkWFprUVRodk5EUWlMQ0o1SWpvaVpFRjJSVlpzV0UxSFVFdGFjMnRXV1RSWlZ6QnpPRUk0UzNZM2Myc3hZemt5VDA1WVJFcHZlRjlJY3lKOSMwIn0.eyJpc3MiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOaUlzSW1OeWRpSTZJbEF0TWpVMklpd2lhMmxrSWpvaU5FRjFXV2hTUTJOR2JHNHliblJuVTE5cU9YQkZRbVJMZHpJd1VIUXRiR0ZxV1VodFdUZEJNRTFHVFNJc0ltdDBlU0k2SWtWRElpd2llQ0k2SWpKTVdHcE9SRTk2VjNSd1pWTlpNMnRpVGxJMlpteGFUVVI0WVdoMWF6SjJVVzFqZFhaa1FUaHZORFFpTENKNUlqb2laRUYyUlZac1dFMUhVRXRhYzJ0V1dUUlpWekJ6T0VJNFMzWTNjMnN4WXpreVQwNVlSRXB2ZUY5SWN5SjkiLCJzdWIiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOaUlzSW1OeWRpSTZJbEF0TWpVMklpd2lhMmxrSWpvaU5FRjFXV2hTUTJOR2JHNHliblJuVTE5cU9YQkZRbVJMZHpJd1VIUXRiR0ZxV1VodFdUZEJNRTFHVFNJc0ltdDBlU0k2SWtWRElpd2llQ0k2SWpKTVdHcE9SRTk2VjNSd1pWTlpNMnRpVGxJMlpteGFUVVI0WVdoMWF6SjJVVzFqZFhaa1FUaHZORFFpTENKNUlqb2laRUYyUlZac1dFMUhVRXRhYzJ0V1dUUlpWekJ6T0VJNFMzWTNjMnN4WXpreVQwNVlSRXB2ZUY5SWN5SjkiLCJhdWQiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOaUlzSW1OeWRpSTZJbEF0TWpVMklpd2lhMmxrSWpvaVlrNDNiSEpaWVhOUlZrNDNMVUpZY0MxMFdFVldTR1l0YVhkTWRsVnRiWHByVUZsc2VHWlRWRkZvVlNJc0ltdDBlU0k2SWtWRElpd2llQ0k2SW1odVkyNU5UM2sxU0dGWGJ6SmFTbmhCWW5sWU1GOW1NVTFHU1dsMlRrRmtUMjFXYjNSWGVWZG9ielFpTENKNUlqb2libE5wYkhwMllsTmFYMUp1VWpOU2RreHdkRWxITmpkVWJWVkVhR1ZQWVZGNlltczJhVFJmWDBkeVFTSjkiLCJleHAiOjE3MjMwMjkyMjUsImlhdCI6MTcyMzAyODYyNSwibm9uY2UiOiJ0aGlzIGlzIGEgbm9uY2UifQ.w202CZKOeGM9k35tysJylksBUGI3fvkOgsPPVrfXYZzurns7KF5plMiR_KHH4H_GpYg57Nf2JWa3YEcXGDTVdw"; @@ -236,6 +330,9 @@ mod tests { lazy_static::lazy_static! { static ref SECRET_MANAGER_CONFIG: SecretManagerConfig = SecretManagerConfig { stronghold_password: "sup3rSecr3t".to_string(), + stronghold_path: "/tmp/stronghold".to_string(), + issuer_eddsa_key_id: default_issuer_eddsa_key_id(), + issuer_es256_key_id: default_issuer_es256_key_id(), }; } diff --git a/agent_secret_manager/tests/res/selv.stronghold b/agent_secret_manager/tests/res/selv.stronghold index 110ad624b0a6e436f0a9b94daf42744765f0c7cc..6b927e0b2af1829a4a7c59643fd43b65d7bfd9c0 100644 GIT binary patch delta 1909 zcmV-*2a5Rn42KVpCx1svM?_RnSW`t|O*b}lcr$KJO+`$1ATSCrS5a<6c}Qh*V`N2m zFEBMkV^20maxzOeR#ie&R#9tCMptM>D{fC?H&qHPEiE7~PewN~H#cHZFEeX!PDWC4 zSb9xXO;~I&H!x6SOL9tOLT)QIHEc*&X?F@h$&UN@m-xK24S(ACGFo;{t?m;-WmN7o zkRh6`a1VEie@+3NZ8(C^2>BZu*8->p6KoP$yc#AXOoC>h_+NT8E`_JcC2a0C?R=( z87%-F{PCe`_kRSM)Dh*>Vq_w_-?(n|Jo>;56$%i*#AKfh*NbrdY}$SV-2OUj3=UgV zTlKUCkc=4plM-VLkKTL)dytBr`{>v;NuWcCgN^x$z$QpNyQ|F2HHG!g>hB+g0!Li9 z&dpPScIHe8nN}BCu1L=Q17_i*c&&)7eXdkbq-uL&x_`iVnT~-M&|(9{mrUg7N+IC2 zxW72fIXyD)m@<>Wy6V1)y%!Vns{o`XH{WPFT~ndi1-2@$l)bW)R?c|&M}$AuAxFL# z;!+_+KtQm!4ihqC;;%mkHTy5j7VnSW-2bn+}Ir9Eqr4sT$PeMpIi?CJ^R={4LXQ@-P2C$I%kgcGnKWVhJ4&W z0)K|kqS|3P_!JOtDs2b`B_j<)n8xS{@V_BnXf)q9Dq**@KydWz-ibb48X(UV^xcw9LO|wq#Xh!rW zE?Q_Hl-tifWU|_&mWAQzwIW8qbIN^iDKxf0K{SF^Rsyyy^n<%MmgLmRzSDALzLsWi zU(*8N3_LZlkXg9&aiICTOfSI&5Sh!S5+Hxs`&i6Si24JxHCmV4jnZZE8j@?Asec46 z#zQu`p6@zauy;AZwyQq|7$!nzB0?$_s`i1H!w1zwK%R4$xq7;h*6LBG(~dgb`8mV# z1+)b7Vm8=VZ-$ODs6^l)oEq++5(sWQ&uM*as%nGl+a@FET#j&?Mo=3VHp#l`S<%W_ zAifU4jj_)}yPlB0Ad>hml-jnvVri^c37LaiFTTrRZDN(8$uBTca*_;CHerFRq7tE< zvDIWHO9m!972BHG=QO|swUZxHtQ+3vWDLpJHO_5?7LBZ}7DKj&5<)tZFn?4`ZD10J zY2TOb8*W(@I!l#u@FU=l{o0_WK5X}YaE{KcL_Ip(8_GQW(ut2@1~~5L{)nnpAu4ZF zTS2OrcuWCWhuEAEy@vtqqbc9$*YRl@-+YXLu0azk%L%DCv3#RQTP#@%quNDWHB9d4 zR3Injza%^7)Fbe7*C87y^MB2=@lK=-tQoh;wZu~-YUSPFv2|qz3Ejolu_Tg=C^=S~ z=zZhZWDJnqJ&4c`qQQ#eO6Uf-Fg~%IrTqyr38ol4-E#_FmucV$JoOx<}SEM)dcU%SyVtbJPMKgF2)xiwt0DI)niD^xk^nX+37c;Q~x>sq# z0a?1~gf9PyVstFGr>+&vAG(HWMBA12T@^1SrBWyW5Wjl93`eMfHxx^|7r@NAsjCrM z$po)uld$KFFFsodGUmhZ@mILSw~9#JBOPv11jws_P^JAn>!D$oy+Kzh9f{=*o7dE} zNN-xah1(@z?%3*=F(qWbjlT z$e@$;@~j~iO3~^$+E?}#BVyA?2@#?S$l1`hJbluAwlP=uLT>YO444BxtyHaLfrcs* zb-;^eaPYLM{#wJ%e{D-<@04tQ5X&YCr{Pgnltoe%5<|L`$AwOeeEJGP6YjChnnH&naDQ7;YJr~?Yxm2h~1vGj|+ delta 1639 zcmV-t2AKJW5Bm&|Cx1g@Z)syxOE)lZOi*Y{ICfS-W?ErqATSDaX?09RXE$tYP)&A5 zWJNM+dUZKZS8H%}S!_;iFmPsdcsEu!G%CVNGJM&2)R>8gSDB>|){6;jL#;>q^ltz!MLbj$w|V&$+d?ua)^( z3z89XmkvQ4)lr__g7&C%^IWtQ z`Eq`HG~j4vRl4o7glFxw3ltg@=xqYH|CTJWl-CU03S3$Uz??Y(YN3~+H@BAI!9aQT6L{)5)u#fqJhNyK4X!AS^>tw7yP23QMA@7!C?M)EDL94z; zlGjT(;NASF;l5~6Bi(!mdd9}dn^eFz^ogr6+F6umrBWG_@!AhPJ{d$T3#Ox*r+_AP z=aE)$??1KlUd_a()yRnQ!q(HXc&d5(z<(9&@HJ>hR`Z&SglxnMt5_&OH-iXkNJ%kH z^|t>wtnA#LgKS9RYwP2kL4Vb|F(I*JB9X>RFzsQlKx__gYWNs@;OYTNkOa6dJ$F0H z4fHVdwbr%TVk`EcZi2hKII<&G5wrPR%Wu{bWSN+N2qkXwnJIIIJFnO}OD5HnZ-2pl zBQg7;*Lah#HWjwsL^0l}PEm-7i@nbJ%qL#U7n~3#Wg0L3Mz)S|I#z3pOnTyl3YPOX z(DMw>i$l2Pihg3zlZxJh1rIP+{~Jl!`+1>^AasRPX`;$L9aHWIGlCruA4*yQ12^+w z*lR$D)*yRK^LiHh-G>(Go-3TazapR}&FI9JfZbP%b=XN+%ZXxYT<} znhraKz;Hn3W{02{dzz6cJW9*dc$6m6EEFf>|J3TA%y~NZ%9=~hG&=gJm3tzon4G!RF8afm^MOQ`D0$*(|37DC=#{&Ow}y7ZNvCyxB{9R(q%+CuG$ z7W|NOM7v2(8#{Qz^JjE-CYvauYpO?@ws?{KKugBfF%ZaLKNJ_>R)|*&t4%x;J0*W@ zR+~a>yZ|S9&6xO)%KgO{*nc8P8e~O3TT>ncgKcT*w!p)du4}+5&!j3QuQ#~$TA*x^ zZZKzr=d<4tc&W#KDTJT4hq_YF4nqXwf-c@fdXyA!*0lhzfy5!O+N^>=;q~WWt-!)U zBy&w4s6SJ|sAaXTFXRC5{B|zc7c6VIw5PoLu9%Poz5UEZz8L^3Z(yP^jc-4zT2GE? z)^UHqk)hSikGSyVA)iPMGkDl!Qn_Z4z0vI;vxWiH_gttqgaFhyFj`t1XEIo(noXs@ l90Op|*o@J)IC$VHW+3(}I_%j}wC$_Ix>UQv=qaZ{v(YI^7oz|G diff --git a/agent_shared/src/config.rs b/agent_shared/src/config.rs index d7e814d0..6a898900 100644 --- a/agent_shared/src/config.rs +++ b/agent_shared/src/config.rs @@ -16,6 +16,15 @@ use strum::VariantArray; use tracing::{debug, info}; use url::Url; +// TODO: the stronghold path does not need to be configured through the config file anymore. Is this static variable for +// the stronghold path the right solution? +static STRONGHOLD_PATH: &str = "./app/res/stronghold"; + +// TODO: Once we have a proper state implementation for `agent_secret_manager` we can make use of randomly generated Key +// IDs. For now we need to make use of these static variables. +static ED25519_KEY_ID: &str = "ed25519-0"; +static ES256_KEY_ID: &str = "es256-0"; + #[derive(Debug, Deserialize, Clone)] pub struct ApplicationConfiguration { pub log_format: LogFormat, @@ -66,7 +75,25 @@ pub struct EventStorePostgresConfig { #[derive(Debug, Deserialize, Clone)] pub struct SecretManagerConfig { + #[serde(default = "default_stronghold_path")] + pub stronghold_path: String, pub stronghold_password: String, + #[serde(default = "default_issuer_eddsa_key_id")] + pub issuer_eddsa_key_id: String, + #[serde(default = "default_issuer_es256_key_id")] + pub issuer_es256_key_id: String, +} + +fn default_stronghold_path() -> String { + STRONGHOLD_PATH.to_string() +} + +pub fn default_issuer_eddsa_key_id() -> String { + ED25519_KEY_ID.to_string() +} + +pub fn default_issuer_es256_key_id() -> String { + ES256_KEY_ID.to_string() } #[derive(Debug, Deserialize, Clone)] diff --git a/agent_verification/src/authorization_request/aggregate.rs b/agent_verification/src/authorization_request/aggregate.rs index fbd3c311..b3a2c0ad 100644 --- a/agent_verification/src/authorization_request/aggregate.rs +++ b/agent_verification/src/authorization_request/aggregate.rs @@ -208,10 +208,8 @@ impl Aggregate for AuthorizationRequest { #[cfg(test)] pub mod tests { - use std::str::FromStr; - + use super::*; use agent_secret_manager::service::Service as _; - use agent_secret_manager::stronghold_storage; use agent_secret_manager::subject::Subject; use agent_shared::config::set_config; use agent_shared::config::SupportedDidMethod; @@ -229,16 +227,14 @@ pub mod tests { use oid4vp::PresentationDefinition; use rstest::rstest; use serde_json::json; - - use super::*; + use std::str::FromStr; type AuthorizationRequestTestFramework = TestFramework; #[rstest] #[serial_test::serial] async fn test_create_authorization_request( - #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk, SupportedDidMethod::IotaRms)] - verifier_did_method: SupportedDidMethod, + #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk)] verifier_did_method: SupportedDidMethod, ) { set_config().set_preferred_did_method(verifier_did_method.clone()); @@ -276,8 +272,7 @@ pub mod tests { #[rstest] #[serial_test::serial] async fn test_sign_authorization_request_object( - #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk, SupportedDidMethod::IotaRms)] - verifier_did_method: SupportedDidMethod, + #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk)] verifier_did_method: SupportedDidMethod, ) { set_config().set_preferred_did_method(verifier_did_method.clone()); @@ -318,10 +313,8 @@ pub mod tests { // "id_token" represents the `SIOPv2` flow, and "vp_token" represents the `OID4VP` flow. #[values("id_token", "vp_token")] response_type: &str, // TODO: add `did:web`, check for other tests as well. Probably should be moved to E2E test. - #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk, SupportedDidMethod::IotaRms)] - verifier_did_method: SupportedDidMethod, - #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk, SupportedDidMethod::IotaRms)] - provider_did_method: SupportedDidMethod, + #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk)] verifier_did_method: SupportedDidMethod, + #[values(SupportedDidMethod::Key, SupportedDidMethod::Jwk)] provider_did_method: SupportedDidMethod, ) { set_config().set_preferred_did_method(verifier_did_method.clone()); @@ -540,12 +533,7 @@ pub mod tests { } lazy_static! { - pub static ref VERIFIER: Subject = futures::executor::block_on(async { - Subject { - stronghold_storage: stronghold_storage().await, - did_methods: Default::default(), - } - }); + pub static ref VERIFIER: Subject = futures::executor::block_on(async { Subject::new().await }); pub static ref REDIRECT_URI: url::Url = "https://my-domain.example.org/redirect".parse::().unwrap(); pub static ref PRESENTATION_DEFINITION: PresentationDefinition = serde_json::from_value(json!( {