Skip to main content

aep_agent/
types.rs

1use std::{collections::BTreeMap, sync::Arc, time::Duration};
2
3use aep_core::{
4    AssertionOperation, AuthenticationMethod, BuiltInGrantResponse, ClaimValues,
5    ClientAssertionClaims, Command, GrantType, HttpTransport, IdentityMethod, InspectDocument,
6    ProtectedResourceAuthorization, SigningAlgorithm,
7};
8use async_trait::async_trait;
9use http::HeaderMap;
10use serde_json::Value;
11use time::OffsetDateTime;
12use url::Url;
13
14use crate::AgentError;
15
16#[derive(Clone, Debug, PartialEq)]
17pub struct AgentIdentity {
18    pub agent_did: String,
19    pub identity_method: IdentityMethod,
20    pub service_did: String,
21    pub signing_algorithms: Vec<SigningAlgorithm>,
22    pub metadata: BTreeMap<String, String>,
23}
24
25#[derive(Clone, Debug, PartialEq)]
26pub struct IdentityRequest {
27    pub inspection: Inspection,
28}
29
30#[async_trait]
31pub trait AssertionSigner: Send + Sync {
32    async fn sign(
33        &self,
34        claims: &ClientAssertionClaims,
35        algorithms: &[SigningAlgorithm],
36    ) -> Result<String, AgentError>;
37}
38
39#[async_trait]
40pub trait IdentityProvider: Send + Sync {
41    async fn get_or_create_identity(
42        &self,
43        request: IdentityRequest,
44    ) -> Result<AgentIdentity, AgentError>;
45    async fn signer_for(
46        &self,
47        identity: &AgentIdentity,
48    ) -> Result<Arc<dyn AssertionSigner>, AgentError>;
49}
50
51#[derive(Clone, Debug, Eq, PartialEq)]
52pub struct OperationKey {
53    pub command: Command,
54    pub credential_id: Option<String>,
55    pub grant_type: Option<GrantType>,
56    pub service_did: String,
57    pub service_url: Url,
58}
59
60#[async_trait]
61pub trait IdempotencyKeyProvider: Send + Sync {
62    async fn create_key(&self, operation: &OperationKey) -> Result<String, AgentError>;
63}
64
65pub trait Clock: Send + Sync {
66    fn now(&self) -> OffsetDateTime;
67}
68
69#[async_trait]
70pub trait Delay: Send + Sync {
71    async fn sleep(&self, duration: Duration);
72}
73
74#[derive(Clone, Debug, PartialEq)]
75pub struct CredentialRecord {
76    pub credential_id: String,
77    pub expires_at: OffsetDateTime,
78    pub grant_type: GrantType,
79    pub issued_at: OffsetDateTime,
80    pub payload: Value,
81    pub service_did: String,
82    pub service_url: Url,
83}
84
85#[derive(Clone, Debug, PartialEq)]
86pub struct Inspection {
87    pub cache_control: Option<String>,
88    pub document: InspectDocument,
89    pub etag: Option<String>,
90    pub final_url: Url,
91    pub inspect_url: Url,
92    pub last_modified: Option<String>,
93    pub service_url: Url,
94}
95
96impl Inspection {
97    pub fn command_url(&self, command: &Command) -> Result<Url, AgentError> {
98        let path = aep_core::command_path_from_inspect(&self.document, command)?;
99        Ok(self.service_url.join(&path)?)
100    }
101}
102
103#[derive(Clone, Debug, PartialEq)]
104pub struct InspectCacheEntry {
105    pub cache_control: Option<String>,
106    pub cached_at: OffsetDateTime,
107    pub document: InspectDocument,
108    pub etag: Option<String>,
109    pub final_url: Url,
110    pub last_modified: Option<String>,
111}
112
113#[async_trait]
114pub trait IdentityStore: Send + Sync {
115    async fn find(&self, service_did: &str) -> Result<Option<AgentIdentity>, AgentError>;
116    async fn save(&self, identity: AgentIdentity) -> Result<(), AgentError>;
117}
118
119#[async_trait]
120pub trait CredentialStore: Send + Sync {
121    async fn delete(&self, service_did: &str, credential_id: &str) -> Result<(), AgentError>;
122    async fn find(
123        &self,
124        service_did: &str,
125        credential_id: &str,
126    ) -> Result<Option<CredentialRecord>, AgentError>;
127    async fn list(&self, service_did: &str) -> Result<Vec<CredentialRecord>, AgentError>;
128    async fn save(&self, credential: CredentialRecord) -> Result<(), AgentError>;
129}
130
131#[async_trait]
132pub trait InspectCache: Send + Sync {
133    async fn delete(&self, inspect_url: &Url) -> Result<(), AgentError>;
134    async fn find(&self, inspect_url: &Url) -> Result<Option<InspectCacheEntry>, AgentError>;
135    async fn save(&self, inspect_url: &Url, entry: InspectCacheEntry) -> Result<(), AgentError>;
136}
137
138#[derive(Clone)]
139pub struct ClientOptions {
140    pub allow_insecure_loopback: bool,
141    pub assertion_lifetime: Duration,
142    pub clock: Option<Arc<dyn Clock>>,
143    pub command_transport: Option<Arc<dyn HttpTransport>>,
144    pub credential_store: Option<Arc<dyn CredentialStore>>,
145    pub delay: Option<Arc<dyn Delay>>,
146    pub identity_provider: Arc<dyn IdentityProvider>,
147    pub identity_store: Option<Arc<dyn IdentityStore>>,
148    pub idempotency_keys: Option<Arc<dyn IdempotencyKeyProvider>>,
149    pub inspect_cache: Option<Arc<dyn InspectCache>>,
150    pub inspect_transport: Option<Arc<dyn HttpTransport>>,
151    pub maximum_response_bytes: usize,
152    pub request_timeout: Duration,
153}
154
155impl ClientOptions {
156    pub fn new(identity_provider: Arc<dyn IdentityProvider>) -> Self {
157        Self {
158            allow_insecure_loopback: false,
159            assertion_lifetime: aep_core::MAX_ASSERTION_LIFETIME,
160            clock: None,
161            command_transport: None,
162            credential_store: None,
163            delay: None,
164            identity_provider,
165            identity_store: None,
166            idempotency_keys: None,
167            inspect_cache: None,
168            inspect_transport: None,
169            maximum_response_bytes: 1 << 20,
170            request_timeout: Duration::from_secs(30),
171        }
172    }
173}
174
175#[derive(Clone, Debug, PartialEq)]
176pub struct CommandResult<T> {
177    pub body: T,
178    pub status: u16,
179    pub url: Url,
180}
181
182#[derive(Clone, Debug, Default, PartialEq)]
183pub struct EnrollOptions {
184    pub claims: Option<ClaimValues>,
185    pub idempotency_key: Option<String>,
186}
187
188#[derive(Clone, Debug, Default, Eq, PartialEq)]
189pub struct GrantOptions {
190    pub grant_type: Option<GrantType>,
191    pub idempotency_key: Option<String>,
192    pub preferred_grant_types: Vec<GrantType>,
193    pub requested_scopes: Vec<String>,
194}
195
196#[derive(Clone, Debug, PartialEq)]
197pub struct GrantResult {
198    pub credential: Option<BuiltInGrantResponse>,
199    pub grant_type: GrantType,
200    pub raw: Value,
201}
202
203#[derive(Clone, Debug, Default, Eq, PartialEq)]
204pub struct RevokeOptions {
205    pub all_grant_types: bool,
206    pub credential_id: Option<String>,
207    pub grant_type: Option<GrantType>,
208    pub idempotency_key: Option<String>,
209}
210
211#[derive(Clone, Copy, Debug, Eq, PartialEq)]
212pub struct WaitOptions {
213    pub interval: Duration,
214    pub timeout: Duration,
215}
216
217impl Default for WaitOptions {
218    fn default() -> Self {
219        Self {
220            interval: Duration::from_secs(1),
221            timeout: Duration::from_secs(30),
222        }
223    }
224}
225
226#[derive(Clone, Debug, PartialEq)]
227pub struct AuthenticationOptions {
228    pub carrier: aep_core::AuthorizationCarrier,
229    pub client_assertion_only: bool,
230    pub credential_id: Option<String>,
231    pub grant_type: Option<GrantType>,
232    pub resource: Url,
233}
234
235#[derive(Clone, Debug, PartialEq)]
236pub struct AuthenticationResult {
237    pub headers: HeaderMap,
238    pub method: AuthenticationMethod,
239}
240
241pub(crate) fn assertion_operation(command: &Command) -> Option<AssertionOperation> {
242    match command {
243        Command::Enroll => Some(AssertionOperation::Enroll),
244        Command::Grant => Some(AssertionOperation::Grant),
245        Command::Revoke => Some(AssertionOperation::Revoke),
246        Command::Status => Some(AssertionOperation::Status),
247        Command::Inspect | Command::Other(_) => None,
248    }
249}
250
251pub(crate) fn authorization(
252    carrier: aep_core::AuthorizationCarrier,
253    scheme: aep_core::CredentialScheme,
254    credentials: String,
255) -> ProtectedResourceAuthorization {
256    ProtectedResourceAuthorization {
257        carrier,
258        scheme,
259        credentials,
260    }
261}