rusttls_jwt_authorizer/
error.rs1use axum::{
2 body::Body,
3 http::StatusCode,
4 response::{IntoResponse, Response},
5};
6use http::header;
7use jsonwebtoken::Algorithm;
8use thiserror::Error;
9
10use tracing::debug;
11
12#[derive(Debug, Error)]
13pub enum InitError {
14 #[error("Builder Error {0}")]
15 BuilderError(String),
16
17 #[error(transparent)]
18 KeyFileError(#[from] std::io::Error),
19
20 #[error(transparent)]
21 KeyDecodingError(#[from] jsonwebtoken::errors::Error),
22
23 #[error("Builder Error {0}")]
24 DiscoveryError(String),
25
26 #[error("Builder Error {0}")]
27 JwksUrlError(String),
28
29 #[error("Jwks Parsing Error {0}")]
30 JwksParsingError(#[from] serde_json::Error),
31}
32
33#[derive(Debug, Error)]
34pub enum AuthError {
35 #[error(transparent)]
36 JwksSerialisationError(#[from] serde_json::Error),
37
38 #[error("JwksRefreshError {0}")]
39 JwksRefreshError(String),
40
41 #[error("InvalidKey {0}")]
42 InvalidKey(String),
43
44 #[error("Invalid Kid {0}")]
45 InvalidKid(String),
46
47 #[error("Invalid Key Algorithm {0:?}")]
48 InvalidKeyAlg(Algorithm),
49
50 #[error("Missing Token")]
51 MissingToken(),
52
53 #[error(transparent)]
54 InvalidToken(#[from] jsonwebtoken::errors::Error),
55
56 #[error("Invalid Claim")]
57 InvalidClaims(),
58
59 #[error("No Authorizer")]
60 NoAuthorizer(),
61
62 #[error("No Authorizer Layer")]
64 NoAuthorizerLayer(),
65
66 #[error("Failed to create HTTP client: {0}")]
67 ClientBuildError(#[from] reqwest::Error),
68}
69
70fn response_wwwauth(status: StatusCode, bearer: &str) -> Response<Body> {
71 let mut res = Response::new(Body::empty());
72 *res.status_mut() = status;
73 let h = if bearer.is_empty() {
74 "Bearer".to_owned()
75 } else {
76 format!("Bearer {bearer}")
77 };
78 res.headers_mut().insert(header::WWW_AUTHENTICATE, h.parse().unwrap());
79
80 res
81}
82
83fn response_500() -> Response<Body> {
84 let mut res = Response::new(Body::empty());
85 *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
86
87 res
88}
89
90#[cfg(feature = "tonic")]
91impl From<AuthError> for Response<tonic::body::BoxBody> {
92 fn from(e: AuthError) -> Self {
93 match e {
94 AuthError::JwksRefreshError(err) => {
95 tracing::error!("AuthErrors::JwksRefreshError: {}", err);
96 tonic::Status::internal("")
97 }
98 AuthError::InvalidKey(err) => {
99 tracing::error!("AuthErrors::InvalidKey: {}", err);
100 tonic::Status::internal("")
101 }
102 AuthError::JwksSerialisationError(err) => {
103 tracing::error!("AuthErrors::JwksSerialisationError: {}", err);
104 tonic::Status::internal("")
105 }
106 AuthError::InvalidKeyAlg(err) => {
107 debug!("AuthErrors::InvalidKeyAlg: {:?}", err);
108 tonic::Status::unauthenticated("error=\"invalid_token\", error_description=\"invalid key algorithm\"")
109 }
110 AuthError::InvalidKid(err) => {
111 debug!("AuthErrors::InvalidKid: {}", err);
112 tonic::Status::unauthenticated("error=\"invalid_token\", error_description=\"invalid kid\"")
113 }
114 AuthError::InvalidToken(err) => {
115 debug!("AuthErrors::InvalidToken: {}", err);
116 tonic::Status::unauthenticated("error=\"invalid_token\"")
117 }
118 AuthError::MissingToken() => {
119 debug!("AuthErrors::MissingToken");
120 tonic::Status::unauthenticated("")
121 }
122 AuthError::InvalidClaims() => {
123 debug!("AuthErrors::InvalidClaims");
124 tonic::Status::unauthenticated("error=\"insufficient_scope\"")
125 }
126 AuthError::NoAuthorizer() => {
127 debug!("AuthErrors::NoAuthorizer");
128 tonic::Status::unauthenticated("error=\"invalid_token\"")
129 }
130 AuthError::NoAuthorizerLayer() => {
131 debug!("AuthErrors::NoAuthorizerLayer");
132 tonic::Status::unauthenticated("error=\"no_authorizer_layer\"")
133 }
134 }
135 .into_http()
136 }
137}
138
139impl From<AuthError> for Response {
140 fn from(e: AuthError) -> Self {
141 e.into_response()
142 }
143}
144
145impl IntoResponse for AuthError {
147 fn into_response(self) -> Response {
148 match self {
149 AuthError::JwksRefreshError(err) => {
150 tracing::error!("AuthErrors::JwksRefreshError: {}", err);
151 response_500()
152 }
153 AuthError::InvalidKey(err) => {
154 tracing::error!("AuthErrors::InvalidKey: {}", err);
155 response_500()
156 }
157 AuthError::JwksSerialisationError(err) => {
158 tracing::error!("AuthErrors::JwksSerialisationError: {}", err);
159 response_500()
160 }
161 AuthError::InvalidKeyAlg(err) => {
162 debug!("AuthErrors::InvalidKeyAlg: {:?}", err);
163 response_wwwauth(
164 StatusCode::UNAUTHORIZED,
165 "error=\"invalid_token\", error_description=\"invalid key algorithm\"",
166 )
167 }
168 AuthError::InvalidKid(err) => {
169 debug!("AuthErrors::InvalidKid: {}", err);
170 response_wwwauth(
171 StatusCode::UNAUTHORIZED,
172 "error=\"invalid_token\", error_description=\"invalid kid\"",
173 )
174 }
175 AuthError::InvalidToken(err) => {
176 debug!("AuthErrors::InvalidToken: {}", err);
177 response_wwwauth(StatusCode::UNAUTHORIZED, "error=\"invalid_token\"")
178 }
179 AuthError::MissingToken() => {
180 debug!("AuthErrors::MissingToken");
181 response_wwwauth(StatusCode::UNAUTHORIZED, "")
182 }
183 AuthError::InvalidClaims() => {
184 debug!("AuthErrors::InvalidClaims");
185 response_wwwauth(StatusCode::FORBIDDEN, "error=\"insufficient_scope\"")
186 }
187 AuthError::NoAuthorizer() => {
188 debug!("AuthErrors::NoAuthorizer");
189 response_wwwauth(StatusCode::FORBIDDEN, "error=\"invalid_token\"")
190 }
191 AuthError::NoAuthorizerLayer() => {
192 debug!("AuthErrors::NoAuthorizerLayer");
193 response_wwwauth(StatusCode::UNAUTHORIZED, "error=\"no_authorizer_layer\"")
195 }
196 AuthError::ClientBuildError(_) => {
197 debug!("AuthErrors::ClientBuildError");
198 response_500()
199 }
200 }
201 }
202}