]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/access/user.rs
update to first proxmox crate split
[proxmox-backup.git] / src / api2 / access / user.rs
CommitLineData
bf78f708
DM
1//! User Management
2
08ac90f9 3use anyhow::{bail, format_err, Error};
6746bbb1 4use serde::{Serialize, Deserialize};
942078c4 5use serde_json::{json, Value};
6746bbb1 6use std::collections::HashMap;
579728c6 7
6ef1b649
WB
8use proxmox_router::{ApiMethod, Router, RpcEnvironment, SubdirMap, Permission};
9use proxmox_schema::api;
579728c6 10
2b7f8dd5 11use pbs_api_types::{
b65dfff5
DM
12 PROXMOX_CONFIG_DIGEST_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA, Authid,
13 Tokenname, UserWithTokens, Userid, User, UserUpdater, ApiToken,
14 ENABLE_USER_SCHEMA, EXPIRE_USER_SCHEMA, PBS_PASSWORD_SCHEMA,
15 PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY,
2b7f8dd5 16};
1cb08a0a 17use pbs_config::token_shadow;
2b7f8dd5 18
ba3d7e19 19use pbs_config::CachedUserInfo;
579728c6 20
b65dfff5 21fn new_user_with_tokens(user: User) -> UserWithTokens {
2b7f8dd5
WB
22 UserWithTokens {
23 userid: user.userid,
24 comment: user.comment,
25 enable: user.enable,
26 expire: user.expire,
27 firstname: user.firstname,
28 lastname: user.lastname,
29 email: user.email,
30 tokens: Vec::new(),
6746bbb1
FG
31 }
32}
33
579728c6
DM
34#[api(
35 input: {
6746bbb1
FG
36 properties: {
37 include_tokens: {
38 type: bool,
39 description: "Include user's API tokens in returned list.",
40 optional: true,
41 default: false,
42 },
43 },
579728c6
DM
44 },
45 returns: {
46 description: "List users (with config digest).",
47 type: Array,
906ef6c5 48 items: { type: UserWithTokens },
579728c6 49 },
d4f020f4 50 access: {
be3bd0f9 51 permission: &Permission::Anybody,
08ac90f9 52 description: "Returns all or just the logged-in user (/API token owner), depending on privileges.",
d4f020f4 53 },
579728c6 54)]
be3bd0f9 55/// List users
579728c6 56pub fn list_users(
6746bbb1 57 include_tokens: bool,
579728c6 58 _info: &ApiMethod,
522c0da0 59 mut rpcenv: &mut dyn RpcEnvironment,
6746bbb1 60) -> Result<Vec<UserWithTokens>, Error> {
579728c6 61
ba3d7e19 62 let (config, digest) = pbs_config::user::config()?;
579728c6 63
08ac90f9
FG
64 let auth_id: Authid = rpcenv
65 .get_auth_id()
66 .ok_or_else(|| format_err!("no authid available"))?
67 .parse()?;
68
69 let userid = auth_id.user();
e6dc35ac 70
be3bd0f9
FG
71 let user_info = CachedUserInfo::new()?;
72
e6dc35ac 73 let top_level_privs = user_info.lookup_privs(&auth_id, &["access", "users"]);
be3bd0f9
FG
74 let top_level_allowed = (top_level_privs & PRIV_SYS_AUDIT) != 0;
75
b65dfff5 76 let filter_by_privs = |user: &User| {
08ac90f9 77 top_level_allowed || user.userid == *userid
be3bd0f9
FG
78 };
79
6746bbb1 80
b65dfff5 81 let list:Vec<User> = config.convert_to_typed_array("user")?;
522c0da0
DC
82
83 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
579728c6 84
6746bbb1
FG
85 let iter = list.into_iter().filter(filter_by_privs);
86 let list = if include_tokens {
b65dfff5 87 let tokens: Vec<ApiToken> = config.convert_to_typed_array("token")?;
6746bbb1
FG
88 let mut user_to_tokens = tokens
89 .into_iter()
90 .fold(
91 HashMap::new(),
b65dfff5 92 |mut map: HashMap<Userid, Vec<ApiToken>>, token: ApiToken| {
6746bbb1
FG
93 if token.tokenid.is_token() {
94 map
95 .entry(token.tokenid.user().clone())
96 .or_default()
97 .push(token);
98 }
99 map
100 });
101 iter
b65dfff5 102 .map(|user: User| {
2b7f8dd5 103 let mut user = new_user_with_tokens(user);
ea1853a1 104 user.tokens = user_to_tokens.remove(&user.userid).unwrap_or_default();
6746bbb1
FG
105 user
106 })
107 .collect()
108 } else {
2b7f8dd5 109 iter.map(new_user_with_tokens)
6746bbb1
FG
110 .collect()
111 };
112
113 Ok(list)
579728c6
DM
114}
115
116#[api(
117 protected: true,
118 input: {
119 properties: {
b65dfff5
DM
120 config: {
121 type: User,
122 flatten: true,
579728c6
DM
123 },
124 password: {
125 schema: PBS_PASSWORD_SCHEMA,
126 optional: true,
127 },
579728c6
DM
128 },
129 },
d4f020f4 130 access: {
74c08a57 131 permission: &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
d4f020f4 132 },
579728c6
DM
133)]
134/// Create new user.
5aa10190
OB
135pub fn create_user(
136 password: Option<String>,
b65dfff5 137 config: User,
5aa10190
OB
138 rpcenv: &mut dyn RpcEnvironment
139) -> Result<(), Error> {
579728c6 140
ba3d7e19 141 let _lock = pbs_config::user::lock_config()?;
579728c6 142
ba3d7e19 143 let (mut section_config, _digest) = pbs_config::user::config()?;
579728c6 144
b65dfff5
DM
145 if section_config.sections.get(config.userid.as_str()).is_some() {
146 bail!("user '{}' already exists.", config.userid);
579728c6
DM
147 }
148
b65dfff5 149 section_config.set_data(config.userid.as_str(), "user", &config)?;
579728c6 150
b65dfff5 151 let realm = config.userid.realm();
5aa10190
OB
152
153 // Fails if realm does not exist!
154 let authenticator = crate::auth::lookup_authenticator(realm)?;
155
ba3d7e19 156 pbs_config::user::save_config(&section_config)?;
579728c6 157
7d817b03 158 if let Some(password) = password {
5aa10190
OB
159 let user_info = CachedUserInfo::new()?;
160 let current_auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
161 if realm == "pam" && !user_info.is_superuser(&current_auth_id) {
162 bail!("only superuser can edit pam credentials!");
163 }
b65dfff5 164 authenticator.store_password(config.userid.name(), &password)?;
7d817b03
DM
165 }
166
579728c6
DM
167 Ok(())
168}
169
170#[api(
171 input: {
172 properties: {
173 userid: {
e7cb4dc5 174 type: Userid,
579728c6 175 },
685e1334 176 },
579728c6 177 },
b65dfff5 178 returns: { type: User },
d4f020f4 179 access: {
be3bd0f9
FG
180 permission: &Permission::Or(&[
181 &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
182 &Permission::UserParam("userid"),
183 ]),
d4f020f4 184 },
579728c6
DM
185)]
186/// Read user configuration data.
b65dfff5 187pub fn read_user(userid: Userid, mut rpcenv: &mut dyn RpcEnvironment) -> Result<User, Error> {
ba3d7e19 188 let (config, digest) = pbs_config::user::config()?;
e7cb4dc5 189 let user = config.lookup("user", userid.as_str())?;
522c0da0
DC
190 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
191 Ok(user)
579728c6
DM
192}
193
c0026563
DC
194#[api()]
195#[derive(Serialize, Deserialize)]
196#[serde(rename_all="kebab-case")]
197#[allow(non_camel_case_types)]
198pub enum DeletableProperty {
199 /// Delete the comment property.
200 comment,
201 /// Delete the firstname property.
202 firstname,
203 /// Delete the lastname property.
204 lastname,
205 /// Delete the email property.
206 email,
207}
208
579728c6
DM
209#[api(
210 protected: true,
211 input: {
212 properties: {
213 userid: {
e7cb4dc5 214 type: Userid,
579728c6 215 },
b65dfff5
DM
216 update: {
217 type: UserUpdater,
218 flatten: true,
579728c6
DM
219 },
220 password: {
221 schema: PBS_PASSWORD_SCHEMA,
222 optional: true,
223 },
c0026563
DC
224 delete: {
225 description: "List of properties to delete.",
226 type: Array,
227 optional: true,
228 items: {
229 type: DeletableProperty,
230 }
231 },
579728c6
DM
232 digest: {
233 optional: true,
234 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
235 },
236 },
237 },
d4f020f4 238 access: {
be3bd0f9
FG
239 permission: &Permission::Or(&[
240 &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
241 &Permission::UserParam("userid"),
242 ]),
d4f020f4 243 },
579728c6
DM
244)]
245/// Update user configuration.
367c0ff7 246#[allow(clippy::too_many_arguments)]
579728c6 247pub fn update_user(
e7cb4dc5 248 userid: Userid,
b65dfff5 249 update: UserUpdater,
579728c6 250 password: Option<String>,
c0026563 251 delete: Option<Vec<DeletableProperty>>,
579728c6 252 digest: Option<String>,
5aa10190 253 rpcenv: &mut dyn RpcEnvironment,
579728c6
DM
254) -> Result<(), Error> {
255
ba3d7e19 256 let _lock = pbs_config::user::lock_config()?;
579728c6 257
ba3d7e19 258 let (mut config, expected_digest) = pbs_config::user::config()?;
579728c6
DM
259
260 if let Some(ref digest) = digest {
261 let digest = proxmox::tools::hex_to_digest(digest)?;
262 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
263 }
264
b65dfff5 265 let mut data: User = config.lookup("user", userid.as_str())?;
579728c6 266
c0026563
DC
267 if let Some(delete) = delete {
268 for delete_prop in delete {
269 match delete_prop {
270 DeletableProperty::comment => data.comment = None,
271 DeletableProperty::firstname => data.firstname = None,
272 DeletableProperty::lastname => data.lastname = None,
273 DeletableProperty::email => data.email = None,
274 }
275 }
276 }
277
b65dfff5 278 if let Some(comment) = update.comment {
579728c6
DM
279 let comment = comment.trim().to_string();
280 if comment.is_empty() {
281 data.comment = None;
282 } else {
283 data.comment = Some(comment);
284 }
285 }
286
b65dfff5 287 if let Some(enable) = update.enable {
579728c6
DM
288 data.enable = if enable { None } else { Some(false) };
289 }
290
b65dfff5 291 if let Some(expire) = update.expire {
579728c6
DM
292 data.expire = if expire > 0 { Some(expire) } else { None };
293 }
294
295 if let Some(password) = password {
5aa10190
OB
296 let user_info = CachedUserInfo::new()?;
297 let current_auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
298 let self_service = current_auth_id.user() == &userid;
299 let target_realm = userid.realm();
300 if !self_service && target_realm == "pam" && !user_info.is_superuser(&current_auth_id) {
301 bail!("only superuser can edit pam credentials!");
302 }
e7cb4dc5
WB
303 let authenticator = crate::auth::lookup_authenticator(userid.realm())?;
304 authenticator.store_password(userid.name(), &password)?;
579728c6
DM
305 }
306
b65dfff5 307 if let Some(firstname) = update.firstname {
579728c6
DM
308 data.firstname = if firstname.is_empty() { None } else { Some(firstname) };
309 }
310
b65dfff5 311 if let Some(lastname) = update.lastname {
579728c6
DM
312 data.lastname = if lastname.is_empty() { None } else { Some(lastname) };
313 }
b65dfff5 314 if let Some(email) = update.email {
579728c6
DM
315 data.email = if email.is_empty() { None } else { Some(email) };
316 }
317
e7cb4dc5 318 config.set_data(userid.as_str(), "user", &data)?;
579728c6 319
ba3d7e19 320 pbs_config::user::save_config(&config)?;
579728c6
DM
321
322 Ok(())
323}
324
325#[api(
326 protected: true,
327 input: {
328 properties: {
329 userid: {
e7cb4dc5 330 type: Userid,
579728c6
DM
331 },
332 digest: {
333 optional: true,
334 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
335 },
336 },
337 },
d4f020f4 338 access: {
be3bd0f9
FG
339 permission: &Permission::Or(&[
340 &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
341 &Permission::UserParam("userid"),
342 ]),
d4f020f4 343 },
579728c6
DM
344)]
345/// Remove a user from the configuration file.
e7cb4dc5 346pub fn delete_user(userid: Userid, digest: Option<String>) -> Result<(), Error> {
579728c6 347
ba3d7e19 348 let _lock = pbs_config::user::lock_config()?;
f22dfb5e 349 let _tfa_lock = crate::config::tfa::write_lock()?;
b65dfff5 350
ba3d7e19 351 let (mut config, expected_digest) = pbs_config::user::config()?;
579728c6
DM
352
353 if let Some(ref digest) = digest {
354 let digest = proxmox::tools::hex_to_digest(digest)?;
355 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
356 }
357
e7cb4dc5
WB
358 match config.sections.get(userid.as_str()) {
359 Some(_) => { config.sections.remove(userid.as_str()); },
579728c6
DM
360 None => bail!("user '{}' does not exist.", userid),
361 }
362
ba3d7e19 363 pbs_config::user::save_config(&config)?;
579728c6 364
a4e871f5
DC
365 let authenticator = crate::auth::lookup_authenticator(userid.realm())?;
366 match authenticator.remove_password(userid.name()) {
367 Ok(()) => {},
368 Err(err) => {
369 eprintln!(
370 "error removing password after deleting user {:?}: {}",
371 userid, err
372 );
373 }
374 }
375
f22dfb5e
WB
376 match crate::config::tfa::read().and_then(|mut cfg| {
377 let _: bool = cfg.remove_user(&userid);
378 crate::config::tfa::write(&cfg)
379 }) {
380 Ok(()) => (),
381 Err(err) => {
382 eprintln!(
383 "error updating TFA config after deleting user {:?}: {}",
384 userid, err
385 );
386 }
387 }
388
579728c6
DM
389 Ok(())
390}
391
942078c4
FG
392#[api(
393 input: {
394 properties: {
395 userid: {
396 type: Userid,
397 },
f54634a8 398 "token-name": {
942078c4
FG
399 type: Tokenname,
400 },
401 },
402 },
b65dfff5 403 returns: { type: ApiToken },
942078c4
FG
404 access: {
405 permission: &Permission::Or(&[
406 &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
407 &Permission::UserParam("userid"),
408 ]),
409 },
410)]
411/// Read user's API token metadata
412pub fn read_token(
413 userid: Userid,
f54634a8 414 token_name: Tokenname,
942078c4
FG
415 _info: &ApiMethod,
416 mut rpcenv: &mut dyn RpcEnvironment,
b65dfff5 417) -> Result<ApiToken, Error> {
942078c4 418
ba3d7e19 419 let (config, digest) = pbs_config::user::config()?;
942078c4 420
f54634a8 421 let tokenid = Authid::from((userid, Some(token_name)));
942078c4
FG
422
423 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
424 config.lookup("token", &tokenid.to_string())
425}
426
427#[api(
428 protected: true,
429 input: {
430 properties: {
431 userid: {
432 type: Userid,
433 },
f54634a8 434 "token-name": {
942078c4
FG
435 type: Tokenname,
436 },
437 comment: {
438 optional: true,
439 schema: SINGLE_LINE_COMMENT_SCHEMA,
440 },
441 enable: {
b65dfff5 442 schema: ENABLE_USER_SCHEMA,
942078c4
FG
443 optional: true,
444 },
445 expire: {
b65dfff5 446 schema: EXPIRE_USER_SCHEMA,
942078c4
FG
447 optional: true,
448 },
449 digest: {
450 optional: true,
451 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
452 },
453 },
454 },
455 access: {
456 permission: &Permission::Or(&[
457 &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
458 &Permission::UserParam("userid"),
459 ]),
460 },
461 returns: {
462 description: "API token identifier + generated secret.",
463 properties: {
464 value: {
465 type: String,
466 description: "The API token secret",
467 },
468 tokenid: {
469 type: String,
470 description: "The API token identifier",
471 },
472 },
473 },
474)]
475/// Generate a new API token with given metadata
476pub fn generate_token(
477 userid: Userid,
f54634a8 478 token_name: Tokenname,
942078c4
FG
479 comment: Option<String>,
480 enable: Option<bool>,
481 expire: Option<i64>,
482 digest: Option<String>,
483) -> Result<Value, Error> {
484
ba3d7e19 485 let _lock = pbs_config::user::lock_config()?;
942078c4 486
ba3d7e19 487 let (mut config, expected_digest) = pbs_config::user::config()?;
942078c4
FG
488
489 if let Some(ref digest) = digest {
490 let digest = proxmox::tools::hex_to_digest(digest)?;
491 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
492 }
493
f54634a8 494 let tokenid = Authid::from((userid.clone(), Some(token_name.clone())));
942078c4
FG
495 let tokenid_string = tokenid.to_string();
496
3984a5fd 497 if config.sections.get(&tokenid_string).is_some() {
f54634a8 498 bail!("token '{}' for user '{}' already exists.", token_name.as_str(), userid);
942078c4
FG
499 }
500
6ef1b649 501 let secret = format!("{:x}", proxmox_uuid::Uuid::generate());
942078c4
FG
502 token_shadow::set_secret(&tokenid, &secret)?;
503
b65dfff5 504 let token = ApiToken {
44288184 505 tokenid,
942078c4
FG
506 comment,
507 enable,
508 expire,
509 };
510
511 config.set_data(&tokenid_string, "token", &token)?;
512
ba3d7e19 513 pbs_config::user::save_config(&config)?;
942078c4
FG
514
515 Ok(json!({
516 "tokenid": tokenid_string,
517 "value": secret
518 }))
519}
520
521#[api(
522 protected: true,
523 input: {
524 properties: {
525 userid: {
526 type: Userid,
527 },
f54634a8 528 "token-name": {
942078c4
FG
529 type: Tokenname,
530 },
531 comment: {
532 optional: true,
533 schema: SINGLE_LINE_COMMENT_SCHEMA,
534 },
535 enable: {
b65dfff5 536 schema: ENABLE_USER_SCHEMA,
942078c4
FG
537 optional: true,
538 },
539 expire: {
b65dfff5 540 schema: EXPIRE_USER_SCHEMA,
942078c4
FG
541 optional: true,
542 },
543 digest: {
544 optional: true,
545 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
546 },
547 },
548 },
549 access: {
550 permission: &Permission::Or(&[
551 &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
552 &Permission::UserParam("userid"),
553 ]),
554 },
555)]
556/// Update user's API token metadata
557pub fn update_token(
558 userid: Userid,
f54634a8 559 token_name: Tokenname,
942078c4
FG
560 comment: Option<String>,
561 enable: Option<bool>,
562 expire: Option<i64>,
563 digest: Option<String>,
564) -> Result<(), Error> {
565
ba3d7e19 566 let _lock = pbs_config::user::lock_config()?;
942078c4 567
ba3d7e19 568 let (mut config, expected_digest) = pbs_config::user::config()?;
942078c4
FG
569
570 if let Some(ref digest) = digest {
571 let digest = proxmox::tools::hex_to_digest(digest)?;
572 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
573 }
574
f54634a8 575 let tokenid = Authid::from((userid, Some(token_name)));
942078c4
FG
576 let tokenid_string = tokenid.to_string();
577
b65dfff5 578 let mut data: ApiToken = config.lookup("token", &tokenid_string)?;
942078c4
FG
579
580 if let Some(comment) = comment {
581 let comment = comment.trim().to_string();
582 if comment.is_empty() {
583 data.comment = None;
584 } else {
585 data.comment = Some(comment);
586 }
587 }
588
589 if let Some(enable) = enable {
590 data.enable = if enable { None } else { Some(false) };
591 }
592
593 if let Some(expire) = expire {
594 data.expire = if expire > 0 { Some(expire) } else { None };
595 }
596
597 config.set_data(&tokenid_string, "token", &data)?;
598
ba3d7e19 599 pbs_config::user::save_config(&config)?;
942078c4
FG
600
601 Ok(())
602}
603
604#[api(
605 protected: true,
606 input: {
607 properties: {
608 userid: {
609 type: Userid,
610 },
f54634a8 611 "token-name": {
942078c4
FG
612 type: Tokenname,
613 },
614 digest: {
615 optional: true,
616 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
617 },
618 },
619 },
620 access: {
621 permission: &Permission::Or(&[
622 &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
623 &Permission::UserParam("userid"),
624 ]),
625 },
626)]
627/// Delete a user's API token
628pub fn delete_token(
629 userid: Userid,
f54634a8 630 token_name: Tokenname,
942078c4
FG
631 digest: Option<String>,
632) -> Result<(), Error> {
633
ba3d7e19 634 let _lock = pbs_config::user::lock_config()?;
942078c4 635
ba3d7e19 636 let (mut config, expected_digest) = pbs_config::user::config()?;
942078c4
FG
637
638 if let Some(ref digest) = digest {
639 let digest = proxmox::tools::hex_to_digest(digest)?;
640 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
641 }
642
f54634a8 643 let tokenid = Authid::from((userid.clone(), Some(token_name.clone())));
942078c4
FG
644 let tokenid_string = tokenid.to_string();
645
646 match config.sections.get(&tokenid_string) {
647 Some(_) => { config.sections.remove(&tokenid_string); },
f54634a8 648 None => bail!("token '{}' of user '{}' does not exist.", token_name.as_str(), userid),
942078c4
FG
649 }
650
651 token_shadow::delete_secret(&tokenid)?;
652
ba3d7e19 653 pbs_config::user::save_config(&config)?;
942078c4
FG
654
655 Ok(())
656}
657
f54634a8
DC
658#[api(
659 properties: {
660 "token-name": { type: Tokenname },
661 token: { type: ApiToken },
662 }
663)]
664#[derive(Serialize, Deserialize)]
665#[serde(rename_all="kebab-case")]
666/// A Token Entry that contains the token-name
667pub struct TokenApiEntry {
668 /// The Token name
669 pub token_name: Tokenname,
670 #[serde(flatten)]
671 pub token: ApiToken,
672}
673
942078c4
FG
674#[api(
675 input: {
676 properties: {
677 userid: {
678 type: Userid,
679 },
680 },
681 },
682 returns: {
683 description: "List user's API tokens (with config digest).",
684 type: Array,
f54634a8 685 items: { type: TokenApiEntry },
942078c4
FG
686 },
687 access: {
688 permission: &Permission::Or(&[
689 &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
690 &Permission::UserParam("userid"),
691 ]),
692 },
693)]
694/// List user's API tokens
695pub fn list_tokens(
696 userid: Userid,
697 _info: &ApiMethod,
698 mut rpcenv: &mut dyn RpcEnvironment,
f54634a8 699) -> Result<Vec<TokenApiEntry>, Error> {
942078c4 700
ba3d7e19 701 let (config, digest) = pbs_config::user::config()?;
942078c4 702
b65dfff5 703 let list:Vec<ApiToken> = config.convert_to_typed_array("token")?;
942078c4
FG
704
705 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
706
f54634a8
DC
707 let filter_by_owner = |token: ApiToken| {
708 if token.tokenid.is_token() && token.tokenid.user() == &userid {
709 let token_name = token.tokenid.tokenname().unwrap().to_owned();
710 Some(TokenApiEntry {
711 token_name,
712 token,
713 })
942078c4 714 } else {
f54634a8 715 None
942078c4
FG
716 }
717 };
718
f54634a8
DC
719 let res = list.into_iter().filter_map(filter_by_owner).collect();
720
721 Ok(res)
942078c4
FG
722}
723
724const TOKEN_ITEM_ROUTER: Router = Router::new()
725 .get(&API_METHOD_READ_TOKEN)
726 .put(&API_METHOD_UPDATE_TOKEN)
727 .post(&API_METHOD_GENERATE_TOKEN)
728 .delete(&API_METHOD_DELETE_TOKEN);
729
730const TOKEN_ROUTER: Router = Router::new()
731 .get(&API_METHOD_LIST_TOKENS)
f54634a8 732 .match_all("token-name", &TOKEN_ITEM_ROUTER);
942078c4
FG
733
734const USER_SUBDIRS: SubdirMap = &[
735 ("token", &TOKEN_ROUTER),
736];
737
738const USER_ROUTER: Router = Router::new()
579728c6
DM
739 .get(&API_METHOD_READ_USER)
740 .put(&API_METHOD_UPDATE_USER)
942078c4
FG
741 .delete(&API_METHOD_DELETE_USER)
742 .subdirs(USER_SUBDIRS);
579728c6
DM
743
744pub const ROUTER: Router = Router::new()
745 .get(&API_METHOD_LIST_USERS)
746 .post(&API_METHOD_CREATE_USER)
942078c4 747 .match_all("userid", &USER_ROUTER);