base_dn => {
description => "LDAP base domain name",
type => 'string',
- pattern => '\w+=[^,]+(,\s*\w+=[^,]+)*',
optional => 1,
maxLength => 256,
},
bind_dn => {
description => "LDAP bind domain name",
type => 'string',
- pattern => '\w+=[^,]+(,\s*\w+=[^,]+)*',
optional => 1,
maxLength => 256,
},
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,
},
type => 'boolean',
optional => 1,
default => 1,
- }
+ },
};
}
};
}
+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) = @_;
}
sub connect_and_bind {
- my ($class, $config, $realm) = @_;
+ my ($class, $config, $realm, $param) = @_;
my $servers = [$config->{server1}];
push @$servers, $config->{server2} if $config->{server2};
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}) {
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;
}
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;
}
}
ldap_delete_credentials($realm);
}
+sub check_connection {
+ my ($class, $realm, $config, %param) = @_;
+
+ $class->connect_and_bind($config, $realm, \%param);
+}
+
1;