On March 6, 2020 11:05 am, Dominik Csapak wrote: > 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> > --- > 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@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_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*$/);
IMHO, this is now exactly the other way round compared to the API schema description. Which likely means that we should specify it clearly there ;) > + $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, expire is already defaulted to 0 by user.cfg's write_config enable defaults to 0 there, but to 1 here - intentionally? > + }; > + > + foreach my $attr (keys %$user_attrs) { > + if (my $key = $attrs->{$attr}) { > + $ret->{$username}->{$key} = $user_attrs->{$attr}->[0]; there are too many variables with 'attr' in the name here. could we at least rename $attrs to make it clear that it contains the mapping of LDAP -> user.cfg attributes/keys? > + } > + } > + > + if (!wantarray) { accidental negation? > + 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"; maybe it would be a further improvement to mark users and groups as 'synced' and - only allow overwriting previously synced entries when syncing - disallow editing of synced entries via the regular API ? > + > + # 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 > > _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel