]> git.proxmox.com Git - pve-access-control.git/blobdiff - src/PVE/Auth/LDAP.pm
bump version to 8.1.4
[pve-access-control.git] / src / PVE / Auth / LDAP.pm
index 4792586673ec815a1945d6f40437dc8f1d0cadea..bf7e968cb1824065bd5225ce1fe53df50e8e0fb7 100755 (executable)
@@ -19,7 +19,6 @@ sub properties {
        base_dn => {
            description => "LDAP base domain name",
            type => 'string',
-           pattern => '\w+=[^,]+(,\s*\w+=[^,]+)*',
            optional => 1,
            maxLength => 256,
        },
@@ -33,7 +32,6 @@ sub properties {
        bind_dn => {
            description => "LDAP bind domain name",
            type => 'string',
-           pattern => '\w+=[^,]+(,\s*\w+=[^,]+)*',
            optional => 1,
            maxLength => 256,
        },
@@ -91,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 => '\w+=[^,]+(,\s*\w+=[^,]+)*',
            optional => 1,
            maxLength => 256,
        },
@@ -134,7 +131,7 @@ sub properties {
            type => 'boolean',
            optional => 1,
            default => 1,
-       }
+       },
     };
 }
 
@@ -169,6 +166,25 @@ sub options {
     };
 }
 
+my sub verify_sync_attribute_value {
+    my ($attr, $value) = @_;
+
+    # The attribute does not include the realm, so can't use PVE::Auth::Plugin::verify_username
+    if ($attr eq 'username') {
+       die "value '$value' does not look like a valid user name\n"
+           if $value !~ m/${PVE::Auth::Plugin::user_regex}/;
+       return;
+    }
+
+    return if $attr eq 'enable'; # for backwards compat, don't parse/validate
+
+    if (my $schema = PVE::JSONSchema::get_standard_option("user-$attr")) {
+       PVE::JSONSchema::validate($value, $schema, "invalid value '$value'\n");
+    } else {
+       die "internal error: no schema for attribute '$attr' with value '$value' available!\n";
+    }
+}
+
 sub get_scheme_and_port {
     my ($class, $config) = @_;
 
@@ -181,7 +197,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};
@@ -212,7 +228,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}) {
@@ -270,10 +286,17 @@ sub get_users {
        email => 'email',
        comment => 'comment',
        keys => 'keys',
+       # NOTE: also ensure verify_sync_attribute_value can handle any new/changed attribute name
     };
+    # build on the fly as this is small and only called once per realm in a ldap-sync anyway
+    my $valid_sync_attributes = { map { $_ => 1 } values $ldap_attribute_map->%* };
 
     foreach my $attr (PVE::Tools::split_list($config->{sync_attributes})) {
        my ($ours, $ldap) = ($attr =~ m/^\s*(\w+)=(.*)\s*$/);
+       if (!$valid_sync_attributes->{$ours}) {
+           warn "skipping bad 'sync_attributes' entry – '$ours' is not a valid target attribute\n";
+           next;
+       }
        $ldap_attribute_map->{$ldap} = $ours;
     }
 
@@ -304,7 +327,13 @@ sub get_users {
 
        foreach my $attr (keys %$user_attributes) {
            if (my $ours = $ldap_attribute_map->{$attr}) {
-               $ret->{$username}->{$ours} = $user_attributes->{$attr}->[0];
+               my $value = $user_attributes->{$attr}->[0];
+               eval { verify_sync_attribute_value($ours, $value) };
+               if (my $err = $@) {
+                   warn "skipping attribute mapping '$attr'->'$ours' for user '$username' - $err";
+                   next;
+               }
+               $ret->{$username}->{$ours} = $value;
            }
        }
 
@@ -451,4 +480,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;