Skip to main content

crab_vault_auth/
error.rs

1use std::{string::FromUtf8Error, sync::Arc};
2
3use axum::{
4    http::StatusCode,
5    response::{IntoResponse, Response},
6};
7use base64::DecodeError;
8use jsonwebtoken::Algorithm;
9use serde::Serialize;
10use thiserror::Error;
11
12#[derive(Debug, Serialize, Clone, Error)]
13#[serde(rename_all = "camelCase", tag = "code")]
14pub enum AuthError {
15    #[error("missing authorization header")]
16    MissingAuthHeader,
17
18    #[error("key of algorithm `{0:?}` is undefined")]
19    InvalidAlgorithm(Algorithm),
20
21    #[error("invalid authorization format: expected 'Bearer <token>'")]
22    InvalidAuthFormat,
23
24    #[error("no key id fed")]
25    InvalidKeyId,
26
27    #[error("Some of the text was invalid UTF-8: {0}")]
28    InvalidUtf8(
29        #[from]
30        #[serde(skip)]
31        FromUtf8Error,
32    ),
33
34    #[error("An error happened while serializing/deserializing JSON: {0}")]
35    InvalidJson(
36        #[from]
37        #[serde(skip)]
38        Arc<serde_json::Error>,
39    ),
40
41    #[error("An error happened when decoding some base64 text: {0}")]
42    InvalidBase64(
43        #[from]
44        #[serde(skip)]
45        DecodeError,
46    ),
47
48    #[error("token is invalid")]
49    InvalidToken,
50
51    #[error("token has expired")]
52    TokenExpired,
53
54    #[error("token is not yet valid")]
55    TokenNotYetValid,
56
57    #[error("invalid signature")]
58    InvalidSignature,
59
60    #[error("untrusted issuer")]
61    InvalidIssuer,
62
63    #[error("invalid audience")]
64    InvalidAudience,
65
66    #[error("invalid subject")]
67    InvalidSubject,
68
69    #[error("required claim `{0}` missing")]
70    MissingClaim(String),
71
72    #[error("insufficient permissions for this operation")]
73    InsufficientPermissions,
74
75    #[error("token has been revoked")]
76    TokenRevoked,
77
78    #[error("internal server error during authentication, details: {0}")]
79    InternalError(#[serde(skip)] String),
80}
81
82impl From<jsonwebtoken::errors::Error> for AuthError {
83    fn from(value: jsonwebtoken::errors::Error) -> Self {
84        use jsonwebtoken::errors::ErrorKind::*;
85
86        match value.into_kind() {
87            ExpiredSignature => AuthError::TokenExpired,
88            InvalidSignature => AuthError::InvalidSignature,
89            InvalidIssuer => AuthError::InvalidIssuer,
90            InvalidAudience => AuthError::InvalidAudience,
91            InvalidSubject => AuthError::InvalidSubject,
92            MissingRequiredClaim(claim) => AuthError::MissingClaim(claim),
93            ImmatureSignature => AuthError::TokenNotYetValid,
94            InvalidToken => AuthError::InvalidToken,
95            Base64(e) => AuthError::InvalidBase64(e),
96            Utf8(e) => AuthError::InvalidUtf8(e),
97            Json(e) => AuthError::InvalidJson(e),
98
99            InvalidEcdsaKey => AuthError::InternalError("the secret given is not a valid ECDSA key".into()),
100            InvalidRsaKey(_) => AuthError::InternalError("the secret given is not a valid RSA key".into()),
101            RsaFailedSigning => AuthError::InternalError("could not sign with the given key".into()),
102            InvalidAlgorithmName => AuthError::InternalError("cannot parse algorithm from str".into()),
103            InvalidKeyFormat => AuthError::InternalError("a key is provided with an invalid format".into()),
104            InvalidAlgorithm => AuthError::InternalError("the algorithm in the header doesn't match the one passed to decode or the encoding/decoding key used doesn't match the alg requested".to_string()),
105            MissingAlgorithm => AuthError::InternalError("the Validation struct does not contain at least 1 algorithm".into()),
106            Crypto(e) => AuthError::InternalError(format!("Something unspecified went wrong with crypto: {e}")),
107            _ => todo!()
108        }
109    }
110}
111
112impl IntoResponse for AuthError {
113    fn into_response(self) -> Response {
114        let status_code = match self {
115            AuthError::MissingAuthHeader
116            | AuthError::InvalidKeyId
117            | AuthError::InvalidAuthFormat
118            | AuthError::InvalidToken
119            | AuthError::TokenExpired
120            | AuthError::TokenNotYetValid
121            | AuthError::InvalidAlgorithm(_)
122            | AuthError::InvalidSignature
123            | AuthError::InvalidIssuer
124            | AuthError::InvalidAudience
125            | AuthError::InvalidSubject
126            | AuthError::MissingClaim(_)
127            | AuthError::InvalidUtf8(_)
128            | AuthError::InvalidJson(_)
129            | AuthError::InvalidBase64(_)
130            | AuthError::TokenRevoked => StatusCode::UNAUTHORIZED,
131
132            AuthError::InsufficientPermissions => StatusCode::FORBIDDEN,
133
134            AuthError::InternalError(_) => StatusCode::UNAUTHORIZED,
135        };
136
137        status_code.into_response()
138    }
139}
140
141impl From<serde_json::Error> for AuthError {
142    fn from(value: serde_json::Error) -> Self {
143        Self::InvalidJson(Arc::new(value))
144    }
145}
146
147impl From<AuthError> for Response {
148    #[inline(always)]
149    fn from(val: AuthError) -> Response {
150        val.into_response()
151    }
152}