mirror of
https://git.proxmox.com/git/pve-access-control
synced 2025-07-24 18:59:01 +00:00
Auth/LDAP: add get_{users, groups} subs for syncing
this adds the subs which actually query the LDAP for users/groups and returns the value in format which makes it easy to insert in our parsed user.cfg when we find a user/groupname which cannot be in our config, we warn the verification error for groups, we append "-$realm" to the groupname, to lower the chance of accidental overwriting of existing groups (this will be documented in the api call since it technically does not prevent overwriting, just makes it more unlikely) Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
parent
eba326d2df
commit
2c6e956e0a
132
PVE/Auth/LDAP.pm
132
PVE/Auth/LDAP.pm
@ -190,6 +190,138 @@ sub connect_and_bind {
|
||||
return $ldap;
|
||||
}
|
||||
|
||||
# returns:
|
||||
# {
|
||||
# 'username@realm' => {
|
||||
# 'attr1' => 'value1',
|
||||
# 'attr2' => 'value2',
|
||||
# ...
|
||||
# },
|
||||
# ...
|
||||
# }
|
||||
#
|
||||
# or in list context:
|
||||
# (
|
||||
# {
|
||||
# 'username@realm' => {
|
||||
# 'attr1' => 'value1',
|
||||
# 'attr2' => 'value2',
|
||||
# ...
|
||||
# },
|
||||
# ...
|
||||
# },
|
||||
# {
|
||||
# 'uid=username,dc=....' => 'username@realm',
|
||||
# ...
|
||||
# }
|
||||
# )
|
||||
# the map of dn->username is needed for group membership sync
|
||||
sub get_users {
|
||||
my ($class, $config, $realm) = @_;
|
||||
|
||||
my $ldap = $class->connect_and_bind($config, $realm);
|
||||
|
||||
my $user_name_attr = $config->{user_attr} // 'uid';
|
||||
my $ldap_attribute_map = {
|
||||
$user_name_attr => 'username',
|
||||
enable => 'enable',
|
||||
expire => 'expire',
|
||||
firstname => 'firstname',
|
||||
lastname => 'lastname',
|
||||
email => 'email',
|
||||
comment => 'comment',
|
||||
keys => 'keys',
|
||||
};
|
||||
|
||||
foreach my $attr (PVE::Tools::split_list($config->{sync_attributes})) {
|
||||
my ($ours, $ldap) = ($attr =~ m/^\s*(\w+)=(.*)\s*$/);
|
||||
$ldap_attribute_map->{$ldap} = $ours;
|
||||
}
|
||||
|
||||
my $filter = $config->{filter};
|
||||
my $basedn = $config->{base_dn};
|
||||
|
||||
$config->{user_classes} //= 'inetorgperson, posixaccount, person, user';
|
||||
my $classes = [PVE::Tools::split_list($config->{user_classes})];
|
||||
|
||||
my $users = PVE::LDAP::query_users($ldap, $filter, [keys %$ldap_attribute_map], $basedn, $classes);
|
||||
|
||||
my $ret = {};
|
||||
my $dnmap = {};
|
||||
|
||||
foreach my $user (@$users) {
|
||||
my $user_attributes = $user->{attributes};
|
||||
my $userid = $user_attributes->{$user_name_attr}->[0];
|
||||
my $username = "$userid\@$realm";
|
||||
|
||||
# we cannot sync usernames that do not meet our criteria
|
||||
eval { PVE::Auth::Plugin::verify_username($username) };
|
||||
if (my $err = $@) {
|
||||
warn "$err";
|
||||
next;
|
||||
}
|
||||
|
||||
$ret->{$username} = {};
|
||||
|
||||
foreach my $attr (keys %$user_attributes) {
|
||||
if (my $ours = $ldap_attribute_map->{$attr}) {
|
||||
$ret->{$username}->{$ours} = $user_attributes->{$attr}->[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (wantarray) {
|
||||
my $dn = $user->{dn};
|
||||
$dnmap->{$dn} = $username;
|
||||
}
|
||||
}
|
||||
|
||||
return wantarray ? ($ret, $dnmap) : $ret;
|
||||
}
|
||||
|
||||
# needs a map for dn -> username, we get this from the get_users call
|
||||
# otherwise we cannot determine the group membership
|
||||
sub get_groups {
|
||||
my ($class, $config, $realm, $dnmap) = @_;
|
||||
|
||||
my $filter = $config->{group_filter};
|
||||
my $basedn = $config->{group_dn} // $config->{base_dn};
|
||||
my $attr = $config->{group_name_attr};
|
||||
$config->{group_classes} //= 'groupOfNames, group, univentionGroup, ipausergroup';
|
||||
my $classes = [PVE::Tools::split_list($config->{group_classes})];
|
||||
|
||||
my $ldap = $class->connect_and_bind($config, $realm);
|
||||
|
||||
my $groups = PVE::LDAP::query_groups($ldap, $basedn, $classes, $filter, $attr);
|
||||
|
||||
my $ret = {};
|
||||
|
||||
foreach my $group (@$groups) {
|
||||
my $name = $group->{name};
|
||||
if (!$name && $group->{dn} =~ m/^[^=]+=([^,]+),/){
|
||||
$name = PVE::Tools::trim($1);
|
||||
}
|
||||
if ($name) {
|
||||
$name .= "-$realm";
|
||||
|
||||
# we cannot sync groups that do not meet our criteria
|
||||
eval { PVE::AccessControl::verify_groupname($name) };
|
||||
if (my $err = $@) {
|
||||
warn "$err";
|
||||
next;
|
||||
}
|
||||
|
||||
$ret->{$name} = { users => {} };
|
||||
foreach my $member (@{$group->{members}}) {
|
||||
if (my $user = $dnmap->{$member}) {
|
||||
$ret->{$name}->{users}->{$user} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub authenticate_user {
|
||||
my ($class, $config, $realm, $username, $password) = @_;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user