canic_core/api/auth/
mod.rs1use crate::{
8 cdk::types::Principal,
9 dto::{auth::DelegatedToken, error::Error},
10 error::InternalErrorClass,
11 ops::{
12 auth::{AuthOps, VerifyDelegatedTokenRuntimeInput},
13 config::ConfigOps,
14 ic::IcOps,
15 },
16};
17
18mod attestation;
24mod root;
25mod session;
26mod token;
27
28pub struct AuthApi;
36
37impl AuthApi {
38 const DELEGATED_TOKENS_DISABLED: &str =
39 "delegated token auth disabled; set auth.delegated_tokens.enabled=true in canic.toml";
40 const DELEGATED_TOKEN_ISSUER_DISABLED: &str = "delegated token issuer disabled for this canister; set subnets.<subnet>.canisters.<role>.auth.delegated_token_issuer=true in canic.toml";
41 const MAX_DELEGATED_SESSION_TTL_SECS: u64 = 24 * 60 * 60;
42 const SESSION_BOOTSTRAP_TOKEN_FINGERPRINT_DOMAIN: &[u8] =
43 b"canic-session-bootstrap-token-fingerprint";
44
45 fn map_auth_error(err: crate::InternalError) -> Error {
47 match err.class() {
48 InternalErrorClass::Infra | InternalErrorClass::Ops | InternalErrorClass::Workflow => {
49 Error::internal(err.to_string())
50 }
51 _ => Error::from(err),
52 }
53 }
54
55 fn require_delegated_token_issuer_enabled() -> Result<(), Error> {
56 let delegated_tokens_cfg =
57 ConfigOps::delegated_tokens_config().map_err(Self::map_auth_error)?;
58 if !delegated_tokens_cfg.enabled {
59 return Err(Error::invalid(Self::DELEGATED_TOKENS_DISABLED));
60 }
61
62 let canister_cfg = ConfigOps::current_canister().map_err(Self::map_auth_error)?;
63 if !canister_cfg.auth.delegated_token_issuer {
64 return Err(Error::forbidden(Self::DELEGATED_TOKEN_ISSUER_DISABLED));
65 }
66
67 Ok(())
68 }
69
70 fn verify_token_material(
75 token: &DelegatedToken,
76 max_cert_ttl_ns: u64,
77 max_token_ttl_ns: u64,
78 required_scopes: &[String],
79 now_ns: u64,
80 ) -> Result<Principal, Error> {
81 AuthOps::verify_token(VerifyDelegatedTokenRuntimeInput {
82 token,
83 caller: IcOps::msg_caller(),
84 max_cert_ttl_ns,
85 max_token_ttl_ns,
86 required_scopes,
87 now_ns,
88 })
89 .map(|verified| verified.subject)
90 .map_err(Self::map_auth_error)
91 }
92
93 fn delegated_token_max_ttl_ns() -> Result<u64, Error> {
95 let cfg = ConfigOps::delegated_tokens_config().map_err(Error::from)?;
96 if !cfg.enabled {
97 return Err(Error::forbidden(Self::DELEGATED_TOKENS_DISABLED));
98 }
99
100 let max_ttl_secs = cfg
101 .max_ttl_secs
102 .unwrap_or(Self::MAX_DELEGATED_SESSION_TTL_SECS);
103 max_ttl_secs.checked_mul(1_000_000_000).ok_or_else(|| {
104 Error::invalid("auth.delegated_tokens.max_ttl_secs overflows nanoseconds")
105 })
106 }
107}