mirror of
https://github.com/TECHNOFAB11/jwt-authorizer.git
synced 2025-12-11 23:50:07 +01:00
Add support for reading keys from a static JWKS
Allow creating authorizer from JWKS files similar to other static certificates. Signed-off-by: Sjoerd Simons <sjoerd@collabora.com>
This commit is contained in:
parent
6e19f31c77
commit
ef8ac07271
7 changed files with 175 additions and 26 deletions
|
|
@ -18,3 +18,7 @@ curve name: prime256v1 (secp256r1, secp384r1)
|
||||||
(Ed25519 - EdDSA signature scheme using SHA-512 (SHA-2) and Curve25519)
|
(Ed25519 - EdDSA signature scheme using SHA-512 (SHA-2) and Curve25519)
|
||||||
|
|
||||||
> openssl genpkey -algorithm ed25519
|
> openssl genpkey -algorithm ed25519
|
||||||
|
|
||||||
|
## JWK - combined file of above keys
|
||||||
|
|
||||||
|
> rnbyc -j -f rsa-public1.pem -k rsa01 -a RS256 -f ecdsa-public1.pem -k ec01 -a ES256 -f ed25519-public1.pem -k ed01 -a EdDSA -o public1.jw
|
||||||
|
|
|
||||||
26
config/public1.jwks
Normal file
26
config/public1.jwks
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"keys": [
|
||||||
|
{
|
||||||
|
"alg": "RS256",
|
||||||
|
"e": "AQAB",
|
||||||
|
"kid": "rsa01",
|
||||||
|
"kty": "RSA",
|
||||||
|
"n": "2pQeZdxa7q093K7bj5h6-leIpxfTnuAxzXdhjfGEJHxmt2ekHyCBWWWXCBiDn2RTcEBcy6gZqOW45Uy_tw-5e-Px1xFj1PykGEkRlOpYSAeWsNaAWvvpGB9m4zQ0PgZeMDDXE5IIBrY6YAzmGQxV-fcGGLhJnXl0-5_z7tKC7RvBoT3SGwlc_AmJqpFtTpEBn_fDnyqiZbpcjXYLExFpExm41xDitRKHWIwfc3dV8_vlNntlxCPGy_THkjdXJoHv2IJmlhvmr5_h03iGMLWDKSywxOol_4Wc1BT7Hb6byMxW40GKwSJJ4p7W8eI5mqggRHc8jlwSsTN9LZ2VOvO-XiVShZRVg7JeraGAfWwaIgIJ1D8C1h5Pi0iFpp2suxpHAXHfyLMJXuVotpXbDh4NDX-A4KRMgaxcfAcui_x6gybksq6gF90-9nfQfmVMVJctZ6M-FvRr-itd1Nef5WAtwUp1qyZygAXU3cH3rarscajmurOsP6dE1OHl3grY_eZhQxk33VBK9lavqNKPg6Q_PLiq1ojbYBj3bcYifJrsNeQwxldQP83aWt5rGtgZTehKVJwa40Uy_Grae1iRnsDtdSy5sTJIJ6EiShnWAdMoGejdiI8vpkjrdU8SWH8lv1KXI54DsbyAuke2cYz02zPWc6JEotQqI0HwhzU0KHyoY4s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": "ES256",
|
||||||
|
"crv": "P-256",
|
||||||
|
"kid": "ec01",
|
||||||
|
"kty": "EC",
|
||||||
|
"x": "MZiwc5EVP_E3vkd2oKedr4lWVMN9vgdyBBpBIVFJjwY",
|
||||||
|
"y": "1npLU75B6M0mb01zUAVoeYJSDOlQJmvjBdqLPjJvy3Y"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": "EdDSA",
|
||||||
|
"crv": "Ed25519",
|
||||||
|
"kid": "ed01",
|
||||||
|
"kty": "OKP",
|
||||||
|
"x": "uWtSkE-I9aTMYTTvuTE1rtu0rNdxp3DU33cJ_ksL1Gk"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -41,6 +41,7 @@ pub enum KeySourceType {
|
||||||
EDString(String),
|
EDString(String),
|
||||||
Secret(String),
|
Secret(String),
|
||||||
Jwks(String),
|
Jwks(String),
|
||||||
|
JwksPath(String),
|
||||||
JwksString(String), // TODO: expose JwksString in JwtAuthorizer or remove it
|
JwksString(String), // TODO: expose JwksString in JwtAuthorizer or remove it
|
||||||
Discovery(String),
|
Discovery(String),
|
||||||
}
|
}
|
||||||
|
|
@ -148,13 +149,36 @@ where
|
||||||
jwt_source,
|
jwt_source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
KeySourceType::JwksPath(path) => {
|
||||||
|
let set: JwkSet = serde_json::from_slice(&read_data(path.as_str())?)?;
|
||||||
|
let keys = set
|
||||||
|
.keys
|
||||||
|
.iter()
|
||||||
|
.map(|k| match KeyData::from_jwk(k) {
|
||||||
|
Ok(kdata) => Ok(Arc::new(kdata)),
|
||||||
|
Err(err) => Err(InitError::KeyDecodingError(err)),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
Authorizer {
|
||||||
|
key_source: KeySource::MultiKeySource(keys.into()),
|
||||||
|
claims_checker,
|
||||||
|
validation,
|
||||||
|
jwt_source,
|
||||||
|
}
|
||||||
|
}
|
||||||
KeySourceType::JwksString(jwks_str) => {
|
KeySourceType::JwksString(jwks_str) => {
|
||||||
// TODO: expose it in JwtAuthorizer or remove
|
// TODO: expose it in JwtAuthorizer or remove
|
||||||
let set: JwkSet = serde_json::from_str(jwks_str.as_str())?;
|
let set: JwkSet = serde_json::from_str(jwks_str.as_str())?;
|
||||||
// TODO: replace [0] by kid/alg search
|
let keys = set
|
||||||
let k = KeyData::from_jwk(&set.keys[0]).map_err(InitError::KeyDecodingError)?;
|
.keys
|
||||||
|
.iter()
|
||||||
|
.map(|k| match KeyData::from_jwk(k) {
|
||||||
|
Ok(kdata) => Ok(Arc::new(kdata)),
|
||||||
|
Err(err) => Err(InitError::KeyDecodingError(err)),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
Authorizer {
|
Authorizer {
|
||||||
key_source: KeySource::SingleKeySource(Arc::new(k)),
|
key_source: KeySource::MultiKeySource(keys.into()),
|
||||||
claims_checker,
|
claims_checker,
|
||||||
validation,
|
validation,
|
||||||
jwt_source,
|
jwt_source,
|
||||||
|
|
@ -363,6 +387,28 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let k = a.key_source.get_key(Header::new(Algorithm::EdDSA));
|
let k = a.key_source.get_key(Header::new(Algorithm::EdDSA));
|
||||||
assert!(k.await.is_ok());
|
assert!(k.await.is_ok());
|
||||||
|
|
||||||
|
let a = Authorizer::<Value>::build(
|
||||||
|
KeySourceType::JwksPath("../config/public1.jwks".to_owned()),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Validation::new(),
|
||||||
|
JwtSource::AuthorizationHeader,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
a.key_source
|
||||||
|
.get_key(Header::new(Algorithm::RS256))
|
||||||
|
.await
|
||||||
|
.expect("Couldn't get RS256 key from jwk");
|
||||||
|
a.key_source
|
||||||
|
.get_key(Header::new(Algorithm::ES256))
|
||||||
|
.await
|
||||||
|
.expect("Couldn't get ES256 key from jwk");
|
||||||
|
a.key_source
|
||||||
|
.get_key(Header::new(Algorithm::EdDSA))
|
||||||
|
.await
|
||||||
|
.expect("Couldn't get EdDSA key from jwk");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,26 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_jwks(path: &str) -> AuthorizerBuilder<C> {
|
||||||
|
AuthorizerBuilder {
|
||||||
|
key_source_type: KeySourceType::JwksPath(path.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_jwks_text(text: &str) -> AuthorizerBuilder<C> {
|
||||||
|
AuthorizerBuilder {
|
||||||
|
key_source_type: KeySourceType::JwksString(text.to_owned()),
|
||||||
|
refresh: Default::default(),
|
||||||
|
claims_checker: None,
|
||||||
|
validation: None,
|
||||||
|
jwt_source: JwtSource::AuthorizationHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds Authorizer Layer from a RSA PEM file
|
/// Builds Authorizer Layer from a RSA PEM file
|
||||||
pub fn from_rsa_pem(path: &str) -> AuthorizerBuilder<C> {
|
pub fn from_rsa_pem(path: &str) -> AuthorizerBuilder<C> {
|
||||||
AuthorizerBuilder {
|
AuthorizerBuilder {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::error::AuthError;
|
use crate::error::AuthError;
|
||||||
|
|
||||||
use super::KeyData;
|
use super::{KeyData, KeySet};
|
||||||
|
|
||||||
/// Defines the strategy for the JWKS refresh.
|
/// Defines the strategy for the JWKS refresh.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -59,7 +59,7 @@ pub struct KeyStoreManager {
|
||||||
|
|
||||||
pub struct KeyStore {
|
pub struct KeyStore {
|
||||||
/// key set
|
/// key set
|
||||||
keys: Vec<Arc<KeyData>>,
|
keys: KeySet,
|
||||||
/// time of the last successfully loaded jwkset
|
/// time of the last successfully loaded jwkset
|
||||||
load_time: Option<Instant>,
|
load_time: Option<Instant>,
|
||||||
/// time of the last failed load
|
/// time of the last failed load
|
||||||
|
|
@ -72,7 +72,7 @@ impl KeyStoreManager {
|
||||||
key_url,
|
key_url,
|
||||||
refresh,
|
refresh,
|
||||||
keystore: Arc::new(Mutex::new(KeyStore {
|
keystore: Arc::new(Mutex::new(KeyStore {
|
||||||
keys: vec![],
|
keys: KeySet::default(),
|
||||||
load_time: None,
|
load_time: None,
|
||||||
fail_time: None,
|
fail_time: None,
|
||||||
})),
|
})),
|
||||||
|
|
@ -87,11 +87,7 @@ impl KeyStoreManager {
|
||||||
if ks_gard.can_refresh(self.refresh.refresh_interval, self.refresh.retry_interval) {
|
if ks_gard.can_refresh(self.refresh.refresh_interval, self.refresh.retry_interval) {
|
||||||
ks_gard.refresh(&self.key_url, &[]).await?;
|
ks_gard.refresh(&self.key_url, &[]).await?;
|
||||||
}
|
}
|
||||||
if let Some(ref kid) = header.kid {
|
ks_gard.get_key(header)?
|
||||||
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))?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
RefreshStrategy::KeyNotFound => {
|
RefreshStrategy::KeyNotFound => {
|
||||||
if let Some(ref kid) = header.kid {
|
if let Some(ref kid) = header.kid {
|
||||||
|
|
@ -133,11 +129,7 @@ impl KeyStoreManager {
|
||||||
{
|
{
|
||||||
ks_gard.refresh(&self.key_url, &[]).await?;
|
ks_gard.refresh(&self.key_url, &[]).await?;
|
||||||
}
|
}
|
||||||
if let Some(ref kid) = header.kid {
|
ks_gard.get_key(header)?
|
||||||
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))?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(key.clone())
|
Ok(key.clone())
|
||||||
|
|
@ -186,7 +178,7 @@ impl KeyStore {
|
||||||
if keys.is_empty() {
|
if keys.is_empty() {
|
||||||
Err(AuthError::JwksRefreshError("No valid keys in the Jwk Set!".to_owned()))
|
Err(AuthError::JwksRefreshError("No valid keys in the Jwk Set!".to_owned()))
|
||||||
} else {
|
} else {
|
||||||
self.keys = keys;
|
self.keys = keys.into();
|
||||||
self.fail_time = None;
|
self.fail_time = None;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -199,17 +191,21 @@ impl KeyStore {
|
||||||
|
|
||||||
/// Find the key in the set that matches the given key id, if any.
|
/// Find the key in the set that matches the given key id, if any.
|
||||||
pub fn find_kid(&self, kid: &str) -> Option<&Arc<KeyData>> {
|
pub fn find_kid(&self, kid: &str) -> Option<&Arc<KeyData>> {
|
||||||
self.keys.iter().find(|k| k.kid.is_some() && k.kid.as_ref().unwrap() == kid)
|
self.keys.find_kid(kid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the key in the set that matches the given key id, if any.
|
/// Find the key in the set that matches the given key id, if any.
|
||||||
pub fn find_alg(&self, alg: &Algorithm) -> Option<&Arc<KeyData>> {
|
pub fn find_alg(&self, alg: &Algorithm) -> Option<&Arc<KeyData>> {
|
||||||
self.keys.iter().find(|k| k.alg.contains(alg))
|
self.keys.find_alg(alg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self, header: &jsonwebtoken::Header) -> Result<&Arc<KeyData>, AuthError> {
|
||||||
|
self.keys.get_key(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find first key.
|
/// Find first key.
|
||||||
pub fn find_first(&self) -> Option<&Arc<KeyData>> {
|
pub fn find_first(&self) -> Option<&Arc<KeyData>> {
|
||||||
self.keys.get(0)
|
self.keys.first()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,7 +223,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::jwks::key_store_manager::{KeyStore, KeyStoreManager};
|
use crate::jwks::key_store_manager::{KeyStore, KeyStoreManager};
|
||||||
use crate::jwks::KeyData;
|
use crate::jwks::{KeyData, KeySet};
|
||||||
use crate::{Refresh, RefreshStrategy};
|
use crate::{Refresh, RefreshStrategy};
|
||||||
|
|
||||||
const JWK_RSA01: &str = r#"{
|
const JWK_RSA01: &str = r#"{
|
||||||
|
|
@ -281,7 +277,7 @@ mod tests {
|
||||||
fn keystore_can_refresh() {
|
fn keystore_can_refresh() {
|
||||||
// FAIL, NO LOAD
|
// FAIL, NO LOAD
|
||||||
let ks = KeyStore {
|
let ks = KeyStore {
|
||||||
keys: vec![],
|
keys: KeySet::default(),
|
||||||
fail_time: Instant::now().checked_sub(Duration::from_secs(5)),
|
fail_time: Instant::now().checked_sub(Duration::from_secs(5)),
|
||||||
load_time: None,
|
load_time: None,
|
||||||
};
|
};
|
||||||
|
|
@ -290,7 +286,7 @@ mod tests {
|
||||||
|
|
||||||
// NO FAIL, LOAD
|
// NO FAIL, LOAD
|
||||||
let ks = KeyStore {
|
let ks = KeyStore {
|
||||||
keys: vec![],
|
keys: KeySet::default(),
|
||||||
fail_time: None,
|
fail_time: None,
|
||||||
load_time: Instant::now().checked_sub(Duration::from_secs(5)),
|
load_time: Instant::now().checked_sub(Duration::from_secs(5)),
|
||||||
};
|
};
|
||||||
|
|
@ -299,7 +295,7 @@ mod tests {
|
||||||
|
|
||||||
// FAIL, LOAD
|
// FAIL, LOAD
|
||||||
let ks = KeyStore {
|
let ks = KeyStore {
|
||||||
keys: vec![],
|
keys: KeySet::default(),
|
||||||
fail_time: Instant::now().checked_sub(Duration::from_secs(5)),
|
fail_time: Instant::now().checked_sub(Duration::from_secs(5)),
|
||||||
load_time: Instant::now().checked_sub(Duration::from_secs(10)),
|
load_time: Instant::now().checked_sub(Duration::from_secs(10)),
|
||||||
};
|
};
|
||||||
|
|
@ -318,7 +314,8 @@ mod tests {
|
||||||
keys: vec![
|
keys: vec![
|
||||||
Arc::new(KeyData::from_jwk(&jwk0).unwrap()),
|
Arc::new(KeyData::from_jwk(&jwk0).unwrap()),
|
||||||
Arc::new(KeyData::from_jwk(&jwk1).unwrap()),
|
Arc::new(KeyData::from_jwk(&jwk1).unwrap()),
|
||||||
],
|
]
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
assert!(ks.find_kid("rsa01").is_some());
|
assert!(ks.find_kid("rsa01").is_some());
|
||||||
assert!(ks.find_kid("ec01").is_some());
|
assert!(ks.find_kid("ec01").is_some());
|
||||||
|
|
@ -331,7 +328,7 @@ mod tests {
|
||||||
let ks = KeyStore {
|
let ks = KeyStore {
|
||||||
load_time: None,
|
load_time: None,
|
||||||
fail_time: None,
|
fail_time: None,
|
||||||
keys: vec![Arc::new(KeyData::from_jwk(&jwk0).unwrap())],
|
keys: vec![Arc::new(KeyData::from_jwk(&jwk0).unwrap())].into(),
|
||||||
};
|
};
|
||||||
assert!(ks.find_alg(&Algorithm::RS256).is_some());
|
assert!(ks.find_alg(&Algorithm::RS256).is_some());
|
||||||
assert!(ks.find_alg(&Algorithm::EdDSA).is_none());
|
assert!(ks.find_alg(&Algorithm::EdDSA).is_none());
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ pub mod key_store_manager;
|
||||||
pub enum KeySource {
|
pub enum KeySource {
|
||||||
/// KeyDataSource managing a refreshable key sets
|
/// KeyDataSource managing a refreshable key sets
|
||||||
KeyStoreSource(KeyStoreManager),
|
KeyStoreSource(KeyStoreManager),
|
||||||
|
/// Manages public key sets, initialized on startup
|
||||||
|
MultiKeySource(KeySet),
|
||||||
/// Manages one public key, initialized on startup
|
/// Manages one public key, initialized on startup
|
||||||
SingleKeySource(Arc<KeyData>),
|
SingleKeySource(Arc<KeyData>),
|
||||||
}
|
}
|
||||||
|
|
@ -33,10 +35,49 @@ impl KeyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct KeySet(Vec<Arc<KeyData>>);
|
||||||
|
|
||||||
|
impl From<Vec<Arc<KeyData>>> for KeySet {
|
||||||
|
fn from(value: Vec<Arc<KeyData>>) -> Self {
|
||||||
|
KeySet(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeySet {
|
||||||
|
/// Find the key in the set that matches the given key id, if any.
|
||||||
|
pub fn find_kid(&self, kid: &str) -> Option<&Arc<KeyData>> {
|
||||||
|
self.0.iter().find(|k| match &k.kid {
|
||||||
|
Some(k) => k == kid,
|
||||||
|
None => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the key in the set that matches the given key id, if any.
|
||||||
|
pub fn find_alg(&self, alg: &Algorithm) -> Option<&Arc<KeyData>> {
|
||||||
|
self.0.iter().find(|k| k.alg.contains(alg))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find first key.
|
||||||
|
pub fn first(&self) -> Option<&Arc<KeyData>> {
|
||||||
|
self.0.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_key(&self, header: &Header) -> Result<&Arc<KeyData>, AuthError> {
|
||||||
|
let key = if let Some(ref kid) = header.kid {
|
||||||
|
self.find_kid(kid).ok_or_else(|| AuthError::InvalidKid(kid.to_owned()))?
|
||||||
|
} else {
|
||||||
|
self.find_alg(&header.alg).ok_or(AuthError::InvalidKeyAlg(header.alg))?
|
||||||
|
};
|
||||||
|
Ok(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl KeySource {
|
impl KeySource {
|
||||||
pub async fn get_key(&self, header: Header) -> Result<Arc<KeyData>, AuthError> {
|
pub async fn get_key(&self, header: Header) -> Result<Arc<KeyData>, AuthError> {
|
||||||
match self {
|
match self {
|
||||||
KeySource::KeyStoreSource(kstore) => kstore.get_key(&header).await,
|
KeySource::KeyStoreSource(kstore) => kstore.get_key(&header).await,
|
||||||
|
KeySource::MultiKeySource(keys) => keys.get_key(&header).cloned(),
|
||||||
KeySource::SingleKeySource(key) => Ok(key.clone()),
|
KeySource::SingleKeySource(key) => Ok(key.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,21 @@ mod tests {
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
||||||
assert_eq!(&body[..], b"hello: b@b.com");
|
assert_eq!(&body[..], b"hello: b@b.com");
|
||||||
|
|
||||||
|
let response = make_proteced_request(JwtAuthorizer::from_jwks("../config/public1.jwks"), common::JWT_RSA1_OK).await;
|
||||||
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
||||||
|
assert_eq!(&body[..], b"hello: b@b.com");
|
||||||
|
|
||||||
|
let response = make_proteced_request(JwtAuthorizer::from_jwks("../config/public1.jwks"), common::JWT_EC1_OK).await;
|
||||||
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
||||||
|
assert_eq!(&body[..], b"hello: b@b.com");
|
||||||
|
|
||||||
|
let response = make_proteced_request(JwtAuthorizer::from_jwks("../config/public1.jwks"), common::JWT_ED1_OK).await;
|
||||||
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
||||||
|
assert_eq!(&body[..], b"hello: b@b.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue