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.csa...@proxmox.com> --- changs from v1: * better variable naming (less confusion) * no defaults for enable/expire (let the api call and user.cfg handle this) * correct accidental condition reversing (!wantarray) -> (wantarray) PVE/Auth/LDAP.pm | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/PVE/Auth/LDAP.pm b/PVE/Auth/LDAP.pm index 7d1d1ed..f1c9dba 100755 --- a/PVE/Auth/LDAP.pm +++ b/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) = @_; -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel