all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Christoph Heiss <c.heiss@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH access-control 1/2] api: domains: add off-by-default `check-connection` parameter
Date: Thu, 27 Jul 2023 15:33:17 +0200	[thread overview]
Message-ID: <20230727133341.1009881-2-c.heiss@proxmox.com> (raw)
In-Reply-To: <20230727133341.1009881-1-c.heiss@proxmox.com>

Removes the dreaded DN regex, instead introducing a connect/bind check
on creation/update, aligning it with the way PBS does it. This is
enabled by default for new realms, but opt-in for existing, to not break
backwards-compatibility.

Additionally, it has the benefit that instead of letting a sync fail on
the first try due to e.g. bad bind credentials, it gives the user some
direct feedback when trying to add/update a LDAP realm, if enabled.

Should be rather a corner case, but it's the easiest way for us to
accomodate and the most versatile for users needing this.

This is part of the result of a previous discussion [0], and the same
approach is already implemented for PBS [1].

[0] https://lists.proxmox.com/pipermail/pve-devel/2023-May/056839.html
[1] https://git.proxmox.com/?p=proxmox-backup.git;a=commitdiff;h=5210f3b5

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
The decision to put this behind an optional (off-by-default) parameter
was made during an off-list discussion with Lukas. The summary of that
can be found as a follow-up on the previous series [2].

Note that the `base_dn`/`group_dn` now goes completely unvalided - but
again, that is how it works in PBS. We could use canonical_dn() for this
(as implemented in the previous series [3]), depending on whether we
want this kind of "divergence" between PVE & PBS. I'm happy to re-add
that should be the way forward.

[2] https://lists.proxmox.com/pipermail/pve-devel/2023-July/058540.html
[3] https://lists.proxmox.com/pipermail/pve-devel/2023-July/058392.html

 src/PVE/API2/Domains.pm |  8 ++++++++
 src/PVE/Auth/LDAP.pm    | 26 +++++++++++++++++---------
 src/PVE/Auth/Plugin.pm  |  8 ++++++++
 3 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/src/PVE/API2/Domains.pm b/src/PVE/API2/Domains.pm
index 9332aa7..e921208 100644
--- a/src/PVE/API2/Domains.pm
+++ b/src/PVE/API2/Domains.pm
@@ -165,6 +165,10 @@ __PACKAGE__->register_method ({
 		}
 		$plugin->on_add_hook($realm, $config, password => $password);

+		# Only for LDAP/AD, implied through the existence of the 'check-connection' param
+		$plugin->check_connection($realm, $config, password => $password)
+		    if defined($param->{'check-connection'}) && $param->{'check-connection'};
+
 		cfs_write_file($domainconfigfile, $cfg);
 	    }, "add auth server failed");

@@ -237,6 +241,10 @@ __PACKAGE__->register_method ({
 		    $plugin->on_update_hook($realm, $config);
 		}

+		# Only for LDAP/AD, implied through the existence of the 'check-connection' param
+		$plugin->check_connection($realm, $config, password => $password)
+		    if defined($param->{'check-connection'}) && $param->{'check-connection'};
+
 		cfs_write_file($domainconfigfile, $cfg);
 	    }, "update auth server failed");

diff --git a/src/PVE/Auth/LDAP.pm b/src/PVE/Auth/LDAP.pm
index fc82a17..c4c4cda 100755
--- a/src/PVE/Auth/LDAP.pm
+++ b/src/PVE/Auth/LDAP.pm
@@ -10,9 +10,6 @@ use PVE::Tools;

 use base qw(PVE::Auth::Plugin);

-my  $dn_part_regex = qr!("[^"]+"|[^ ,+"/<>;=#][^,+"/<>;=]*[^ ,+"/<>;=]|[^ ,+"/<>;=#])!;
-our $dn_regex = qr!\w+=${dn_part_regex}(,\s*\w+=${dn_part_regex})*!;
-
 sub type {
     return 'ldap';
 }
@@ -22,7 +19,6 @@ sub properties {
 	base_dn => {
 	    description => "LDAP base domain name",
 	    type => 'string',
-	    pattern => $dn_regex,
 	    optional => 1,
 	    maxLength => 256,
 	},
@@ -36,7 +32,6 @@ sub properties {
 	bind_dn => {
 	    description => "LDAP bind domain name",
 	    type => 'string',
-	    pattern => $dn_regex,
 	    optional => 1,
 	    maxLength => 256,
 	},
@@ -94,7 +89,6 @@ sub properties {
 	    description => "LDAP base domain name for group sync. If not set, the"
 		." base_dn will be used.",
 	    type => 'string',
-	    pattern => $dn_regex,
 	    optional => 1,
 	    maxLength => 256,
 	},
@@ -137,7 +131,14 @@ sub properties {
 	    type => 'boolean',
 	    optional => 1,
 	    default => 1,
-	}
+	},
+	'check-connection' => {
+	    description => 'Check bind connection to LDAP server.',
+	    type => 'boolean',
+	    optional => 1,
+	    # TODO: Make it enabled-by-default with PVE 9.0?
+	    default => 0,
+	},
     };
 }

@@ -169,6 +170,7 @@ sub options {
 	'sync-defaults-options' => { optional => 1 },
 	mode => { optional => 1 },
 	'case-sensitive' => { optional => 1 },
+	'check-connection' => { optional => 1 },
     };
 }

@@ -184,7 +186,7 @@ sub get_scheme_and_port {
 }

 sub connect_and_bind {
-    my ($class, $config, $realm) = @_;
+    my ($class, $config, $realm, $param) = @_;

     my $servers = [$config->{server1}];
     push @$servers, $config->{server2} if $config->{server2};
@@ -215,7 +217,7 @@ sub connect_and_bind {

     if ($config->{bind_dn}) {
 	my $bind_dn = $config->{bind_dn};
-	my $bind_pass = ldap_get_credentials($realm);
+	my $bind_pass = $param->{password} || ldap_get_credentials($realm);
 	die "missing password for realm $realm\n" if !defined($bind_pass);
 	PVE::LDAP::ldap_bind($ldap, $bind_dn, $bind_pass);
     } elsif ($config->{cert} && $config->{certkey}) {
@@ -454,4 +456,10 @@ sub on_delete_hook {
     ldap_delete_credentials($realm);
 }

+sub check_connection {
+    my ($class, $realm, $config, %param) = @_;
+
+    $class->connect_and_bind($config, $realm, \%param);
+}
+
 1;
diff --git a/src/PVE/Auth/Plugin.pm b/src/PVE/Auth/Plugin.pm
index 2f64a13..429bc88 100755
--- a/src/PVE/Auth/Plugin.pm
+++ b/src/PVE/Auth/Plugin.pm
@@ -317,4 +317,12 @@ sub on_delete_hook {
     # do nothing by default
 }

+# called during addition and updates of realms (before the new domain config gets written)
+# die to abort addition/update in case the connection/bind fails
+# NOTE: runs in a storage config *locked* context
+sub check_connection {
+    my ($class, $realm, $config, %param) = @_;
+    # do nothing by default
+}
+
 1;
--
2.41.0





  reply	other threads:[~2023-07-27 13:34 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-27 13:33 [pve-devel] [PATCH access-control/manager 0/2] ldap: check bind connection on realm add/update Christoph Heiss
2023-07-27 13:33 ` Christoph Heiss [this message]
2023-07-28  8:29   ` [pve-devel] [PATCH access-control 1/2] api: domains: add off-by-default `check-connection` parameter Lukas Wagner
2023-08-01  9:17     ` Christoph Heiss
2023-07-27 13:33 ` [pve-devel] [PATCH manager 2/2] ui: ldap: add 'Check connection' checkbox as advanced option Christoph Heiss
2023-07-28  8:37   ` Lukas Wagner
2023-08-01  9:18     ` Christoph Heiss

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=20230727133341.1009881-2-c.heiss@proxmox.com \
    --to=c.heiss@proxmox.com \
    --cc=pve-devel@lists.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