refactor: JwtAuthorizer creation simplification

This commit is contained in:
cduvray 2023-01-23 23:36:29 +01:00
parent 9101f91ad8
commit 2c0266b4f8
5 changed files with 40 additions and 38 deletions

View file

@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Changed
- JwtAuthorizer creation simplified:
- JwtAuthorizer::from_* creates an instance, new() is not necessary anymore
### Fixed ### Fixed
- claims extractor (JwtClaims) without authorizer should not panic, should send a 500 error - claims extractor (JwtClaims) without authorizer should not panic, should send a 500 error

View file

@ -28,8 +28,8 @@ async fn main() {
// First let's create an authorizer builder from a JWKS Endpoint // First let's create an authorizer builder from a JWKS Endpoint
// User is a struct deserializable from JWT claims representing the authorized user // User is a struct deserializable from JWT claims representing the authorized user
let jwt_auth: JwtAuthorizer<User> = JwtAuthorizer::new() let jwt_auth: JwtAuthorizer<User> = JwtAuthorizer::
.from_jwks_url("http://localhost:3000/oidc/jwks") from_jwks_url("http://localhost:3000/oidc/jwks")
.with_check(claim_checker); .with_check(claim_checker);
let oidc = Router::new() let oidc = Router::new()

View file

@ -16,8 +16,8 @@ Example:
} }
// let's create an authorizer builder from a JWKS Endpoint // let's create an authorizer builder from a JWKS Endpoint
let jwt_auth: JwtAuthorizer<User> = JwtAuthorizer::new() let jwt_auth: JwtAuthorizer<User> =
.from_jwks_url("http://localhost:3000/oidc/jwks"); JwtAuthorizer::from_jwks_url("http://localhost:3000/oidc/jwks");
// adding the authorization layer // adding the authorization layer
let app = Router::new().route("/protected", get(protected)) let app = Router::new().route("/protected", get(protected))
@ -54,8 +54,7 @@ Example:
sub: String, sub: String,
} }
let authorizer = JwtAuthorizer::new() let authorizer = JwtAuthorizer::from_rsa_pem("../config/jwtRS256.key.pub")
.from_rsa_pem("../config/jwtRS256.key.pub")
.with_check( .with_check(
|claims: &User| claims.sub.contains('@') // must be an email |claims: &User| claims.sub.contains('@') // must be an email
); );

View file

@ -35,46 +35,44 @@ impl<C> JwtAuthorizer<C>
where where
C: Clone + DeserializeOwned + Send + Sync, C: Clone + DeserializeOwned + Send + Sync,
{ {
pub fn new() -> Self { /// Build Authorizer Layer from a JWKS endpoint
pub fn from_jwks_url(url: &'static str) -> JwtAuthorizer<C> {
JwtAuthorizer { JwtAuthorizer {
key_source_type: None, key_source_type: Some(KeySourceType::Jwks(url.to_owned())),
claims_checker: None, claims_checker: None,
} }
} }
/// Build Authorizer Layer from a JWKS endpoint
pub fn from_jwks_url(mut self, url: &'static str) -> JwtAuthorizer<C> {
self.key_source_type = Some(KeySourceType::Jwks(url.to_owned()));
self
}
/// Build Authorizer Layer from a RSA PEM file /// Build Authorizer Layer from a RSA PEM file
pub fn from_rsa_pem(mut self, path: &'static str) -> JwtAuthorizer<C> { pub fn from_rsa_pem(path: &'static str) -> JwtAuthorizer<C> {
self.key_source_type = Some(KeySourceType::RSA(path.to_owned())); JwtAuthorizer {
key_source_type: Some(KeySourceType::RSA(path.to_owned())),
self claims_checker: None,
}
} }
/// Build Authorizer Layer from a EC PEM file /// Build Authorizer Layer from a EC PEM file
pub fn from_ec_pem(mut self, path: &'static str) -> JwtAuthorizer<C> { pub fn from_ec_pem(path: &'static str) -> JwtAuthorizer<C> {
self.key_source_type = Some(KeySourceType::EC(path.to_owned())); JwtAuthorizer {
key_source_type: Some(KeySourceType::EC(path.to_owned())),
self claims_checker: None,
}
} }
/// Build Authorizer Layer from a EC PEM file /// Build Authorizer Layer from a EC PEM file
pub fn from_ed_pem(mut self, path: &'static str) -> JwtAuthorizer<C> { pub fn from_ed_pem(path: &'static str) -> JwtAuthorizer<C> {
self.key_source_type = Some(KeySourceType::ED(path.to_owned())); JwtAuthorizer {
key_source_type: Some(KeySourceType::ED(path.to_owned())),
self claims_checker: None,
}
} }
/// Build Authorizer Layer from a secret phrase /// Build Authorizer Layer from a secret phrase
pub fn from_secret(mut self, secret: &'static str) -> JwtAuthorizer<C> { pub fn from_secret(secret: &'static str) -> JwtAuthorizer<C> {
self.key_source_type = Some(KeySourceType::Secret(secret)); JwtAuthorizer {
key_source_type: Some(KeySourceType::Secret(secret)),
self claims_checker: None,
}
} }
/// layer that checks token validity and claim constraints (custom function) /// layer that checks token validity and claim constraints (custom function)

View file

@ -40,8 +40,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn protected_without_jwt() { async fn protected_without_jwt() {
let jwt_auth: JwtAuthorizer<User> = JwtAuthorizer::new() let jwt_auth: JwtAuthorizer<User> = JwtAuthorizer::from_rsa_pem("../config/jwtRS256.key.pub");
.from_rsa_pem("../config/jwtRS256.key.pub");
let response = app(jwt_auth) let response = app(jwt_auth)
.oneshot(Request::builder().uri("/protected").body(Body::empty()).unwrap()) .oneshot(Request::builder().uri("/protected").body(Body::empty()).unwrap())
@ -58,7 +57,7 @@ mod tests {
async fn protected_with_jwt() { async fn protected_with_jwt() {
let response = make_proteced_request( let response = make_proteced_request(
JwtAuthorizer::new().from_rsa_pem("../config/jwtRS256.key.pub"), JwtAuthorizer::from_rsa_pem("../config/jwtRS256.key.pub"),
JWT_RSA_OK JWT_RSA_OK
).await; ).await;
@ -72,7 +71,7 @@ mod tests {
async fn protected_with_bad_jwt() { async fn protected_with_bad_jwt() {
let response = make_proteced_request( let response = make_proteced_request(
JwtAuthorizer::new().from_rsa_pem("../config/jwtRS256.key.pub"), JwtAuthorizer::from_rsa_pem("../config/jwtRS256.key.pub"),
"xxx.xxx.xxx" "xxx.xxx.xxx"
).await; ).await;
@ -84,14 +83,14 @@ mod tests {
async fn protected_with_claims_check() { async fn protected_with_claims_check() {
let rsp_ok = make_proteced_request( let rsp_ok = make_proteced_request(
JwtAuthorizer::new().from_rsa_pem("../config/jwtRS256.key.pub").with_check(|_|true), JwtAuthorizer::from_rsa_pem("../config/jwtRS256.key.pub").with_check(|_|true),
JWT_RSA_OK JWT_RSA_OK
).await; ).await;
assert_eq!(rsp_ok.status(), StatusCode::OK); assert_eq!(rsp_ok.status(), StatusCode::OK);
let rsp_ko = make_proteced_request( let rsp_ko = make_proteced_request(
JwtAuthorizer::new().from_rsa_pem("../config/jwtRS256.key.pub").with_check(|_|false), JwtAuthorizer::from_rsa_pem("../config/jwtRS256.key.pub").with_check(|_|false),
JWT_RSA_OK JWT_RSA_OK
).await; ).await;
@ -108,7 +107,7 @@ mod tests {
async fn protected_with_bad_jwks_url() { async fn protected_with_bad_jwks_url() {
let response = make_proteced_request( let response = make_proteced_request(
JwtAuthorizer::new().from_jwks_url("http://bad-url/xxx/yyy"), JwtAuthorizer::from_jwks_url("http://bad-url/xxx/yyy"),
JWT_RSA_OK JWT_RSA_OK
).await; ).await;