all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes
@ 2021-08-06 11:57 Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH pve-rs] depend on proxmox-openid 0.7.0, bump version to 0.3.0 Dietmar Maurer
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

---
 src/lib.rs | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 72bcd31..dcd08dd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -34,16 +34,19 @@ use openidconnect::{
     Scope,
 };
 
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Debug, Deserialize, Serialize, Clone)]
 pub struct OpenIdConfig {
     pub issuer_url: String,
     pub client_id: String,
     #[serde(skip_serializing_if="Option::is_none")]
     pub client_key: Option<String>,
+    #[serde(skip_serializing_if="Option::is_none")]
+    pub scopes: Option<Vec<String>>,
 }
 
 pub struct OpenIdAuthenticator {
     client: CoreClient,
+    config: OpenIdConfig,
 }
 
 #[derive(Debug, Deserialize, Serialize)]
@@ -111,6 +114,7 @@ impl OpenIdAuthenticator {
 
         Ok(Self {
             client,
+            config: config.clone(),
         })
     }
 
@@ -123,18 +127,25 @@ impl OpenIdAuthenticator {
         store_auth_state(Path::new(state_dir), realm, &private_auth_state)?;
 
          // Generate the authorization URL to which we'll redirect the user.
-        let (authorize_url, _csrf_state, _nonce) = self.client
+        let mut request = self.client
             .authorize_url(
                 CoreAuthenticationFlow::AuthorizationCode,
                 || CsrfToken::new(public_auth_state),
                 || nonce,
             )
-            .set_display(CoreAuthDisplay::Page)
-            .add_prompt(CoreAuthPrompt::Login)
-            .add_scope(Scope::new("email".to_string()))
-            .add_scope(Scope::new("profile".to_string()))
-            .set_pkce_challenge(private_auth_state.pkce_challenge())
-            .url();
+            .set_pkce_challenge(private_auth_state.pkce_challenge());
+
+        request = request.set_display(CoreAuthDisplay::Page);
+
+        request = request.add_prompt(CoreAuthPrompt::Login);
+
+        if let Some(ref scopes) = self.config.scopes {
+            for scope in scopes.clone() {
+                request = request.add_scope(Scope::new(scope));
+            }
+        }
+
+        let (authorize_url, _csrf_state, _nonce) = request.url();
 
         Ok(authorize_url.to_string())
     }
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH pve-rs] depend on proxmox-openid 0.7.0, bump version to 0.3.0
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-backup v2] openid: allow to configure scopes, prompt, ACRs and arbitrary username-claim values Dietmar Maurer
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

---
 Cargo.toml        | 2 +-
 debian/changelog  | 8 ++++++++
 src/openid/mod.rs | 2 +-
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 736bc49..ef8c27c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,5 +20,5 @@ anyhow = "1.0"
 proxmox = { version = "0.12.1", default-features = false }
 perlmod = { version = "0.5.2", features = [ "exporter" ] }
 proxmox-apt = "0.6.0"
-proxmox-openid = "0.6.1"
+proxmox-openid = "0.7.0"
 serde = "1.0"
diff --git a/debian/changelog b/debian/changelog
index b247a35..33ab4a6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+libpve-rs-perl (0.3.0) bullseye; urgency=medium
+
+  * depend on proxmox-openid 0.7.0 (support prompt an d scopes)
+
+  * openid: use new verify_authorization_code_simple() to return all claims
+
+ -- Proxmox Support Team <support@proxmox.com>  Fri, 06 Aug 2021 08:48:59 +0200
+
 libpve-rs-perl (0.2.3) bullseye; urgency=medium
 
   * use newer dependencies for apt to improve repo+suite handling
diff --git a/src/openid/mod.rs b/src/openid/mod.rs
index febe927..aa31f9c 100644
--- a/src/openid/mod.rs
+++ b/src/openid/mod.rs
@@ -81,7 +81,7 @@ mod export {
     ) -> Result<Value, Error> {
 
         let open_id = this.inner.lock().unwrap();
-        let claims = open_id.verify_authorization_code(code, &private_auth_state)?;
+        let claims = open_id.verify_authorization_code_simple(code, &private_auth_state)?;
 
         Ok(to_value(&claims)?)
     }
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH proxmox-backup v2] openid: allow to configure scopes, prompt, ACRs and arbitrary username-claim values
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH pve-rs] depend on proxmox-openid 0.7.0, bump version to 0.3.0 Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH pve-access-control] openid: support " Dietmar Maurer
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

- no longer set prompt to 'login' (makes auto-login possible)
- new prompt configuration
- allow arbitrary username-claim values

Depend on proxmox-openid 0.7.0.
---

Changes in v2;
- support ACRs
- no update API for im username-claim

 Cargo.toml                       |  2 +-
 pbs-api-types/src/lib.rs         | 48 ++++++++++++++++++++++-
 src/api2/access/openid.rs        | 65 ++++++++++++++++++++++----------
 src/api2/config/access/openid.rs | 29 ++++++++++++++
 src/config/domains.rs            | 41 ++++++++++----------
 5 files changed, 145 insertions(+), 40 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index c6141842..e71b87ba 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -92,7 +92,7 @@ proxmox = { version = "0.12.1", features = [ "sortable-macro", "api-macro", "cli
 proxmox-acme-rs = "0.2.1"
 proxmox-apt = "0.6.0"
 proxmox-http = { version = "0.3.0", features = [ "client", "http-helpers", "websocket" ] }
-proxmox-openid = "0.6.1"
+proxmox-openid = "0.7.0"
 
 pbs-api-types = { path = "pbs-api-types" }
 pbs-buildcfg = { path = "pbs-buildcfg" }
diff --git a/pbs-api-types/src/lib.rs b/pbs-api-types/src/lib.rs
index 576099eb..ee497789 100644
--- a/pbs-api-types/src/lib.rs
+++ b/pbs-api-types/src/lib.rs
@@ -3,7 +3,7 @@
 use serde::{Deserialize, Serialize};
 
 use proxmox::api::api;
-use proxmox::api::schema::{ApiStringFormat, EnumEntry, IntegerSchema, Schema, StringSchema};
+use proxmox::api::schema::{ApiStringFormat, EnumEntry, IntegerSchema, Schema, StringSchema, ArraySchema};
 use proxmox::const_regex;
 use proxmox::{IPRE, IPRE_BRACKET, IPV4OCTET, IPV4RE, IPV6H16, IPV6LS32, IPV6RE};
 
@@ -184,6 +184,52 @@ pub const PRUNE_SCHEMA_KEEP_YEARLY: Schema =
 pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat =
     ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
 
+pub const OPENID_SCOPE_FORMAT: ApiStringFormat =
+    ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
+
+pub const OPENID_SCOPE_SCHEMA: Schema = StringSchema::new("OpenID Scope Name.")
+    .format(&OPENID_SCOPE_FORMAT)
+    .schema();
+
+pub const OPENID_SCOPE_ARRAY_SCHEMA: Schema = ArraySchema::new(
+    "Array of OpenId Scopes.", &OPENID_SCOPE_SCHEMA).schema();
+
+pub const OPENID_SCOPE_LIST_FORMAT: ApiStringFormat =
+    ApiStringFormat::PropertyString(&OPENID_SCOPE_ARRAY_SCHEMA);
+
+pub const OPENID_DEFAILT_SCOPE_LIST: &'static str = "email profile";
+pub const OPENID_SCOPE_LIST_SCHEMA: Schema = StringSchema::new("OpenID Scope List")
+    .format(&OPENID_SCOPE_LIST_FORMAT)
+    .default(OPENID_DEFAILT_SCOPE_LIST)
+    .schema();
+
+pub const OPENID_ACR_FORMAT: ApiStringFormat =
+    ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
+
+pub const OPENID_ACR_SCHEMA: Schema = StringSchema::new("OpenID Authentication Context Class Reference.")
+    .format(&OPENID_SCOPE_FORMAT)
+    .schema();
+
+pub const OPENID_ACR_ARRAY_SCHEMA: Schema = ArraySchema::new(
+    "Array of OpenId ACRs.", &OPENID_ACR_SCHEMA).schema();
+
+pub const OPENID_ACR_LIST_FORMAT: ApiStringFormat =
+    ApiStringFormat::PropertyString(&OPENID_ACR_ARRAY_SCHEMA);
+
+pub const OPENID_ACR_LIST_SCHEMA: Schema = StringSchema::new("OpenID ACR List")
+    .format(&OPENID_ACR_LIST_FORMAT)
+    .schema();
+
+pub const OPENID_USERNAME_CLAIM_SCHEMA: Schema = StringSchema::new(
+    "Use the value of this attribute/claim as unique user name. It \
+    is up to the identity provider to guarantee the uniqueness. The \
+    OpenID specification only guarantees that Subject ('sub') is \
+    unique. Also make sure that the user is not allowed to change that \
+    attribute by himself!")
+    .max_length(64)
+    .min_length(1)
+    .format(&PROXMOX_SAFE_ID_FORMAT) .schema();
+
 pub const SINGLE_LINE_COMMENT_FORMAT: ApiStringFormat =
     ApiStringFormat::Pattern(&SINGLE_LINE_COMMENT_REGEX);
 
diff --git a/src/api2/access/openid.rs b/src/api2/access/openid.rs
index f78e4674..34dc9789 100644
--- a/src/api2/access/openid.rs
+++ b/src/api2/access/openid.rs
@@ -18,7 +18,7 @@ use pbs_tools::ticket::Ticket;
 
 use crate::server::ticket::ApiTicket;
 
-use crate::config::domains::{OpenIdUserAttribute, OpenIdRealmConfig};
+use crate::config::domains::OpenIdRealmConfig;
 use crate::config::cached_user_info::CachedUserInfo;
 
 use crate::backup::open_backup_lockfile;
@@ -27,15 +27,35 @@ use crate::api2::types::*;
 use crate::auth_helpers::*;
 
 fn openid_authenticator(realm_config: &OpenIdRealmConfig, redirect_url: &str) -> Result<OpenIdAuthenticator, Error> {
+
+    let scopes: Vec<String> = realm_config.scopes.as_deref().unwrap_or(OPENID_DEFAILT_SCOPE_LIST)
+        .split(|c: char| c == ',' || c == ';' || char::is_ascii_whitespace(&c))
+        .filter(|s| !s.is_empty())
+        .map(String::from)
+        .collect();
+
+    let mut acr_values = None;
+    if let Some(ref list) = realm_config.acr_values {
+        acr_values = Some(
+            list
+                .split(|c: char| c == ',' || c == ';' || char::is_ascii_whitespace(&c))
+                .filter(|s| !s.is_empty())
+                .map(String::from)
+                .collect()
+        );
+   }
+
     let config = OpenIdConfig {
         issuer_url: realm_config.issuer_url.clone(),
         client_id: realm_config.client_id.clone(),
         client_key: realm_config.client_key.clone(),
+        prompt: realm_config.prompt.clone(),
+        scopes: Some(scopes),
+        acr_values,
     };
     OpenIdAuthenticator::discover(&config, redirect_url)
 }
 
-
 #[api(
     input: {
         properties: {
@@ -93,22 +113,29 @@ pub fn openid_login(
 
     let open_id = openid_authenticator(&config, &redirect_url)?;
 
-    let info = open_id.verify_authorization_code(&code, &private_auth_state)?;
+    let info = open_id.verify_authorization_code_simple(&code, &private_auth_state)?;
 
-    // eprintln!("VERIFIED {} {:?} {:?}", info.subject().as_str(), info.name(), info.email());
+    // eprintln!("VERIFIED {:?}", info);
 
-    let unique_name = match config.username_claim {
-        None | Some(OpenIdUserAttribute::Subject) => info.subject().as_str(),
-        Some(OpenIdUserAttribute::Username) => {
-            match info.preferred_username() {
-                Some(name) => name.as_str(),
-                None => bail!("missing claim 'preferred_name'"),
-            }
-        }
-        Some(OpenIdUserAttribute::Email) => {
-            match info.email() {
-                Some(name) => name.as_str(),
-                None => bail!("missing claim 'email'"),
+    let name_attr = config.username_claim.as_deref().unwrap_or("sub");
+
+    // Try to be compatible with previous versions
+    let try_attr = match name_attr {
+        "subject" => Some("sub"),
+        "username" => Some("preferred_username"),
+        _ => None,
+    };
+
+    let unique_name = match info[name_attr].as_str() {
+        Some(name) => name.to_owned(),
+        None => {
+            if let Some(try_attr) = try_attr {
+                match info[try_attr].as_str() {
+                    Some(name) => name.to_owned(),
+                    None => bail!("missing claim '{}'", name_attr),
+                }
+            } else {
+                bail!("missing claim '{}'", name_attr);
             }
         }
     };
@@ -124,9 +151,9 @@ pub fn openid_login(
                 comment: None,
                 enable: None,
                 expire: None,
-                firstname: info.given_name().and_then(|n| n.get(None)).map(|n| n.to_string()),
-                lastname: info.family_name().and_then(|n| n.get(None)).map(|n| n.to_string()),
-                email: info.email().map(|e| e.to_string()),
+                firstname: info["given_name"].as_str().map(|n| n.to_string()),
+                lastname: info["family_name"].as_str().map(|n| n.to_string()),
+                email: info["email"].as_str().map(|e| e.to_string()),
             };
             let (mut config, _digest) = user::config()?;
             if config.sections.get(user.userid.as_str()).is_some() {
diff --git a/src/api2/config/access/openid.rs b/src/api2/config/access/openid.rs
index b8b07306..06079e4e 100644
--- a/src/api2/config/access/openid.rs
+++ b/src/api2/config/access/openid.rs
@@ -155,6 +155,12 @@ pub enum DeletableProperty {
     comment,
     /// Delete the autocreate property
     autocreate,
+    /// Delete the scopes property
+    scopes,
+    /// Delete the prompt property
+    prompt,
+    /// Delete the acr_values property
+    acr_values,
 }
 
 #[api(
@@ -179,6 +185,20 @@ pub enum DeletableProperty {
                 type: String,
                 optional: true,
             },
+            "scopes": {
+                schema: OPENID_SCOPE_LIST_SCHEMA,
+                optional: true,
+            },
+            "acr-values": {
+                schema: OPENID_ACR_LIST_SCHEMA,
+                optional: true,
+            },
+            prompt: {
+                description: "OpenID Prompt",
+                type: String,
+                format: &PROXMOX_SAFE_ID_FORMAT,
+                optional: true,
+            },
             autocreate: {
                 description: "Automatically create users if they do not exist.",
                 optional: true,
@@ -213,6 +233,9 @@ pub fn update_openid_realm(
     issuer_url: Option<String>,
     client_id: Option<String>,
     client_key: Option<String>,
+    scopes: Option<String>,
+    acr_values: Option<String>,
+    prompt: Option<String>,
     autocreate: Option<bool>,
     comment: Option<String>,
     delete: Option<Vec<DeletableProperty>>,
@@ -237,6 +260,9 @@ pub fn update_openid_realm(
                 DeletableProperty::client_key => { config.client_key = None; },
                 DeletableProperty::comment => { config.comment = None; },
                 DeletableProperty::autocreate => { config.autocreate = None; },
+                DeletableProperty::scopes => { config.scopes = None; },
+                DeletableProperty::prompt => { config.prompt = None; },
+                DeletableProperty::acr_values => { config.acr_values = None; },
             }
         }
     }
@@ -255,6 +281,9 @@ pub fn update_openid_realm(
 
     if client_key.is_some() { config.client_key = client_key; }
     if autocreate.is_some() { config.autocreate = autocreate; }
+    if scopes.is_some() { config.scopes = scopes; }
+    if prompt.is_some() { config.prompt = prompt; }
+    if acr_values.is_some() { config.acr_values = acr_values; }
 
     domains.set_data(&realm, "openid", &config)?;
 
diff --git a/src/config/domains.rs b/src/config/domains.rs
index 0d695777..f227410f 100644
--- a/src/config/domains.rs
+++ b/src/config/domains.rs
@@ -20,23 +20,6 @@ lazy_static! {
     pub static ref CONFIG: SectionConfig = init();
 }
 
-#[api()]
-#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
-#[serde(rename_all = "lowercase")]
-/// Use the value of this attribute/claim as unique user name. It is
-/// up to the identity provider to guarantee the uniqueness. The
-/// OpenID specification only guarantees that Subject ('sub') is unique. Also
-/// make sure that the user is not allowed to change that attribute by
-/// himself!
-pub enum OpenIdUserAttribute {
-    /// Subject (OpenId 'sub' claim)
-    Subject,
-    /// Username (OpenId 'preferred_username' claim)
-    Username,
-    /// Email (OpenId 'email' claim)
-    Email,
-}
-
 #[api(
     properties: {
         realm: {
@@ -55,6 +38,20 @@ pub enum OpenIdUserAttribute {
             type: String,
             optional: true,
         },
+        "scopes": {
+            schema: OPENID_SCOPE_LIST_SCHEMA,
+            optional: true,
+        },
+        "acr-values": {
+            schema: OPENID_ACR_LIST_SCHEMA,
+            optional: true,
+        },
+        prompt: {
+            description: "OpenID Prompt",
+            type: String,
+            format: &PROXMOX_SAFE_ID_FORMAT,
+            optional: true,
+        },
         comment: {
             optional: true,
             schema: SINGLE_LINE_COMMENT_SCHEMA,
@@ -66,7 +63,7 @@ pub enum OpenIdUserAttribute {
             default: false,
         },
         "username-claim": {
-            type: OpenIdUserAttribute,
+            schema: OPENID_USERNAME_CLAIM_SCHEMA,
             optional: true,
         },
     },
@@ -79,13 +76,19 @@ pub struct OpenIdRealmConfig {
     pub issuer_url: String,
     pub client_id: String,
     #[serde(skip_serializing_if="Option::is_none")]
+    pub scopes: Option<String>,
+    #[serde(skip_serializing_if="Option::is_none")]
+    pub acr_values: Option<String>,
+    #[serde(skip_serializing_if="Option::is_none")]
+    pub prompt: Option<String>,
+    #[serde(skip_serializing_if="Option::is_none")]
     pub client_key: Option<String>,
     #[serde(skip_serializing_if="Option::is_none")]
     pub comment: Option<String>,
     #[serde(skip_serializing_if="Option::is_none")]
     pub autocreate: Option<bool>,
     #[serde(skip_serializing_if="Option::is_none")]
-    pub username_claim: Option<OpenIdUserAttribute>,
+    pub username_claim: Option<String>,
 }
 
 fn init() -> SectionConfig {
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH pve-access-control] openid: support scopes, prompt, ACRs and arbitrary username-claim values
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH pve-rs] depend on proxmox-openid 0.7.0, bump version to 0.3.0 Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-backup v2] openid: allow to configure scopes, prompt, ACRs and arbitrary username-claim values Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 2/6] also return data from UserInfo endpoint Dietmar Maurer
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

Depend on libpve-rs-perl (>= 0.3.0)
---
 debian/control         |  4 ++--
 src/PVE/API2/OpenId.pm | 30 ++++++++++++++++++---------
 src/PVE/Auth/OpenId.pm | 47 +++++++++++++++++++++++++++++++++++++++---
 3 files changed, 66 insertions(+), 15 deletions(-)

diff --git a/debian/control b/debian/control
index 3ef748b..3323d9b 100644
--- a/debian/control
+++ b/debian/control
@@ -10,7 +10,7 @@ Build-Depends: debhelper (>= 12~),
                lintian,
                perl,
                libpve-cluster-perl,
-	       libpve-rs-perl,
+	       libpve-rs-perl (>= 0.3.0),
                pve-cluster (>= 6.1-4),
                pve-doc-generator (>= 5.3-3),
 Standards-Version: 4.5.1
@@ -28,7 +28,7 @@ Depends: libauthen-pam-perl,
          libnet-ssleay-perl,
          libpve-common-perl (>= 6.0-18),
          libpve-cluster-perl,
-	 libpve-rs-perl,
+	 libpve-rs-perl (>= 0.3.0),
          libpve-u2f-server-perl (>= 1.0-2),
          libuuid-perl,
          pve-cluster (>= 6.1-4),
diff --git a/src/PVE/API2/OpenId.pm b/src/PVE/API2/OpenId.pm
index 22423ba..0357b65 100644
--- a/src/PVE/API2/OpenId.pm
+++ b/src/PVE/API2/OpenId.pm
@@ -35,8 +35,21 @@ my $lookup_openid_auth = sub {
 	issuer_url => $config->{'issuer-url'},
 	client_id => $config->{'client-id'},
 	client_key => $config->{'client-key'},
+	prompt => $config->{'prompt'},
     };
 
+    if (defined(my $value = $config->{'scopes'})) {
+	my $scopes = [PVE::Tools::split_list($value)];
+	$openid_config->{'scopes'} = $scopes;
+    } else {
+	$openid_config->{'scopes'} = ['email', 'profile'];
+    }
+
+    if (defined(my $value = $config->{'acr-values'})) {
+	my $list = [PVE::Tools::split_list($value)];
+	$openid_config->{'acr_values'} = $list;
+    }
+
     my $openid = PVE::RS::OpenId->discover($openid_config, $redirect_url);
     return ($config, $openid);
 };
@@ -163,18 +176,15 @@ __PACKAGE__->register_method ({
 
 	    my $unique_name = $subject; # default
 	    if (defined(my $user_attr = $config->{'username-claim'})) {
-		if ($user_attr eq 'subject') {
+
+		if (defined(my $value = $info->{$user_attr})) {
+		    $unique_name = $value;
+		} elsif ($user_attr == 'subject') {
 		    $unique_name = $subject;
-		} elsif ($user_attr eq 'username') {
-		    my $username = $info->{'preferred_username'};
-		    die "missing claim 'preferred_username'\n" if !defined($username);
-		    $unique_name =  $username;
-		} elsif ($user_attr eq 'email') {
-		    my $email = $info->{'email'};
-		    die "missing claim 'email'\n" if !defined($email);
-		    $unique_name = $email;
+		} elsif ($user_attr == 'username' && defined(my $name = $info->{'preferred_username'})) {
+		    $unique_name = $name;
 		} else {
-		    die "got unexpected value for 'username-claim': '${user_attr}'\n";
+		    die "mising claim '${user_attr}'\n";
 		}
 	    }
 
diff --git a/src/PVE/Auth/OpenId.pm b/src/PVE/Auth/OpenId.pm
index 515d2f4..0c82aeb 100755
--- a/src/PVE/Auth/OpenId.pm
+++ b/src/PVE/Auth/OpenId.pm
@@ -6,9 +6,30 @@ use warnings;
 use PVE::Tools;
 use PVE::Auth::Plugin;
 use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::JSONSchema qw(get_standard_option register_standard_option);
 
 use base qw(PVE::Auth::Plugin);
 
+PVE::JSONSchema::register_format('openid-simple-name', \&verify_openid_simple_name);
+sub verify_openid_simple_name {
+    my ($name, $noerr) = @_;
+
+    if ($name !~ m/^[A-Za-z0-9\.\-_]+$/) {
+
+	die "OpenId name '$name' contains invalid characters\n" if !$noerr;
+
+	return undef;
+    }
+
+    return $name;
+}
+
+register_standard_option('openid-scope', {
+    description => 'OpenID scope',
+    type => 'string',
+    format => 'openid-simple-name',
+});
+
 sub type {
     return 'openid';
 }
@@ -30,8 +51,25 @@ sub properties {
 	    type => 'string',
 	    optional => 1,
 	    maxLength => 256,
-       },
-       autocreate => {
+	},
+	scopes => {
+	    description => 'List of OpenID scopes',
+	    type => 'string', format => 'openid-simple-name-list',
+	    optional => 1,
+	    default => 'email, profile',
+	},
+        "acr-values" => {
+	    description => 'List of OpenID ACRs.',
+	    type => 'string', format => 'openid-simple-name-list',
+	    optional => 1,
+        },
+	prompt => {
+            description => "OpenID Prompt settings.",
+	    type => 'string',
+	    format => 'openid-simple-name',
+	    optional => 1,
+        },
+	autocreate => {
 	   description => "Automatically create users if they do not exist.",
 	   optional => 1,
 	   type => 'boolean',
@@ -40,7 +78,7 @@ sub properties {
        "username-claim" => {
 	   description => "OpenID claim used to generate the unique username.",
 	   type => 'string',
-	   enum => ['subject', 'username', 'email'],
+	   format => 'openid-simple-name',
 	   optional => 1,
        },
    };
@@ -53,6 +91,9 @@ sub options {
 	 "client-key" => { optional => 1 },
 	 autocreate => { optional => 1 },
 	 "username-claim" => { optional => 1, fixed => 1 },
+	 scopes => { optional => 1 },
+	 prompt => { optional => 1 },
+	 "acr-values" => { optional => 1 },
 	 default => { optional => 1 },
 	 comment => { optional => 1 },
     };
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH proxmox-openid-rs v2 2/6] also return data from UserInfo endpoint
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
                   ` (2 preceding siblings ...)
  2021-08-06 11:57 ` [pbs-devel] [PATCH pve-access-control] openid: support " Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 3/6] new helper verify_authorization_code_simple() Dietmar Maurer
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

---
 src/lib.rs | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index dcd08dd..abcd06e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,6 +20,7 @@ use openidconnect::{
         CoreAuthenticationFlow,
         CoreAuthDisplay,
         CoreAuthPrompt,
+        CoreGenderClaim,
     },
     PkceCodeChallenge,
     PkceCodeVerifier,
@@ -32,9 +33,18 @@ use openidconnect::{
     OAuth2TokenResponse,
     RedirectUrl,
     Scope,
+    UserInfoClaims,
+    AdditionalClaims,
 };
 
-#[derive(Debug, Deserialize, Serialize, Clone)]
+/// Stores Additional Claims into a serde_json::Value;
+#[derive(Debug, Deserialize, Serialize)]
+pub struct GenericClaims(serde_json::Value);
+impl AdditionalClaims for GenericClaims {}
+
+pub type GenericUserInfoClaims = UserInfoClaims<GenericClaims, CoreGenderClaim>;
+
+    #[derive(Debug, Deserialize, Serialize, Clone)]
 pub struct OpenIdConfig {
     pub issuer_url: String,
     pub client_id: String,
@@ -161,7 +171,7 @@ impl OpenIdAuthenticator {
         &self,
         code: &str,
         private_auth_state: &PrivateAuthState,
-    ) -> Result<CoreIdTokenClaims, Error> {
+    ) -> Result<(CoreIdTokenClaims, GenericUserInfoClaims), Error> {
 
         let code = AuthorizationCode::new(code.to_string());
         // Exchange the code with a token.
@@ -179,6 +189,11 @@ impl OpenIdAuthenticator {
             .claims(&id_token_verifier, &private_auth_state.nonce)
             .map_err(|err| format_err!("Failed to verify ID token: {}", err))?;
 
-        Ok(id_token_claims.clone())
+        let userinfo_claims: GenericUserInfoClaims = self.client
+            .user_info(token_response.access_token().to_owned(), None)?
+            .request(http_client)
+            .map_err(|err| format_err!("Failed to contact userinfo endpoint: {}", err))?;
+
+        Ok((id_token_claims.clone(), userinfo_claims))
     }
 }
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH proxmox-openid-rs v2 3/6] new helper verify_authorization_code_simple()
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
                   ` (3 preceding siblings ...)
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 2/6] also return data from UserInfo endpoint Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 4/6] allow to configure prompt behaviour Dietmar Maurer
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

Simply return data as serde_json::Value.
---
 src/lib.rs | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index abcd06e..5d8b758 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,7 @@ use std::path::Path;
 
 use anyhow::{format_err, Error};
 use serde::{Deserialize, Serialize};
+use serde_json::Value;
 
 mod http_client;
 pub use http_client::http_client;
@@ -39,7 +40,7 @@ use openidconnect::{
 
 /// Stores Additional Claims into a serde_json::Value;
 #[derive(Debug, Deserialize, Serialize)]
-pub struct GenericClaims(serde_json::Value);
+pub struct GenericClaims(Value);
 impl AdditionalClaims for GenericClaims {}
 
 pub type GenericUserInfoClaims = UserInfoClaims<GenericClaims, CoreGenderClaim>;
@@ -196,4 +197,29 @@ impl OpenIdAuthenticator {
 
         Ok((id_token_claims.clone(), userinfo_claims))
     }
+
+    /// Like verify_authorization_code(), but returns claims as serde_json::Value
+    pub fn verify_authorization_code_simple(
+        &self,
+        code: &str,
+        private_auth_state: &PrivateAuthState,
+    ) -> Result<Value, Error> {
+
+        let (id_token_claims, userinfo_claims) = self.verify_authorization_code(&code, &private_auth_state)?;
+
+        let mut data = serde_json::to_value(id_token_claims)?;
+
+        let data2 = serde_json::to_value(userinfo_claims)?;
+
+        if let Some(map) = data2.as_object() {
+            for (key, value) in map {
+                if data[key] != Value::Null {
+                    continue; // already set
+                }
+                data[key] = value.clone();
+            }
+        }
+
+        Ok(data)
+    }
 }
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH proxmox-openid-rs v2 4/6] allow to configure prompt behaviour
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
                   ` (4 preceding siblings ...)
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 3/6] new helper verify_authorization_code_simple() Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 5/6] allow to configure acr values Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 6/6] bump version to 0.7.0-1 Dietmar Maurer
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

And do not set it by default.
---
 src/lib.rs | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 5d8b758..555e5ad 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,7 +45,7 @@ impl AdditionalClaims for GenericClaims {}
 
 pub type GenericUserInfoClaims = UserInfoClaims<GenericClaims, CoreGenderClaim>;
 
-    #[derive(Debug, Deserialize, Serialize, Clone)]
+#[derive(Debug, Deserialize, Serialize, Clone)]
 pub struct OpenIdConfig {
     pub issuer_url: String,
     pub client_id: String,
@@ -53,6 +53,8 @@ pub struct OpenIdConfig {
     pub client_key: Option<String>,
     #[serde(skip_serializing_if="Option::is_none")]
     pub scopes: Option<Vec<String>>,
+    #[serde(skip_serializing_if="Option::is_none")]
+    pub prompt: Option<String>,
 }
 
 pub struct OpenIdAuthenticator {
@@ -148,7 +150,24 @@ impl OpenIdAuthenticator {
 
         request = request.set_display(CoreAuthDisplay::Page);
 
-        request = request.add_prompt(CoreAuthPrompt::Login);
+        match self.config.prompt.as_deref() {
+            None => { /* nothing */ },
+            Some("none") => {
+                request = request.add_prompt(CoreAuthPrompt::None);
+            }
+            Some("login") => {
+                request = request.add_prompt(CoreAuthPrompt::Login);
+            }
+            Some("consent") => {
+                request = request.add_prompt(CoreAuthPrompt::Consent);
+            }
+            Some("select_account") => {
+                request = request.add_prompt(CoreAuthPrompt::SelectAccount);
+            }
+            Some(extension) => {
+                request = request.add_prompt(CoreAuthPrompt::Extension(extension.into()));
+            }
+        }
 
         if let Some(ref scopes) = self.config.scopes {
             for scope in scopes.clone() {
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH proxmox-openid-rs v2 5/6] allow to configure acr values
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
                   ` (5 preceding siblings ...)
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 4/6] allow to configure prompt behaviour Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 6/6] bump version to 0.7.0-1 Dietmar Maurer
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

---
 src/lib.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index 555e5ad..53b08c8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -36,6 +36,7 @@ use openidconnect::{
     Scope,
     UserInfoClaims,
     AdditionalClaims,
+    AuthenticationContextClass,
 };
 
 /// Stores Additional Claims into a serde_json::Value;
@@ -55,6 +56,8 @@ pub struct OpenIdConfig {
     pub scopes: Option<Vec<String>>,
     #[serde(skip_serializing_if="Option::is_none")]
     pub prompt: Option<String>,
+    #[serde(skip_serializing_if="Option::is_none")]
+    pub acr_values: Option<Vec<String>>,
 }
 
 pub struct OpenIdAuthenticator {
@@ -175,6 +178,12 @@ impl OpenIdAuthenticator {
             }
         }
 
+        if let Some(ref acr_values) = self.config.acr_values {
+            for acr in acr_values.clone() {
+                request = request.add_auth_context_value(AuthenticationContextClass::new(acr));
+            }
+        }
+
         let (authorize_url, _csrf_state, _nonce) = request.url();
 
         Ok(authorize_url.to_string())
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH proxmox-openid-rs v2 6/6] bump version to 0.7.0-1
  2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
                   ` (6 preceding siblings ...)
  2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 5/6] allow to configure acr values Dietmar Maurer
@ 2021-08-06 11:57 ` Dietmar Maurer
  7 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06 11:57 UTC (permalink / raw)
  To: pbs-devel

---
 Cargo.toml       |  2 +-
 debian/changelog | 12 ++++++++++++
 debian/control   |  8 ++++----
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index fc839c2..ed41091 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "proxmox-openid"
-version = "0.6.1"
+version = "0.7.0"
 authors = ["Dietmar Maurer <dietmar@proxmox.com>"]
 edition = "2018"
 license = "AGPL-3"
diff --git a/debian/changelog b/debian/changelog
index 2e0baf4..0b400a5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+rust-proxmox-openid (0.7.0-1) unstable; urgency=medium
+
+  * allow to configure prompt behaviour
+
+  * new helper verify_authorization_code_simple()
+
+  * also return data from UserInfo endpoint
+
+  * allow to configure used scopes
+
+ -- Proxmox Support Team <support@proxmox.com>  Fri, 06 Aug 2021 08:07:12 +0200
+
 rust-proxmox-openid (0.6.1-1) unstable; urgency=medium
 
   * depend on proxmox 0.12.0
diff --git a/debian/control b/debian/control
index 297a1bb..44c5a18 100644
--- a/debian/control
+++ b/debian/control
@@ -41,10 +41,10 @@ Provides:
  librust-proxmox-openid+default-dev (= ${binary:Version}),
  librust-proxmox-openid-0-dev (= ${binary:Version}),
  librust-proxmox-openid-0+default-dev (= ${binary:Version}),
- librust-proxmox-openid-0.6-dev (= ${binary:Version}),
- librust-proxmox-openid-0.6+default-dev (= ${binary:Version}),
- librust-proxmox-openid-0.6.1-dev (= ${binary:Version}),
- librust-proxmox-openid-0.6.1+default-dev (= ${binary:Version})
+ librust-proxmox-openid-0.7-dev (= ${binary:Version}),
+ librust-proxmox-openid-0.7+default-dev (= ${binary:Version}),
+ librust-proxmox-openid-0.7.0-dev (= ${binary:Version}),
+ librust-proxmox-openid-0.7.0+default-dev (= ${binary:Version})
 Description: Rust crate "proxmox-openid" - Rust source code
  This package contains the source for the Rust proxmox-openid crate, packaged by
  debcargo for use with cargo and dh-cargo.
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pbs-devel] [PATCH pve-rs] depend on proxmox-openid 0.7.0, bump version to 0.3.0
  2021-08-06  7:17 [pbs-devel] [PATCH proxmox-openid-rs 1/5] allow to configure used scopes Dietmar Maurer
@ 2021-08-06  7:17 ` Dietmar Maurer
  0 siblings, 0 replies; 10+ messages in thread
From: Dietmar Maurer @ 2021-08-06  7:17 UTC (permalink / raw)
  To: pbs-devel

---
 Cargo.toml        | 2 +-
 debian/changelog  | 8 ++++++++
 src/openid/mod.rs | 2 +-
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 736bc49..ef8c27c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,5 +20,5 @@ anyhow = "1.0"
 proxmox = { version = "0.12.1", default-features = false }
 perlmod = { version = "0.5.2", features = [ "exporter" ] }
 proxmox-apt = "0.6.0"
-proxmox-openid = "0.6.1"
+proxmox-openid = "0.7.0"
 serde = "1.0"
diff --git a/debian/changelog b/debian/changelog
index b247a35..33ab4a6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+libpve-rs-perl (0.3.0) bullseye; urgency=medium
+
+  * depend on proxmox-openid 0.7.0 (support prompt an d scopes)
+
+  * openid: use new verify_authorization_code_simple() to return all claims
+
+ -- Proxmox Support Team <support@proxmox.com>  Fri, 06 Aug 2021 08:48:59 +0200
+
 libpve-rs-perl (0.2.3) bullseye; urgency=medium
 
   * use newer dependencies for apt to improve repo+suite handling
diff --git a/src/openid/mod.rs b/src/openid/mod.rs
index febe927..aa31f9c 100644
--- a/src/openid/mod.rs
+++ b/src/openid/mod.rs
@@ -81,7 +81,7 @@ mod export {
     ) -> Result<Value, Error> {
 
         let open_id = this.inner.lock().unwrap();
-        let claims = open_id.verify_authorization_code(code, &private_auth_state)?;
+        let claims = open_id.verify_authorization_code_simple(code, &private_auth_state)?;
 
         Ok(to_value(&claims)?)
     }
-- 
2.30.2





^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-08-06 11:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-06 11:57 [pbs-devel] [PATCH proxmox-openid-rs v2 1/6] allow to configure used scopes Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH pve-rs] depend on proxmox-openid 0.7.0, bump version to 0.3.0 Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-backup v2] openid: allow to configure scopes, prompt, ACRs and arbitrary username-claim values Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH pve-access-control] openid: support " Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 2/6] also return data from UserInfo endpoint Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 3/6] new helper verify_authorization_code_simple() Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 4/6] allow to configure prompt behaviour Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 5/6] allow to configure acr values Dietmar Maurer
2021-08-06 11:57 ` [pbs-devel] [PATCH proxmox-openid-rs v2 6/6] bump version to 0.7.0-1 Dietmar Maurer
  -- strict thread matches above, loose matches on Subject: below --
2021-08-06  7:17 [pbs-devel] [PATCH proxmox-openid-rs 1/5] allow to configure used scopes Dietmar Maurer
2021-08-06  7:17 ` [pbs-devel] [PATCH pve-rs] depend on proxmox-openid 0.7.0, bump version to 0.3.0 Dietmar Maurer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal