mirror of
https://github.com/TECHNOFAB11/jwt-authorizer.git
synced 2025-12-12 08:00:07 +01:00
Merge pull request #35 from cduvray/refactor
refactor: renaming, reorganising
This commit is contained in:
commit
f452f15b0b
6 changed files with 233 additions and 226 deletions
|
|
@ -9,7 +9,7 @@ use serde::de::DeserializeOwned;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{AuthError, InitError},
|
error::{AuthError, InitError},
|
||||||
jwks::{key_store_manager::KeyStoreManager, KeyData, KeySource},
|
jwks::{key_store_manager::KeyStoreManager, KeyData, KeySource},
|
||||||
layer::{self, AsyncAuthorizationLayer, JwtSource},
|
layer::{self, AuthorizationLayer, JwtSource},
|
||||||
oidc, Refresh, RegisteredClaims,
|
oidc, Refresh, RegisteredClaims,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -237,15 +237,15 @@ pub trait IntoLayer<C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
fn into_layer(self) -> AsyncAuthorizationLayer<C>;
|
fn into_layer(self) -> AuthorizationLayer<C>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> IntoLayer<C> for Vec<Authorizer<C>>
|
impl<C> IntoLayer<C> for Vec<Authorizer<C>>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
fn into_layer(self) -> AsyncAuthorizationLayer<C> {
|
fn into_layer(self) -> AuthorizationLayer<C> {
|
||||||
AsyncAuthorizationLayer::new(self.into_iter().map(Arc::new).collect())
|
AuthorizationLayer::new(self.into_iter().map(Arc::new).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,8 +253,8 @@ impl<C> IntoLayer<C> for Vec<Arc<Authorizer<C>>>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
fn into_layer(self) -> AsyncAuthorizationLayer<C> {
|
fn into_layer(self) -> AuthorizationLayer<C> {
|
||||||
AsyncAuthorizationLayer::new(self.into_iter().collect())
|
AuthorizationLayer::new(self.into_iter().collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,8 +262,8 @@ impl<C, const N: usize> IntoLayer<C> for [Authorizer<C>; N]
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
fn into_layer(self) -> AsyncAuthorizationLayer<C> {
|
fn into_layer(self) -> AuthorizationLayer<C> {
|
||||||
AsyncAuthorizationLayer::new(self.into_iter().map(Arc::new).collect())
|
AuthorizationLayer::new(self.into_iter().map(Arc::new).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,8 +271,8 @@ impl<C, const N: usize> IntoLayer<C> for [Arc<Authorizer<C>>; N]
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
fn into_layer(self) -> AsyncAuthorizationLayer<C> {
|
fn into_layer(self) -> AuthorizationLayer<C> {
|
||||||
AsyncAuthorizationLayer::new(self.into_iter().collect())
|
AuthorizationLayer::new(self.into_iter().collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,8 +280,8 @@ impl<C> IntoLayer<C> for Authorizer<C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
fn into_layer(self) -> AsyncAuthorizationLayer<C> {
|
fn into_layer(self) -> AuthorizationLayer<C> {
|
||||||
AsyncAuthorizationLayer::new(vec![Arc::new(self)])
|
AuthorizationLayer::new(vec![Arc::new(self)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,8 +289,8 @@ impl<C> IntoLayer<C> for Arc<Authorizer<C>>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
fn into_layer(self) -> AsyncAuthorizationLayer<C> {
|
fn into_layer(self) -> AuthorizationLayer<C> {
|
||||||
AsyncAuthorizationLayer::new(vec![self])
|
AuthorizationLayer::new(vec![self])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
190
jwt-authorizer/src/builder.rs
Normal file
190
jwt-authorizer/src/builder.rs
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
authorizer::{FnClaimsChecker, KeySourceType},
|
||||||
|
error::InitError,
|
||||||
|
layer::{AuthorizationLayer, JwtSource},
|
||||||
|
Authorizer, Refresh, RefreshStrategy, RegisteredClaims, Validation,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Authorizer Layer builder
|
||||||
|
///
|
||||||
|
/// - initialisation of the Authorizer from jwks, rsa, ed, ec or secret
|
||||||
|
/// - can define a checker (jwt claims check)
|
||||||
|
pub struct JwtAuthorizer<C = RegisteredClaims>
|
||||||
|
where
|
||||||
|
C: Clone + DeserializeOwned,
|
||||||
|
{
|
||||||
|
key_source_type: KeySourceType,
|
||||||
|
refresh: Option<Refresh>,
|
||||||
|
claims_checker: Option<FnClaimsChecker<C>>,
|
||||||
|
validation: Option<Validation>,
|
||||||
|
jwt_source: JwtSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// authorization layer builder
|
||||||
|
impl<C> JwtAuthorizer<C>
|
||||||
|
where
|
||||||
|
C: Clone + DeserializeOwned + Send + Sync,
|
||||||
|
{
|
||||||
|
/// Builds Authorizer Layer from a OpenId Connect discover metadata
|
||||||
|
pub fn from_oidc(issuer: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::Discovery(issuer.to_string()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from a JWKS endpoint
|
||||||
|
pub fn from_jwks_url(url: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::Jwks(url.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from a RSA PEM file
|
||||||
|
pub fn from_rsa_pem(path: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::RSA(path.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from an RSA PEM raw text
|
||||||
|
pub fn from_rsa_pem_text(text: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::RSAString(text.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from a EC PEM file
|
||||||
|
pub fn from_ec_pem(path: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::EC(path.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from a EC PEM raw text
|
||||||
|
pub fn from_ec_pem_text(text: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::ECString(text.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from a EC PEM file
|
||||||
|
pub fn from_ed_pem(path: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::ED(path.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from a EC PEM raw text
|
||||||
|
pub fn from_ed_pem_text(text: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::EDString(text.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds Authorizer Layer from a secret phrase
|
||||||
|
pub fn from_secret(secret: &str) -> JwtAuthorizer<C> {
|
||||||
|
JwtAuthorizer {
|
||||||
|
key_source_type: KeySourceType::Secret(secret.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Refreshes configuration for jwk store
|
||||||
|
pub fn refresh(mut self, refresh: Refresh) -> JwtAuthorizer<C> {
|
||||||
|
if self.refresh.is_some() {
|
||||||
|
tracing::warn!("More than one refresh configuration found!");
|
||||||
|
}
|
||||||
|
self.refresh = Some(refresh);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// no refresh, jwks will be loaded juste once
|
||||||
|
pub fn no_refresh(mut self) -> JwtAuthorizer<C> {
|
||||||
|
if self.refresh.is_some() {
|
||||||
|
tracing::warn!("More than one refresh configuration found!");
|
||||||
|
}
|
||||||
|
self.refresh = Some(Refresh {
|
||||||
|
strategy: RefreshStrategy::NoRefresh,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// configures token content check (custom function), if false a 403 will be sent.
|
||||||
|
/// (AuthError::InvalidClaims())
|
||||||
|
pub fn check(mut self, checker_fn: fn(&C) -> bool) -> JwtAuthorizer<C> {
|
||||||
|
self.claims_checker = Some(FnClaimsChecker { checker_fn });
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validation(mut self, validation: Validation) -> JwtAuthorizer<C> {
|
||||||
|
self.validation = Some(validation);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// configures the source of the bearer token
|
||||||
|
///
|
||||||
|
/// (default: AuthorizationHeader)
|
||||||
|
pub fn jwt_source(mut self, src: JwtSource) -> JwtAuthorizer<C> {
|
||||||
|
self.jwt_source = src;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build axum layer
|
||||||
|
#[deprecated(since = "0.10.0", note = "please use `IntoLayer::into_layer()` instead")]
|
||||||
|
pub async fn layer(self) -> Result<AuthorizationLayer<C>, InitError> {
|
||||||
|
let val = self.validation.unwrap_or_default();
|
||||||
|
let auth = Arc::new(
|
||||||
|
Authorizer::build(self.key_source_type, self.claims_checker, self.refresh, val, self.jwt_source).await?,
|
||||||
|
);
|
||||||
|
Ok(AuthorizationLayer::new(vec![auth]))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn build(self) -> Result<Authorizer<C>, InitError> {
|
||||||
|
let val = self.validation.unwrap_or_default();
|
||||||
|
|
||||||
|
Authorizer::build(self.key_source_type, self.claims_checker, self.refresh, val, self.jwt_source).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,195 +11,11 @@ use std::task::{Context, Poll};
|
||||||
use tower_layer::Layer;
|
use tower_layer::Layer;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
use crate::authorizer::{Authorizer, FnClaimsChecker, KeySourceType};
|
use crate::authorizer::Authorizer;
|
||||||
use crate::claims::RegisteredClaims;
|
use crate::AuthError;
|
||||||
use crate::error::InitError;
|
|
||||||
use crate::jwks::key_store_manager::Refresh;
|
|
||||||
use crate::validation::Validation;
|
|
||||||
use crate::{AuthError, RefreshStrategy};
|
|
||||||
|
|
||||||
/// Authorizer Layer builder
|
|
||||||
///
|
|
||||||
/// - initialisation of the Authorizer from jwks, rsa, ed, ec or secret
|
|
||||||
/// - can define a checker (jwt claims check)
|
|
||||||
pub struct JwtAuthorizer<C = RegisteredClaims>
|
|
||||||
where
|
|
||||||
C: Clone + DeserializeOwned,
|
|
||||||
{
|
|
||||||
key_source_type: KeySourceType,
|
|
||||||
refresh: Option<Refresh>,
|
|
||||||
claims_checker: Option<FnClaimsChecker<C>>,
|
|
||||||
validation: Option<Validation>,
|
|
||||||
jwt_source: JwtSource,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// authorization layer builder
|
|
||||||
impl<C> JwtAuthorizer<C>
|
|
||||||
where
|
|
||||||
C: Clone + DeserializeOwned + Send + Sync,
|
|
||||||
{
|
|
||||||
/// Builds Authorizer Layer from a OpenId Connect discover metadata
|
|
||||||
pub fn from_oidc(issuer: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::Discovery(issuer.to_string()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a JWKS endpoint
|
|
||||||
pub fn from_jwks_url(url: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::Jwks(url.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a RSA PEM file
|
|
||||||
pub fn from_rsa_pem(path: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::RSA(path.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from an RSA PEM raw text
|
|
||||||
pub fn from_rsa_pem_text(text: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::RSAString(text.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a EC PEM file
|
|
||||||
pub fn from_ec_pem(path: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::EC(path.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a EC PEM raw text
|
|
||||||
pub fn from_ec_pem_text(text: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::ECString(text.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a EC PEM file
|
|
||||||
pub fn from_ed_pem(path: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::ED(path.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a EC PEM raw text
|
|
||||||
pub fn from_ed_pem_text(text: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::EDString(text.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a secret phrase
|
|
||||||
pub fn from_secret(secret: &str) -> JwtAuthorizer<C> {
|
|
||||||
JwtAuthorizer {
|
|
||||||
key_source_type: KeySourceType::Secret(secret.to_owned()),
|
|
||||||
refresh: Default::default(),
|
|
||||||
claims_checker: None,
|
|
||||||
validation: None,
|
|
||||||
jwt_source: JwtSource::AuthorizationHeader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Refreshes configuration for jwk store
|
|
||||||
pub fn refresh(mut self, refresh: Refresh) -> JwtAuthorizer<C> {
|
|
||||||
if self.refresh.is_some() {
|
|
||||||
tracing::warn!("More than one refresh configuration found!");
|
|
||||||
}
|
|
||||||
self.refresh = Some(refresh);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// no refresh, jwks will be loaded juste once
|
|
||||||
pub fn no_refresh(mut self) -> JwtAuthorizer<C> {
|
|
||||||
if self.refresh.is_some() {
|
|
||||||
tracing::warn!("More than one refresh configuration found!");
|
|
||||||
}
|
|
||||||
self.refresh = Some(Refresh {
|
|
||||||
strategy: RefreshStrategy::NoRefresh,
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// configures token content check (custom function), if false a 403 will be sent.
|
|
||||||
/// (AuthError::InvalidClaims())
|
|
||||||
pub fn check(mut self, checker_fn: fn(&C) -> bool) -> JwtAuthorizer<C> {
|
|
||||||
self.claims_checker = Some(FnClaimsChecker { checker_fn });
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validation(mut self, validation: Validation) -> JwtAuthorizer<C> {
|
|
||||||
self.validation = Some(validation);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// configures the source of the bearer token
|
|
||||||
///
|
|
||||||
/// (default: AuthorizationHeader)
|
|
||||||
pub fn jwt_source(mut self, src: JwtSource) -> JwtAuthorizer<C> {
|
|
||||||
self.jwt_source = src;
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build axum layer
|
|
||||||
#[deprecated(since = "0.10.0", note = "please use `IntoLayer::into_layer()` instead")]
|
|
||||||
pub async fn layer(self) -> Result<AsyncAuthorizationLayer<C>, InitError> {
|
|
||||||
let val = self.validation.unwrap_or_default();
|
|
||||||
let auth = Arc::new(
|
|
||||||
Authorizer::build(self.key_source_type, self.claims_checker, self.refresh, val, self.jwt_source).await?,
|
|
||||||
);
|
|
||||||
Ok(AsyncAuthorizationLayer::new(vec![auth]))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn build(self) -> Result<Authorizer<C>, InitError> {
|
|
||||||
let val = self.validation.unwrap_or_default();
|
|
||||||
|
|
||||||
Authorizer::build(self.key_source_type, self.claims_checker, self.refresh, val, self.jwt_source).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait for authorizing requests.
|
/// Trait for authorizing requests.
|
||||||
pub trait AsyncAuthorizer<B> {
|
pub trait Authorize<B> {
|
||||||
type RequestBody;
|
type RequestBody;
|
||||||
type Future: Future<Output = Result<Request<Self::RequestBody>, AuthError>>;
|
type Future: Future<Output = Result<Request<Self::RequestBody>, AuthError>>;
|
||||||
|
|
||||||
|
|
@ -209,7 +25,7 @@ pub trait AsyncAuthorizer<B> {
|
||||||
fn authorize(&self, request: Request<B>) -> Self::Future;
|
fn authorize(&self, request: Request<B>) -> Self::Future;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, S, C> AsyncAuthorizer<B> for AsyncAuthorizationService<S, C>
|
impl<B, S, C> Authorize<B> for AuthorizationService<S, C>
|
||||||
where
|
where
|
||||||
B: Send + Sync + 'static,
|
B: Send + Sync + 'static,
|
||||||
C: Clone + DeserializeOwned + Send + Sync + 'static,
|
C: Clone + DeserializeOwned + Send + Sync + 'static,
|
||||||
|
|
@ -256,34 +72,34 @@ where
|
||||||
// -------------- Layer -----------------
|
// -------------- Layer -----------------
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AsyncAuthorizationLayer<C>
|
pub struct AuthorizationLayer<C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
auths: Vec<Arc<Authorizer<C>>>,
|
auths: Vec<Arc<Authorizer<C>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> AsyncAuthorizationLayer<C>
|
impl<C> AuthorizationLayer<C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send,
|
C: Clone + DeserializeOwned + Send,
|
||||||
{
|
{
|
||||||
pub fn new(auths: Vec<Arc<Authorizer<C>>>) -> AsyncAuthorizationLayer<C> {
|
pub fn new(auths: Vec<Arc<Authorizer<C>>>) -> AuthorizationLayer<C> {
|
||||||
Self { auths }
|
Self { auths }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C> Layer<S> for AsyncAuthorizationLayer<C>
|
impl<S, C> Layer<S> for AuthorizationLayer<C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send + Sync,
|
C: Clone + DeserializeOwned + Send + Sync,
|
||||||
{
|
{
|
||||||
type Service = AsyncAuthorizationService<S, C>;
|
type Service = AuthorizationService<S, C>;
|
||||||
|
|
||||||
fn layer(&self, inner: S) -> Self::Service {
|
fn layer(&self, inner: S) -> Self::Service {
|
||||||
AsyncAuthorizationService::new(inner, self.auths.clone())
|
AuthorizationService::new(inner, self.auths.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- AsyncAuthorizationService --------
|
// ---------- AuthorizationService --------
|
||||||
|
|
||||||
/// Source of the bearer token
|
/// Source of the bearer token
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -301,7 +117,7 @@ pub enum JwtSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AsyncAuthorizationService<S, C>
|
pub struct AuthorizationService<S, C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send + Sync,
|
C: Clone + DeserializeOwned + Send + Sync,
|
||||||
{
|
{
|
||||||
|
|
@ -309,7 +125,7 @@ where
|
||||||
pub auths: Vec<Arc<Authorizer<C>>>,
|
pub auths: Vec<Arc<Authorizer<C>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C> AsyncAuthorizationService<S, C>
|
impl<S, C> AuthorizationService<S, C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send + Sync,
|
C: Clone + DeserializeOwned + Send + Sync,
|
||||||
{
|
{
|
||||||
|
|
@ -328,19 +144,19 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C> AsyncAuthorizationService<S, C>
|
impl<S, C> AuthorizationService<S, C>
|
||||||
where
|
where
|
||||||
C: Clone + DeserializeOwned + Send + Sync,
|
C: Clone + DeserializeOwned + Send + Sync,
|
||||||
{
|
{
|
||||||
/// Authorize requests using a custom scheme.
|
/// Authorize requests using a custom scheme.
|
||||||
///
|
///
|
||||||
/// The `Authorization` header is required to have the value provided.
|
/// The `Authorization` header is required to have the value provided.
|
||||||
pub fn new(inner: S, auths: Vec<Arc<Authorizer<C>>>) -> AsyncAuthorizationService<S, C> {
|
pub fn new(inner: S, auths: Vec<Arc<Authorizer<C>>>) -> AuthorizationService<S, C> {
|
||||||
Self { inner, auths }
|
Self { inner, auths }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ReqBody, S, C> Service<Request<ReqBody>> for AsyncAuthorizationService<S, C>
|
impl<ReqBody, S, C> Service<Request<ReqBody>> for AuthorizationService<S, C>
|
||||||
where
|
where
|
||||||
ReqBody: Send + Sync + 'static,
|
ReqBody: Send + Sync + 'static,
|
||||||
S: Service<Request<ReqBody>> + Clone,
|
S: Service<Request<ReqBody>> + Clone,
|
||||||
|
|
@ -370,7 +186,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
/// Response future for [`AsyncAuthorizationService`].
|
/// Response future for [`AuthorizationService`].
|
||||||
pub struct ResponseFuture<S, ReqBody, C>
|
pub struct ResponseFuture<S, ReqBody, C>
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>>,
|
S: Service<Request<ReqBody>>,
|
||||||
|
|
@ -378,7 +194,7 @@ where
|
||||||
C: Clone + DeserializeOwned + Send + Sync + 'static,
|
C: Clone + DeserializeOwned + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
#[pin]
|
#[pin]
|
||||||
state: State<<AsyncAuthorizationService<S, C> as AsyncAuthorizer<ReqBody>>::Future, S::Future>,
|
state: State<<AuthorizationService<S, C> as Authorize<ReqBody>>::Future, S::Future>,
|
||||||
service: S,
|
service: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,7 +249,7 @@ where
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{authorizer::Authorizer, IntoLayer, JwtAuthorizer, RegisteredClaims};
|
use crate::{authorizer::Authorizer, IntoLayer, JwtAuthorizer, RegisteredClaims};
|
||||||
|
|
||||||
use super::AsyncAuthorizationLayer;
|
use super::AuthorizationLayer;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn auth_into_layer() {
|
async fn auth_into_layer() {
|
||||||
|
|
@ -447,7 +263,7 @@ mod tests {
|
||||||
let auth1 = JwtAuthorizer::from_secret("aaa").build().await.unwrap();
|
let auth1 = JwtAuthorizer::from_secret("aaa").build().await.unwrap();
|
||||||
let auth2 = JwtAuthorizer::from_secret("bbb").build().await.unwrap();
|
let auth2 = JwtAuthorizer::from_secret("bbb").build().await.unwrap();
|
||||||
|
|
||||||
let layer: AsyncAuthorizationLayer<RegisteredClaims> = [auth1, auth2].into_layer();
|
let layer: AuthorizationLayer<RegisteredClaims> = [auth1, auth2].into_layer();
|
||||||
assert_eq!(2, layer.auths.len());
|
assert_eq!(2, layer.auths.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -456,7 +272,7 @@ mod tests {
|
||||||
let auth1 = JwtAuthorizer::from_secret("aaa").build().await.unwrap();
|
let auth1 = JwtAuthorizer::from_secret("aaa").build().await.unwrap();
|
||||||
let auth2 = JwtAuthorizer::from_secret("bbb").build().await.unwrap();
|
let auth2 = JwtAuthorizer::from_secret("bbb").build().await.unwrap();
|
||||||
|
|
||||||
let layer: AsyncAuthorizationLayer<RegisteredClaims> = vec![auth1, auth2].into_layer();
|
let layer: AuthorizationLayer<RegisteredClaims> = vec![auth1, auth2].into_layer();
|
||||||
assert_eq!(2, layer.auths.len());
|
assert_eq!(2, layer.auths.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,13 @@ use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
pub use self::error::AuthError;
|
pub use self::error::AuthError;
|
||||||
pub use authorizer::{Authorizer, IntoLayer};
|
pub use authorizer::{Authorizer, IntoLayer};
|
||||||
|
pub use builder::JwtAuthorizer;
|
||||||
pub use claims::{NumericDate, OneOrArray, RegisteredClaims};
|
pub use claims::{NumericDate, OneOrArray, RegisteredClaims};
|
||||||
pub use jwks::key_store_manager::{Refresh, RefreshStrategy};
|
pub use jwks::key_store_manager::{Refresh, RefreshStrategy};
|
||||||
pub use layer::JwtAuthorizer;
|
|
||||||
pub use validation::Validation;
|
pub use validation::Validation;
|
||||||
|
|
||||||
pub mod authorizer;
|
pub mod authorizer;
|
||||||
|
pub mod builder;
|
||||||
pub mod claims;
|
pub mod claims;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod jwks;
|
pub mod jwks;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ mod tests {
|
||||||
use http::{header, HeaderValue};
|
use http::{header, HeaderValue};
|
||||||
use jwt_authorizer::{
|
use jwt_authorizer::{
|
||||||
authorizer::Authorizer,
|
authorizer::Authorizer,
|
||||||
layer::{AsyncAuthorizationLayer, JwtSource},
|
layer::{AuthorizationLayer, JwtSource},
|
||||||
validation::Validation,
|
validation::Validation,
|
||||||
IntoLayer, JwtAuthorizer, JwtClaims,
|
IntoLayer, JwtAuthorizer, JwtClaims,
|
||||||
};
|
};
|
||||||
|
|
@ -28,7 +28,7 @@ mod tests {
|
||||||
sub: String,
|
sub: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn app(layer: AsyncAuthorizationLayer<User>) -> Router {
|
async fn app(layer: AuthorizationLayer<User>) -> Router {
|
||||||
Router::new().route("/public", get(|| async { "hello" })).route(
|
Router::new().route("/public", get(|| async { "hello" })).route(
|
||||||
"/protected",
|
"/protected",
|
||||||
get(|JwtClaims(user): JwtClaims<User>| async move { format!("hello: {}", user.sub) }).layer(
|
get(|JwtClaims(user): JwtClaims<User>| async move { format!("hello: {}", user.sub) }).layer(
|
||||||
|
|
@ -48,7 +48,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn proteced_request_with_header_and_layer(
|
async fn proteced_request_with_header_and_layer(
|
||||||
layer: AsyncAuthorizationLayer<User>,
|
layer: AuthorizationLayer<User>,
|
||||||
header_name: &str,
|
header_name: &str,
|
||||||
header_value: &str,
|
header_value: &str,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::{sync::Once, task::Poll};
|
||||||
use axum::body::HttpBody;
|
use axum::body::HttpBody;
|
||||||
use futures_core::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
use http::header::AUTHORIZATION;
|
use http::header::AUTHORIZATION;
|
||||||
use jwt_authorizer::{layer::AsyncAuthorizationService, IntoLayer, JwtAuthorizer};
|
use jwt_authorizer::{layer::AuthorizationService, IntoLayer, JwtAuthorizer};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tonic::{server::UnaryService, transport::NamedService, IntoRequest, Status};
|
use tonic::{server::UnaryService, transport::NamedService, IntoRequest, Status};
|
||||||
use tower::{buffer::Buffer, Service};
|
use tower::{buffer::Buffer, Service};
|
||||||
|
|
@ -82,7 +82,7 @@ impl NamedService for GreeterServer {
|
||||||
async fn app(
|
async fn app(
|
||||||
jwt_auth: JwtAuthorizer<User>,
|
jwt_auth: JwtAuthorizer<User>,
|
||||||
expected_sub: String,
|
expected_sub: String,
|
||||||
) -> AsyncAuthorizationService<Buffer<tonic::transport::server::Routes, http::Request<tonic::transport::Body>>, User> {
|
) -> AuthorizationService<Buffer<tonic::transport::server::Routes, http::Request<tonic::transport::Body>>, User> {
|
||||||
let layer = jwt_auth.build().await.unwrap().into_layer();
|
let layer = jwt_auth.build().await.unwrap().into_layer();
|
||||||
tonic::transport::Server::builder()
|
tonic::transport::Server::builder()
|
||||||
.layer(layer)
|
.layer(layer)
|
||||||
|
|
@ -144,7 +144,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn make_protected_request<S: Clone>(
|
async fn make_protected_request<S: Clone>(
|
||||||
app: AsyncAuthorizationService<S, User>,
|
app: AuthorizationService<S, User>,
|
||||||
bearer: Option<&str>,
|
bearer: Option<&str>,
|
||||||
message: &str,
|
message: &str,
|
||||||
) -> Result<tonic::Response<HelloMessage>, Status>
|
) -> Result<tonic::Response<HelloMessage>, Status>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue