[pve-devel] [PATCH access-control v2] auth ldap/ad: make password a parameter for the api

Dominik Csapak d.csapak at proxmox.com
Tue Apr 7 13:11:31 CEST 2020


Instead of simply requiring it to exist in /etc/pve.

Takes after the password handling of CIFS in pve-storage.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
changes from v1:
* delete pw when given via 'delete' parameter
* do not delete pw when updating without giving 'password' parameter

 PVE/API2/Domains.pm | 26 ++++++++++++++++
 PVE/Auth/AD.pm      |  1 +
 PVE/Auth/LDAP.pm    | 73 ++++++++++++++++++++++++++++++++++++++++++++-
 PVE/Auth/Plugin.pm  | 15 ++++++++++
 4 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/PVE/API2/Domains.pm b/PVE/API2/Domains.pm
index 8ae1db0..b25a5fe 100644
--- a/PVE/API2/Domains.pm
+++ b/PVE/API2/Domains.pm
@@ -88,6 +88,9 @@ __PACKAGE__->register_method ({
     code => sub {
 	my ($param) = @_;
 
+	# always extract, add it with hook
+	my $password = extract_param($param, 'password');
+
 	PVE::Auth::Plugin::lock_domain_config(
 	    sub {
 
@@ -117,6 +120,13 @@ __PACKAGE__->register_method ({
 
 		$ids->{$realm} = $config;
 
+		my $opts = $plugin->options();
+		if (defined($password) && !defined($opts->{password})) {
+		    $password = undef;
+		    warn "ignoring password parameter";
+		}
+		$plugin->on_add_hook($realm, $config, password => $password);
+
 		cfs_write_file($domainconfigfile, $cfg);
 	    }, "add auth server failed");
 
@@ -137,6 +147,9 @@ __PACKAGE__->register_method ({
     code => sub {
 	my ($param) = @_;
 
+	# always extract, update in hook
+	my $password = extract_param($param, 'password');
+
 	PVE::Auth::Plugin::lock_domain_config(
 	    sub {
 
@@ -154,8 +167,10 @@ __PACKAGE__->register_method ({
 		my $delete_str = extract_param($param, 'delete');
 		die "no options specified\n" if !$delete_str && !scalar(keys %$param);
 
+		my $delete_pw = 0;
 		foreach my $opt (PVE::Tools::split_list($delete_str)) {
 		    delete $ids->{$realm}->{$opt};
+		    $delete_pw = 1 if $opt eq 'password';
 		}
 
 		my $plugin = PVE::Auth::Plugin->lookup($ids->{$realm}->{type});
@@ -171,6 +186,14 @@ __PACKAGE__->register_method ({
 		    $ids->{$realm}->{$p} = $config->{$p};
 		}
 
+		my $opts = $plugin->options();
+		if ($delete_pw || ($opts->{password} && defined($password))) {
+		    $plugin->on_update_hook($realm, $config, password => $password);
+		} else {
+		    warn "ignoring password parameter" if defined($password);
+		    $plugin->on_update_hook($realm, $config);
+		}
+
 		cfs_write_file($domainconfigfile, $cfg);
 	    }, "update auth server failed");
 
@@ -238,6 +261,9 @@ __PACKAGE__->register_method ({
 
 		die "domain '$realm' does not exist\n" if !$ids->{$realm};
 
+		my $plugin = PVE::Auth::Plugin->lookup($ids->{$realm}->{type});
+		$plugin->on_delete_hook($realm, $ids->{$realm});
+
 		delete $ids->{$realm};
 
 		cfs_write_file($domainconfigfile, $cfg);
diff --git a/PVE/Auth/AD.pm b/PVE/Auth/AD.pm
index 4f40be3..24b0e9f 100755
--- a/PVE/Auth/AD.pm
+++ b/PVE/Auth/AD.pm
@@ -83,6 +83,7 @@ sub options {
 	certkey => { optional => 1 },
 	base_dn => { optional => 1 },
 	bind_dn => { optional => 1 },
+	password => { optional => 1 },
 	user_attr => { optional => 1 },
 	filter => { optional => 1 },
 	sync_attributes => { optional => 1 },
diff --git a/PVE/Auth/LDAP.pm b/PVE/Auth/LDAP.pm
index 905cc47..1b2c606 100755
--- a/PVE/Auth/LDAP.pm
+++ b/PVE/Auth/LDAP.pm
@@ -37,6 +37,11 @@ sub properties {
 	    optional => 1,
 	    maxLength => 256,
 	},
+	password => {
+	    description => "LDAP bind password. Will be stored in '/etc/pve/priv/ldap/<REALM>.pw'.",
+	    type => 'string',
+	    optional => 1,
+	},
 	verify => {
 	    description => "Verify the server's SSL certificate",
 	    type => 'boolean',
@@ -126,6 +131,7 @@ sub options {
 	server2 => { optional => 1 },
 	base_dn => {},
 	bind_dn => { optional => 1 },
+	password => { optional => 1 },
 	user_attr => {},
 	port => { optional => 1 },
 	secure => { optional => 1 },
@@ -185,7 +191,7 @@ sub connect_and_bind {
 
     if ($config->{bind_dn}) {
 	$bind_dn = $config->{bind_dn};
-	$bind_pass = PVE::Tools::file_read_firstline("/etc/pve/priv/ldap/${realm}.pw");
+	$bind_pass = ldap_get_credentials($realm);
 	die "missing password for realm $realm\n" if !defined($bind_pass);
     }
 
@@ -343,4 +349,69 @@ sub authenticate_user {
     return 1;
 }
 
+my $ldap_pw_dir = "/etc/pve/priv/ldap";
+
+sub ldap_cred_filename {
+    my ($realm) = @_;
+    return "${ldap_pw_dir}/${realm}.pw";
+}
+
+sub ldap_set_credentials {
+    my ($password, $realm) = @_;
+
+    my $file = ldap_cred_filename($realm);
+    mkdir $ldap_pw_dir;
+
+    PVE::Tools::file_set_contents($file, $password);
+
+    return $file;
+}
+
+sub ldap_get_credentials {
+    my ($realm) = @_;
+
+    my $file = ldap_cred_filename($realm);
+
+    if (-e $file) {
+	return PVE::Tools::file_read_firstline($file);
+    }
+    return undef;
+}
+
+sub ldap_delete_credentials {
+    my ($realm) = @_;
+
+    my $file = ldap_cred_filename($realm);
+
+    unlink($file) or warn "removing ldap credentials '$file' failed: $!\n";
+}
+
+sub on_add_hook {
+    my ($class, $realm, $config, %param) = @_;
+
+    if (defined($param{password})) {
+	ldap_set_credentials($param{password}, $realm);
+    } else {
+	ldap_delete_credentials($realm);
+    }
+}
+
+sub on_update_hook {
+    my ($class, $realm, $config, %param) = @_;
+
+    return if !exists($param{password});
+
+    if (defined($param{password})) {
+	ldap_set_credentials($param{password}, $realm);
+    } else {
+	ldap_delete_credentials($realm);
+    }
+}
+
+sub on_delete_hook {
+    my ($class, $realm, $config) = @_;
+
+    ldap_delete_credentials($realm);
+}
+
 1;
diff --git a/PVE/Auth/Plugin.pm b/PVE/Auth/Plugin.pm
index 7a08d27..7843599 100755
--- a/PVE/Auth/Plugin.pm
+++ b/PVE/Auth/Plugin.pm
@@ -268,4 +268,19 @@ sub delete_user {
     # do nothing by default
 }
 
+sub on_add_hook {
+    my ($class, $realm, $config, %param) = @_;
+    # do nothing by default
+}
+
+sub on_update_hook {
+    my ($class, $realm, $config, %param) = @_;
+    # do nothing by default
+}
+
+sub on_delete_hook {
+    my ($class, $realm, $config) = @_;
+    # do nothing by default
+}
+
 1;
-- 
2.20.1





More information about the pve-devel mailing list