1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::validation::deserialize_optional_non_null;
7
8pub type AdditionalMembers = BTreeMap<String, Value>;
9
10macro_rules! closed_string_enum {
11 ($name:ident { $($variant:ident => $value:literal),+ $(,)? }) => {
12 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
13 pub enum $name {
14 $(#[serde(rename = $value)] $variant),+
15 }
16
17 impl $name {
18 pub const fn as_str(self) -> &'static str {
19 match self {
20 $(Self::$variant => $value),+
21 }
22 }
23 }
24 };
25}
26
27macro_rules! extensible_string_enum {
28 ($name:ident { $($variant:ident => $value:literal),+ $(,)? }) => {
29 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
30 pub enum $name {
31 $($variant),+,
32 Other(String),
33 }
34
35 impl $name {
36 pub fn as_str(&self) -> &str {
37 match self {
38 $(Self::$variant => $value),+,
39 Self::Other(value) => value,
40 }
41 }
42 }
43
44 impl From<&str> for $name {
45 fn from(value: &str) -> Self {
46 match value {
47 $($value => Self::$variant),+,
48 other => Self::Other(other.to_owned()),
49 }
50 }
51 }
52
53 impl From<String> for $name {
54 fn from(value: String) -> Self {
55 Self::from(value.as_str())
56 }
57 }
58
59 impl Serialize for $name {
60 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
61 where
62 S: serde::Serializer,
63 {
64 serializer.serialize_str(self.as_str())
65 }
66 }
67
68 impl<'de> Deserialize<'de> for $name {
69 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
70 where
71 D: serde::Deserializer<'de>,
72 {
73 Ok(Self::from(String::deserialize(deserializer)?))
74 }
75 }
76 };
77}
78
79extensible_string_enum!(Command {
80 Inspect => "inspect",
81 Enroll => "enroll",
82 Grant => "grant",
83 Revoke => "revoke",
84 Status => "status",
85});
86
87closed_string_enum!(AssertionOperation {
88 Enroll => "enroll",
89 Grant => "grant",
90 Revoke => "revoke",
91 Status => "status",
92 Authenticate => "authenticate",
93});
94
95extensible_string_enum!(SigningAlgorithm {
96 EdDsa => "EdDSA",
97 Es256 => "ES256",
98});
99
100extensible_string_enum!(GrantType {
101 OAuthBearer => "oauth-bearer",
102 ApiKey => "api-key",
103 Basic => "basic",
104});
105
106extensible_string_enum!(AuthenticationMethod {
107 AepJwt => "aep-jwt",
108 OAuthBearer => "oauth-bearer",
109 ApiKey => "api-key",
110 Basic => "basic",
111});
112
113extensible_string_enum!(Binding { Http => "http" });
114extensible_string_enum!(IdentityMethod { DidWeb => "did:web" });
115
116extensible_string_enum!(ClaimName {
117 ContactAddressPrimary => "contact.address.primary",
118 ContactEmail => "contact.email",
119 ContactMobile => "contact.mobile",
120 PersonBirthdate => "person.birthdate",
121 PersonFirstName => "person.first_name",
122 PersonLastName => "person.last_name",
123 PersonUsername => "person.username",
124});
125
126extensible_string_enum!(ErrorCode {
127 EnrollmentFailed => "enrollment_failed",
128 InvalidRequest => "invalid_request",
129 NotRecognized => "not_recognized",
130 IdentitySuspended => "identity_suspended",
131 IdentityTerminated => "identity_terminated",
132 IdentityUnavailable => "identity_unavailable",
133 VerificationPending => "verification_pending",
134 VerificationTimeout => "verification_timeout",
135 RequirementsUnmet => "requirements_unmet",
136 RateLimited => "rate_limited",
137 UnsupportedGrantType => "unsupported_grant_type",
138 IdempotencyConflict => "idempotency_conflict",
139 AuthenticationRequired => "authentication_required",
140 UnsupportedAuthenticationMethod => "unsupported_authentication_method",
141 InsufficientScope => "insufficient_scope",
142});
143
144closed_string_enum!(EnrollmentDecisionStatus {
145 Active => "active",
146 Pending => "pending",
147 Rejected => "rejected",
148});
149
150pub type EnrollmentStatus = EnrollmentDecisionStatus;
151
152closed_string_enum!(AgentStatus {
153 Active => "active",
154 Pending => "pending",
155 Rejected => "rejected",
156 Suspended => "suspended",
157 Terminated => "terminated",
158 Unavailable => "unavailable",
159});
160
161closed_string_enum!(StringBoolean { True => "true", False => "false" });
162closed_string_enum!(OpenApiTrailingSlash { Strict => "strict", Equivalent => "equivalent" });
163closed_string_enum!(AuthorizationCarrier {
164 Standard => "Authorization",
165 Dedicated => "AEP-Authorization",
166});
167closed_string_enum!(CredentialScheme { Aep => "AEP", Bearer => "Bearer", Basic => "Basic" });
168
169#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
170#[serde(deny_unknown_fields)]
171pub struct Authentication {
172 pub methods: Vec<AuthenticationMethod>,
173}
174
175#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
176pub struct Bindings {
177 pub supported: Vec<Binding>,
178 #[serde(flatten)]
179 pub additional: AdditionalMembers,
180}
181
182#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
183pub struct InspectClaims {
184 #[serde(default, skip_serializing_if = "Vec::is_empty")]
185 pub required: Vec<ClaimName>,
186 #[serde(default, skip_serializing_if = "Vec::is_empty")]
187 pub preferred: Vec<ClaimName>,
188 #[serde(default, skip_serializing_if = "Vec::is_empty")]
189 pub optional: Vec<ClaimName>,
190 #[serde(flatten)]
191 pub additional: AdditionalMembers,
192}
193
194#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
195pub struct GrantTypeConfig {
196 #[serde(
197 default,
198 deserialize_with = "deserialize_optional_non_null",
199 skip_serializing_if = "Option::is_none"
200 )]
201 pub supports_per_credential_revoke: Option<StringBoolean>,
202 #[serde(flatten)]
203 pub additional: AdditionalMembers,
204}
205
206#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
207pub struct Commands {
208 pub supported: Vec<Command>,
209 #[serde(default, skip_serializing_if = "Vec::is_empty")]
210 pub grant_types: Vec<GrantType>,
211 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
212 pub grant_types_config: BTreeMap<String, GrantTypeConfig>,
213 #[serde(flatten)]
214 pub additional: AdditionalMembers,
215}
216
217#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
218pub struct CoreConfiguration {
219 pub signing_algorithms: Vec<SigningAlgorithm>,
220 #[serde(flatten)]
221 pub additional: AdditionalMembers,
222}
223
224#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
225pub struct Extensions {
226 #[serde(default, skip_serializing_if = "Vec::is_empty")]
227 pub supported: Vec<String>,
228 #[serde(flatten)]
229 pub additional: AdditionalMembers,
230}
231
232#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
233#[serde(deny_unknown_fields)]
234pub struct OpenApiPathMatching {
235 pub trailing_slash: OpenApiTrailingSlash,
236}
237
238#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
239#[serde(deny_unknown_fields)]
240pub struct OpenApiReference {
241 pub url: String,
242 pub path_matching: OpenApiPathMatching,
243}
244
245#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
246pub struct HttpConfiguration {
247 #[serde(
248 default,
249 deserialize_with = "deserialize_optional_non_null",
250 skip_serializing_if = "Option::is_none"
251 )]
252 pub endpoint_base: Option<String>,
253 #[serde(
254 default,
255 deserialize_with = "deserialize_optional_non_null",
256 skip_serializing_if = "Option::is_none"
257 )]
258 pub openapi: Option<OpenApiReference>,
259 #[serde(flatten)]
260 pub additional: AdditionalMembers,
261}
262
263#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
264pub struct Identity {
265 pub methods: Vec<IdentityMethod>,
266 #[serde(flatten)]
267 pub additional: AdditionalMembers,
268}
269
270#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
271pub struct ServiceIdentity {
272 pub did: String,
273 #[serde(flatten)]
274 pub additional: AdditionalMembers,
275}
276
277#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
278pub struct InspectDocument {
279 pub aep_version: String,
280 #[serde(
281 default,
282 deserialize_with = "deserialize_optional_non_null",
283 skip_serializing_if = "Option::is_none"
284 )]
285 pub authentication: Option<Authentication>,
286 pub bindings: Bindings,
287 #[serde(
288 default,
289 deserialize_with = "deserialize_optional_non_null",
290 skip_serializing_if = "Option::is_none"
291 )]
292 pub claims: Option<InspectClaims>,
293 pub commands: Commands,
294 pub core: CoreConfiguration,
295 #[serde(
296 default,
297 deserialize_with = "deserialize_optional_non_null",
298 skip_serializing_if = "Option::is_none"
299 )]
300 pub extensions: Option<Extensions>,
301 pub http: HttpConfiguration,
302 pub identity: Identity,
303 pub service: ServiceIdentity,
304 #[serde(flatten)]
305 pub additional: AdditionalMembers,
306}
307
308#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
309pub struct ContactAddressPrimary {
310 #[serde(
311 default,
312 deserialize_with = "deserialize_optional_non_null",
313 skip_serializing_if = "Option::is_none"
314 )]
315 pub city: Option<String>,
316 pub country: String,
317 pub first_name: String,
318 pub last_name: String,
319 pub line1: String,
320 #[serde(
321 default,
322 deserialize_with = "deserialize_optional_non_null",
323 skip_serializing_if = "Option::is_none"
324 )]
325 pub line2: Option<String>,
326 #[serde(
327 default,
328 deserialize_with = "deserialize_optional_non_null",
329 skip_serializing_if = "Option::is_none"
330 )]
331 pub line3: Option<String>,
332 #[serde(
333 default,
334 deserialize_with = "deserialize_optional_non_null",
335 skip_serializing_if = "Option::is_none"
336 )]
337 pub postcode: Option<String>,
338 #[serde(
339 default,
340 deserialize_with = "deserialize_optional_non_null",
341 skip_serializing_if = "Option::is_none"
342 )]
343 pub region: Option<String>,
344 #[serde(flatten)]
345 pub additional: AdditionalMembers,
346}
347
348#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
349pub struct ClaimValues {
350 #[serde(
351 default,
352 deserialize_with = "deserialize_optional_non_null",
353 rename = "contact.address.primary",
354 skip_serializing_if = "Option::is_none"
355 )]
356 pub contact_address_primary: Option<ContactAddressPrimary>,
357 #[serde(
358 default,
359 deserialize_with = "deserialize_optional_non_null",
360 rename = "contact.email",
361 skip_serializing_if = "Option::is_none"
362 )]
363 pub contact_email: Option<String>,
364 #[serde(
365 default,
366 deserialize_with = "deserialize_optional_non_null",
367 rename = "contact.mobile",
368 skip_serializing_if = "Option::is_none"
369 )]
370 pub contact_mobile: Option<String>,
371 #[serde(
372 default,
373 deserialize_with = "deserialize_optional_non_null",
374 rename = "person.birthdate",
375 skip_serializing_if = "Option::is_none"
376 )]
377 pub person_birthdate: Option<String>,
378 #[serde(
379 default,
380 deserialize_with = "deserialize_optional_non_null",
381 rename = "person.first_name",
382 skip_serializing_if = "Option::is_none"
383 )]
384 pub person_first_name: Option<String>,
385 #[serde(
386 default,
387 deserialize_with = "deserialize_optional_non_null",
388 rename = "person.last_name",
389 skip_serializing_if = "Option::is_none"
390 )]
391 pub person_last_name: Option<String>,
392 #[serde(
393 default,
394 deserialize_with = "deserialize_optional_non_null",
395 rename = "person.username",
396 skip_serializing_if = "Option::is_none"
397 )]
398 pub person_username: Option<String>,
399 #[serde(flatten)]
400 pub additional: AdditionalMembers,
401}
402
403#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
404pub struct EnrollRequest {
405 pub agent_did: String,
406 #[serde(
407 default,
408 deserialize_with = "deserialize_optional_non_null",
409 skip_serializing_if = "Option::is_none"
410 )]
411 pub claims: Option<ClaimValues>,
412 #[serde(
413 default,
414 deserialize_with = "deserialize_optional_non_null",
415 skip_serializing_if = "Option::is_none"
416 )]
417 pub idempotency_key: Option<String>,
418 #[serde(flatten)]
419 pub additional: AdditionalMembers,
420}
421
422fn owner_action_is_not_true(value: &Option<StringBoolean>) -> bool {
423 !matches!(value, Some(StringBoolean::True))
424}
425
426#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
427pub struct EnrollResponse {
428 pub status: AgentStatus,
429 #[serde(
430 default,
431 deserialize_with = "deserialize_optional_non_null",
432 skip_serializing_if = "owner_action_is_not_true"
433 )]
434 pub owner_action_required: Option<StringBoolean>,
435 #[serde(
436 default,
437 deserialize_with = "deserialize_optional_non_null",
438 skip_serializing_if = "Option::is_none"
439 )]
440 pub verification_pending: Option<Vec<String>>,
441 #[serde(
442 default,
443 deserialize_with = "deserialize_optional_non_null",
444 skip_serializing_if = "Option::is_none"
445 )]
446 pub requirements_pending: Option<Vec<String>>,
447 #[serde(flatten)]
448 pub additional: AdditionalMembers,
449}
450
451#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
452pub struct StatusResponse {
453 pub status: AgentStatus,
454 #[serde(
455 default,
456 deserialize_with = "deserialize_optional_non_null",
457 skip_serializing_if = "owner_action_is_not_true"
458 )]
459 pub owner_action_required: Option<StringBoolean>,
460 #[serde(
461 default,
462 deserialize_with = "deserialize_optional_non_null",
463 skip_serializing_if = "Option::is_none"
464 )]
465 pub verification_pending: Option<Vec<String>>,
466 #[serde(
467 default,
468 deserialize_with = "deserialize_optional_non_null",
469 skip_serializing_if = "Option::is_none"
470 )]
471 pub requirements_pending: Option<Vec<String>>,
472 #[serde(
473 default,
474 deserialize_with = "deserialize_optional_non_null",
475 skip_serializing_if = "Option::is_none"
476 )]
477 pub since: Option<String>,
478 #[serde(flatten)]
479 pub additional: AdditionalMembers,
480}
481
482#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
483pub struct GrantRequest {
484 pub grant_type: GrantType,
485 #[serde(default, skip_serializing_if = "Vec::is_empty")]
486 pub requested_scopes: Vec<String>,
487 #[serde(flatten)]
488 pub additional: AdditionalMembers,
489}
490
491#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
492pub struct RevokeRequest {
493 #[serde(
494 default,
495 deserialize_with = "deserialize_optional_non_null",
496 skip_serializing_if = "Option::is_none"
497 )]
498 pub grant_type: Option<GrantType>,
499 #[serde(
500 default,
501 deserialize_with = "deserialize_optional_non_null",
502 skip_serializing_if = "Option::is_none"
503 )]
504 pub credential_id: Option<String>,
505 #[serde(
506 default,
507 deserialize_with = "deserialize_optional_non_null",
508 skip_serializing_if = "Option::is_none"
509 )]
510 pub all_grant_types: Option<StringBoolean>,
511 #[serde(flatten)]
512 pub additional: AdditionalMembers,
513}
514
515#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
516#[serde(deny_unknown_fields)]
517pub struct RevokeResponse {}
518
519#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
520pub struct IdempotencyMetadata {
521 #[serde(
522 default,
523 deserialize_with = "deserialize_optional_non_null",
524 skip_serializing_if = "Option::is_none"
525 )]
526 pub agent_did: Option<String>,
527 pub idempotency_key: String,
528 #[serde(
529 default,
530 deserialize_with = "deserialize_optional_non_null",
531 skip_serializing_if = "Option::is_none"
532 )]
533 pub first_body_hash: Option<String>,
534 #[serde(
535 default,
536 deserialize_with = "deserialize_optional_non_null",
537 skip_serializing_if = "Option::is_none"
538 )]
539 pub second_body_hash: Option<String>,
540 #[serde(flatten)]
541 pub additional: AdditionalMembers,
542}
543
544#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
545pub struct OpenApiAepSecurityScheme {
546 #[serde(rename = "x-aep-authentication-method")]
547 pub authentication_method: AuthenticationMethod,
548 #[serde(flatten)]
549 pub additional: AdditionalMembers,
550}
551
552#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
553pub struct ClientAssertionClaims {
554 pub aud: String,
555 pub exp: i64,
556 pub iat: i64,
557 pub iss: String,
558 pub jti: String,
559 pub op: AssertionOperation,
560 #[serde(
561 default,
562 deserialize_with = "deserialize_optional_non_null",
563 skip_serializing_if = "Option::is_none"
564 )]
565 pub resource: Option<String>,
566 pub sub: String,
567 #[serde(flatten)]
568 pub additional: AdditionalMembers,
569}
570
571#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
572pub struct ProblemDetails {
573 #[serde(rename = "type")]
574 pub problem_type: String,
575 pub title: String,
576 pub status: i64,
577 #[serde(
578 default,
579 deserialize_with = "deserialize_optional_non_null",
580 skip_serializing_if = "Option::is_none"
581 )]
582 pub detail: Option<String>,
583 #[serde(
584 default,
585 deserialize_with = "deserialize_optional_non_null",
586 skip_serializing_if = "Option::is_none"
587 )]
588 pub instance: Option<String>,
589 pub code: ErrorCode,
590 #[serde(
591 default,
592 deserialize_with = "deserialize_optional_non_null",
593 skip_serializing_if = "owner_action_is_not_true"
594 )]
595 pub owner_action_required: Option<StringBoolean>,
596 #[serde(
597 default,
598 deserialize_with = "deserialize_optional_non_null",
599 skip_serializing_if = "Option::is_none"
600 )]
601 pub requirements_pending: Option<Vec<String>>,
602 #[serde(
603 default,
604 deserialize_with = "deserialize_optional_non_null",
605 skip_serializing_if = "Option::is_none"
606 )]
607 pub verification_pending: Option<Vec<String>>,
608 #[serde(flatten)]
609 pub additional: AdditionalMembers,
610}
611
612fn deserialize_nullable_scopes<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
613where
614 D: serde::Deserializer<'de>,
615{
616 Ok(Option::<Vec<String>>::deserialize(deserializer)?.unwrap_or_default())
617}
618
619#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
620pub struct OAuthBearerGrantResponse {
621 pub access_token: String,
622 pub credential_id: String,
623 pub expires_at: String,
624 #[serde(default, deserialize_with = "deserialize_nullable_scopes")]
625 pub scopes: Vec<String>,
626 pub token_type: String,
627 #[serde(flatten)]
628 pub additional: AdditionalMembers,
629}
630
631#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
632pub struct ApiKeyGrantResponse {
633 pub api_key: String,
634 pub credential_id: String,
635 pub expires_at: String,
636 pub header: String,
637 #[serde(default, deserialize_with = "deserialize_nullable_scopes")]
638 pub scopes: Vec<String>,
639 #[serde(flatten)]
640 pub additional: AdditionalMembers,
641}
642
643#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
644pub struct BasicGrantResponse {
645 pub credential_id: String,
646 pub expires_at: String,
647 pub password: String,
648 #[serde(
649 default,
650 deserialize_with = "deserialize_optional_non_null",
651 skip_serializing_if = "Option::is_none"
652 )]
653 pub realm: Option<String>,
654 #[serde(default, deserialize_with = "deserialize_nullable_scopes")]
655 pub scopes: Vec<String>,
656 pub username: String,
657 #[serde(flatten)]
658 pub additional: AdditionalMembers,
659}
660
661#[derive(Clone, Debug, PartialEq)]
662pub enum BuiltInGrantResponse {
663 OAuthBearer(OAuthBearerGrantResponse),
664 ApiKey(ApiKeyGrantResponse),
665 Basic(BasicGrantResponse),
666}
667
668impl BuiltInGrantResponse {
669 pub fn grant_type(&self) -> GrantType {
670 match self {
671 Self::OAuthBearer(_) => GrantType::OAuthBearer,
672 Self::ApiKey(_) => GrantType::ApiKey,
673 Self::Basic(_) => GrantType::Basic,
674 }
675 }
676}
677
678#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
679#[serde(deny_unknown_fields)]
680pub struct ProtectedResourceAuthorization {
681 pub carrier: AuthorizationCarrier,
682 pub scheme: CredentialScheme,
683 pub credentials: String,
684}