Skip to content

Commit

Permalink
fix: remove Subjects type
Browse files Browse the repository at this point in the history
  • Loading branch information
nanderstabel committed Apr 4, 2024
1 parent dd9c1d0 commit cc192b4
Show file tree
Hide file tree
Showing 25 changed files with 119 additions and 173 deletions.
4 changes: 2 additions & 2 deletions oid4vc-core/src/authentication/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::sync::Arc;
pub trait Sign: Send + Sync {
// TODO: add this?
// fn jwt_alg_name() -> &'static str;
fn key_id(&self, did_method: &str) -> Option<String>;
fn sign(&self, message: &str, did_method: &str) -> Result<Vec<u8>>;
fn key_id(&self, subject_syntax_type: &str) -> Option<String>;
fn sign(&self, message: &str, subject_syntax_type: &str) -> Result<Vec<u8>>;
fn external_signer(&self) -> Option<Arc<dyn ExternalSign>>;
}

Expand Down
24 changes: 3 additions & 21 deletions oid4vc-core/src/authentication/subject.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
use crate::{Collection, Sign, SubjectSyntaxType, Verify};
use crate::{Sign, Verify};
use anyhow::Result;
use std::{str::FromStr, sync::Arc};
use std::sync::Arc;

pub type SigningSubject = Arc<dyn Subject>;

// TODO: Use a URI of some sort.
/// This [`Subject`] trait is used to sign and verify JWTs.
pub trait Subject: Sign + Verify + Send + Sync {
fn identifier(&self, did_method: &str) -> Result<String>;
fn type_(&self) -> Result<SubjectSyntaxType> {
SubjectSyntaxType::from_str(&self.identifier("FIX_THIS")?)
}
}

pub type Subjects = Collection<dyn Subject>;

impl<const N: usize> TryFrom<[Arc<dyn Subject>; N]> for Subjects {
type Error = anyhow::Error;

fn try_from(subjects: [Arc<dyn Subject>; N]) -> Result<Self> {
Ok(Self::from(
subjects
.iter()
.map(|subject| subject.type_().map(|subject_type| (subject_type, subject.clone())))
.collect::<Result<Vec<_>>>()?,
))
}
fn identifier(&self, subject_syntax_type: &str) -> Result<String>;
}
20 changes: 1 addition & 19 deletions oid4vc-core/src/authentication/validator.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
use crate::{jwt, Collection, Subject, Subjects, Verify};
use crate::{jwt, Subject, Verify};
use anyhow::Result;
use serde::de::DeserializeOwned;
use std::sync::Arc;

pub type Validators = Collection<Validator>;

impl From<&Subjects> for Validators {
fn from(subjects: &Subjects) -> Self {
Self::from(
subjects
.iter()
.map(|(subject_syntax_type, subject)| {
(
subject_syntax_type.clone(),
Arc::new(Validator::Subject(subject.clone())),
)
})
.collect::<Vec<_>>(),
)
}
}

pub enum Validator {
Subject(Arc<dyn Subject>),
Verifier(Arc<dyn Verify>),
Expand Down
37 changes: 0 additions & 37 deletions oid4vc-core/src/collection.rs

This file was deleted.

8 changes: 5 additions & 3 deletions oid4vc-core/src/jwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,20 @@ where
Ok(jsonwebtoken::decode::<T>(jwt, &key, &validation)?.claims)
}

pub fn encode<C, S>(signer: Arc<S>, header: Header, claims: C, did_method: &str) -> Result<String>
pub fn encode<C, S>(signer: Arc<S>, header: Header, claims: C, subject_syntax_type: &str) -> Result<String>
where
C: Serialize,
S: Sign + ?Sized,
{
let kid = signer.key_id(did_method).ok_or(anyhow!("No key identifier found."))?;
let kid = signer
.key_id(subject_syntax_type)
.ok_or(anyhow!("No key identifier found."))?;

let jwt = JsonWebToken::new(header, claims).kid(kid);

let message = [base64_url_encode(&jwt.header)?, base64_url_encode(&jwt.payload)?].join(".");

let proof_value = signer.sign(&message, did_method)?;
let proof_value = signer.sign(&message, subject_syntax_type)?;
let signature = base64_url::encode(proof_value.as_slice());
let message = [message, signature].join(".");
Ok(message)
Expand Down
9 changes: 1 addition & 8 deletions oid4vc-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,13 @@ pub mod authentication;
pub mod authorization_request;
pub mod authorization_response;
pub mod client_metadata;
pub mod collection;
pub mod jwt;
pub mod openid4vc_extension;
pub mod rfc7519_claims;
pub mod scope;
pub mod subject_syntax_type;

pub use authentication::{
sign::Sign,
subject::{Subject, Subjects},
validator::{Validator, Validators},
verify::Verify,
};
pub use collection::Collection;
pub use authentication::{sign::Sign, subject::Subject, validator::Validator, verify::Verify};
use rand::{distributions::Alphanumeric, Rng};
pub use rfc7519_claims::RFC7519Claims;
use serde::Serialize;
Expand Down
4 changes: 2 additions & 2 deletions oid4vc-core/src/openid4vc_extension.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{authorization_response::AuthorizationResponse, Subject, Validator};
use crate::{authorization_response::AuthorizationResponse, Subject, SubjectSyntaxType, Validator};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{future::Future, sync::Arc};

Expand Down Expand Up @@ -28,7 +28,7 @@ pub trait Extension: Serialize + PartialEq + Sized + std::fmt::Debug + Clone + S
_client_id: &str,
_extension_parameters: &<Self::RequestHandle as RequestHandle>::Parameters,
_user_input: &<Self::ResponseHandle as ResponseHandle>::Input,
_did_method: &str,
_subject_syntax_type: impl TryInto<SubjectSyntaxType>,
) -> anyhow::Result<Vec<String>> {
// Will be overwritten by the extension.
Err(anyhow::anyhow!("Not implemented."))
Expand Down
17 changes: 17 additions & 0 deletions oid4vc-core/src/subject_syntax_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@ impl FromStr for SubjectSyntaxType {
}
}

impl Display for SubjectSyntaxType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SubjectSyntaxType::JwkThumbprint => write!(f, "urn:ietf:params:oauth:jwk-thumbprint"),
SubjectSyntaxType::Did(did_method) => write!(f, "{}", did_method),
}
}
}

impl TryFrom<&str> for SubjectSyntaxType {
type Error = anyhow::Error;

fn try_from(value: &str) -> Result<Self, Self::Error> {
SubjectSyntaxType::from_str(value)
}
}

impl From<DidMethod> for SubjectSyntaxType {
fn from(did_method: DidMethod) -> Self {
SubjectSyntaxType::Did(did_method)
Expand Down
2 changes: 1 addition & 1 deletion oid4vc-core/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl Verify for TestSubject {
}

impl Subject for TestSubject {
fn identifier(&self, _default_did_method: &str) -> Result<String> {
fn identifier(&self, _subject_syntax_type: &str) -> Result<String> {
Ok(self.did.to_string())
}
}
Expand Down
17 changes: 5 additions & 12 deletions oid4vc-manager/src/managers/credential_issuer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::storage::Storage;
use anyhow::Result;
use oid4vc_core::{Subject, Subjects};
use oid4vc_core::Subject;
use oid4vci::{
credential_format_profiles::CredentialFormatCollection,
credential_issuer::{
Expand All @@ -15,26 +15,19 @@ use std::{net::TcpListener, sync::Arc};
#[derive(Clone)]
pub struct CredentialIssuerManager<S: Storage<CFC>, CFC: CredentialFormatCollection> {
pub credential_issuer: CredentialIssuer<CFC>,
pub subjects: Arc<Subjects>,
pub subject: Arc<dyn Subject>,
pub storage: S,
pub listener: Arc<TcpListener>,
}

impl<S: Storage<CFC>, CFC: CredentialFormatCollection> CredentialIssuerManager<S, CFC> {
pub fn new<const N: usize>(
listener: Option<TcpListener>,
storage: S,
subjects: [Arc<dyn Subject>; N],
) -> Result<Self> {
pub fn new(listener: Option<TcpListener>, storage: S, subject: Arc<dyn Subject>) -> Result<Self> {
// `TcpListener::bind("127.0.0.1:0")` will bind to a random port.
let listener = listener.unwrap_or_else(|| TcpListener::bind("127.0.0.1:0").unwrap());
let issuer_url: Url = format!("http://{:?}", listener.local_addr()?).parse()?;
Ok(Self {
credential_issuer: CredentialIssuer {
subject: subjects
.first()
.ok_or_else(|| anyhow::anyhow!("No subjects found."))?
.clone(),
subject: subject.clone(),
metadata: CredentialIssuerMetadata {
credential_issuer: issuer_url.clone(),
authorization_servers: vec![],
Expand All @@ -56,7 +49,7 @@ impl<S: Storage<CFC>, CFC: CredentialFormatCollection> CredentialIssuerManager<S
..Default::default()
},
},
subjects: Arc::new(Subjects::try_from(subjects)?),
subject,
storage,
listener: Arc::new(listener),
})
Expand Down
11 changes: 5 additions & 6 deletions oid4vc-manager/src/managers/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ pub struct ProviderManager {
}

impl ProviderManager {
pub fn new<const N: usize>(subjects: [Arc<dyn Subject>; N], default_did_method: String) -> Result<Self> {
pub fn new(
subject: Arc<dyn Subject>,
default_subject_syntax_type: impl TryInto<SubjectSyntaxType>,
) -> Result<Self> {
Ok(Self {
provider: Provider::new(subjects[0].clone(), default_did_method)?,
provider: Provider::new(subject, default_subject_syntax_type)?,
})
}

Expand All @@ -39,8 +42,4 @@ impl ProviderManager {
) -> Result<StatusCode> {
self.provider.send_response(authorization_response).await
}

pub fn current_subject_syntax_type(&self) -> Result<SubjectSyntaxType> {
self.provider.subject.type_()
}
}
15 changes: 4 additions & 11 deletions oid4vc-manager/src/managers/relying_party.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use anyhow::{anyhow, Result};
use anyhow::Result;
use oid4vc_core::{
authorization_request::{AuthorizationRequest, Object},
authorization_response::AuthorizationResponse,
openid4vc_extension::{Extension, ResponseHandle},
Subject, SubjectSyntaxType,
Subject,
};
use siopv2::RelyingParty;
use std::sync::Arc;
Expand All @@ -14,12 +14,9 @@ pub struct RelyingPartyManager {
}

impl RelyingPartyManager {
pub fn new<const N: usize>(subjects: [Arc<dyn Subject>; N], default_did_method: String) -> Result<Self> {
pub fn new(subject: Arc<dyn Subject>, subject_syntax_type: String) -> Result<Self> {
Ok(Self {
relying_party: RelyingParty::new(
subjects.get(0).ok_or_else(|| anyhow!("No subjects found."))?.clone(),
default_did_method,
)?,
relying_party: RelyingParty::new(subject, subject_syntax_type)?,
})
}

Expand All @@ -33,8 +30,4 @@ impl RelyingPartyManager {
) -> Result<<E::ResponseHandle as ResponseHandle>::ResponseItem> {
self.relying_party.validate_response(authorization_response).await
}

pub fn current_subject_syntax_type(&self) -> Result<SubjectSyntaxType> {
self.relying_party.subject.type_()
}
}
6 changes: 3 additions & 3 deletions oid4vc-manager/src/methods/key_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl Verify for KeySubject {
}

impl Subject for KeySubject {
fn identifier(&self, _did_method: &str) -> Result<String> {
fn identifier(&self, _subject_syntax_type: &str) -> Result<String> {
Ok(self.document.id.clone())
}
}
Expand Down Expand Up @@ -120,7 +120,7 @@ mod tests {
let subject = KeySubject::new();

// Create a new provider manager.
let provider_manager = ProviderManager::new([Arc::new(subject)], "did:key".to_string()).unwrap();
let provider_manager = ProviderManager::new(Arc::new(subject), "did:key").unwrap();

// Get a new SIOP authorization_request with response mode `direct_post` for cross-device communication.
let request_url = "\
Expand Down Expand Up @@ -152,7 +152,7 @@ mod tests {

// Let the relying party validate the authorization_response.
let relying_party_manager =
RelyingPartyManager::new([Arc::new(KeySubject::new())], "did:key".to_string()).unwrap();
RelyingPartyManager::new(Arc::new(KeySubject::new()), "did:key".to_string()).unwrap();
assert!(relying_party_manager
.validate_response(&authorization_response)
.await
Expand Down
2 changes: 1 addition & 1 deletion oid4vc-manager/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl Verify for TestSubject {
}

impl Subject for TestSubject {
fn identifier(&self, _did_method: &str) -> Result<String> {
fn identifier(&self, _subject_syntax_type: &str) -> Result<String> {
Ok(self.did.to_string())
}
}
Expand Down
4 changes: 2 additions & 2 deletions oid4vc-manager/tests/oid4vci/authorization_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ async fn test_authorization_code_flow() {
CredentialIssuerManager::<_, CredentialFormats<WithParameters>>::new(
None,
MemoryStorage,
[Arc::new(KeySubject::from_keypair(
Arc::new(KeySubject::from_keypair(
generate::<Ed25519KeyPair>(Some(
"this-is-a-very-UNSAFE-issuer-secret-key".as_bytes().try_into().unwrap(),
)),
None,
))],
)),
)
.unwrap(),
None,
Expand Down
4 changes: 2 additions & 2 deletions oid4vc-manager/tests/oid4vci/pre_authorized_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ async fn test_pre_authorized_code_flow(#[case] batch: bool, #[case] by_reference
CredentialIssuerManager::new(
None,
MemoryStorage,
[Arc::new(KeySubject::from_keypair(
Arc::new(KeySubject::from_keypair(
generate::<Ed25519KeyPair>(Some(
"this-is-a-very-UNSAFE-issuer-secret-key".as_bytes().try_into().unwrap(),
)),
None,
))],
)),
)
.unwrap(),
None,
Expand Down
4 changes: 2 additions & 2 deletions oid4vc-manager/tests/oid4vp/implicit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async fn test_implicit_flow() {
// Create a new relying party.
let relying_party = Arc::new(KeySubject::new());
let relying_party_did = relying_party.identifier("did:key").unwrap();
let relying_party_manager = RelyingPartyManager::new([relying_party], "did:key".to_string()).unwrap();
let relying_party_manager = RelyingPartyManager::new(relying_party, "did:key".to_string()).unwrap();

// Create authorization request with response_type `id_token vp_token`
let authorization_request = AuthorizationRequest::<Object<OID4VP>>::builder()
Expand All @@ -101,7 +101,7 @@ async fn test_implicit_flow() {
.unwrap();

// Create a provider manager and validate the authorization request.
let provider_manager = ProviderManager::new([subject], "did:key".to_string()).unwrap();
let provider_manager = ProviderManager::new(subject, "did:key").unwrap();

// Create a new verifiable credential.
let verifiable_credential = VerifiableCredentialJwt::builder()
Expand Down
Loading

0 comments on commit cc192b4

Please sign in to comment.