[pve-devel] [PATCH access-control 7/9] Auth/LDAP: add get_{users, groups} subs for syncing
Dominik Csapak
d.csapak at proxmox.com
Fri Mar 6 11:05:43 CET 2020
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 at proxmox.com>
---
PVE/Auth/LDAP.pm | 135 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 135 insertions(+)
diff --git a/PVE/Auth/LDAP.pm b/PVE/Auth/LDAP.pm
index 6047dfb..45e4299 100755
--- a/PVE/Auth/LDAP.pm
+++ b/PVE/Auth/LDAP.pm
@@ -189,6 +189,141 @@ sub connect_and_bind {
return $ldap;
}
+# returns:
+# {
+# 'username at realm' => {
+# 'attr1' => 'value1',
+# 'attr2' => 'value2',
+# ...
+# },
+# ...
+# }
+#
+# or in list context:
+# (
+# {
+# 'username at realm' => {
+# 'attr1' => 'value1',
+# 'attr2' => 'value2',
+# ...
+# },
+# ...
+# },
+# {
+# 'uid=username,dc=....' => 'username at 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_attr = $config->{user_attr} // 'uid';
+ my $attrs = {
+ $user_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*$/);
+ $attrs->{$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 %$attrs], $basedn, $classes);
+
+ my $ret = {};
+ my $dnmap = {};
+
+ foreach my $user (@$users) {
+ my $user_attrs = $user->{attributes};
+ my $userid = $user_attrs->{$user_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} = {
+ enable => 1,
+ expire => 0,
+ };
+
+ foreach my $attr (keys %$user_attrs) {
+ if (my $key = $attrs->{$attr}) {
+ $ret->{$username}->{$key} = $user_attrs->{$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_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
More information about the pve-devel
mailing list