all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: "Shannon Sterz" <s.sterz@proxmox.com>
To: "Thomas Lamprecht" <t.lamprecht@proxmox.com>,
	<pve-devel@lists.proxmox.com>
Subject: Re: [PATCH manager 6/9] ui: dc options: allow editing the API token policy
Date: Tue, 10 Nov 2026 16:05:12 +0100	[thread overview]
Message-ID: <DMRMGIIDSDLE.1O01U8486ISQ6@proxmox.com> (raw)
In-Reply-To: <20260923210000.4031318-7-t.lamprecht@proxmox.com>

On Wed Sep 23, 2026 at 10:59 PM CEST, Thomas Lamprecht wrote:
> Render and edit the new datacenter token-policy option. The maximum
> lifetime is entered in days, fractional values are allowed for
> sub-day lifetimes, and the exact stored value is kept when the field
> is left untouched, so a finer grained value set via the API survives
> unrelated edits.
>
> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
> ---
>  www/manager6/dc/OptionView.js | 107 ++++++++++++++++++++++++++++++++++
>  1 file changed, 107 insertions(+)
>
> diff --git a/www/manager6/dc/OptionView.js b/www/manager6/dc/OptionView.js
> index dc12aa7e1..595a8f070 100644
> --- a/www/manager6/dc/OptionView.js
> +++ b/www/manager6/dc/OptionView.js
> @@ -384,6 +384,113 @@ Ext.define('PVE.dc.OptionView', {
>                  },
>              ],
>          });
> +        me.rows['token-policy'] = {
> +            required: true,
> +            header: gettext('API Token Policy'),
> +            renderer: function (policy) {
> +                if (!policy) {
> +                    return Proxmox.Utils.NoneText;
> +                }
> +                let parts = [];
> +                if (Number(policy['require-expiry'])) {
> +                    parts.push(gettext('Require Expiration Date'));

nit: to visually indicate that max-lifetime always implies
require-expiry, this field could check if a max-lifetime is set and be
set to ticked and disabled if it is.

> +                }
> +                if (policy['max-lifetime'] !== undefined) {
> +                    let lifetime = Proxmox.Utils.format_duration_human(
> +                        Number(policy['max-lifetime']),
> +                    );
> +                    parts.push(Ext.String.format(gettext('Max. Lifetime: {0}'), lifetime));
> +                }
> +                if (Number(policy['disallow-expiry-changes'])) {
> +                    parts.push(gettext('Disallow Expiration Changes'));
> +                }
> +                if (Number(policy['require-privilege-separation'])) {
> +                    parts.push(gettext('Require Privilege Separation'));
> +                }
> +                return parts.length ? parts.join(', ') : Proxmox.Utils.NoneText;
> +            },
> +            editor: {
> +                xtype: 'proxmoxWindowEdit',
> +                subject: gettext('API Token Policy'),
> +                onlineHelp: 'pveum_token_policy',
> +                url: '/api2/extjs/cluster/options',
> +                fieldDefaults: {
> +                    labelWidth: 150,
> +                },
> +                setValues: function (values) {
> +                    let me = this;
> +                    // work on a copy, max-lifetime is stored in seconds but entered in days,
> +                    // fractional values are allowed; round up at two decimals for display and
> +                    // remember the exact stored value so that saving with the field untouched
> +                    // does not alter it
> +                    let policy = Ext.apply({}, values['token-policy'] || {});
> +                    me.storedMaxLifetime = policy['max-lifetime'];
> +                    if (policy['max-lifetime'] !== undefined) {
> +                        policy['max-lifetime'] =
> +                            Math.ceil((Number(policy['max-lifetime']) / 86400) * 100) / 100;
> +                    }
> +                    Ext.Array.each(me.query('inputpanel'), (panel) => panel.setValues(policy));
> +                },
> +                items: [
> +                    {
> +                        xtype: 'inputpanel',
> +                        onGetValues: function (values) {
> +                            let me = this;
> +                            let win = me.up('proxmoxWindowEdit');
> +                            let policy = {};
> +                            if (values['require-expiry']) {
> +                                policy['require-expiry'] = 1;
> +                            }
> +                            if (values['disallow-expiry-changes']) {
> +                                policy['disallow-expiry-changes'] = 1;
> +                            }
> +                            if (values['require-privilege-separation']) {
> +                                policy['require-privilege-separation'] = 1;
> +                            }
> +                            let days = values['max-lifetime'];
> +                            if (days !== undefined && days !== null && days !== '') {
> +                                let untouched = !me.down('field[name=max-lifetime]').isDirty();
> +                                policy['max-lifetime'] =
> +                                    untouched && win.storedMaxLifetime !== undefined
> +                                        ? win.storedMaxLifetime
> +                                        : Math.round(Number(days) * 86400);
> +                            }
> +                            if (Object.keys(policy).length === 0) {
> +                                return { delete: 'token-policy' };
> +                            }
> +                            return { 'token-policy': PVE.Parser.printPropertyString(policy) };
> +                        },
> +                        items: [
> +                            {
> +                                xtype: 'proxmoxcheckbox',
> +                                name: 'require-expiry',
> +                                uncheckedValue: 0,
> +                                fieldLabel: gettext('Require Expiration Date'),
> +                            },
> +                            {
> +                                xtype: 'numberfield',
> +                                name: 'max-lifetime',
> +                                minValue: 0.01,
> +                                emptyText: gettext('No limit'),
> +                                fieldLabel: gettext('Maximum Lifetime (days)'),
> +                            },
> +                            {
> +                                xtype: 'proxmoxcheckbox',
> +                                name: 'disallow-expiry-changes',
> +                                uncheckedValue: 0,
> +                                fieldLabel: gettext('Disallow Expiration Changes'),
> +                            },
> +                            {
> +                                xtype: 'proxmoxcheckbox',
> +                                name: 'require-privilege-separation',
> +                                uncheckedValue: 0,
> +                                fieldLabel: gettext('Require Privilege Separation'),
> +                            },
> +                        ],
> +                    },
> +                ],
> +            },
> +        };
>          me.rows['tag-style'] = {
>              required: true,
>              renderer: (value) => {





  reply	other threads:[~2026-11-10 15:05 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-23 20:59 [PATCH cluster/access-control/manager/docs/proxmox 0/9] fix #7805: add a datacenter-wide API token policy Thomas Lamprecht
2026-09-23 20:59 ` [PATCH cluster 1/9] datacenter config: add token-policy option Thomas Lamprecht
2026-11-10 15:05   ` Shannon Sterz
2026-11-10 16:00     ` Thomas Lamprecht
2026-09-23 20:59 ` [PATCH access-control 2/9] fix #7805: api: token: enforce datacenter token policy Thomas Lamprecht
2026-09-23 20:59 ` [PATCH docs 3/9] user management: document the API " Thomas Lamprecht
2026-11-10 15:05   ` Shannon Sterz
2026-09-23 20:59 ` [PATCH manager 4/9] ui: token edit: only submit the expiration date when changed Thomas Lamprecht
2026-09-23 20:59 ` [PATCH manager 5/9] api: cluster options: return token-policy without Sys.Audit Thomas Lamprecht
2026-09-23 20:59 ` [PATCH manager 6/9] ui: dc options: allow editing the API token policy Thomas Lamprecht
2026-11-10 15:05   ` Shannon Sterz [this message]
2026-09-23 20:59 ` [PATCH manager 7/9] ui: token edit: adapt to the datacenter " Thomas Lamprecht
2026-09-23 20:59 ` [PATCH proxmox 8/9] access-control: add API token policy type with expiry checks Thomas Lamprecht
2026-11-10 15:05   ` Shannon Sterz
2026-09-23 20:59 ` [PATCH proxmox 9/9] access-control: enforce token policy on token create and update Thomas Lamprecht
2026-11-10 15:04   ` Shannon Sterz
2026-11-10 15:05 ` [PATCH cluster/access-control/manager/docs/proxmox 0/9] fix #7805: add a datacenter-wide API token policy Shannon Sterz
2026-11-10 15:28   ` Thomas Lamprecht

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DMRMGIIDSDLE.1O01U8486ISQ6@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    --cc=t.lamprecht@proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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