-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from NOLAI/multiple-auths
Support multiple auths and errors
- Loading branch information
Showing
9 changed files
with
325 additions
and
134 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "paas-client" | ||
version = "0.5.8" | ||
version = "0.6.0" | ||
authors = [ | ||
"Job Doesburg <[email protected]>", | ||
"Julian van der Horst <[email protected]" | ||
|
@@ -36,6 +36,8 @@ chrono = "0.4.39" | |
clap = { version = "4.5.27", optional = true } | ||
tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros"] } | ||
base64 = "0.22.1" | ||
async-trait = "0.1.86" | ||
thiserror = "2.0.11" | ||
|
||
[dev-dependencies] | ||
tokio = { version = "1", features = ["full"] } | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,97 @@ | ||
use crate::transcryptor_client::AuthToken; | ||
use async_trait::async_trait; | ||
use paas_api::status::SystemId; | ||
use serde::{Deserialize, Serialize}; | ||
use std::collections::HashMap; | ||
use std::str::FromStr; | ||
use std::error::Error; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
pub struct AuthTokens(pub HashMap<SystemId, AuthToken>); | ||
#[derive(Debug, thiserror::Error)] | ||
pub enum AuthError { | ||
#[error("Failed to get token: {0}")] | ||
TokenError(String), | ||
#[error("Failed to set header: {0}")] | ||
HeaderError(#[from] reqwest::header::InvalidHeaderValue), | ||
} | ||
|
||
#[async_trait] | ||
pub trait Auth { | ||
fn token_type(&self) -> &str; | ||
async fn token(&self) -> Result<String, Box<dyn Error + Send + Sync>>; | ||
|
||
async fn authenticate( | ||
&self, | ||
headers: &mut reqwest::header::HeaderMap, | ||
) -> Result<(), Box<dyn Error + Send + Sync>> { | ||
let auth_value = format!("{} {}", self.token_type(), self.token().await?); | ||
headers.insert( | ||
reqwest::header::AUTHORIZATION, | ||
reqwest::header::HeaderValue::from_str(&auth_value)?, | ||
); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl AuthTokens { | ||
pub fn get(&self, system_id: &SystemId) -> Option<&AuthToken> { | ||
self.0.get(system_id) | ||
#[async_trait] | ||
pub(crate) trait RequestBuilderExt { | ||
async fn with_auth<A: Auth + Send + Sync + ?Sized>( | ||
self, | ||
auth: &A, | ||
) -> Result<reqwest::RequestBuilder, AuthError>; | ||
} | ||
|
||
#[async_trait] | ||
impl RequestBuilderExt for reqwest::RequestBuilder { | ||
async fn with_auth<A: Auth + Send + Sync + ?Sized>( | ||
self, | ||
auth: &A, | ||
) -> Result<reqwest::RequestBuilder, AuthError> { | ||
let auth_value = format!( | ||
"{} {}", | ||
auth.token_type(), | ||
auth.token() | ||
.await | ||
.map_err(|e| AuthError::TokenError(e.to_string()))? | ||
); | ||
Ok(self.header(reqwest::header::AUTHORIZATION, auth_value)) | ||
} | ||
} | ||
|
||
impl FromStr for AuthTokens { | ||
type Err = serde_json::Error; | ||
#[derive(Clone, Serialize, Deserialize)] | ||
pub struct BearerTokenAuth { | ||
token: String, | ||
} | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
let map: HashMap<SystemId, AuthToken> = serde_json::from_str(s)?; | ||
Ok(Self(map)) | ||
impl BearerTokenAuth { | ||
pub fn new(token: String) -> BearerTokenAuth { | ||
BearerTokenAuth { token } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl Auth for BearerTokenAuth { | ||
fn token_type(&self) -> &str { | ||
"Bearer" | ||
} | ||
|
||
async fn token(&self) -> Result<String, Box<dyn Error + Send + Sync>> { | ||
Ok(self.token.clone()) | ||
} | ||
} | ||
|
||
pub struct SystemAuths(pub HashMap<SystemId, Box<dyn Auth + Send + Sync>>); | ||
|
||
impl SystemAuths { | ||
pub fn new(auths: HashMap<SystemId, Box<dyn Auth + Send + Sync>>) -> Self { | ||
Self(auths) | ||
} | ||
pub fn from_auths<A: Auth + Send + Sync + 'static>(auths: HashMap<SystemId, A>) -> Self { | ||
Self::new( | ||
auths | ||
.into_iter() | ||
.map(|(id, auth)| (id, Box::new(auth) as Box<dyn Auth + Send + Sync>)) | ||
.collect(), | ||
) | ||
} | ||
pub fn get(&self, system_id: &SystemId) -> Option<&(dyn Auth + Send + Sync)> { | ||
self.0.get(system_id).map(|auth| auth.as_ref()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.