1use async_trait::async_trait;
2use paas_api::status::SystemId;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::error::Error;
6use std::sync::Arc;
7
8#[derive(Debug, thiserror::Error)]
9pub enum AuthError {
10 #[error("Failed to get token: {0}")]
11 TokenError(String),
12 #[error("Failed to set header: {0}")]
13 HeaderError(#[from] reqwest::header::InvalidHeaderValue),
14}
15
16#[async_trait]
17pub trait Auth: Send + Sync + 'static {
18 fn token_type(&self) -> &str;
19 async fn token(&self) -> Result<String, Box<dyn Error>>;
20
21 async fn authenticate(
22 &self,
23 headers: &mut reqwest::header::HeaderMap,
24 ) -> Result<(), Box<dyn Error>> {
25 let auth_value = format!("{} {}", self.token_type(), self.token().await?);
26 headers.insert(
27 reqwest::header::AUTHORIZATION,
28 reqwest::header::HeaderValue::from_str(&auth_value)?,
29 );
30 Ok(())
31 }
32}
33
34#[async_trait]
35pub(crate) trait RequestBuilderExt {
36 async fn with_auth(self, auth: &Arc<dyn Auth>) -> Result<reqwest::RequestBuilder, AuthError>;
37}
38
39#[async_trait]
40impl RequestBuilderExt for reqwest::RequestBuilder {
41 async fn with_auth(self, auth: &Arc<dyn Auth>) -> Result<reqwest::RequestBuilder, AuthError> {
42 let auth_value = format!(
43 "{} {}",
44 auth.token_type(),
45 auth.token()
46 .await
47 .map_err(|e| AuthError::TokenError(e.to_string()))?
48 );
49 Ok(self.header(reqwest::header::AUTHORIZATION, auth_value))
50 }
51}
52
53#[derive(Clone, Serialize, Deserialize)]
54pub struct BearerTokenAuth {
55 token: String,
56}
57
58impl BearerTokenAuth {
59 pub fn new(token: String) -> BearerTokenAuth {
60 BearerTokenAuth { token }
61 }
62}
63
64#[async_trait]
65impl Auth for BearerTokenAuth {
66 fn token_type(&self) -> &str {
67 "Bearer"
68 }
69
70 async fn token(&self) -> Result<String, Box<dyn Error>> {
71 Ok(self.token.clone())
72 }
73}
74
75pub struct SystemAuths(pub HashMap<SystemId, Arc<dyn Auth>>);
76
77impl SystemAuths {
78 pub fn new(auths: HashMap<SystemId, Arc<dyn Auth>>) -> Self {
79 Self(auths)
80 }
81
82 pub fn from_auths<A: Auth>(auths: HashMap<SystemId, A>) -> Self {
83 Self::new(
84 auths
85 .into_iter()
86 .map(|(id, auth)| (id, Arc::new(auth) as Arc<dyn Auth>))
87 .collect(),
88 )
89 }
90
91 pub fn get(&self, system_id: &SystemId) -> Option<Arc<dyn Auth>> {
92 self.0.get(system_id).map(Arc::clone)
93 }
94}