drogue_bazaar/auth/openid/
config.rs1use crate::{core::config::CommaSeparatedVec, reqwest::ClientFactory};
2use anyhow::Context;
3use core::fmt::Debug;
4use drogue_client::openid::OpenIdTokenProvider;
5use serde::Deserialize;
6use std::time::Duration;
7use url::Url;
8
9#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
11pub struct TokenConfig {
12 pub client_id: String,
13
14 pub client_secret: String,
15
16 pub issuer_url: Url,
17
18 #[serde(default)]
19 pub tls_insecure: bool,
20
21 #[serde(default)]
22 pub tls_ca_certificates: CommaSeparatedVec,
23
24 #[serde(default)]
25 #[serde(with = "humantime_serde")]
26 pub refresh_before: Option<Duration>,
27}
28
29impl TokenConfig {
30 pub async fn into_client(self, redirect: Option<String>) -> anyhow::Result<openid::Client> {
31 let mut client = ClientFactory::new();
32 client = client.add_ca_certs(self.tls_ca_certificates.0);
33
34 if self.tls_insecure {
35 client = client.make_insecure();
36 }
37
38 openid::Client::discover_with_client(
39 client.build()?,
40 self.client_id,
41 self.client_secret,
42 redirect,
43 self.issuer_url,
44 )
45 .await
46 .context("Discovering endpoint")
47 }
48
49 pub async fn discover_from(self) -> anyhow::Result<OpenIdTokenProvider> {
51 let refresh_before = self
52 .refresh_before
53 .and_then(|d| chrono::Duration::from_std(d).ok())
54 .unwrap_or_else(|| chrono::Duration::seconds(15));
55
56 Ok(OpenIdTokenProvider::new(
57 self.into_client(None).await?,
58 refresh_before,
59 ))
60 }
61}
62
63#[cfg(test)]
64mod test {
65 use super::*;
66 use crate::core::config::ConfigFromEnv;
67 use std::collections::HashMap;
68
69 #[test]
70 fn test_ca_certs() {
71 let mut envs = HashMap::new();
72
73 envs.insert("CLIENT_ID", "id");
74 envs.insert("CLIENT_SECRET", "secret");
75 envs.insert("ISSUER_URL", "http://foo.bar/baz/buz");
76 envs.insert("REALM", "drogue");
77 envs.insert("TLS_CA_CERTIFICATES", "/foo/bar/baz");
78
79 let config = TokenConfig::from_set(envs).unwrap();
80
81 assert_eq!(
82 TokenConfig {
83 client_id: "id".to_string(),
84 client_secret: "secret".to_string(),
85 issuer_url: Url::parse("http://foo.bar/baz/buz").unwrap(),
86 refresh_before: None,
87 tls_insecure: false,
88 tls_ca_certificates: vec!["/foo/bar/baz".to_string()].into(),
89 },
90 config
91 );
92 }
93
94 #[test]
95 fn test_ca_certs_multi() {
96 let mut envs = HashMap::new();
97
98 envs.insert("CLIENT_ID", "id");
99 envs.insert("CLIENT_SECRET", "secret");
100 envs.insert("ISSUER_URL", "http://foo.bar/baz/buz");
101 envs.insert("REALM", "drogue");
102 envs.insert("TLS_CA_CERTIFICATES", "/foo/bar/baz,/foo/bar/baz2");
103
104 let config = TokenConfig::from_set(envs).unwrap();
105
106 assert_eq!(
107 TokenConfig {
108 client_id: "id".to_string(),
109 client_secret: "secret".to_string(),
110 issuer_url: Url::parse("http://foo.bar/baz/buz").unwrap(),
111 refresh_before: None,
112 tls_insecure: false,
113 tls_ca_certificates: vec!["/foo/bar/baz".to_string(), "/foo/bar/baz2".to_string()]
114 .into(),
115 },
116 config
117 );
118 }
119}