1 use std
::collections
::HashMap
;
4 use lazy_static
::lazy_static
;
5 use serde
::{Serialize, Deserialize}
;
7 use proxmox_schema
::{api, ApiType, Updater, Schema}
;
8 use proxmox_section_config
::{SectionConfig, SectionConfigData, SectionConfigPlugin}
;
10 use pbs_api_types
::{REALM_ID_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA}
;
11 use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard}
;
14 pub static ref CONFIG
: SectionConfig
= init();
18 #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
19 #[serde(rename_all = "lowercase")]
20 /// Use the value of this attribute/claim as unique user name. It is
21 /// up to the identity provider to guarantee the uniqueness. The
22 /// OpenID specification only guarantees that Subject ('sub') is unique. Also
23 /// make sure that the user is not allowed to change that attribute by
25 pub enum OpenIdUserAttribute
{
26 /// Subject (OpenId 'sub' claim)
28 /// Username (OpenId 'preferred_username' claim)
30 /// Email (OpenId 'email' claim)
37 schema
: REALM_ID_SCHEMA
,
44 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
51 type: OpenIdUserAttribute
,
56 #[derive(Serialize, Deserialize, Updater)]
57 #[serde(rename_all="kebab-case")]
58 /// OpenID configuration properties.
59 pub struct OpenIdRealmConfig
{
63 pub issuer_url
: String
,
65 pub client_id
: String
,
67 #[serde(skip_serializing_if="Option::is_none")]
68 pub client_key
: Option
<String
>,
69 #[serde(skip_serializing_if="Option::is_none")]
70 pub comment
: Option
<String
>,
71 /// Automatically create users if they do not exist.
72 #[serde(skip_serializing_if="Option::is_none")]
73 pub autocreate
: Option
<bool
>,
75 #[serde(skip_serializing_if="Option::is_none")]
76 pub username_claim
: Option
<OpenIdUserAttribute
>,
79 fn init() -> SectionConfig
{
80 let obj_schema
= match OpenIdRealmConfig
::API_SCHEMA
{
81 Schema
::Object(ref obj_schema
) => obj_schema
,
85 let plugin
= SectionConfigPlugin
::new("openid".to_string(), Some(String
::from("realm")), obj_schema
);
86 let mut config
= SectionConfig
::new(&REALM_ID_SCHEMA
);
87 config
.register_plugin(plugin
);
92 pub const DOMAINS_CFG_FILENAME
: &str = "/etc/proxmox-backup/domains.cfg";
93 pub const DOMAINS_CFG_LOCKFILE
: &str = "/etc/proxmox-backup/.domains.lck";
95 /// Get exclusive lock
96 pub fn lock_config() -> Result
<BackupLockGuard
, Error
> {
97 open_backup_lockfile(DOMAINS_CFG_LOCKFILE
, None
, true)
100 pub fn config() -> Result
<(SectionConfigData
, [u8;32]), Error
> {
102 let content
= proxmox
::tools
::fs
::file_read_optional_string(DOMAINS_CFG_FILENAME
)?
103 .unwrap_or_else(|| "".to_string());
105 let digest
= openssl
::sha
::sha256(content
.as_bytes());
106 let data
= CONFIG
.parse(DOMAINS_CFG_FILENAME
, &content
)?
;
110 pub fn save_config(config
: &SectionConfigData
) -> Result
<(), Error
> {
111 let raw
= CONFIG
.write(DOMAINS_CFG_FILENAME
, &config
)?
;
112 replace_backup_config(DOMAINS_CFG_FILENAME
, raw
.as_bytes())
115 // shell completion helper
116 pub fn complete_realm_name(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
118 Ok((data
, _digest
)) => data
.sections
.iter().map(|(id
, _
)| id
.to_string()).collect(),
119 Err(_
) => return vec
![],
123 pub fn complete_openid_realm_name(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
125 Ok((data
, _digest
)) => data
.sections
.iter()
126 .filter_map(|(id
, (t
, _
))| if t
== "openid" { Some(id.to_string()) }
else { None }
)
128 Err(_
) => return vec
![],