[PATCH datacenter-manager v5 6/8] fix #5076: api-types/api: support audiences property for open id realms

Shannon Sterz
2026-04-23T13:36:55Z

to allow for better compatability with open id providers, support the
audiences field for open id realms. users can specify which audiences
are trusted in addition to the client-id.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
lib/pdm-api-types/src/openid.rs | 30 +++++++++++++++++++++++++-
server/src/api/access/openid.rs | 8 +++++++
server/src/api/config/access/openid.rs | 8 +++++++
3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/lib/pdm-api-types/src/openid.rs b/lib/pdm-api-types/src/openid.rs
index c129d35..a241c54 100644
--- a/lib/pdm-api-types/src/openid.rs
+++ b/lib/pdm-api-types/src/openid.rs
@@ -3,7 +3,9 @@ use serde::{Deserialize, Serialize};
use proxmox_schema::api_types::SAFE_ID_REGEX;
use proxmox_schema::{api, ApiStringFormat, ArraySchema, Schema, StringSchema, Updater};

-use super::{PROXMOX_SAFE_ID_FORMAT, REALM_ID_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA};
+use super::{
+ GENERIC_URI_REGEX, PROXMOX_SAFE_ID_FORMAT, REALM_ID_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA,
+};

pub const OPENID_SCOPE_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SAFE_ID_REGEX);

@@ -40,6 +42,26 @@ pub const OPENID_ACR_LIST_SCHEMA: Schema = StringSchema::new("OpenID ACR List")
.format(&OPENID_ACR_LIST_FORMAT)
.schema();

+pub const OPENID_AUDIENCE_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&GENERIC_URI_REGEX);
+
+pub const OPENID_AUDIENCE_SCHEMA: Schema = StringSchema::new("OpenID audience.")
+ .format(&OPENID_AUDIENCE_FORMAT)
+ .max_length(256)
+ .schema();
+
+pub const OPENID_AUDIENCE_ARRAY_SCHEMA: Schema = ArraySchema::new(
+ "A list of OpenID audiences that is allowed in addition to the 'client-id'.",
+ &OPENID_AUDIENCE_SCHEMA,
+)
+.schema();
+
+pub const OPENID_AUDIENCE_LIST_FORMAT: ApiStringFormat =
+ ApiStringFormat::PropertyString(&OPENID_AUDIENCE_ARRAY_SCHEMA);
+
+pub const OPENID_AUDIENCE_LIST_SCHEMA: Schema = StringSchema::new("OpenID audience list.")
+ .format(&OPENID_AUDIENCE_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 \
@@ -68,6 +90,10 @@ pub const OPENID_USERNAME_CLAIM_SCHEMA: Schema = StringSchema::new(
schema: OPENID_ACR_LIST_SCHEMA,
optional: true,
},
+ audiences: {
+ schema: OPENID_AUDIENCE_LIST_SCHEMA,
+ optional: true,
+ },
prompt: {
description: "OpenID Prompt",
type: String,
@@ -103,6 +129,8 @@ pub struct OpenIdRealmConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub acr_values: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ pub audiences: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
pub prompt: Option<String>,
/// OpenID Client Key
#[serde(skip_serializing_if = "Option::is_none")]
diff --git a/server/src/api/access/openid.rs b/server/src/api/access/openid.rs
index 1dccb29..dd03a7e 100644
--- a/server/src/api/access/openid.rs
+++ b/server/src/api/access/openid.rs
@@ -48,6 +48,13 @@ fn openid_authenticator(
);
}

+ let audiences = realm_config.audiences.as_ref().map(|list| {
+ 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(),
@@ -55,6 +62,7 @@ fn openid_authenticator(
prompt: realm_config.prompt.clone(),
scopes: Some(scopes),
acr_values,
+ audiences,
};
OpenIdAuthenticator::discover(&config, redirect_url)
}
diff --git a/server/src/api/config/access/openid.rs b/server/src/api/config/access/openid.rs
index 5e1764a..e6901fd 100644
--- a/server/src/api/config/access/openid.rs
+++ b/server/src/api/config/access/openid.rs
@@ -157,6 +157,8 @@ pub enum DeletableProperty {
Prompt,
/// Delete the acr_values property
AcrValues,
+ /// Delete the audiences property
+ Audiences,
}

#[api(
@@ -227,6 +229,9 @@ pub fn update_openid_realm(
DeletableProperty::AcrValues => {
config.acr_values = None;
}
+ DeletableProperty::Audiences => {
+ config.audiences = None;
+ }
}
}
}
@@ -269,6 +274,9 @@ pub fn update_openid_realm(
if update.acr_values.is_some() {
config.acr_values = update.acr_values;
}
+ if update.audiences.is_some() {
+ config.audiences = update.audiences;
+ }

domains.set_data(&realm, "openid", &config)?;

--
2.47.3