kanidmd_lib/idm/
oauth2_client.rs1use crate::idm::server::IdmServerProxyWriteTransaction;
2use crate::prelude::*;
3use std::collections::BTreeSet;
4use std::fmt;
5
6pub const OAUTH2_CLIENT_AUTHORISATION_RESPONSE_PATH: &str = "/ui/login/oauth2_landing";
10
11#[derive(Clone)]
12pub struct OAuth2ClientProvider {
13 pub(crate) name: String,
14 pub(crate) uuid: Uuid,
15 pub(crate) client_id: String,
16 pub(crate) client_basic_secret: String,
17 pub(crate) client_redirect_uri: Url,
19 pub(crate) request_scopes: BTreeSet<String>,
20 pub(crate) authorisation_endpoint: Url,
21 pub(crate) token_endpoint: Url,
22}
23
24impl fmt::Debug for OAuth2ClientProvider {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 f.debug_struct("OAuth2ClientProvider")
27 .field("provider_id", &self.name)
28 .field("provider_name", &self.uuid)
29 .field("client_id", &self.client_id)
30 .finish()
31 }
32}
33
34impl OAuth2ClientProvider {
35 #[cfg(test)]
36 pub fn new_test<'a, I: IntoIterator<Item = &'a str>>(
37 client_id: &str,
38 domain: &str,
39 request_scopes: I,
40 ) -> Self {
41 let mut client_redirect_uri =
43 Url::parse("https://idm.example.com").expect("invalid test data");
44 client_redirect_uri.set_path(OAUTH2_CLIENT_AUTHORISATION_RESPONSE_PATH);
45
46 let mut domain = Url::parse(domain).expect("invalid test data");
47
48 domain.set_path("/oauth2/authorise");
49 let authorisation_endpoint = domain.clone();
50
51 domain.set_path("/oauth2/token");
52 let token_endpoint = domain.clone();
53
54 let client_basic_secret = crate::utils::password_from_random();
55
56 let request_scopes = request_scopes.into_iter().map(String::from).collect();
57
58 Self {
59 name: "test_client_provider".to_string(),
60 uuid: Uuid::new_v4(),
61 client_id: client_id.to_string(),
62 client_basic_secret,
63 client_redirect_uri,
64 request_scopes,
65 authorisation_endpoint,
66 token_endpoint,
67 }
68 }
69}
70
71impl IdmServerProxyWriteTransaction<'_> {
72 #[instrument(level = "debug", skip_all)]
73 pub(crate) fn reload_oauth2_client_providers(&mut self) -> Result<(), OperationError> {
74 let oauth2_client_provider_entries = self.qs_write.internal_search(filter!(f_eq(
75 Attribute::Class,
76 EntryClass::OAuth2Client.into(),
77 )))?;
78
79 let mut oauth2_client_provider_structs =
81 Vec::with_capacity(oauth2_client_provider_entries.len());
82
83 let mut client_redirect_uri = self.origin.clone();
84 client_redirect_uri.set_path(OAUTH2_CLIENT_AUTHORISATION_RESPONSE_PATH);
85
86 for provider_entry in oauth2_client_provider_entries {
87 let uuid = provider_entry.get_uuid();
88 trace!(?uuid, "Checking OAuth2 Provider configuration");
89
90 let name = provider_entry
91 .get_ava_single_iname(Attribute::Name)
92 .map(str::to_string)
93 .ok_or(OperationError::InvalidValueState)?;
94
95 let client_id = provider_entry
96 .get_ava_single_utf8(Attribute::OAuth2ClientId)
97 .map(str::to_string)
98 .ok_or(OperationError::InvalidValueState)?;
99
100 let client_basic_secret = provider_entry
101 .get_ava_single_utf8(Attribute::OAuth2ClientSecret)
102 .map(str::to_string)
103 .ok_or(OperationError::InvalidValueState)?;
104
105 let authorisation_endpoint = provider_entry
106 .get_ava_single_url(Attribute::OAuth2AuthorisationEndpoint)
107 .cloned()
108 .ok_or(OperationError::InvalidValueState)?;
109
110 let token_endpoint = provider_entry
111 .get_ava_single_url(Attribute::OAuth2TokenEndpoint)
112 .cloned()
113 .ok_or(OperationError::InvalidValueState)?;
114
115 let request_scopes = provider_entry
116 .get_ava_as_oauthscopes(Attribute::OAuth2RequestScopes)
117 .ok_or(OperationError::InvalidValueState)?
118 .map(str::to_string)
119 .collect();
120
121 let provider = OAuth2ClientProvider {
122 name,
123 uuid,
124 client_id,
125 client_basic_secret,
126 client_redirect_uri: client_redirect_uri.clone(),
127 request_scopes,
128 authorisation_endpoint,
129 token_endpoint,
130 };
131
132 oauth2_client_provider_structs.push((uuid, provider));
133 }
134
135 self.oauth2_client_providers.clear();
137
138 self.oauth2_client_providers
140 .extend(oauth2_client_provider_structs);
141
142 Ok(())
144 }
145}