From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pmg-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id EA7CB1FF16E for <inbox@lore.proxmox.com>; Mon, 3 Mar 2025 09:50:28 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 1694F4C29; Mon, 3 Mar 2025 09:50:25 +0100 (CET) From: Markus Frank <m.frank@proxmox.com> To: pmg-devel@lists.proxmox.com Date: Mon, 3 Mar 2025 09:49:58 +0100 Message-Id: <20250303084958.2742-1-m.frank@proxmox.com> X-Mailer: git-send-email 2.39.5 MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.012 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pmg-devel] [PATCH pmg-gui v2] add OIDC configuration panel for PMG X-BeenThere: pmg-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Mail Gateway development discussion <pmg-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pmg-devel>, <mailto:pmg-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pmg-devel/> List-Post: <mailto:pmg-devel@lists.proxmox.com> List-Help: <mailto:pmg-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pmg-devel>, <mailto:pmg-devel-request@lists.proxmox.com?subject=subscribe> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pmg-devel-bounces@lists.proxmox.com Sender: "pmg-devel" <pmg-devel-bounces@lists.proxmox.com> AuthEditOIDC.js is based on AuthEditOpenId from widget-toolkit and adds additional configuration options for autocreate-role-assignment. It uses sub/preferred_username for username-claim instead of the old names (subject/username/email). Removed email option entirely as it is incompatible with the username scheme. Signed-off-by: Markus Frank <m.frank@proxmox.com> --- v2: * renamed subject to sub * renamed username to preferred_username * removed email entirely js/AuthEditOIDC.js | 270 +++++++++++++++++++++++++++++++++++++++++++++ js/Makefile | 1 + js/Utils.js | 1 + 3 files changed, 272 insertions(+) create mode 100644 js/AuthEditOIDC.js diff --git a/js/AuthEditOIDC.js b/js/AuthEditOIDC.js new file mode 100644 index 0000000..cda9d68 --- /dev/null +++ b/js/AuthEditOIDC.js @@ -0,0 +1,270 @@ +Ext.define('PMG.OIDCInputPanel', { + extend: 'Proxmox.panel.InputPanel', + xtype: 'pmgAuthOIDCPanel', + mixins: ['Proxmox.Mixin.CBind'], + + showDefaultRealm: false, + + type: 'oidc', + + viewModel: { + data: { + roleSource: '__default__', + autocreate: 0, + }, + formulas: { + hideRoleAssignment: function(get) { + let autocreate = get('autocreate'); + if (!autocreate) { + return 1; + } + return autocreate === 0; + }, + hideFixedRoleAssignment: function(get) { + return get('roleSource') !== 'fixed' || get('hideRoleAssignment'); + }, + hideClaimRoleAssignment: function(get) { + return get('roleSource') !== 'from-claim' || get('hideRoleAssignment'); + }, + }, + }, + + onGetValues: function(values) { + let me = this; + + if (me.isCreate && !me.useTypeInUrl) { + values.type = me.type; + } + + if (values.source) { + let autocreateRoleAssignment = {}; + autocreateRoleAssignment.source = values.source; + if (values.source === 'fixed') { + autocreateRoleAssignment['fixed-role'] = values['fixed-role']; + } else if (values.source === 'from-claim') { + autocreateRoleAssignment['role-claim'] = values['role-claim']; + } + values['autocreate-role-assignment'] = + Proxmox.Utils.printPropertyString(autocreateRoleAssignment); + } + + if ((!values.autocreate || !values.source) && !me.isCreate) { + if (values.delete) { + if (Ext.isArray(values.delete)) { + values.delete.push('autocreate-role-assignment'); + } else { + values.delete += ',autocreate-role-assignment'; + } + } else { + values.delete = 'autocreate-role-assignment'; + } + } + delete values.source; + delete values['fixed-role']; + delete values['role-claim']; + + return values; + }, + + setValues: function(values) { + let autocreateRoleAssignment = + Proxmox.Utils.parsePropertyString(values['autocreate-role-assignment']); + + if (autocreateRoleAssignment.source) { + values.source = autocreateRoleAssignment.source; + } else { + values.source = '__default__'; + } + + if (autocreateRoleAssignment.source === 'fixed') { + values['fixed-role'] = autocreateRoleAssignment['fixed-role']; + } + if (autocreateRoleAssignment.source === 'from-claim') { + values['role-claim'] = autocreateRoleAssignment['role-claim']; + } + + this.callParent(arguments); + }, + + + columnT: [ + { + xtype: 'textfield', + name: 'issuer-url', + fieldLabel: gettext('Issuer URL'), + allowBlank: false, + }, + ], + + column1: [ + { + xtype: 'pmxDisplayEditField', + name: 'realm', + cbind: { + value: '{realm}', + editable: '{isCreate}', + }, + fieldLabel: gettext('Realm'), + allowBlank: false, + }, + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Default realm'), + name: 'default', + value: 0, + cbind: { + deleteEmpty: '{!isCreate}', + hidden: '{!showDefaultRealm}', + disabled: '{!showDefaultRealm}', + }, + autoEl: { + tag: 'div', + 'data-qtip': gettext('Set realm as default for login'), + }, + }, + { + xtype: 'proxmoxtextfield', + fieldLabel: gettext('Client ID'), + name: 'client-id', + allowBlank: false, + }, + { + xtype: 'proxmoxtextfield', + fieldLabel: gettext('Client Key'), + cbind: { + deleteEmpty: '{!isCreate}', + }, + name: 'client-key', + }, + ], + + column2: [ + { + xtype: 'pmxDisplayEditField', + name: 'username-claim', + fieldLabel: gettext('Username Claim'), + editConfig: { + xtype: 'proxmoxKVComboBox', + editable: true, + comboItems: [ + ['__default__', Proxmox.Utils.defaultText], + ['sub', 'sub (subject)'], + ['preferred_username', 'preferred_username'], + ], + }, + cbind: { + value: get => get('isCreate') ? '__default__' : Proxmox.Utils.defaultText, + deleteEmpty: '{!isCreate}', + editable: '{isCreate}', + }, + }, + { + xtype: 'proxmoxtextfield', + name: 'scopes', + fieldLabel: gettext('Scopes'), + emptyText: `${Proxmox.Utils.defaultText} (email profile)`, + submitEmpty: false, + cbind: { + deleteEmpty: '{!isCreate}', + }, + }, + { + xtype: 'proxmoxKVComboBox', + name: 'prompt', + fieldLabel: gettext('Prompt'), + editable: true, + emptyText: gettext('Auth-Provider Default'), + comboItems: [ + ['__default__', gettext('Auth-Provider Default')], + ['none', 'none'], + ['login', 'login'], + ['consent', 'consent'], + ['select_account', 'select_account'], + ], + cbind: { + deleteEmpty: '{!isCreate}', + }, + }, + ], + + columnB: [ + { + xtype: 'proxmoxtextfield', + name: 'comment', + fieldLabel: gettext('Comment'), + cbind: { + deleteEmpty: '{!isCreate}', + }, + }, + { + xtype: 'displayfield', + value: gettext('Autocreate Options'), + }, + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Autocreate Users'), + name: 'autocreate', + bind: { + value: '{autocreate}', + }, + cbind: { + deleteEmpty: '{!isCreate}', + }, + }, + { + xtype: 'proxmoxKVComboBox', + name: 'source', + fieldLabel: gettext('Source for Role Assignment'), + allowBlank: false, + deleteEmpty: false, + comboItems: [ + [ + '__default__', + Proxmox.Utils.defaultText + + ' (' + gettext('All auto-created users get audit role') + ')', + ], + ['fixed', 'Fixed role for all auto-created users'], + ['from-claim', 'Get role from OIDC claim'], + ], + bind: { + value: '{roleSource}', + disabled: '{hideRoleAssignment}', + hidden: '{hideRoleAssignment}', + }, + }, + { + xtype: 'pmgRoleSelector', + name: 'fixed-role', + allowBlank: false, + deleteEmpty: false, + fieldLabel: gettext('Fixed Role'), + bind: { + disabled: '{hideFixedRoleAssignment}', + hidden: '{hideFixedRoleAssignment}', + }, + }, + { + xtype: 'proxmoxtextfield', + name: 'role-claim', + allowBlank: false, + deleteEmpty: false, + fieldLabel: gettext('Role Claim'), + bind: { + disabled: '{hideClaimRoleAssignment}', + hidden: '{hideClaimRoleAssignment}', + }, + }, + ], + + advancedColumnB: [ + { + xtype: 'proxmoxtextfield', + name: 'acr-values', + fieldLabel: gettext('ACR Values'), + submitEmpty: false, + cbind: { + deleteEmpty: '{!isCreate}', + }, + }, + ], +}); diff --git a/js/Makefile b/js/Makefile index d1fab9b..c984bf3 100644 --- a/js/Makefile +++ b/js/Makefile @@ -78,6 +78,7 @@ JSSRC= \ LDAPConfig.js \ UserEdit.js \ UserView.js \ + AuthEditOIDC.js \ TFAView.js \ FetchmailEdit.js \ FetchmailView.js \ diff --git a/js/Utils.js b/js/Utils.js index d4a55a8..9dbc76f 100644 --- a/js/Utils.js +++ b/js/Utils.js @@ -871,6 +871,7 @@ Ext.define('PMG.Utils', { // use oidc instead of openid Proxmox.Schema.authDomains.oidc = Proxmox.Schema.authDomains.openid; Proxmox.Schema.authDomains.oidc.useTypeInUrl = false; + Proxmox.Schema.authDomains.oidc.ipanel = 'pmgAuthOIDCPanel'; delete Proxmox.Schema.authDomains.openid; // Disable LDAP/AD as a realm until LDAP/AD login is implemented -- 2.39.5 _______________________________________________ pmg-devel mailing list pmg-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pmg-devel