1use std::{
5 convert::{From, Infallible},
6 fmt::Display,
7};
8use thiserror::Error;
9
10#[derive(Error, Clone, Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
13pub enum Token {
14 #[error("internal error")]
15 InternalError,
16 #[error("error deserializing or verifying the token")]
17 Format(Format),
18 #[error("tried to append a block to a sealed token")]
19 AppendOnSealed,
20 #[error("tried to seal an already sealed token")]
21 AlreadySealed,
22 #[error("authorization failed: {0}")]
23 FailedLogic(Logic),
24 #[error("error generating Datalog: {0}")]
25 Language(biscuit_parser::error::LanguageError),
26 #[error("Reached Datalog execution limits")]
27 RunLimit(RunLimit),
28 #[error("Cannot convert from Term: {0}")]
29 ConversionError(String),
30 #[error("Cannot decode base64 token: {0}")]
31 Base64(Base64Error),
32 #[error("Datalog execution failure: {0}")]
33 Execution(Expression),
34}
35
36impl From<Infallible> for Token {
37 fn from(_: Infallible) -> Self {
38 unreachable!()
39 }
40}
41
42impl From<Format> for Token {
43 fn from(e: Format) -> Self {
44 Token::Format(e)
45 }
46}
47
48impl From<Logic> for Token {
49 fn from(e: Logic) -> Self {
50 Token::FailedLogic(e)
51 }
52}
53
54impl From<biscuit_parser::error::LanguageError> for Token {
55 fn from(e: biscuit_parser::error::LanguageError) -> Self {
56 Token::Language(e)
57 }
58}
59
60impl From<base64::DecodeError> for Token {
61 fn from(e: base64::DecodeError) -> Self {
62 let err = match e {
63 base64::DecodeError::InvalidByte(offset, byte) => {
64 Base64Error::InvalidByte(offset, byte)
65 }
66 base64::DecodeError::InvalidLength => Base64Error::InvalidLength,
67 base64::DecodeError::InvalidLastSymbol(offset, byte) => {
68 Base64Error::InvalidLastSymbol(offset, byte)
69 }
70 };
71
72 Token::Base64(err)
73 }
74}
75
76impl From<Execution> for Token {
77 fn from(e: Execution) -> Self {
78 match e {
79 Execution::RunLimit(limit) => Token::RunLimit(limit),
80 Execution::Expression(e) => Token::Execution(e),
81 }
82 }
83}
84
85#[derive(Clone, Debug, PartialEq, Eq)]
86#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
87pub enum Base64Error {
88 InvalidByte(usize, u8),
89 InvalidLength,
90 InvalidLastSymbol(usize, u8),
91}
92
93impl std::fmt::Display for Base64Error {
94 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
95 match *self {
96 Base64Error::InvalidByte(index, byte) => {
97 write!(f, "Invalid byte {}, offset {}.", byte, index)
98 }
99 Base64Error::InvalidLength => write!(f, "Encoded text cannot have a 6-bit remainder."),
100 Base64Error::InvalidLastSymbol(index, byte) => {
101 write!(f, "Invalid last symbol {}, offset {}.", byte, index)
102 }
103 }
104 }
105}
106
107#[derive(Error, Clone, Debug, PartialEq, Eq)]
110#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
111pub enum Format {
112 #[error("failed verifying the signature")]
113 Signature(Signature),
114 #[error("failed verifying the signature of a sealed token")]
115 SealedSignature,
116 #[error("the token does not provide intermediate public keys")]
117 EmptyKeys,
118 #[error("the root public key was not recognized")]
119 UnknownPublicKey,
120 #[error("could not deserialize the wrapper object")]
121 DeserializationError(String),
122 #[error("could not serialize the wrapper object")]
123 SerializationError(String),
124 #[error("could not deserialize the block")]
125 BlockDeserializationError(String),
126 #[error("could not serialize the block")]
127 BlockSerializationError(String),
128 #[error("Block format version is higher than supported")]
129 Version {
130 maximum: u32,
131 minimum: u32,
132 actual: u32,
133 },
134 #[error("invalid key size")]
135 InvalidKeySize(usize),
136 #[error("invalid signature size")]
137 InvalidSignatureSize(usize),
138 #[error("invalid key")]
139 InvalidKey(String),
140 #[error("could not deserialize signature")]
141 SignatureDeserializationError(String),
142 #[error("could not deserialize the block signature")]
143 BlockSignatureDeserializationError(String),
144 #[error("invalid block id")]
145 InvalidBlockId(usize),
146 #[error("the public key is already present in previous blocks")]
147 ExistingPublicKey(String),
148 #[error("multiple blocks declare the same symbols")]
149 SymbolTableOverlap,
150 #[error("multiple blocks declare the same public keys")]
151 PublicKeyTableOverlap,
152 #[error("the external public key was not recognized")]
153 UnknownExternalKey,
154 #[error("the symbol id was not in the table")]
155 UnknownSymbol(u64),
156 #[cfg(feature = "pem")]
157 #[error("PKCS8 serialization error")]
158 PKCS8(String),
159}
160
161#[derive(Error, Clone, Debug, PartialEq, Eq)]
163#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
164pub enum Signature {
165 #[error("could not parse the signature elements")]
166 InvalidFormat,
167 #[error("the signature did not match")]
168 InvalidSignature(String),
169 #[error("could not sign")]
170 InvalidSignatureGeneration(String),
171}
172
173#[derive(Error, Clone, Debug, PartialEq, Eq)]
175#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
176pub enum Logic {
177 #[error("a rule provided by a block is producing a fact with unbound variables")]
178 InvalidBlockRule(u32, String),
179 #[error("{policy}, and the following checks failed: {}", display_failed_checks(.checks))]
180 Unauthorized {
181 policy: MatchedPolicy,
183 checks: Vec<FailedCheck>,
185 },
186 #[error("the authorizer already contains a token")]
187 AuthorizerNotEmpty,
188 #[error("no matching policy was found, and the following checks failed: {}", display_failed_checks(.checks))]
189 NoMatchingPolicy {
190 checks: Vec<FailedCheck>,
192 },
193}
194
195#[derive(Error, Clone, Debug, PartialEq, Eq)]
196#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
197pub enum MatchedPolicy {
198 #[error("an allow policy matched (policy index: {0})")]
199 Allow(usize),
200 #[error("a deny policy matched (policy index: {0})")]
201 Deny(usize),
202}
203
204#[derive(Error, Clone, Debug, PartialEq, Eq)]
206#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
207pub enum FailedCheck {
208 #[error("{0}")]
209 Block(FailedBlockCheck),
210 #[error("{0}")]
211 Authorizer(FailedAuthorizerCheck),
212}
213
214fn display_failed_checks(c: &[FailedCheck]) -> String {
215 c.iter()
216 .map(|c| c.to_string())
217 .collect::<Vec<_>>()
218 .join(", ")
219}
220
221#[derive(Clone, Debug, PartialEq, Eq)]
222#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
223pub struct FailedBlockCheck {
224 pub block_id: u32,
225 pub check_id: u32,
226 pub rule: String,
228}
229
230impl Display for FailedBlockCheck {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 write!(
233 f,
234 "Check n°{} in block n°{}: {}",
235 self.check_id, self.block_id, self.rule
236 )
237 }
238}
239
240#[derive(Clone, Debug, PartialEq, Eq)]
241#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
242pub struct FailedAuthorizerCheck {
243 pub check_id: u32,
244 pub rule: String,
246}
247
248impl Display for FailedAuthorizerCheck {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 write!(f, "Check n°{} in authorizer: {}", self.check_id, self.rule)
251 }
252}
253
254#[derive(Error, Clone, Debug, PartialEq, Eq)]
256#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
257pub enum Execution {
258 #[error("Reached Datalog execution limits")]
259 RunLimit(RunLimit),
260 #[error("Expression execution failure")]
261 Expression(Expression),
262}
263
264#[derive(Error, Clone, Debug, PartialEq, Eq)]
266#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
267pub enum Expression {
268 #[error("Unknown symbol")]
269 UnknownSymbol(u64),
270 #[error("Unknown variable")]
271 UnknownVariable(u32),
272 #[error("Invalid type")]
273 InvalidType,
274 #[error("Overflow")]
275 Overflow,
276 #[error("Division by zero")]
277 DivideByZero,
278 #[error("Wrong number of elements on stack")]
279 InvalidStack,
280 #[error("Shadowed variable")]
281 ShadowedVariable,
282 #[error("Undefined extern func: {0}")]
283 UndefinedExtern(String),
284 #[error("Error while evaluating extern func {0}: {1}")]
285 ExternEvalError(String, String),
286}
287
288#[derive(Error, Clone, Debug, PartialEq, Eq)]
290#[cfg_attr(feature = "serde-error", derive(serde::Serialize, serde::Deserialize))]
291pub enum RunLimit {
292 #[error("too many facts generated")]
293 TooManyFacts,
294 #[error("too many engine iterations")]
295 TooManyIterations,
296 #[error("spent too much time verifying")]
297 Timeout,
298 #[error("Unexpected query results, expected {0} got {1}")]
299 UnexpectedQueryResult(usize, usize),
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305
306 #[test]
307 fn error_format_strings() {
308 assert_eq!(
309 format!("{}", Token::ConversionError("test".to_owned())),
310 "Cannot convert from Term: test"
311 );
312
313 assert_eq!(
314 format!("{}", Token::Base64(Base64Error::InvalidLength)),
315 "Cannot decode base64 token: Encoded text cannot have a 6-bit remainder."
316 );
317
318 assert_eq!(
319 format!(
320 "{}",
321 Token::FailedLogic(Logic::Unauthorized {
322 policy: MatchedPolicy::Allow(0),
323 checks: vec![
324 FailedCheck::Authorizer(FailedAuthorizerCheck {
325 check_id: 0,
326 rule: "check if false".to_string()
327 }),
328 FailedCheck::Block(FailedBlockCheck {
329 block_id: 0,
330 check_id: 0,
331 rule: "check if false".to_string()
332 })
333 ]
334 })
335 )
336 .to_string(),
337 "authorization failed: an allow policy matched (policy index: 0), and the following checks failed: Check n°0 in authorizer: check if false, Check n°0 in block n°0: check if false"
338 );
339 }
340}