From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 0631C91B3F for ; Thu, 15 Feb 2024 22:33:08 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id D82BD19A91 for ; Thu, 15 Feb 2024 22:33:07 +0100 (CET) Received: from mout.kundenserver.de (mout.kundenserver.de [212.227.126.130]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Thu, 15 Feb 2024 22:33:06 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=danwalex.com; s=s1-ionos; t=1708032786; x=1708637586; i=alexis@danwalex.com; bh=XpHQSbzf907C7Sb8EDtKr6k5FjxRAh5dfnSrolcPQuw=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date; b=c7GS4PbyuRucBcRbBFIsVG8CFNRl8dV3/FVf0H8jqLB573ZH/qGuThFOL/rHboxb cvEUDH2iAfQ0fp65Zlpp9QXqCpKmi2CMYNOvgRmXCWLNrkW+/KYN+SoeQ+TpmDQsl Nf/wE3RGcBnuTr6UJkzpSNHFM9r3H+HBQ7phEOQS8yOonRxg341oGL3ubWP8oCWz0 ylXCZ1Xl3876hbY7PabbxYm8klhv43Z+M8TZxlEJESpd/id0vXXdeoag8tyHGJtFP RW5sIXK+OnCVPaNFsmOW1L61HIJpYqoB8X/XbNOcmbhDBedt1y+5Q3NwUwBL3EwJY aPL544eUghZj/S9RWQ== X-UI-Sender-Class: 55c96926-9e95-11ee-ae09-1f7a4046a0f6 Received: from localhost.localdomain ([90.26.182.239]) by mrelayeu.kundenserver.de (mreue009 [213.165.67.103]) with ESMTPSA (Nemesis) id 1MUGmJ-1rRl6t25gp-00RIsg; Thu, 15 Feb 2024 22:27:56 +0100 From: Alexis | Dawnalex To: pve-devel@lists.proxmox.com Date: Thu, 15 Feb 2024 22:27:00 +0100 Message-ID: <20240215212739.602-1-alexis@danwalex.com> X-Mailer: git-send-email 2.43.0.windows.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Provags-ID: V03:K1:LXe66d5gCJFwJhu2oYpbApZSJLflRQFStGNLjhuEpLgStM5Ky68 OdiKkelNKoD6Wfyyh3ZrNZAq6agrzdtZDYtlm+ARFNg21zfv1F2U943Jvh8CRzyHFxLq4/Q EiyTdQ4wA+6shZgvMx09IzkvssztMHdVqqaNeNTNqJtMTlZhpjpkWlWmwpfBzUfMtmwyHQf ESPOpu0uqjY6KVhK4bSNQ== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:fGvzSP6L94Y=;xejkPfQ2Amn+dmweGJpUMiJL18J Fek9JdFIfzhf6AMZ2G1MKHl7Ve2YLn6P85CMB0SbfZXd+Cv7uYy2c37vz842hCkNRifzBBddi ETLAPFPq4swN4OsWD+jx0RswQRSwlOLOo02UKCWEBfuuX3tV7DJyjj9a7mSQ9Cew7EAA7nSBD FyZKbzsFs1Yb/uaUL3QXh+cNLmyCqsn8FIjokmjH4nnsSrLg7zCGHSq1NZQ19GflDfpRF/T0R DEOE7m0ffhWo/61W4svnRDDBYmRnQt89IV13AMJLl8Rh3xlmxGeb7yxMSUfLwATCw65iByDvO QtVmAIX7gWnBbdmhoJYM/PG+AirwXXbdk/AyzgTbYwwdefAXYyfFJbGesthxegd6GwC39sqUL 1wGgUZRWsYfQVDPEhcRIPkOTezVSGbIFCJ12oFPpBgfJ3WrhOa0vopAE5EytKvymNEUwKFqZk O+TuuZ4o2P+PtwUDlA9/nNlNa0pBpfLMalj67r9t5RVgtysMMb54/jrCBiyK+iwdsBcNG0UcB B3iffsZDCmBCckeHs5Mc4EwF8vvoVr6vSKmlhdz/+Jq+aBjbupKImTQ0HL0/TigXgnZgug0Qa 5yTs3EYQxN7IphaykcLKGw4Vmy5lLg+B3TYYnqmBKZx8bBSY9e9a1ed+iPyaE7KzU5HXGykFS hsc+x2yqLhYJUDLev98/XMCso6j1MbagKpRiY/xriC2kdxK+sWaX503RS2BsTQYFIYpJDTJmd H2nlrGfBMj6zbi6SVhA1xbYYFpEcnirjLuX85kbD+rz9TnKjkLURZs= X-SPAM-LEVEL: Spam detection results: 0 BAYES_00 -1.9 Bayes spam probability is 0 to 1% DKIM_INVALID 0.1 DKIM or DK signature exists, but is not valid DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_DNSWL_NONE -0.0001 Sender listed at https://www.dnswl.org/, no trust RCVD_IN_MSPIKE_H3 0.001 Good reputation (+3) RCVD_IN_MSPIKE_WL 0.001 Mailspike good senders SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [openid.pm, danwalex.com] Subject: [pve-devel] [PATCH access-control] Add OpenID group sync in pve-access-control X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 15 Feb 2024 21:33:08 -0000 This commit adds the group synchronization feature to OpenID authenticatio= n, allowing automatic user group mapping and updates based on the OpenID p= rovider information. Enhances integration and access control within Proxmo= x VE. Signed-off-by: Alexis | Dawnalex =2D-- src/PVE/API2/OpenId.pm | 83 +++++++++++++++++++++++++++++++++++++++--- src/PVE/Auth/OpenId.pm | 18 ++++++++- 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/src/PVE/API2/OpenId.pm b/src/PVE/API2/OpenId.pm index 77410e6..52511ce 100644 =2D-- a/src/PVE/API2/OpenId.pm +++ b/src/PVE/API2/OpenId.pm @@ -35,6 +35,7 @@ my $lookup_openid_auth =3D sub { issuer_url =3D> $config->{'issuer-url'}, client_id =3D> $config->{'client-id'}, client_key =3D> $config->{'client-key'}, + }; $openid_config->{prompt} =3D $config->{'prompt'} if defined($config->= {'prompt'}); @@ -150,6 +151,7 @@ __PACKAGE__->register_method ({ CSRFPreventionToken =3D> { type =3D> 'string' }, cap =3D> { type =3D> 'object' }, # computed api permissions clustername =3D> { type =3D> 'string', optional =3D> 1 }, + groups =3D> get_standard_option('group-list'), }, }, permissions =3D> { user =3D> 'world' }, @@ -190,6 +192,8 @@ __PACKAGE__->register_method ({ } my $username =3D "${unique_name}\@${realm}"; + + # first, check if $username respects our naming conventions PVE::Auth::Plugin::verify_username($username); @@ -210,16 +214,23 @@ __PACKAGE__->register_method ({ if (defined(my $family_name =3D $info->{'family_name'})) { $entry->{lastname} =3D $family_name; } - + if (defined(my $groups =3D $info->{'groups'})) { + sync_group($username, $info, $config, $groups); + } $usercfg->{users}->{$username} =3D $entry; - cfs_write_file("user.cfg", $usercfg); }, "autocreate openid user failed"); } else { + + if (defined(my $groups =3D $info->{'groups'})) { + my $usercfg =3D cfs_read_file("user.cfg"); + sync_group($username, $info, $config, $groups); + } # test if user exists and is enabled $rpcenv->check_user_enabled($username); } - + #check + my $ticket =3D PVE::AccessControl::assemble_ticket($username); my $csrftoken =3D PVE::AccessControl::assemble_csrf_prevention_token= ($username); my $cap =3D $rpcenv->compute_api_permission($username); @@ -243,7 +254,69 @@ __PACKAGE__->register_method ({ die PVE::Exception->new("authentication failure\n", code =3D> 401); } - PVE::Cluster::log_msg('info', 'root@pam', "successful openid auth for us= er '$res->{username}'"); - + PVE::Cluster::log_msg('info', 'root@pam', "successful authentication (Op= enID) for user '$res->{username}'"); return $res; }}); + +#function to create groups with lock user config and create group +sub create_group { + my ($group, $comment) =3D @_; + my $param =3D { + groupid =3D> $group, + comment =3D> $comment, + }; + eval { + PVE::AccessControl::lock_user_config( + sub { + + my $usercfg =3D cfs_read_file("user.cfg"); + + my $group =3D $param->{groupid}; + + die "group '$group' already exists\n" + if $usercfg->{groups}->{$group}; + + $usercfg->{groups}->{$group} =3D { users =3D> {} }; + + $usercfg->{groups}->{$group}->{comment} =3D $param->{comment} if $param= ->{comment}; + + + cfs_write_file("user.cfg", $usercfg); + }, "create group failed"); + }; +} +## function to sync groups waiting update to move without API2 +sub sync_group { + my ($username, $info, $config, $groups) =3D @_; + my $usercfg =3D cfs_read_file("user.cfg"); + # First Check if the group name respects our naming conventions + my @filtered_groups =3D grep { /^[a-zA-Z0-9_\-]+$/ } @{$groups}; + # Then add Add filter regex to check and check the regex is valid + my $filter_regex =3D $config->{'groups-filter'}; + + if (defined($filter_regex)) { + eval { qr/$filter_regex/ }; + if ($@) { + die "Invalid groups-filter regex: $@\n"; + } + @filtered_groups =3D grep { /$filter_regex/ } @filtered_groups; + } + if (defined($config->{'autocreate-groups'})){ + + foreach my $group (@filtered_groups) { + + unless ($usercfg->{groups}->{$group}) { + + create_group($group, "Autocreated by OpenID Connect"); + } + PVE::AccessControl::add_user_group($username, $usercfg, $group); + }; + } + else{ + foreach my $group (@filtered_groups) { + PVE::AccessControl::add_user_group($username, $usercfg, $group); + }; + } + + +} \ No newline at end of file diff --git a/src/PVE/Auth/OpenId.pm b/src/PVE/Auth/OpenId.pm index c8e4db9..6404b49 100755 =2D-- a/src/PVE/Auth/OpenId.pm +++ b/src/PVE/Auth/OpenId.pm @@ -37,6 +37,18 @@ sub properties { type =3D> 'boolean', default =3D> 0, }, + "autocreate-groups" =3D> { + description =3D> "Automatically create users if they do not exist.", + optional =3D> 1, + type =3D> 'boolean', + default =3D> 0, + }, + "groups-filter" =3D> { + description =3D> "Only allow users in these groups.", + optional =3D> 1, + type =3D> 'string', + maxLength =3D> 256, + }, "username-claim" =3D> { description =3D> "OpenID claim used to generate the unique username.= ", type =3D> 'string', @@ -62,7 +74,8 @@ sub properties { type =3D> 'string', pattern =3D> '^[^\x00-\x1F\x7F <>#"]*$', # Prohibit characters not a= llowed in URI RFC 2396. optional =3D> 1, - }, + }, + }; } @@ -72,12 +85,15 @@ sub options { "client-id" =3D> {}, "client-key" =3D> { optional =3D> 1 }, autocreate =3D> { optional =3D> 1 }, + "autocreate-groups" =3D> { optional =3D> 1}, + "groups-filter" =3D> { optional =3D> 1 }, "username-claim" =3D> { optional =3D> 1, fixed =3D> 1 }, prompt =3D> { optional =3D> 1 }, scopes =3D> { optional =3D> 1 }, "acr-values" =3D> { optional =3D> 1 }, default =3D> { optional =3D> 1 }, comment =3D> { optional =3D> 1 }, + }; } =2D- 2.43.0.windows.1