Skip to main content

canic_core/dto/
auth.rs

1use crate::dto::{prelude::*, rpc::RootRequestMetadata};
2
3//
4// DelegationAudience
5//
6
7#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
8pub enum DelegationAudience {
9    Canister(Principal),
10    CanicSubnet(Principal),
11    Project(String),
12}
13
14//
15// DelegatedRoleGrant
16//
17
18#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
19pub struct DelegatedRoleGrant {
20    pub target: CanisterRole,
21    pub scopes: Vec<String>,
22}
23
24//
25// RootProof
26//
27
28#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
29pub enum RootProof {
30    IcCanisterSignatureV1(IcCanisterSignatureProofV1),
31}
32
33//
34// IssuerProof
35//
36
37#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
38pub enum IssuerProof {
39    IcCanisterSignatureV1(IcCanisterSignatureProofV1),
40}
41
42//
43// IcCanisterSignatureProofV1
44//
45
46#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
47pub struct IcCanisterSignatureProofV1 {
48    pub signature_cbor: Vec<u8>,
49    pub public_key_der: Vec<u8>,
50}
51
52//
53// IssuerProofAlgorithm
54//
55
56#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
57pub enum IssuerProofAlgorithm {
58    IcCanisterSignatureV1,
59}
60
61//
62// IssuerProofBinding
63//
64
65#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
66pub enum IssuerProofBinding {
67    IcCanisterSignatureV1 { seed_hash: [u8; 32] },
68}
69
70//
71// DelegationCert
72//
73
74#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
75pub struct DelegationCert {
76    pub root_pid: Principal,
77    pub issuer_pid: Principal,
78    pub issuer_proof_alg: IssuerProofAlgorithm,
79    pub issuer_proof_binding_hash: [u8; 32],
80    pub issuer_proof_binding: IssuerProofBinding,
81    pub issued_at_ns: u64,
82    pub not_before_ns: u64,
83    pub expires_at_ns: u64,
84    pub max_token_ttl_ns: u64,
85    pub aud: DelegationAudience,
86    pub grants: Vec<DelegatedRoleGrant>,
87}
88
89//
90// DelegationProof
91//
92
93#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
94pub struct DelegationProof {
95    pub cert: DelegationCert,
96    pub root_proof: RootProof,
97}
98
99//
100// ActiveDelegationProof
101//
102
103#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
104pub struct ActiveDelegationProof {
105    pub proof: DelegationProof,
106    pub cert_hash: [u8; 32],
107    pub not_before_ns: u64,
108    pub expires_at_ns: u64,
109    pub refresh_after_ns: u64,
110    pub installed_at_ns: u64,
111    pub installed_by: Principal,
112}
113
114//
115// InstallActiveDelegationProofRequest
116//
117
118#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
119pub struct InstallActiveDelegationProofRequest {
120    pub proof: DelegationProof,
121}
122
123//
124// InstallActiveDelegationProofResponse
125//
126
127#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
128pub struct InstallActiveDelegationProofResponse {
129    pub active_proof: ActiveDelegationProof,
130}
131
132//
133// ActiveDelegationProofStatus
134//
135
136#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
137pub enum ActiveDelegationProofStatus {
138    Missing,
139    Valid,
140    RefreshNeeded,
141    Expired,
142}
143
144//
145// ActiveDelegationProofStatusResponse
146//
147
148#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
149pub struct ActiveDelegationProofStatusResponse {
150    pub status: ActiveDelegationProofStatus,
151    pub root_pid: Option<Principal>,
152    pub issuer_pid: Option<Principal>,
153    pub cert_hash: Option<[u8; 32]>,
154    pub expires_at_ns: Option<u64>,
155    pub refresh_after_ns: Option<u64>,
156}
157
158//
159// DelegatedTokenClaims
160//
161
162#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
163pub struct DelegatedTokenClaims {
164    pub subject: Principal,
165    pub issuer_pid: Principal,
166    pub cert_hash: [u8; 32],
167    pub issued_at_ns: u64,
168    pub expires_at_ns: u64,
169    pub aud: DelegationAudience,
170    pub grants: Vec<DelegatedRoleGrant>,
171    pub nonce: [u8; 16],
172    #[serde(default)]
173    pub ext: Option<Vec<u8>>,
174}
175
176//
177// DelegatedToken
178//
179
180#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
181pub struct DelegatedToken {
182    pub claims: DelegatedTokenClaims,
183    pub proof: DelegationProof,
184    pub issuer_proof: IssuerProof,
185}
186
187//
188// AuthRequestMetadata
189//
190
191#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
192pub struct AuthRequestMetadata {
193    pub request_id: [u8; 32],
194    pub ttl_ns: u64,
195}
196
197//
198// RootDelegationProofBatchPrepareRequest
199//
200
201#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
202pub struct RootDelegationProofBatchPrepareRequest {
203    #[serde(default)]
204    pub metadata: Option<AuthRequestMetadata>,
205    pub entries: Vec<RootDelegationProofBatchPrepareEntry>,
206}
207
208//
209// RootDelegationProofBatchPrepareEntry
210//
211
212#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
213pub struct RootDelegationProofBatchPrepareEntry {
214    pub issuer_pid: Principal,
215    pub aud: DelegationAudience,
216    pub grants: Vec<DelegatedRoleGrant>,
217    pub cert_ttl_ns: u64,
218}
219
220//
221// RootDelegationProofBatchPrepareResponse
222//
223
224#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
225pub struct RootDelegationProofBatchPrepareResponse {
226    pub batch_id: [u8; 32],
227    pub entries: Vec<RootDelegationProofBatchEntry>,
228    pub retrieval_expires_at_ns: u64,
229}
230
231//
232// RootDelegationProofBatchEntry
233//
234
235#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
236pub struct RootDelegationProofBatchEntry {
237    pub issuer_pid: Principal,
238    pub cert_hash: [u8; 32],
239    pub expires_at_ns: u64,
240    pub refresh_after_ns: u64,
241}
242
243//
244// RootDelegationProofBatchGetRequest
245//
246
247#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
248pub struct RootDelegationProofBatchGetRequest {
249    pub batch_id: [u8; 32],
250    pub entries: Vec<RootDelegationProofBatchProofRef>,
251}
252
253//
254// RootDelegationRenewalProofBatchGetRequest
255//
256
257#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
258pub struct RootDelegationRenewalProofBatchGetRequest {
259    pub batch_id: [u8; 32],
260}
261
262//
263// RootDelegationRenewalBatchView
264//
265
266#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
267pub struct RootDelegationRenewalBatchView {
268    pub batch_id: [u8; 32],
269    pub attempt_count: u64,
270    pub prepared_at_ns: u64,
271    pub retrieval_expires_at_ns: u64,
272    pub install_deadline_ns: u64,
273    pub attempts: Vec<RootIssuerRenewalAttemptView>,
274}
275
276//
277// RootDelegationRenewalWorkListResponse
278//
279
280#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
281pub struct RootDelegationRenewalWorkListResponse {
282    pub batches: Vec<RootDelegationRenewalBatchView>,
283}
284
285//
286// RootDelegationRenewalProvisionerUpsertRequest
287//
288
289#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
290pub struct RootDelegationRenewalProvisionerUpsertRequest {
291    pub principal: Principal,
292    pub enabled: bool,
293}
294
295//
296// RootDelegationRenewalProvisionerView
297//
298
299#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
300pub struct RootDelegationRenewalProvisionerView {
301    pub principal: Principal,
302    pub enabled: bool,
303}
304
305//
306// RootDelegationRenewalProvisionerResponse
307//
308
309#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
310pub struct RootDelegationRenewalProvisionerResponse {
311    pub provisioner: RootDelegationRenewalProvisionerView,
312}
313
314//
315// RootDelegationRenewalProvisionerListResponse
316//
317
318#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
319pub struct RootDelegationRenewalProvisionerListResponse {
320    pub provisioners: Vec<RootDelegationRenewalProvisionerView>,
321}
322
323//
324// RootDelegationProofBatchProofRef
325//
326
327#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
328pub struct RootDelegationProofBatchProofRef {
329    pub issuer_pid: Principal,
330    pub cert_hash: [u8; 32],
331}
332
333//
334// RootDelegationProofBatchGetResponse
335//
336
337#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
338pub struct RootDelegationProofBatchGetResponse {
339    pub batch_id: [u8; 32],
340    pub proofs: Vec<RootDelegationProofBatchProof>,
341}
342
343//
344// RootDelegationProofBatchProof
345//
346
347#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
348pub struct RootDelegationProofBatchProof {
349    pub issuer_pid: Principal,
350    pub cert_hash: [u8; 32],
351    pub proof: DelegationProof,
352}
353
354//
355// RootDelegationProofBatchInstallRequest
356//
357
358#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
359pub struct RootDelegationProofBatchInstallRequest {
360    pub batch_id: [u8; 32],
361    pub proofs: Vec<RootDelegationProofBatchProof>,
362}
363
364//
365// RootDelegationProofBatchInstallResponse
366//
367
368#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
369pub struct RootDelegationProofBatchInstallResponse {
370    pub batch_id: [u8; 32],
371    pub outcomes: Vec<RootDelegationProofBatchInstallResult>,
372}
373
374//
375// RootDelegationProofBatchInstallResult
376//
377
378#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
379pub struct RootDelegationProofBatchInstallResult {
380    pub issuer_pid: Principal,
381    pub cert_hash: [u8; 32],
382    pub outcome: RootDelegationProofInstallOutcome,
383}
384
385//
386// RootDelegationProofInstallOutcome
387//
388
389#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
390pub enum RootDelegationProofInstallOutcome {
391    Installed,
392    AlreadyInstalled,
393    RejectedBySigner,
394    CallFailed,
395    ProofMismatch,
396    ExpiredOrSuperseded,
397}
398
399//
400// RootIssuerPolicyUpsertRequest
401//
402
403#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
404pub struct RootIssuerPolicyUpsertRequest {
405    pub issuer_pid: Principal,
406    pub enabled: bool,
407    pub allowed_audiences: Vec<DelegationAudience>,
408    pub allowed_grants: Vec<DelegatedRoleGrant>,
409    pub max_cert_ttl_ns: u64,
410    pub refresh_after_ratio_bps: u16,
411}
412
413//
414// RootIssuerPolicyView
415//
416
417#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
418pub struct RootIssuerPolicyView {
419    pub issuer_pid: Principal,
420    pub enabled: bool,
421    pub allowed_audiences: Vec<DelegationAudience>,
422    pub allowed_grants: Vec<DelegatedRoleGrant>,
423    pub max_cert_ttl_ns: u64,
424    pub refresh_after_ratio_bps: u16,
425}
426
427//
428// RootIssuerPolicyResponse
429//
430
431#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
432pub struct RootIssuerPolicyResponse {
433    pub issuer: RootIssuerPolicyView,
434}
435
436//
437// RootIssuerRenewalTemplateUpsertRequest
438//
439
440#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
441pub struct RootIssuerRenewalTemplateUpsertRequest {
442    pub issuer_pid: Principal,
443    pub enabled: bool,
444    pub aud: DelegationAudience,
445    pub grants: Vec<DelegatedRoleGrant>,
446    pub cert_ttl_ns: u64,
447}
448
449//
450// RootIssuerRenewalTemplateView
451//
452
453#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
454pub struct RootIssuerRenewalTemplateView {
455    pub issuer_pid: Principal,
456    pub enabled: bool,
457    pub aud: DelegationAudience,
458    pub grants: Vec<DelegatedRoleGrant>,
459    pub cert_ttl_ns: u64,
460}
461
462//
463// RootIssuerRenewalTemplateResponse
464//
465
466#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
467pub struct RootIssuerRenewalTemplateResponse {
468    pub template: RootIssuerRenewalTemplateView,
469}
470
471//
472// RootIssuerRenewalStatusRequest
473//
474
475#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
476pub struct RootIssuerRenewalStatusRequest {
477    pub issuer_pid: Principal,
478}
479
480//
481// RootIssuerRenewalOutcome
482//
483
484#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
485pub enum RootIssuerRenewalOutcome {
486    AlreadyInstalled,
487    DriftDetected,
488    InstallDeadlineExpired,
489    Installed,
490    IssuerCallFailed,
491    NeverRun,
492    PolicyRejected,
493    ProofMismatch,
494    QuotaExceeded,
495    RejectedByIssuer,
496    RetrievalExpired,
497    TemplateChanged,
498    TemplateDisabled,
499}
500
501//
502// RootIssuerRenewalAttemptStatus
503//
504
505#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
506pub enum RootIssuerRenewalAttemptStatus {
507    Prepared,
508    Installing,
509    Installed,
510    FailedRetryable,
511    FailedTerminal,
512    Disabled,
513    Expired,
514}
515
516//
517// RootIssuerRenewalAttemptView
518//
519
520#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
521pub struct RootIssuerRenewalAttemptView {
522    pub attempt_id: [u8; 32],
523    pub issuer_pid: Principal,
524    pub template_fingerprint: [u8; 32],
525    pub batch_id: [u8; 32],
526    pub proof_ref: RootDelegationProofBatchProofRef,
527    pub status: RootIssuerRenewalAttemptStatus,
528    pub prepared_at_ns: u64,
529    pub retrieval_expires_at_ns: u64,
530    pub install_deadline_ns: u64,
531    pub prepared_cert_hash: [u8; 32],
532    pub prepared_expires_at_ns: u64,
533    pub prepared_refresh_after_ns: u64,
534    pub failure: Option<RootIssuerRenewalOutcome>,
535}
536
537//
538// RootIssuerRenewalStateView
539//
540
541#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
542pub struct RootIssuerRenewalStateView {
543    pub issuer_pid: Principal,
544    pub template_fingerprint: [u8; 32],
545    pub last_installed_cert_hash: Option<[u8; 32]>,
546    pub last_installed_expires_at_ns: Option<u64>,
547    pub last_installed_refresh_after_ns: Option<u64>,
548    pub active_attempt_id: Option<[u8; 32]>,
549    pub last_outcome: RootIssuerRenewalOutcome,
550    pub consecutive_failures: u32,
551    pub next_attempt_after_ns: u64,
552    pub updated_at_ns: u64,
553}
554
555//
556// RootIssuerRenewalStatusResponse
557//
558
559#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
560pub struct RootIssuerRenewalStatusResponse {
561    pub template: Option<RootIssuerRenewalTemplateView>,
562    pub state: Option<RootIssuerRenewalStateView>,
563    pub active_attempt: Option<RootIssuerRenewalAttemptView>,
564}
565
566//
567// DelegatedTokenPrepareRequest
568//
569
570#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
571pub struct DelegatedTokenPrepareRequest {
572    #[serde(default)]
573    pub metadata: Option<AuthRequestMetadata>,
574    pub subject: Principal,
575    pub aud: DelegationAudience,
576    pub grants: Vec<DelegatedRoleGrant>,
577    pub ttl_ns: u64,
578    #[serde(default)]
579    pub ext: Option<Vec<u8>>,
580}
581
582//
583// DelegatedTokenPrepareResponse
584//
585
586#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
587pub struct DelegatedTokenPrepareResponse {
588    pub claims: DelegatedTokenClaims,
589    pub claims_hash: [u8; 32],
590    pub retrieval_expires_at_ns: u64,
591}
592
593//
594// DelegatedTokenGetRequest
595//
596
597#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
598pub struct DelegatedTokenGetRequest {
599    pub claims_hash: [u8; 32],
600}
601
602//
603// RoleAttestationRequest
604//
605
606#[derive(CandidType, Clone, Debug, Deserialize)]
607pub struct RoleAttestationRequest {
608    pub subject: Principal,
609    pub role: CanisterRole,
610    #[serde(default)]
611    pub subnet_id: Option<Principal>,
612    pub audience: Principal,
613    pub ttl_ns: u64,
614    pub epoch: u64,
615    #[serde(default)]
616    pub metadata: Option<RootRequestMetadata>,
617}
618
619//
620// RoleAttestation
621//
622
623#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
624pub struct RoleAttestation {
625    pub subject: Principal,
626    pub role: CanisterRole,
627    #[serde(default)]
628    pub subnet_id: Option<Principal>,
629    pub audience: Principal,
630    pub issued_at_ns: u64,
631    pub expires_at_ns: u64,
632    pub epoch: u64,
633}
634
635//
636// RoleAttestationPrepareResponse
637//
638
639#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
640pub struct RoleAttestationPrepareResponse {
641    pub payload: RoleAttestation,
642    pub payload_hash: [u8; 32],
643    pub retrieval_expires_at_ns: u64,
644}
645
646//
647// RoleAttestationGetRequest
648//
649
650#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
651pub struct RoleAttestationGetRequest {
652    pub payload_hash: [u8; 32],
653}
654
655//
656// SignedRoleAttestation
657//
658
659#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
660pub struct SignedRoleAttestation {
661    pub payload: RoleAttestation,
662    pub root_proof: RootProof,
663}
664
665// -----------------------------------------------------------------------------
666// Tests
667// -----------------------------------------------------------------------------
668
669#[cfg(test)]
670mod tests {
671    #[test]
672    fn auth_dtos_remain_passive_boundary_types() {
673        let source = include_str!("auth.rs");
674        let production_source = source
675            .split("#[cfg(test)]")
676            .next()
677            .expect("production source exists");
678
679        for marker in [
680            "impl DelegatedToken",
681            "impl DelegatedTokenClaims",
682            "impl RoleAttestation",
683            "impl SignedRoleAttestation",
684            "fn verify",
685            "fn sign",
686            "fn resolve",
687            "fn replay",
688            "fn consume",
689            "fn policy",
690            "fn validate",
691        ] {
692            assert!(
693                !production_source.contains(marker),
694                "auth DTOs must stay passive; found marker `{marker}`"
695            );
696        }
697    }
698}