Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions agent_api_rest/src/issuance/credential_issuer/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,11 @@ pub(crate) async fn credential(
}
Some(OfferView {
credential_ids,
subject_id: Some(subject_id),
subject_id,
..
}) => break (credential_ids, subject_id),
}) => {
break (credential_ids, subject_id);
}
_ => {
return Err(internal_server_error());
}
Expand Down Expand Up @@ -163,6 +165,7 @@ pub mod tests {
};

const CREDENTIAL_JWT: &str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2dFODROQ01wTWVBeDlqSzljZjVXNEc4Z2NaOXh1d0p2RzFlN3dOazhLQ2d0I3o2TWtnRTg0TkNNcE1lQXg5aks5Y2Y1VzRHOGdjWjl4dXdKdkcxZTd3Tms4S0NndCJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtnRTg0TkNNcE1lQXg5aks5Y2Y1VzRHOGdjWjl4dXdKdkcxZTd3Tms4S0NndCIsInN1YiI6ImRpZDprZXk6ejZNa2lpZXlvTE1TVnNKQVp2N0pqZTV3V1NrREV5bVVna3lGOGtiY3JqWnBYM3FkIiwibmJmIjoxMjYyMzA0MDAwLCJpYXQiOjEyNjIzMDQwMDAsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6a2V5Ono2TWtpaWV5b0xNU1ZzSkFadjdKamU1d1dTa0RFeW1VZ2t5RjhrYmNyalpwWDNxZCIsImZpcnN0X25hbWUiOiJGZXJyaXMiLCJsYXN0X25hbWUiOiJSdXN0YWNlYW4ifSwiaXNzdWVyIjoiZGlkOmtleTp6Nk1rZ0U4NE5DTXBNZUF4OWpLOWNmNVc0RzhnY1o5eHV3SnZHMWU3d05rOEtDZ3QiLCJpc3N1YW5jZURhdGUiOiIyMDEwLTAxLTAxVDAwOjAwOjAwWiIsImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL215LWRvbWFpbi5leGFtcGxlLm9yZy9pZXRmLW9hdXRoLXRva2VuLXN0YXR1cy1saXN0LzAiLCJ0eXBlIjoic3RhdHVzbGlzdCtqd3QiLCJpZHgiOjEyMywidXJpIjoiaHR0cHM6Ly9teS1kb21haW4uZXhhbXBsZS5vcmcvaWV0Zi1vYXV0aC10b2tlbi1zdGF0dXMtbGlzdC8wIn19LCJzdGF0dXMiOnsic3RhdHVzX2xpc3QiOnsiaWR4IjoxMjMsInVyaSI6Imh0dHBzOi8vbXktZG9tYWluLmV4YW1wbGUub3JnL2lldGYtb2F1dGgtdG9rZW4tc3RhdHVzLWxpc3QvMCJ9fX0.LpNq8l-qqqCA-htsB8KZLaVoNCfxqTrsPxVmEj0dsPAGFhOqO8lXI7DU0FhNwzWedxJ1ySS_Vq7ChBW-TgY7Bw";
const ANONYMOUS_CREDENTIAL_JWT: &str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2dFODROQ01wTWVBeDlqSzljZjVXNEc4Z2NaOXh1d0p2RzFlN3dOazhLQ2d0I3o2TWtnRTg0TkNNcE1lQXg5aks5Y2Y1VzRHOGdjWjl4dXdKdkcxZTd3Tms4S0NndCJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtnRTg0TkNNcE1lQXg5aks5Y2Y1VzRHOGdjWjl4dXdKdkcxZTd3Tms4S0NndCIsIm5iZiI6MTI2MjMwNDAwMCwiaWF0IjoxMjYyMzA0MDAwLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImZpcnN0X25hbWUiOiJGZXJyaXMiLCJsYXN0X25hbWUiOiJSdXN0YWNlYW4ifSwiaXNzdWVyIjoiZGlkOmtleTp6Nk1rZ0U4NE5DTXBNZUF4OWpLOWNmNVc0RzhnY1o5eHV3SnZHMWU3d05rOEtDZ3QiLCJpc3N1YW5jZURhdGUiOiIyMDEwLTAxLTAxVDAwOjAwOjAwWiIsImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL215LWRvbWFpbi5leGFtcGxlLm9yZy9pZXRmLW9hdXRoLXRva2VuLXN0YXR1cy1saXN0LzAiLCJ0eXBlIjoic3RhdHVzbGlzdCtqd3QiLCJpZHgiOjEyMywidXJpIjoiaHR0cHM6Ly9teS1kb21haW4uZXhhbXBsZS5vcmcvaWV0Zi1vYXV0aC10b2tlbi1zdGF0dXMtbGlzdC8wIn19LCJzdGF0dXMiOnsic3RhdHVzX2xpc3QiOnsiaWR4IjoxMjMsInVyaSI6Imh0dHBzOi8vbXktZG9tYWluLmV4YW1wbGUub3JnL2lldGYtb2F1dGgtdG9rZW4tc3RhdHVzLWxpc3QvMCJ9fX0.SxT7dwfIdkqTTYnSDzAEE5-csEUb9ucWWEcgIgDEEiK7VwsdW9k7ozLvi79Yfa71Q1buILLJdzLYf1mHE-V2Bg";
const DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS: u64 = 1000;

trait CredentialEventTrigger {
Expand Down Expand Up @@ -255,15 +258,17 @@ pub 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)]
#[case::without_external_server(false, false, false, 0)]
#[case::with_anonymous_access(true, false, false, 0)]
#[case::with_external_server(false, true, false, 0)]
#[case::with_external_server_and_self_signed_credential(false, true, true, 0)]
#[should_panic(expected = "assertion `left == right` failed\n left: 500\n right: 200")]
#[case::should_panic_due_to_timeout(true, false, DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS + 100)]
#[case::should_panic_due_to_timeout(false, true, false, DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS + 100)]
#[serial_test::serial]
#[tokio::test(flavor = "multi_thread")]
#[tracing_test::traced_test]
async fn test_credential_endpoint(
#[case] with_anonymous_access: bool,
#[case] with_external_server: bool,
#[case] is_self_signed: bool,
#[case] delay: u64,
Expand Down Expand Up @@ -310,6 +315,12 @@ pub mod tests {

let access_token: String = token(&mut app, pre_authorized_code).await;

let jwt = if with_anonymous_access {
"eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IkVkRFNBIiwia2lkIjoiZGlkOmtleTp6Nk1rcHc2OGh1OVFnTUFDNmJDOE0xeFo0cDZ4VXNFeUs0bUtZdEtNYkpnTmRrSjIjejZNa3B3NjhodTlRZ01BQzZiQzhNMXhaNHA2eFVzRXlLNG1LWXRLTWJKZ05ka0oyIn0.eyJhdWQiOiJodHRwOi8vMTI3LjAuMC4xOjQwNzI1LyIsImlhdCI6MTc2MjI2NTgxMH0.GuGCIl-0VGkADdbWkcL56P5jXZjGKBzYbr-gPfQ5Yl7u4KltF1pjle52RuTVInxIQXeP9GuDL1Ag52B6Y0NSAg"
} else {
"eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IkVkRFNBIiwia2lkIjoiZGlkOmtleTp6Nk1raWlleW9MTVNWc0pBWnY3SmplNXdXU2tERXltVWdreUY4a2JjcmpacFgzcWQjejZNa2lpZXlvTE1TVnNKQVp2N0pqZTV3V1NrREV5bVVna3lGOGtiY3JqWnBYM3FkIn0.eyJpc3MiOiJkaWQ6a2V5Ono2TWtpaWV5b0xNU1ZzSkFadjdKamU1d1dTa0RFeW1VZ2t5RjhrYmNyalpwWDNxZCIsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS5jb20vIiwiZXhwIjo5OTk5OTk5OTk5LCJpYXQiOjE1NzEzMjQ4MDAsIm5vbmNlIjoiN2UwM2FkM2Y3NmNiMzMzOGMzYTU2NDJmZTc2MzQ0NzZhYTNhZDkzZmExZDU4NDAxMWJhMjE1MGQ5ZGE0NzEzMyJ9.bDxmEWTGwKJJC8J5N16JHAR2ZBYtgWlhM_o_voJdXLnw_ScZMwGjZwNH6aQWKlgIaFWKonF88KNRFX2UAOAuBQ"
};

let response = app
.oneshot(
Request::builder()
Expand All @@ -322,15 +333,7 @@ pub mod tests {
"credential_configuration_id": CREDENTIAL_CONFIGURATION_ID,
"proof": {
"proof_type": "jwt",
"jwt": "eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IkVkRFNBIiwia2lk\
IjoiZGlkOmtleTp6Nk1raWlleW9MTVNWc0pBWnY3SmplNXdXU2tERXltVWdreUY4\
a2JjcmpacFgzcWQjejZNa2lpZXlvTE1TVnNKQVp2N0pqZTV3V1NrREV5bVVna3lG\
OGtiY3JqWnBYM3FkIn0.eyJpc3MiOiJkaWQ6a2V5Ono2TWtpaWV5b0xNU1ZzSkFa\
djdKamU1d1dTa0RFeW1VZ2t5RjhrYmNyalpwWDNxZCIsImF1ZCI6Imh0dHBzOi8v\
ZXhhbXBsZS5jb20vIiwiZXhwIjo5OTk5OTk5OTk5LCJpYXQiOjE1NzEzMjQ4MDAs\
Im5vbmNlIjoiN2UwM2FkM2Y3NmNiMzMzOGMzYTU2NDJmZTc2MzQ0NzZhYTNhZDkz\
ZmExZDU4NDAxMWJhMjE1MGQ5ZGE0NzEzMyJ9.bDxmEWTGwKJJC8J5N16JHAR2ZBY\
tgWlhM_o_voJdXLnw_ScZMwGjZwNH6aQWKlgIaFWKonF88KNRFX2UAOAuBQ"
"jwt": jwt
}
}))
.unwrap(),
Expand All @@ -345,7 +348,12 @@ pub mod tests {

let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap();
let body: Value = serde_json::from_slice(&body).unwrap();
assert_eq!(body["credentials"][0]["credential"], json!(CREDENTIAL_JWT));

if with_anonymous_access {
assert_eq!(body["credentials"][0]["credential"], json!(ANONYMOUS_CREDENTIAL_JWT));
} else {
assert_eq!(body["credentials"][0]["credential"], json!(CREDENTIAL_JWT));
}

if let Some(external_server) = external_server {
// Assert that the event was dispatched to the target URL.
Expand Down
2 changes: 1 addition & 1 deletion agent_event_publisher_http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ mod tests {
// A new event for the `Offer` aggregate that the publisher is not interested in.
let offer_event = OfferEvent::CredentialRequestVerified {
offer_id: Default::default(),
subject_id: "subject_id".to_string(),
subject_id: Some("subject_id".to_string()),
};

let events = [EventEnvelope::<Offer> {
Expand Down
17 changes: 10 additions & 7 deletions agent_issuance/src/credential/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,10 @@ impl Aggregate for Credential {

// Create a new Map and insert the id field first
let mut new_credential_subject = serde_json::Map::new();
new_credential_subject.insert("id".to_string(), json!(subject_id));

if let Some(subject_id) = &subject_id {
new_credential_subject.insert("id".to_string(), json!(subject_id));
}

// Insert the rest of the fields
for (key, value) in credential_subject {
Expand Down Expand Up @@ -407,11 +410,11 @@ impl Aggregate for Credential {
});

// Add standard claims
let vc_jwt_builder = VerifiableCredentialJwt::builder()
.sub(subject_id)
.iss(issuer_did)
.iat(iat)
.nbf(iat); // TODO: setting the `nbf` to `iat` makes the JWT immediately usable
let mut vc_jwt_builder = VerifiableCredentialJwt::builder().iss(issuer_did).iat(iat).nbf(iat); // TODO: setting the `nbf` to `iat` makes the JWT immediately usable

if let Some(subject_id) = subject_id {
vc_jwt_builder = vc_jwt_builder.sub(subject_id);
}

let vc_jwt_builder = if let Some(exp) = exp {
vc_jwt_builder.exp(exp)
Expand Down Expand Up @@ -651,7 +654,7 @@ pub mod credential_tests {
}])
.when(CredentialCommand::SignCredential {
credential_id: credential_id.clone(),
subject_id: holder.identifier("did:key", Algorithm::EdDSA).await.unwrap(),
subject_id: Some(holder.identifier("did:key", Algorithm::EdDSA).await.unwrap()),
overwrite: false,
})
.then_expect_events(vec![CredentialEvent::CredentialSigned {
Expand Down
2 changes: 1 addition & 1 deletion agent_issuance/src/credential/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub enum CredentialCommand {
},
SignCredential {
credential_id: String,
subject_id: String,
subject_id: Option<String>,
// When true, a credential will be re-signed if it already exists.
overwrite: bool,
},
Expand Down
15 changes: 5 additions & 10 deletions agent_issuance/src/offer/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,7 @@ impl Aggregate for Offer {
.await
.map_err(|e| InvalidProofError(e.to_string()))?;

let subject_did = proof
.rfc7519_claims
.iss()
.as_ref()
.ok_or(MissingProofIssuerError)?
.clone();
let subject_did = proof.rfc7519_claims.iss().as_ref().cloned();

Ok(vec![CredentialRequestVerified {
offer_id,
Expand Down Expand Up @@ -351,7 +346,7 @@ impl Aggregate for Offer {
}
CredentialOfferSent { .. } => {}
CredentialRequestVerified { subject_id, .. } => {
self.subject_id.replace(subject_id);
self.subject_id = subject_id;
}
TokenResponseCreated { token_response, .. } => {
self.token_response.replace(token_response);
Expand Down Expand Up @@ -576,7 +571,7 @@ pub mod tests {
})
.then_expect_events(vec![OfferEvent::CredentialRequestVerified {
offer_id: offer_id.clone(),
subject_id: holder.identifier("did:key", Algorithm::EdDSA).await.unwrap(),
subject_id: Some(holder.identifier("did:key", Algorithm::EdDSA).await.unwrap()),
}]);
}

Expand Down Expand Up @@ -626,7 +621,7 @@ pub mod tests {
},
OfferEvent::CredentialRequestVerified {
offer_id: offer_id.clone(),
subject_id: holder.identifier("did:key", Algorithm::EdDSA).await.unwrap(),
subject_id: Some(holder.identifier("did:key", Algorithm::EdDSA).await.unwrap()),
},
])
.when(OfferCommand::CreateCredentialResponse {
Expand Down Expand Up @@ -684,7 +679,7 @@ pub mod tests {
},
OfferEvent::CredentialRequestVerified {
offer_id: offer_id.clone(),
subject_id: holder.identifier("did:key", Algorithm::EdDSA).await.unwrap(),
subject_id: Some(holder.identifier("did:key", Algorithm::EdDSA).await.unwrap()),
},
// Credentials are only added after the credential request is verified (JIT)
OfferEvent::CredentialsAdded {
Expand Down
2 changes: 1 addition & 1 deletion agent_issuance/src/offer/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub enum OfferEvent {
},
CredentialRequestVerified {
offer_id: String,
subject_id: String,
subject_id: Option<String>,
},
CredentialResponseCreated {
offer_id: String,
Expand Down
2 changes: 1 addition & 1 deletion agent_issuance/src/offer/views/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl View<Offer> for Offer {
}
CredentialRequestVerified { offer_id, subject_id } => {
self.offer_id.clone_from(offer_id);
self.subject_id.replace(subject_id.clone());
self.subject_id.clone_from(subject_id);
}
TokenResponseCreated {
offer_id,
Expand Down
Loading