chore: fmt

This commit is contained in:
cduvray 2023-01-28 08:43:51 +01:00
parent ec02b70a99
commit d8fb138d46
8 changed files with 86 additions and 78 deletions

View file

@ -28,11 +28,13 @@ async fn main() {
// First let's create an authorizer builder from a JWKS Endpoint
// User is a struct deserializable from JWT claims representing the authorized user
let jwt_auth: JwtAuthorizer<User> = JwtAuthorizer::
from_jwks_url("http://localhost:3000/oidc/jwks")
// .no_refresh()
.refresh(Refresh {strategy: RefreshStrategy::Interval, ..Default::default()})
.check(claim_checker);
let jwt_auth: JwtAuthorizer<User> = JwtAuthorizer::from_jwks_url("http://localhost:3000/oidc/jwks")
// .no_refresh()
.refresh(Refresh {
strategy: RefreshStrategy::Interval,
..Default::default()
})
.check(claim_checker);
let oidc = Router::new()
.route("/authorize", post(oidc_provider::authorize))

View file

@ -46,9 +46,7 @@ struct JwkSet {
pub async fn jwks() -> Json<Value> {
// let mut ksmap = serde_json::Map::new();
let mut kset = JwkSet {
keys: Vec::<Jwk>::new(),
};
let mut kset = JwkSet { keys: Vec::<Jwk>::new() };
let keypair = RsaKeyPair::from_pem(include_bytes!("../../../config/jwtRS256.key")).unwrap();
let mut pk = keypair.to_jwk_public_key();
@ -64,19 +62,14 @@ pub async fn jwks() -> Json<Value> {
pk.set_key_use("sig");
kset.keys.push(pk);
let keypair =
EcKeyPair::from_pem(include_bytes!("../../../config/ec256-private.pem"), Some(EcCurve::P256)).unwrap();
let keypair = EcKeyPair::from_pem(include_bytes!("../../../config/ec256-private.pem"), Some(EcCurve::P256)).unwrap();
let mut pk = keypair.to_jwk_public_key();
pk.set_key_id("key-ec");
pk.set_algorithm("ES256");
pk.set_key_use("sig");
kset.keys.push(pk);
let keypair = EcKeyPair::from_pem(
include_bytes!("../../../config/private_ecdsa_key.pem"),
Some(EcCurve::P256),
)
.unwrap();
let keypair = EcKeyPair::from_pem(include_bytes!("../../../config/private_ecdsa_key.pem"), Some(EcCurve::P256)).unwrap();
let mut pk = keypair.to_jwk_public_key();
pk.set_key_id("ec01");
pk.set_algorithm("ES256");
@ -225,8 +218,8 @@ where
let TypedHeader(Authorization(bearer)) = TypedHeader::<Authorization<Bearer>>::from_request_parts(parts, state)
.await
.map_err(|_| AuthError::InvalidToken)?;
let token_data = decode::<Claims>(bearer.token(), &KEYS.decoding, &Validation::default())
.map_err(|_| AuthError::InvalidToken)?;
let token_data =
decode::<Claims>(bearer.token(), &KEYS.decoding, &Validation::default()).map_err(|_| AuthError::InvalidToken)?;
Ok(token_data.claims)
}

View file

@ -5,7 +5,8 @@ use serde::de::DeserializeOwned;
use crate::{
error::{AuthError, InitError},
jwks::{key_store_manager::KeyStoreManager, KeySource}, Refresh,
jwks::{key_store_manager::KeyStoreManager, KeySource},
Refresh,
};
pub trait ClaimsChecker<C> {
@ -66,7 +67,10 @@ where
})
}
pub(crate) fn from(key_source_type: &KeySourceType, claims_checker: Option<FnClaimsChecker<C>>) -> Result<Authorizer<C>, InitError> {
pub(crate) fn from(
key_source_type: &KeySourceType,
claims_checker: Option<FnClaimsChecker<C>>,
) -> Result<Authorizer<C>, InitError> {
let key = match key_source_type {
KeySourceType::RSA(path) => DecodingKey::from_rsa_pem(&read_data(path.as_str())?)?,
KeySourceType::EC(path) => DecodingKey::from_ec_der(&read_data(path.as_str())?),
@ -81,7 +85,11 @@ where
})
}
pub(crate) fn from_jwks_url(url: &str, claims_checker: Option<FnClaimsChecker<C>>, refresh: Refresh) -> Result<Authorizer<C>, InitError> {
pub(crate) fn from_jwks_url(
url: &str,
claims_checker: Option<FnClaimsChecker<C>>,
refresh: Refresh,
) -> Result<Authorizer<C>, InitError> {
let key_store_manager = KeyStoreManager::new(url, refresh);
Ok(Authorizer {
key_source: KeySource::KeyStoreSource(key_store_manager),

View file

@ -1,6 +1,7 @@
use axum::{
body::{self, BoxBody, Empty},
http::StatusCode,
response::{IntoResponse, Response}, body::{self, Empty, BoxBody},
response::{IntoResponse, Response},
};
use http::header;
use jsonwebtoken::Algorithm;
@ -47,7 +48,7 @@ pub enum AuthError {
InvalidClaims(),
}
fn response_wwwauth(status: StatusCode, bearer: &str) -> Response<BoxBody> {
fn response_wwwauth(status: StatusCode, bearer: &str) -> Response<BoxBody> {
let mut res = Response::new(body::boxed(Empty::new()));
*res.status_mut() = status;
let h = if bearer.is_empty() {
@ -60,7 +61,7 @@ fn response_wwwauth(status: StatusCode, bearer: &str) -> Response<BoxBody> {
res
}
fn response_500() -> Response<BoxBody> {
fn response_500() -> Response<BoxBody> {
let mut res = Response::new(body::boxed(Empty::new()));
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
@ -71,38 +72,44 @@ fn response_500() -> Response<BoxBody> {
impl IntoResponse for AuthError {
fn into_response(self) -> Response {
let resp = match self {
AuthError::JwksRefreshError(err) => {
AuthError::JwksRefreshError(err) => {
tracing::error!("AuthErrors::JwksRefreshError: {}", err);
response_500()
},
AuthError::InvalidKey(err) => {
tracing::error!("AuthErrors::InvalidKey: {}", err);
}
AuthError::InvalidKey(err) => {
tracing::error!("AuthErrors::InvalidKey: {}", err);
response_500()
},
}
AuthError::JwksSerialisationError(err) => {
tracing::error!("AuthErrors::JwksSerialisationError: {}", err);
tracing::error!("AuthErrors::JwksSerialisationError: {}", err);
response_500()
},
}
AuthError::InvalidKeyAlg(err) => {
debug!("AuthErrors::InvalidKeyAlg: {:?}", err);
response_wwwauth(StatusCode::UNAUTHORIZED, "error=\"invalid_token\", error_description=\"invalid key algorithm\"")
},
response_wwwauth(
StatusCode::UNAUTHORIZED,
"error=\"invalid_token\", error_description=\"invalid key algorithm\"",
)
}
AuthError::InvalidKid(err) => {
debug!("AuthErrors::InvalidKid: {}", err);
response_wwwauth(StatusCode::UNAUTHORIZED, "error=\"invalid_token\", error_description=\"invalid kid\"")
},
response_wwwauth(
StatusCode::UNAUTHORIZED,
"error=\"invalid_token\", error_description=\"invalid kid\"",
)
}
AuthError::InvalidToken(err) => {
debug!("AuthErrors::InvalidToken: {}", err);
response_wwwauth(StatusCode::UNAUTHORIZED, "error=\"invalid_token\"")
},
}
AuthError::MissingToken() => {
debug!("AuthErrors::MissingToken");
response_wwwauth(StatusCode::UNAUTHORIZED, "")
},
}
AuthError::InvalidClaims() => {
debug!("AuthErrors::InvalidClaims");
response_wwwauth(StatusCode::FORBIDDEN, "error=\"insufficient_scope\"")
},
}
};
resp

View file

@ -12,7 +12,6 @@ use crate::error::AuthError;
#[derive(Clone, Copy)]
pub enum RefreshStrategy {
/// refresh periodicaly
Interval,
@ -37,7 +36,7 @@ pub struct Refresh {
impl Default for Refresh {
fn default() -> Self {
Self {
Self {
strategy: RefreshStrategy::KeyNotFound,
refresh_interval: Duration::from_secs(600),
minimal_refresh_interval: Duration::from_secs(30),
@ -81,17 +80,15 @@ impl KeyStoreManager {
let mut ks_gard = kstore.lock().await;
let key = match self.refresh.strategy {
RefreshStrategy::Interval => {
if ks_gard.should_refresh(self.refresh.refresh_interval) && ks_gard.can_refresh(self.refresh.minimal_refresh_interval, self.refresh.retry_interval) {
if ks_gard.should_refresh(self.refresh.refresh_interval)
&& ks_gard.can_refresh(self.refresh.minimal_refresh_interval, self.refresh.retry_interval)
{
ks_gard.refresh(&self.key_url, &[]).await?;
}
if let Some(ref kid) = header.kid {
ks_gard
.find_kid(kid)
.ok_or_else(|| AuthError::InvalidKid(kid.to_owned()))?
ks_gard.find_kid(kid).ok_or_else(|| AuthError::InvalidKid(kid.to_owned()))?
} else {
ks_gard
.find_alg(&header.alg)
.ok_or(AuthError::InvalidKeyAlg(header.alg))?
ks_gard.find_alg(&header.alg).ok_or(AuthError::InvalidKeyAlg(header.alg))?
}
}
RefreshStrategy::KeyNotFound => {
@ -101,11 +98,8 @@ impl KeyStoreManager {
jwk
} else if ks_gard.can_refresh(self.refresh.minimal_refresh_interval, self.refresh.retry_interval) {
ks_gard.refresh(&self.key_url, &[("kid", kid)]).await?;
ks_gard
.find_kid(kid)
.ok_or_else(|| AuthError::InvalidKid(kid.to_owned()))?
ks_gard.find_kid(kid).ok_or_else(|| AuthError::InvalidKid(kid.to_owned()))?
} else {
return Err(AuthError::InvalidKid(kid.to_owned()));
}
} else {
@ -119,8 +113,7 @@ impl KeyStoreManager {
&self.key_url,
&[(
"alg",
&serde_json::to_string(&header.alg)
.map_err(|_| AuthError::InvalidKeyAlg(header.alg))?,
&serde_json::to_string(&header.alg).map_err(|_| AuthError::InvalidKeyAlg(header.alg))?,
)],
)
.await?;
@ -131,19 +124,15 @@ impl KeyStoreManager {
return Err(AuthError::InvalidKeyAlg(header.alg));
}
}
},
}
RefreshStrategy::NoRefresh => {
if ks_gard.load_time.is_none() {
ks_gard.refresh(&self.key_url, &[]).await?;
}
if let Some(ref kid) = header.kid {
ks_gard
.find_kid(kid)
.ok_or_else(|| AuthError::InvalidKid(kid.to_owned()))?
ks_gard.find_kid(kid).ok_or_else(|| AuthError::InvalidKid(kid.to_owned()))?
} else {
ks_gard
.find_alg(&header.alg)
.ok_or(AuthError::InvalidKeyAlg(header.alg))?
ks_gard.find_alg(&header.alg).ok_or(AuthError::InvalidKeyAlg(header.alg))?
}
}
};
@ -228,8 +217,8 @@ mod tests {
Mock, MockServer, ResponseTemplate,
};
use crate::{RefreshStrategy, Refresh};
use crate::jwks::key_store_manager::{KeyStore, KeyStoreManager};
use crate::{Refresh, RefreshStrategy};
#[test]
fn keystore_should_refresh() {
@ -252,7 +241,6 @@ mod tests {
#[test]
fn keystore_can_refresh() {
// FAIL, NO LOAD
let ks = KeyStore {
jwks: jsonwebtoken::jwk::JwkSet { keys: vec![] },
@ -343,7 +331,11 @@ mod tests {
let ksm = KeyStoreManager::new(
&mock_server.uri(),
Refresh {strategy: RefreshStrategy::Interval, refresh_interval: Duration::from_secs(3000), ..Default::default()}
Refresh {
strategy: RefreshStrategy::Interval,
refresh_interval: Duration::from_secs(3000),
..Default::default()
},
);
let r = ksm.get_key(&Header::new(Algorithm::EdDSA)).await;
assert!(r.is_ok());
@ -368,7 +360,11 @@ mod tests {
let mut ksm = KeyStoreManager::new(
&mock_server.uri(),
Refresh {strategy: RefreshStrategy::KeyNotFound, ..Default::default()});
Refresh {
strategy: RefreshStrategy::KeyNotFound,
..Default::default()
},
);
// STEP 1: initial (lazy) reloading
let r = ksm.get_key(&build_header("key-ed", Algorithm::EdDSA)).await;
@ -440,7 +436,11 @@ mod tests {
let ksm = KeyStoreManager::new(
&mock_server.uri(),
Refresh {strategy: RefreshStrategy::NoRefresh, ..Default::default()});
Refresh {
strategy: RefreshStrategy::NoRefresh,
..Default::default()
},
);
// STEP 1: initial (lazy) reloading
let r = ksm.get_key(&build_header("key-ed", Algorithm::EdDSA)).await;

View file

@ -1,6 +1,6 @@
use axum::body::BoxBody;
use axum::http::Request;
use axum::response::{Response, IntoResponse};
use axum::response::{IntoResponse, Response};
use futures_core::ready;
use futures_util::future::BoxFuture;
use headers::authorization::Bearer;
@ -14,10 +14,10 @@ use std::task::{Context, Poll};
use tower_layer::Layer;
use tower_service::Service;
use crate::{AuthError, RefreshStrategy};
use crate::authorizer::{Authorizer, FnClaimsChecker, KeySourceType};
use crate::error::InitError;
use crate::jwks::key_store_manager::Refresh;
use crate::{AuthError, RefreshStrategy};
/// Authorizer Layer builder
///
@ -118,11 +118,11 @@ where
KeySourceType::RSA(_) | KeySourceType::EC(_) | KeySourceType::ED(_) | KeySourceType::Secret(_) => {
Arc::new(Authorizer::from(key_source_type, self.claims_checker.clone())?)
}
KeySourceType::Jwks(url) => {
Arc::new(
Authorizer::from_jwks_url(
url.as_str(), self.claims_checker.clone(), self.refresh.unwrap_or_default())?)
}
KeySourceType::Jwks(url) => Arc::new(Authorizer::from_jwks_url(
url.as_str(),
self.claims_checker.clone(),
self.refresh.unwrap_or_default(),
)?),
}
} else {
return Err(InitError::BuilderError(
@ -162,16 +162,14 @@ where
Box::pin(async move {
if let Some(bearer) = bearer_o {
match authorizer.check_auth(bearer.token()).await {
Ok(token_data) => {
Ok(token_data) => {
// Set `token_data` as a request extension so it can be accessed by other
// services down the stack.
request.extensions_mut().insert(token_data);
Ok(request)
},
Err(err) => {
Err(err.into_response())
}
Err(err) => Err(err.into_response()),
}
} else {
Err(AuthError::MissingToken().into_response())

View file

@ -6,8 +6,8 @@ use jsonwebtoken::TokenData;
use serde::de::DeserializeOwned;
pub use self::error::AuthError;
pub use layer::JwtAuthorizer;
pub use jwks::key_store_manager::{Refresh, RefreshStrategy};
pub use layer::JwtAuthorizer;
pub mod authorizer;
pub mod error;

View file

@ -1 +1 @@
max_width=120
max_width=125