biscuit_auth/
error.rs

1//! error types
2//!
3
4use std::convert::{From, Infallible};
5use thiserror::Error;
6
7/// the global error type for Biscuit
8#[derive(Error, Clone, Debug, PartialEq, Eq)]
9#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
10pub enum Token {
11    #[error("internal error")]
12    InternalError,
13    #[error("error deserializing or verifying the token")]
14    Format(Format),
15    #[error("tried to append a block to a sealed token")]
16    AppendOnSealed,
17    #[error("tried to seal an already sealed token")]
18    AlreadySealed,
19    #[error("authorization failed")]
20    FailedLogic(Logic),
21    #[error("error generating Datalog: {0}")]
22    Language(biscuit_parser::error::LanguageError),
23    #[error("Reached Datalog execution limits")]
24    RunLimit(RunLimit),
25    #[error("Cannot convert from Term: {0}")]
26    ConversionError(String),
27    #[error("Cannot decode base64 token: {0}")]
28    Base64(Base64Error),
29    #[error("Datalog  execution failure: {0}")]
30    Execution(Expression),
31}
32
33impl From<Infallible> for Token {
34    fn from(_: Infallible) -> Self {
35        unreachable!()
36    }
37}
38
39impl From<Format> for Token {
40    fn from(e: Format) -> Self {
41        Token::Format(e)
42    }
43}
44
45impl From<Logic> for Token {
46    fn from(e: Logic) -> Self {
47        Token::FailedLogic(e)
48    }
49}
50
51impl From<biscuit_parser::error::LanguageError> for Token {
52    fn from(e: biscuit_parser::error::LanguageError) -> Self {
53        Token::Language(e)
54    }
55}
56
57impl From<base64::DecodeError> for Token {
58    fn from(e: base64::DecodeError) -> Self {
59        let err = match e {
60            base64::DecodeError::InvalidByte(offset, byte) => {
61                Base64Error::InvalidByte(offset, byte)
62            }
63            base64::DecodeError::InvalidLength => Base64Error::InvalidLength,
64            base64::DecodeError::InvalidLastSymbol(offset, byte) => {
65                Base64Error::InvalidLastSymbol(offset, byte)
66            }
67        };
68
69        Token::Base64(err)
70    }
71}
72
73impl From<Execution> for Token {
74    fn from(e: Execution) -> Self {
75        match e {
76            Execution::RunLimit(limit) => Token::RunLimit(limit),
77            Execution::Expression(e) => Token::Execution(e),
78        }
79    }
80}
81
82#[derive(Clone, Debug, PartialEq, Eq)]
83#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
84pub enum Base64Error {
85    InvalidByte(usize, u8),
86    InvalidLength,
87    InvalidLastSymbol(usize, u8),
88}
89
90impl std::fmt::Display for Base64Error {
91    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
92        match *self {
93            Base64Error::InvalidByte(index, byte) => {
94                write!(f, "Invalid byte {}, offset {}.", byte, index)
95            }
96            Base64Error::InvalidLength => write!(f, "Encoded text cannot have a 6-bit remainder."),
97            Base64Error::InvalidLastSymbol(index, byte) => {
98                write!(f, "Invalid last symbol {}, offset {}.", byte, index)
99            }
100        }
101    }
102}
103
104/// Errors related to the token's serialization format or cryptographic
105/// signature
106#[derive(Error, Clone, Debug, PartialEq, Eq)]
107#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
108pub enum Format {
109    #[error("failed verifying the signature")]
110    Signature(Signature),
111    #[error("failed verifying the signature of a sealed token")]
112    SealedSignature,
113    #[error("the token does not provide intermediate public keys")]
114    EmptyKeys,
115    #[error("the root public key was not recognized")]
116    UnknownPublicKey,
117    #[error("could not deserialize the wrapper object")]
118    DeserializationError(String),
119    #[error("could not serialize the wrapper object")]
120    SerializationError(String),
121    #[error("could not deserialize the block")]
122    BlockDeserializationError(String),
123    #[error("could not serialize the block")]
124    BlockSerializationError(String),
125    #[error("Block format version is higher than supported")]
126    Version {
127        maximum: u32,
128        minimum: u32,
129        actual: u32,
130    },
131    #[error("invalid key size")]
132    InvalidKeySize(usize),
133    #[error("invalid signature size")]
134    InvalidSignatureSize(usize),
135    #[error("invalid key")]
136    InvalidKey(String),
137    #[error("could not deserialize signature")]
138    SignatureDeserializationError(String),
139    #[error("could not deserialize the block signature")]
140    BlockSignatureDeserializationError(String),
141    #[error("invalid block id")]
142    InvalidBlockId(usize),
143    #[error("the public key is already present in previous blocks")]
144    ExistingPublicKey(String),
145    #[error("multiple blocks declare the same symbols")]
146    SymbolTableOverlap,
147    #[error("multiple blocks declare the same public keys")]
148    PublicKeyTableOverlap,
149    #[error("the external public key was not recognized")]
150    UnknownExternalKey,
151    #[error("the symbol id was not in the table")]
152    UnknownSymbol(u64),
153}
154
155/// Signature errors
156#[derive(Error, Clone, Debug, PartialEq, Eq)]
157#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
158pub enum Signature {
159    #[error("could not parse the signature elements")]
160    InvalidFormat,
161    #[error("the signature did not match")]
162    InvalidSignature(String),
163    #[error("could not sign")]
164    InvalidSignatureGeneration(String),
165}
166
167/// errors in the Datalog evaluation
168#[derive(Error, Clone, Debug, PartialEq, Eq)]
169#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
170pub enum Logic {
171    #[error("a rule provided by a block is generating facts with the authority or ambient tag, or has head variables not used in its body")]
172    InvalidBlockRule(u32, String),
173    #[error("authorization failed")]
174    Unauthorized {
175        /// the policy that matched
176        policy: MatchedPolicy,
177        /// list of checks that failed validation
178        checks: Vec<FailedCheck>,
179    },
180    #[error("the authorizer already contains a token")]
181    AuthorizerNotEmpty,
182    #[error("no matching policy was found")]
183    NoMatchingPolicy {
184        /// list of checks that failed validation
185        checks: Vec<FailedCheck>,
186    },
187}
188
189#[derive(Error, Clone, Debug, PartialEq, Eq)]
190#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
191pub enum MatchedPolicy {
192    #[error("an allow policy matched")]
193    Allow(usize),
194    #[error("a deny policy matched")]
195    Deny(usize),
196}
197
198/// check errors
199#[derive(Error, Clone, Debug, PartialEq, Eq)]
200#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
201pub enum FailedCheck {
202    #[error("a check failed in a block")]
203    Block(FailedBlockCheck),
204    #[error("a check provided by the authorizer failed")]
205    Authorizer(FailedAuthorizerCheck),
206}
207
208#[derive(Clone, Debug, PartialEq, Eq)]
209#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
210pub struct FailedBlockCheck {
211    pub block_id: u32,
212    pub check_id: u32,
213    /// pretty print of the rule that failed
214    pub rule: String,
215}
216
217#[derive(Clone, Debug, PartialEq, Eq)]
218#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
219pub struct FailedAuthorizerCheck {
220    pub check_id: u32,
221    /// pretty print of the rule that failed
222    pub rule: String,
223}
224
225/// Datalog execution errors
226#[derive(Error, Clone, Debug, PartialEq, Eq)]
227#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
228pub enum Execution {
229    #[error("Reached Datalog execution limits")]
230    RunLimit(RunLimit),
231    #[error("Expression execution failure")]
232    Expression(Expression),
233}
234
235/// Datalog expression execution failure
236#[derive(Error, Clone, Debug, PartialEq, Eq)]
237#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
238pub enum Expression {
239    #[error("Unknown symbol")]
240    UnknownSymbol(u64),
241    #[error("Unknown variable")]
242    UnknownVariable(u32),
243    #[error("Invalid type")]
244    InvalidType,
245    #[error("Overflow")]
246    Overflow,
247    #[error("Division by zero")]
248    DivideByZero,
249    #[error("Wrong number of elements on stack")]
250    InvalidStack,
251}
252
253/// runtime limits errors
254#[derive(Error, Clone, Debug, PartialEq, Eq)]
255#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
256pub enum RunLimit {
257    #[error("too many facts generated")]
258    TooManyFacts,
259    #[error("too many engine iterations")]
260    TooManyIterations,
261    #[error("spent too much time verifying")]
262    Timeout,
263}
264
265#[cfg(test)]
266mod tests {
267    use super::*;
268
269    #[test]
270    fn error_format_strings() {
271        assert_eq!(
272            format!("{}", Token::ConversionError("test".to_owned())),
273            "Cannot convert from Term: test"
274        );
275
276        assert_eq!(
277            format!("{}", Token::Base64(Base64Error::InvalidLength)),
278            "Cannot decode base64 token: Encoded text cannot have a 6-bit remainder."
279        );
280    }
281}