use crate::{
cdk::types::Principal,
dto::{auth::DelegatedToken, error::Error},
error::InternalErrorClass,
ops::{
auth::{AuthOps, VerifyDelegatedTokenRuntimeInput},
config::ConfigOps,
ic::IcOps,
},
};
mod attestation;
mod root;
mod session;
mod token;
pub struct AuthApi;
impl AuthApi {
const DELEGATED_TOKENS_DISABLED: &str =
"delegated token auth disabled; set auth.delegated_tokens.enabled=true in canic.toml";
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";
const MAX_DELEGATED_SESSION_TTL_SECS: u64 = 24 * 60 * 60;
const SESSION_BOOTSTRAP_TOKEN_FINGERPRINT_DOMAIN: &[u8] =
b"canic-session-bootstrap-token-fingerprint";
fn map_auth_error(err: crate::InternalError) -> Error {
match err.class() {
InternalErrorClass::Infra | InternalErrorClass::Ops | InternalErrorClass::Workflow => {
Error::internal(err.to_string())
}
_ => Error::from(err),
}
}
fn require_delegated_token_issuer_enabled() -> Result<(), Error> {
let delegated_tokens_cfg =
ConfigOps::delegated_tokens_config().map_err(Self::map_auth_error)?;
if !delegated_tokens_cfg.enabled {
return Err(Error::invalid(Self::DELEGATED_TOKENS_DISABLED));
}
let canister_cfg = ConfigOps::current_canister().map_err(Self::map_auth_error)?;
if !canister_cfg.auth.delegated_token_issuer {
return Err(Error::forbidden(Self::DELEGATED_TOKEN_ISSUER_DISABLED));
}
Ok(())
}
fn verify_token_material(
token: &DelegatedToken,
max_cert_ttl_ns: u64,
max_token_ttl_ns: u64,
required_scopes: &[String],
now_ns: u64,
) -> Result<Principal, Error> {
AuthOps::verify_token(VerifyDelegatedTokenRuntimeInput {
token,
caller: IcOps::msg_caller(),
max_cert_ttl_ns,
max_token_ttl_ns,
required_scopes,
now_ns,
})
.map(|verified| verified.subject)
.map_err(Self::map_auth_error)
}
fn delegated_token_max_ttl_ns() -> Result<u64, Error> {
let cfg = ConfigOps::delegated_tokens_config().map_err(Error::from)?;
if !cfg.enabled {
return Err(Error::forbidden(Self::DELEGATED_TOKENS_DISABLED));
}
let max_ttl_secs = cfg
.max_ttl_secs
.unwrap_or(Self::MAX_DELEGATED_SESSION_TTL_SECS);
max_ttl_secs.checked_mul(1_000_000_000).ok_or_else(|| {
Error::invalid("auth.delegated_tokens.max_ttl_secs overflows nanoseconds")
})
}
}