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// RootDelegationProofBatchProofRef
255//
256
257#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
258pub struct RootDelegationProofBatchProofRef {
259    pub issuer_pid: Principal,
260    pub cert_hash: [u8; 32],
261}
262
263//
264// RootDelegationProofBatchGetResponse
265//
266
267#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
268pub struct RootDelegationProofBatchGetResponse {
269    pub batch_id: [u8; 32],
270    pub proofs: Vec<RootDelegationProofBatchProof>,
271}
272
273//
274// RootDelegationProofBatchProof
275//
276
277#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
278pub struct RootDelegationProofBatchProof {
279    pub issuer_pid: Principal,
280    pub cert_hash: [u8; 32],
281    pub proof: DelegationProof,
282}
283
284//
285// RootDelegationProofBatchInstallRequest
286//
287
288#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
289pub struct RootDelegationProofBatchInstallRequest {
290    pub batch_id: [u8; 32],
291    pub proofs: Vec<RootDelegationProofBatchProof>,
292}
293
294//
295// RootDelegationProofBatchInstallResponse
296//
297
298#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
299pub struct RootDelegationProofBatchInstallResponse {
300    pub batch_id: [u8; 32],
301    pub outcomes: Vec<RootDelegationProofBatchInstallResult>,
302}
303
304//
305// RootDelegationProofBatchInstallResult
306//
307
308#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
309pub struct RootDelegationProofBatchInstallResult {
310    pub issuer_pid: Principal,
311    pub cert_hash: [u8; 32],
312    pub outcome: RootDelegationProofInstallOutcome,
313}
314
315//
316// RootDelegationProofInstallOutcome
317//
318
319#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
320pub enum RootDelegationProofInstallOutcome {
321    Installed,
322    AlreadyInstalled,
323    RejectedBySigner,
324    CallFailed,
325    ProofMismatch,
326    ExpiredOrSuperseded,
327}
328
329//
330// RootIssuerPolicyUpsertRequest
331//
332
333#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
334pub struct RootIssuerPolicyUpsertRequest {
335    pub issuer_pid: Principal,
336    pub enabled: bool,
337    pub allowed_audiences: Vec<DelegationAudience>,
338    pub allowed_grants: Vec<DelegatedRoleGrant>,
339    pub max_cert_ttl_ns: u64,
340    pub refresh_after_ratio_bps: u16,
341}
342
343//
344// RootIssuerPolicyView
345//
346
347#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
348pub struct RootIssuerPolicyView {
349    pub issuer_pid: Principal,
350    pub enabled: bool,
351    pub allowed_audiences: Vec<DelegationAudience>,
352    pub allowed_grants: Vec<DelegatedRoleGrant>,
353    pub max_cert_ttl_ns: u64,
354    pub refresh_after_ratio_bps: u16,
355}
356
357//
358// RootIssuerPolicyResponse
359//
360
361#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
362pub struct RootIssuerPolicyResponse {
363    pub issuer: RootIssuerPolicyView,
364}
365
366//
367// DelegatedTokenPrepareRequest
368//
369
370#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
371pub struct DelegatedTokenPrepareRequest {
372    #[serde(default)]
373    pub metadata: Option<AuthRequestMetadata>,
374    pub subject: Principal,
375    pub aud: DelegationAudience,
376    pub grants: Vec<DelegatedRoleGrant>,
377    pub ttl_ns: u64,
378    #[serde(default)]
379    pub ext: Option<Vec<u8>>,
380}
381
382//
383// DelegatedTokenPrepareResponse
384//
385
386#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
387pub struct DelegatedTokenPrepareResponse {
388    pub claims: DelegatedTokenClaims,
389    pub claims_hash: [u8; 32],
390    pub retrieval_expires_at_ns: u64,
391}
392
393//
394// DelegatedTokenGetRequest
395//
396
397#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
398pub struct DelegatedTokenGetRequest {
399    pub claims_hash: [u8; 32],
400}
401
402//
403// RoleAttestationRequest
404//
405
406#[derive(CandidType, Clone, Debug, Deserialize)]
407pub struct RoleAttestationRequest {
408    pub subject: Principal,
409    pub role: CanisterRole,
410    #[serde(default)]
411    pub subnet_id: Option<Principal>,
412    pub audience: Principal,
413    pub ttl_ns: u64,
414    pub epoch: u64,
415    #[serde(default)]
416    pub metadata: Option<RootRequestMetadata>,
417}
418
419//
420// RoleAttestation
421//
422
423#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
424pub struct RoleAttestation {
425    pub subject: Principal,
426    pub role: CanisterRole,
427    #[serde(default)]
428    pub subnet_id: Option<Principal>,
429    pub audience: Principal,
430    pub issued_at_ns: u64,
431    pub expires_at_ns: u64,
432    pub epoch: u64,
433}
434
435//
436// RoleAttestationPrepareResponse
437//
438
439#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
440pub struct RoleAttestationPrepareResponse {
441    pub payload: RoleAttestation,
442    pub payload_hash: [u8; 32],
443    pub retrieval_expires_at_ns: u64,
444}
445
446//
447// RoleAttestationGetRequest
448//
449
450#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
451pub struct RoleAttestationGetRequest {
452    pub payload_hash: [u8; 32],
453}
454
455//
456// SignedRoleAttestation
457//
458
459#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
460pub struct SignedRoleAttestation {
461    pub payload: RoleAttestation,
462    pub root_proof: RootProof,
463}
464
465// -----------------------------------------------------------------------------
466// Tests
467// -----------------------------------------------------------------------------
468
469#[cfg(test)]
470mod tests {
471    #[test]
472    fn auth_dtos_remain_passive_boundary_types() {
473        let source = include_str!("auth.rs");
474        let production_source = source
475            .split("#[cfg(test)]")
476            .next()
477            .expect("production source exists");
478
479        for marker in [
480            "impl DelegatedToken",
481            "impl DelegatedTokenClaims",
482            "impl RoleAttestation",
483            "impl SignedRoleAttestation",
484            "fn verify",
485            "fn sign",
486            "fn resolve",
487            "fn replay",
488            "fn consume",
489            "fn policy",
490            "fn validate",
491        ] {
492            assert!(
493                !production_source.contains(marker),
494                "auth DTOs must stay passive; found marker `{marker}`"
495            );
496        }
497    }
498}