public inbox for pmg-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Stoiko Ivanov <s.ivanov@proxmox.com>
To: Thomas Lamprecht <t.lamprecht@proxmox.com>
Cc: pmg-devel@lists.proxmox.com
Subject: Re: [pmg-devel] applied: [PATCH api] oidc realm: add more flexiple access-role assignment
Date: Thu, 27 Feb 2025 11:01:17 +0100	[thread overview]
Message-ID: <20250227110117.41c6b97b@rosa.proxmox.com> (raw)
In-Reply-To: <20250227095152.281531-1-t.lamprecht@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


  reply	other threads:[~2025-02-27 10:01 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-27  9:51 Thomas Lamprecht
2025-02-27 10:01 ` Stoiko Ivanov [this message]
2025-02-27 10:04   ` 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=20250227110117.41c6b97b@rosa.proxmox.com \
    --to=s.ivanov@proxmox.com \
    --cc=pmg-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal