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}