1use crate::dto::{prelude::*, rpc::RootRequestMetadata};
2
3#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
8pub enum DelegationAudience {
9 Canister(Principal),
10 CanicSubnet(Principal),
11 Project(String),
12}
13
14#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
19pub struct DelegatedRoleGrant {
20 pub target: CanisterRole,
21 pub scopes: Vec<String>,
22}
23
24#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
29pub enum RootProof {
30 IcCanisterSignatureV1(IcCanisterSignatureProofV1),
31}
32
33#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
38pub enum IssuerProof {
39 IcCanisterSignatureV1(IcCanisterSignatureProofV1),
40}
41
42#[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#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
57pub enum IssuerProofAlgorithm {
58 IcCanisterSignatureV1,
59}
60
61#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
66pub enum IssuerProofBinding {
67 IcCanisterSignatureV1 { seed_hash: [u8; 32] },
68}
69
70#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
94pub struct DelegationProof {
95 pub cert: DelegationCert,
96 pub root_proof: RootProof,
97}
98
99#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
119pub struct InstallActiveDelegationProofRequest {
120 pub proof: DelegationProof,
121}
122
123#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
128pub struct InstallActiveDelegationProofResponse {
129 pub active_proof: ActiveDelegationProof,
130}
131
132#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
137pub enum ActiveDelegationProofStatus {
138 Missing,
139 Valid,
140 RefreshNeeded,
141 Expired,
142}
143
144#[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#[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#[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#[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#[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#[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#[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#[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#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
258pub struct RootDelegationRenewalProofBatchGetRequest {
259 pub batch_id: [u8; 32],
260}
261
262#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
281pub struct RootDelegationRenewalWorkListResponse {
282 pub batches: Vec<RootDelegationRenewalBatchView>,
283}
284
285#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
290pub struct RootDelegationRenewalProvisionerUpsertRequest {
291 pub principal: Principal,
292 pub enabled: bool,
293}
294
295#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
300pub struct RootDelegationRenewalProvisionerView {
301 pub principal: Principal,
302 pub enabled: bool,
303}
304
305#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
310pub struct RootDelegationRenewalProvisionerResponse {
311 pub provisioner: RootDelegationRenewalProvisionerView,
312}
313
314#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
319pub struct RootDelegationRenewalProvisionerListResponse {
320 pub provisioners: Vec<RootDelegationRenewalProvisionerView>,
321}
322
323#[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#[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#[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#[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#[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#[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#[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#[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#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
432pub struct RootIssuerPolicyResponse {
433 pub issuer: RootIssuerPolicyView,
434}
435
436#[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#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
467pub struct RootIssuerRenewalTemplateResponse {
468 pub template: RootIssuerRenewalTemplateView,
469}
470
471#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
476pub struct RootIssuerRenewalStatusRequest {
477 pub issuer_pid: Principal,
478}
479
480#[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#[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#[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#[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#[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#[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#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
598pub struct DelegatedTokenGetRequest {
599 pub claims_hash: [u8; 32],
600}
601
602#[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#[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#[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#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
651pub struct RoleAttestationGetRequest {
652 pub payload_hash: [u8; 32],
653}
654
655#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
660pub struct SignedRoleAttestation {
661 pub payload: RoleAttestation,
662 pub root_proof: RootProof,
663}
664
665#[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}