mirror of
https://github.com/TECHNOFAB11/jwt-authorizer.git
synced 2025-12-11 23:50:07 +01:00
refactor: AuthError
This commit is contained in:
parent
582206b24c
commit
9f459fb362
3 changed files with 75 additions and 22 deletions
|
|
@ -1,11 +1,12 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response}, body::{self, Empty},
|
||||||
};
|
};
|
||||||
|
use http::header;
|
||||||
use jsonwebtoken::Algorithm;
|
use jsonwebtoken::Algorithm;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use tracing::log::warn;
|
use tracing::{log::warn, debug};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum InitError {
|
pub enum InitError {
|
||||||
|
|
@ -36,8 +37,8 @@ pub enum AuthError {
|
||||||
#[error("Invalid Key Algorithm {0:?}")]
|
#[error("Invalid Key Algorithm {0:?}")]
|
||||||
InvalidKeyAlg(Algorithm),
|
InvalidKeyAlg(Algorithm),
|
||||||
|
|
||||||
// #[error(transparent)]
|
#[error("Missing Token")]
|
||||||
// InvalidTokenHeader(#[from] TypedHeaderRejection),
|
MissingToken(),
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
InvalidToken(#[from] jsonwebtoken::errors::Error),
|
InvalidToken(#[from] jsonwebtoken::errors::Error),
|
||||||
|
|
@ -46,23 +47,72 @@ pub enum AuthError {
|
||||||
InvalidClaims(),
|
InvalidClaims(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// (https://datatracker.ietf.org/doc/html/rfc6750#section-3.1)
|
||||||
impl IntoResponse for AuthError {
|
impl IntoResponse for AuthError {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
// TODO: add error code (https://datatracker.ietf.org/doc/html/rfc6750#section-3.1)
|
|
||||||
warn!("AuthError: {}", &self);
|
warn!("AuthError: {}", &self);
|
||||||
let (status, error_message) = match self {
|
let resp = match self {
|
||||||
AuthError::JwksRefreshError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
|
AuthError::JwksRefreshError(err) => {
|
||||||
AuthError::InvalidKid(msg) => (StatusCode::UNAUTHORIZED, msg),
|
tracing::error!("AuthErrors::JwksRefreshError: {}", err);
|
||||||
// AuthError::InvalidTokenHeader(_) => (StatusCode::BAD_REQUEST, self.to_string()),
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
AuthError::InvalidToken(_) => (StatusCode::UNAUTHORIZED, self.to_string()),
|
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
|
||||||
AuthError::InvalidKey(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
|
res
|
||||||
AuthError::JwksSerialisationError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
|
},
|
||||||
AuthError::InvalidKeyAlg(_) => (StatusCode::BAD_REQUEST, self.to_string()),
|
AuthError::InvalidKey(err) => {
|
||||||
AuthError::InvalidClaims() => (StatusCode::UNAUTHORIZED, self.to_string()),
|
tracing::error!("AuthErrors::InvalidKey: {}", err);
|
||||||
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
|
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
|
||||||
|
res
|
||||||
|
},
|
||||||
|
AuthError::JwksSerialisationError(err) => {
|
||||||
|
tracing::error!("AuthErrors::JwksSerialisationError: {}", err);
|
||||||
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
|
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
|
||||||
|
res
|
||||||
|
},
|
||||||
|
AuthError::InvalidKeyAlg(err) => {
|
||||||
|
debug!("AuthErrors::InvalidKeyAlg: {:?}", err);
|
||||||
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
|
*res.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
res.headers_mut().insert(header::WWW_AUTHENTICATE, "Bearer error=\"invalid_token\", error_description=\"invalid key algorithm\"".parse().unwrap());
|
||||||
|
res
|
||||||
|
},
|
||||||
|
AuthError::InvalidKid(err) => {
|
||||||
|
debug!("AuthErrors::InvalidKid: {}", err);
|
||||||
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
|
*res.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
res.headers_mut().insert(header::WWW_AUTHENTICATE, "Bearer error=\"invalid_token\", error_description=\"invalid kid\"".parse().unwrap());
|
||||||
|
res
|
||||||
|
},
|
||||||
|
AuthError::InvalidToken(err) => {
|
||||||
|
debug!("AuthErrors::InvalidToken: {}", err);
|
||||||
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
|
*res.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
res.headers_mut().insert(header::WWW_AUTHENTICATE, "Bearer error=\"invalid_token\"".parse().unwrap());
|
||||||
|
res
|
||||||
|
},
|
||||||
|
AuthError::MissingToken() => {
|
||||||
|
// WWW-Authenticate: Bearer realm="example"
|
||||||
|
debug!("AuthErrors::MissingToken");
|
||||||
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
|
*res.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
res.headers_mut().insert(header::WWW_AUTHENTICATE, "Bearer".parse().unwrap());
|
||||||
|
res
|
||||||
|
},
|
||||||
|
AuthError::InvalidClaims() => {
|
||||||
|
// WWW-Authenticate: Bearer error="insufficient_scope"
|
||||||
|
debug!("AuthErrors::InvalidClaims");
|
||||||
|
let mut res = Response::new(body::boxed(Empty::new()));
|
||||||
|
*res.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
res.headers_mut().insert(header::WWW_AUTHENTICATE, "Bearer error=\"insufficient_scope\"".parse().unwrap());
|
||||||
|
|
||||||
|
res
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let body = axum::Json(serde_json::json!({
|
// let body = axum::Json(serde_json::json!({
|
||||||
"error": error_message,
|
// "error": error_message,
|
||||||
}));
|
// }));
|
||||||
(status, body).into_response()
|
|
||||||
|
resp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ use futures_core::ready;
|
||||||
use futures_util::future::BoxFuture;
|
use futures_util::future::BoxFuture;
|
||||||
use headers::authorization::Bearer;
|
use headers::authorization::Bearer;
|
||||||
use headers::{Authorization, HeaderMapExt};
|
use headers::{Authorization, HeaderMapExt};
|
||||||
use http::StatusCode;
|
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
@ -15,6 +14,7 @@ use std::task::{Context, Poll};
|
||||||
use tower_layer::Layer;
|
use tower_layer::Layer;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
|
use crate::AuthError;
|
||||||
use crate::authorizer::{Authorizer, FnClaimsChecker, KeySourceType};
|
use crate::authorizer::{Authorizer, FnClaimsChecker, KeySourceType};
|
||||||
use crate::error::InitError;
|
use crate::error::InitError;
|
||||||
|
|
||||||
|
|
@ -145,7 +145,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err((StatusCode::UNAUTHORIZED).into_response())
|
Err(AuthError::MissingToken().into_response())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ mod tests {
|
||||||
http::{Request, StatusCode},
|
http::{Request, StatusCode},
|
||||||
routing::get, Router, response::Response,
|
routing::get, Router, response::Response,
|
||||||
};
|
};
|
||||||
|
use http::header;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tower::ServiceExt;
|
use tower::ServiceExt;
|
||||||
|
|
||||||
|
|
@ -48,7 +49,9 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
// TODO: check error code (https://datatracker.ietf.org/doc/html/rfc6750#section-3.1)
|
|
||||||
|
assert!(response.headers().get(header::WWW_AUTHENTICATE).is_some(), "Must have a WWW-Authenticate header!");
|
||||||
|
assert_eq!(response.headers().get(header::WWW_AUTHENTICATE).unwrap(), &"Bearer"); // TODO: realm="example"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue