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 3BFCD1FF16F
	for <inbox@lore.proxmox.com>; Thu, 27 Feb 2025 11:01:53 +0100 (CET)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
	by firstgate.proxmox.com (Proxmox) with ESMTP id 24A5A2EA54;
	Thu, 27 Feb 2025 11:01:52 +0100 (CET)
Date: Thu, 27 Feb 2025 11:01:17 +0100
From: Stoiko Ivanov <s.ivanov@proxmox.com>
To: Thomas Lamprecht <t.lamprecht@proxmox.com>
Message-ID: <20250227110117.41c6b97b@rosa.proxmox.com>
In-Reply-To: <20250227095152.281531-1-t.lamprecht@proxmox.com>
References: <20250227095152.281531-1-t.lamprecht@proxmox.com>
X-Mailer: Claws Mail 4.1.1 (GTK 3.24.38; x86_64-pc-linux-gnu)
MIME-Version: 1.0
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.064 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
 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to
 Validity was blocked. See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more
 information.
 RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to
 Validity was blocked. See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more
 information.
 RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to
 Validity was blocked. See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more
 information.
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
Subject: Re: [pmg-devel] applied: [PATCH api] oidc realm: add more flexiple
 access-role assignment
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>
Cc: pmg-devel@lists.proxmox.com
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>

Thanks! from a quick look - it seems sensible, and the naming is in order.

one typo and 2 minor nits inline:
On Thu, 27 Feb 2025 10:51:52 +0100
Thomas Lamprecht <t.lamprecht@proxmox.com> wrote:

> deprecate the fixed role assignment property and replace it with one
> that allows to select the source of the role, for now allow static,
> which is equivalent with what we had, and also to query the role from
> a role claim, so that the OIDC provider can return the correct role
> inside the returned user information.
> 
> Tested the dynamic role assignment with keycload by setting up an
> 'User Attribute' Mapper for a client and added added the respective
> user attribute to some test user.
> 
> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
> ---
> 
> It's not much code and most is schema and parsing, the implementation
> itself is pretty straigt forward, basically the only questionable thing
> is naming of properties.
> 
>  src/PMG/API2/OIDC.pm | 26 ++++++++++++++++++++-
>  src/PMG/Auth/OIDC.pm | 54 +++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 76 insertions(+), 4 deletions(-)
> 
> diff --git a/src/PMG/API2/OIDC.pm b/src/PMG/API2/OIDC.pm
> index 92ff88d..20acc41 100644
> --- a/src/PMG/API2/OIDC.pm
> +++ b/src/PMG/API2/OIDC.pm
> @@ -13,6 +13,7 @@ use PVE::JSONSchema qw(get_standard_option);
>  use PVE::RESTHandler;
>  
>  use PMG::AccessControl;
> +use PMG::Auth::OIDC;
>  use PMG::Auth::Plugin;
>  use PMG::RESTEnvironment;
>  
> @@ -204,7 +205,30 @@ __PACKAGE__->register_method ({
>  		    if (defined(my $family_name = $info->{'family_name'})) {
>  			$entry->{lastname} = $family_name;
>  		    }
> -		    $entry->{role} = $config->{'autocreate-role'} // 'audit';
> +
> +		    # NOTE: 'autocreate-role' is deprecated and has less priority than the more
> +		    # flexible 'autocreate-role-assignment'
> +		    $entry->{role} = $config->{'autocreate-role'} // 'audit'; # default
> +		    if (my $role_assignment_raw = $config->{'autocreate-role-assignment'}) {
> +			my $role_assignment =
> +			    PMG::Auth::OIDC::parse_autocreate_role_assignment($role_assignment_raw);
> +
> +			if ($role_assignment->{source} eq 'fixed') {
> +			    $entry->{role} = $role_assignment->{'fixed-role'};
> +			} elsif ($role_assignment->{source} eq 'from-claim') {
> +			    my $role_attr = $role_assignment->{'role-claim'};
> +			    if (my $role = $info->{$role_attr}) {
> +				$role = lc($role); # normalize to lower-case
> +				die "required '$role_attr' role-claim attribute not found, cannot autocreate user\n"
> +				    if $role !~ /^(?:admin|qmanager|audit|helpdesk)$/;
> +				$entry->{role} = $role;
> +			    } else {
> +				die "required '$role_attr' role-claim attribute not found, cannot autocreate user\n";
> +			    }
> +			} else {
> +			    die "unkown role assignment source '$role_assignment->{source}' - implement me";
> +			}
> +		    }
>  		    $entry->{userid} = $username;
>  		    $entry->{username} = $unique_name;
>  		    $entry->{realm} = $realm;
> diff --git a/src/PMG/Auth/OIDC.pm b/src/PMG/Auth/OIDC.pm
> index 4129d47..9082c75 100755
> --- a/src/PMG/Auth/OIDC.pm
> +++ b/src/PMG/Auth/OIDC.pm
> @@ -4,6 +4,8 @@ use strict;
>  use warnings;
>  
>  use PVE::Tools;
> +use PVE::JSONSchema qw(parse_property_string);
> +
>  use PMG::Auth::Plugin;
>  
>  use base qw(PMG::Auth::Plugin);
> @@ -12,6 +14,44 @@ sub type {
>      return 'oidc';
>  }
>  
> +my $autocreate_role_assignment_format = {
> +    source => {
> +	type => 'string',
> +	enum => ['fixed', 'from-claim'],
> +	default => 'fixed',
> +	description => "How the access role for a newly auto-created user should be selected.",
> +    },
> +    'fixed-role' => {
> +	type => 'string',
> +	enum => ['admin', 'qmanager', 'audit', 'helpdesk'],
> +	default => 'audit',
> +	optional => 1,
> +	description => "The fixed role that should be assigned to auto-created users.",
> +    },
> +    'role-claim' => {
> +	description => "OIDC claim used to assign the unique username.",
> +	type => 'string',
> +	default => 'role',
> +	optional => 1,
> +	pattern => qr/^[a-zA-Z0-9._:-]+$/,
> +    },
> +};
> +
> +
> +sub parse_autocreate_role_assignment {
> +    my ($raw) = @_;
> +    return undef if !$raw or !length($raw);
> +
> +    my $role_assignment = parse_property_string($autocreate_role_assignment_format, $raw);
> +    $role_assignment->{'fixed-role'} = 'audit'
> +	if $role_assignment->{'source'} eq 'fixed' && !defined($role_assignment->{'fixed-role'});
> +
> +    $role_assignment->{'role-claim'} = 'role'
> +	if $role_assignment->{'source'} eq 'from-clain' && !defined($role_assignment->{'role-claim'});
`s/from-clain/from-claim/`
> +
> +    return $role_assignment;
> +}
> +
>  sub properties {
>      return {
>  	'issuer-url' => {
> @@ -39,13 +79,20 @@ sub properties {
>  	    type => 'boolean',
>  	    default => 0,
>  	},
> -	'autocreate-role' => {
> -	    description => "Automatically create users with a specific role.",
> +	'autocreate-role' => { # NOTE: depreacated since the beginning, just here for compat
nit: `s/depreacated/deprecated/` (had to google myself, as I always get
that wrong)

> +	    description => "Automatically create users with a specific role."
> +		." NOTE: Depreacated, favor 'autocreate-role-assignment'",
nit: deprecated
>  	    type => 'string',
>  	    enum => ['admin', 'qmanager', 'audit', 'helpdesk'],
>  	    default => 'audit',
>  	    optional => 1,
>  	},
> +	'autocreate-role-assignment' => {
> +	    description => "Defines which role should be assigned to auto-created users.",
> +	    type => 'string', format => $autocreate_role_assignment_format,
> +	    default => 'source=fixed,fixed-role=auditor',
> +	    optional => 1,
> +	},
>  	'username-claim' => {
>  	    description => "OpenID Connect claim used to generate the unique username.",
>  	    type => 'string',
> @@ -84,7 +131,8 @@ sub options {
>  	'client-id' => {},
>  	'client-key' => { optional => 1 },
>  	autocreate => { optional => 1 },
> -	'autocreate-role' => { optional => 1 },
> +	'autocreate-role' => { optional => 1 }, # NOTE: depreacated in favor of 'autocreate-role-assignment'
nit: deprecated

> +	'autocreate-role-assignment' => { optional => 1 },
>  	'username-claim' => { optional => 1, fixed => 1 },
>  	prompt => { optional => 1 },
>  	scopes => { optional => 1 },



_______________________________________________
pmg-devel mailing list
pmg-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pmg-devel