1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use actix_web::{body::BoxBody, http::StatusCode, HttpResponse, ResponseError};
use jwt_compact::{CreationError, ParseError, ValidationError};
pub type AuthResult<T> = Result<T, AuthError>;
#[derive(Debug)]
pub enum AuthError {
Internal(actix_web::Error),
NoCookie,
NoCookieSigner,
RefreshAuthorizerDenied(actix_web::Error),
TokenCreation(CreationError),
TokenParse(ParseError),
TokenValidation(ValidationError),
}
impl PartialEq for AuthError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::TokenCreation(_), Self::TokenCreation(_))
| (Self::TokenValidation(_), Self::TokenValidation(_))
| (Self::TokenParse(_), Self::TokenParse(_))
| (Self::Internal(_), Self::Internal(_)) => true,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
impl Into<AuthError> for CreationError {
fn into(self) -> AuthError {
AuthError::TokenCreation(self)
}
}
impl Into<AuthError> for ParseError {
fn into(self) -> AuthError {
AuthError::TokenParse(self)
}
}
impl Into<AuthError> for ValidationError {
fn into(self) -> AuthError {
AuthError::TokenValidation(self)
}
}
impl std::fmt::Display for AuthError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
const NO_COOKIE_MESSAGE: &str = "An error occurred, no cookie containing a jwt was found in the request. Please first authenticate with this application.";
#[cfg(not(debug_assertions))]
match self {
AuthError::NoCookie => f.write_str(NO_COOKIE_MESSAGE),
AuthError::RefreshAuthorizerDenied(err) => f.write_str(&err.to_string()),
AuthError::TokenParse(_) | AuthError::TokenValidation(_) => {
f.write_str("An error occurred, the provided jwt could not be processed.")
}
AuthError::Internal(_) | AuthError::NoCookieSigner | AuthError::TokenCreation(_) => {
f.write_str("An internal error occurred. Please try again later.")
}
}
#[cfg(debug_assertions)]
match self {
AuthError::NoCookie => f.write_str(NO_COOKIE_MESSAGE),
AuthError::NoCookieSigner => f.write_str(
"An error occurred because no CookieSigner was configured on the Authority struct.",
),
AuthError::TokenCreation(err) => f.write_fmt(format_args!(
"An error occurred creating the jwt.\n\t Error: \"{err}\""
)),
AuthError::TokenValidation(err) => f.write_fmt(format_args!(
"An error occurred validating the jwt.\n\t Error: \"{err}\""
)),
AuthError::TokenParse(err) => f.write_fmt(format_args!(
"An error occurred parsing the jwt.\n\t Error: \"{err}\""
)),
AuthError::RefreshAuthorizerDenied(err) | AuthError::Internal(err) => {
f.write_str(&err.to_string())
}
}
}
}
impl ResponseError for AuthError {
fn status_code(&self) -> StatusCode {
match self {
AuthError::TokenCreation(_) | AuthError::NoCookieSigner => {
StatusCode::INTERNAL_SERVER_ERROR
}
AuthError::TokenParse(_) => StatusCode::BAD_REQUEST,
AuthError::NoCookie | AuthError::TokenValidation(_) => StatusCode::UNAUTHORIZED,
AuthError::Internal(err) | AuthError::RefreshAuthorizerDenied(err) => {
err.as_response_error().status_code()
}
}
}
fn error_response(&self) -> HttpResponse<BoxBody> {
match self {
AuthError::RefreshAuthorizerDenied(err) | AuthError::Internal(err) => {
err.error_response()
}
_ => HttpResponse::build(self.status_code()).body(self.to_string()),
}
}
}