Skip to main content

biscuit_ssh_core/
error.rs

1use biscuit_auth::error::Token as TokenError;
2
3/// Why a request or a token was rejected.
4///
5/// Every variant means "deny": callers must never grant access on error.
6///
7/// Messages of [`Error::Denied`], [`Error::InvalidToken`] and
8/// [`Error::Datalog`] can quote Datalog written by the token holder, which
9/// may carry arbitrary data: services should log and return [`Error::kind`]
10/// only, and show full messages to people handling their own tokens.
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13    /// A request field or command-line value is malformed.
14    #[error("invalid {field}: {reason}")]
15    InvalidInput {
16        /// What was malformed.
17        field: &'static str,
18        /// Why it was refused.
19        reason: &'static str,
20    },
21
22    /// The token cannot be decoded or its signatures do not match the root key.
23    #[error("invalid token: {0}")]
24    InvalidToken(#[source] TokenError),
25
26    /// One of the token's blocks carries a revoked identifier.
27    #[error("token revoked: {0}")]
28    Revoked(String),
29
30    /// The token is valid but its checks or the verifier policies refuse the request.
31    #[error("access denied: {0}")]
32    Denied(#[source] TokenError),
33    /// The evaluation ran out of time. That may come from the load, and the
34    /// request may then succeed when retried; a costly token can also time
35    /// out every time. Access is refused meanwhile.
36    #[error("token evaluation timed out")]
37    Overloaded,
38
39    /// Datalog could not be built (bad operator policy, internal error).
40    #[error("datalog error: {0}")]
41    Datalog(#[source] TokenError),
42}
43
44impl Error {
45    /// A stable, content-free label for logs and client responses.
46    pub fn kind(&self) -> &'static str {
47        match self {
48            Self::InvalidInput { .. } => "invalid_input",
49            Self::InvalidToken(_) => "invalid_token",
50            Self::Revoked(_) => "revoked",
51            Self::Denied(_) => "denied",
52            Self::Overloaded => "overloaded",
53            Self::Datalog(_) => "datalog",
54        }
55    }
56
57    pub(crate) fn invalid(field: &'static str, reason: &'static str) -> Self {
58        Self::InvalidInput { field, reason }
59    }
60}