]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/config/access/openid.rs
3dfa8de4c9d541597ebc337c72d2134810448f39
[proxmox-backup.git] / src / api2 / config / access / openid.rs
1 /// Configure OpenId realms
2
3 use anyhow::{bail, Error};
4 use serde_json::Value;
5 use ::serde::{Deserialize, Serialize};
6
7 use proxmox::api::{api, Permission, Router, RpcEnvironment};
8
9 use pbs_api_types::{
10 PROXMOX_CONFIG_DIGEST_SCHEMA, REALM_ID_SCHEMA, PRIV_SYS_AUDIT, PRIV_REALM_ALLOCATE,
11 };
12 use pbs_config::domains::{self, OpenIdRealmConfig, OpenIdRealmConfigUpdater};
13
14 #[api(
15 input: {
16 properties: {},
17 },
18 returns: {
19 description: "List of configured OpenId realms.",
20 type: Array,
21 items: { type: OpenIdRealmConfig },
22 },
23 access: {
24 permission: &Permission::Privilege(&["access", "domains"], PRIV_REALM_ALLOCATE, false),
25 },
26 )]
27 /// List configured OpenId realms
28 pub fn list_openid_realms(
29 _param: Value,
30 mut rpcenv: &mut dyn RpcEnvironment,
31 ) -> Result<Vec<OpenIdRealmConfig>, Error> {
32
33 let (config, digest) = domains::config()?;
34
35 let list = config.convert_to_typed_array("openid")?;
36
37 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
38
39 Ok(list)
40 }
41
42 #[api(
43 protected: true,
44 input: {
45 properties: {
46 config: {
47 type: OpenIdRealmConfig,
48 flatten: true,
49 },
50 },
51 },
52 access: {
53 permission: &Permission::Privilege(&["access", "domains"], PRIV_REALM_ALLOCATE, false),
54 },
55 )]
56 /// Create a new OpenId realm
57 pub fn create_openid_realm(config: OpenIdRealmConfig) -> Result<(), Error> {
58
59 let _lock = domains::lock_config()?;
60
61 let (mut domains, _digest) = domains::config()?;
62
63 if config.realm == "pbs" ||
64 config.realm == "pam" ||
65 domains.sections.get(&config.realm).is_some()
66 {
67 bail!("realm '{}' already exists.", config.realm);
68 }
69
70 domains.set_data(&config.realm, "openid", &config)?;
71
72 domains::save_config(&domains)?;
73
74 Ok(())
75 }
76
77 #[api(
78 protected: true,
79 input: {
80 properties: {
81 realm: {
82 schema: REALM_ID_SCHEMA,
83 },
84 digest: {
85 optional: true,
86 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
87 },
88 },
89 },
90 access: {
91 permission: &Permission::Privilege(&["access", "domains"], PRIV_REALM_ALLOCATE, false),
92 },
93 )]
94 /// Remove a OpenID realm configuration
95 pub fn delete_openid_realm(
96 realm: String,
97 digest: Option<String>,
98 _rpcenv: &mut dyn RpcEnvironment,
99 ) -> Result<(), Error> {
100
101 let _lock = domains::lock_config()?;
102
103 let (mut domains, expected_digest) = domains::config()?;
104
105 if let Some(ref digest) = digest {
106 let digest = proxmox::tools::hex_to_digest(digest)?;
107 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
108 }
109
110 if domains.sections.remove(&realm).is_none() {
111 bail!("realm '{}' does not exist.", realm);
112 }
113
114 domains::save_config(&domains)?;
115
116 Ok(())
117 }
118
119 #[api(
120 input: {
121 properties: {
122 realm: {
123 schema: REALM_ID_SCHEMA,
124 },
125 },
126 },
127 returns: { type: OpenIdRealmConfig },
128 access: {
129 permission: &Permission::Privilege(&["access", "domains"], PRIV_SYS_AUDIT, false),
130 },
131 )]
132 /// Read the OpenID realm configuration
133 pub fn read_openid_realm(
134 realm: String,
135 mut rpcenv: &mut dyn RpcEnvironment,
136 ) -> Result<OpenIdRealmConfig, Error> {
137
138 let (domains, digest) = domains::config()?;
139
140 let config = domains.lookup("openid", &realm)?;
141
142 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
143
144 Ok(config)
145 }
146
147 #[api()]
148 #[derive(Serialize, Deserialize)]
149 #[serde(rename_all="kebab-case")]
150 #[allow(non_camel_case_types)]
151 /// Deletable property name
152 pub enum DeletableProperty {
153 /// Delete the client key.
154 client_key,
155 /// Delete the comment property.
156 comment,
157 /// Delete the autocreate property
158 autocreate,
159 }
160
161 #[api(
162 protected: true,
163 input: {
164 properties: {
165 realm: {
166 schema: REALM_ID_SCHEMA,
167 },
168 update: {
169 type: OpenIdRealmConfigUpdater,
170 flatten: true,
171 },
172 delete: {
173 description: "List of properties to delete.",
174 type: Array,
175 optional: true,
176 items: {
177 type: DeletableProperty,
178 }
179 },
180 digest: {
181 optional: true,
182 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
183 },
184 },
185 },
186 returns: { type: OpenIdRealmConfig },
187 access: {
188 permission: &Permission::Privilege(&["access", "domains"], PRIV_REALM_ALLOCATE, false),
189 },
190 )]
191 /// Update an OpenID realm configuration
192 pub fn update_openid_realm(
193 realm: String,
194 update: OpenIdRealmConfigUpdater,
195 delete: Option<Vec<DeletableProperty>>,
196 digest: Option<String>,
197 _rpcenv: &mut dyn RpcEnvironment,
198 ) -> Result<(), Error> {
199
200 let _lock = domains::lock_config()?;
201
202 let (mut domains, expected_digest) = domains::config()?;
203
204 if let Some(ref digest) = digest {
205 let digest = proxmox::tools::hex_to_digest(digest)?;
206 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
207 }
208
209 let mut config: OpenIdRealmConfig = domains.lookup("openid", &realm)?;
210
211 if let Some(delete) = delete {
212 for delete_prop in delete {
213 match delete_prop {
214 DeletableProperty::client_key => { config.client_key = None; },
215 DeletableProperty::comment => { config.comment = None; },
216 DeletableProperty::autocreate => { config.autocreate = None; },
217 }
218 }
219 }
220
221 if let Some(comment) = update.comment {
222 let comment = comment.trim().to_string();
223 if comment.is_empty() {
224 config.comment = None;
225 } else {
226 config.comment = Some(comment);
227 }
228 }
229
230 if let Some(issuer_url) = update.issuer_url { config.issuer_url = issuer_url; }
231 if let Some(client_id) = update.client_id { config.client_id = client_id; }
232
233 if update.client_key.is_some() { config.client_key = update.client_key; }
234 if update.autocreate.is_some() { config.autocreate = update.autocreate; }
235
236 domains.set_data(&realm, "openid", &config)?;
237
238 domains::save_config(&domains)?;
239
240 Ok(())
241 }
242
243 const ITEM_ROUTER: Router = Router::new()
244 .get(&API_METHOD_READ_OPENID_REALM)
245 .put(&API_METHOD_UPDATE_OPENID_REALM)
246 .delete(&API_METHOD_DELETE_OPENID_REALM);
247
248 pub const ROUTER: Router = Router::new()
249 .get(&API_METHOD_LIST_OPENID_REALMS)
250 .post(&API_METHOD_CREATE_OPENID_REALM)
251 .match_all("realm", &ITEM_ROUTER);