[pve-devel] [PATCH common] ldap: de-duplicate LDAP search for users and groups
Christoph Heiss
c.heiss at proxmox.com
Tue Jul 25 15:12:55 CEST 2023
For the most part, query_users() and query_groups() are identical, so
extract the common part into a separate method and let
query_{users,groups}() be simple wrappers over it.
No change in functionality.
Signed-off-by: Christoph Heiss <c.heiss at proxmox.com>
---
src/PVE/LDAP.pm | 192 ++++++++++++++++++++----------------------------
1 file changed, 81 insertions(+), 111 deletions(-)
diff --git a/src/PVE/LDAP.pm b/src/PVE/LDAP.pm
index 342c352..a56b957 100644
--- a/src/PVE/LDAP.pm
+++ b/src/PVE/LDAP.pm
@@ -99,29 +99,41 @@ sub auth_user_dn {
return 1;
}
-sub query_users {
- my ($ldap, $filter, $attributes, $base_dn, $classes) = @_;
+my $build_filter = sub {
+ my ($expr, $parts) = @_;
- # build filter from given filter and attribute list
- my $tmp = "(|";
- foreach my $att (@$attributes) {
- $tmp .= "($att=*)";
+ my $res = '(|';
+ for my $part (@$parts) {
+ $res .= &$expr($part);
}
- $tmp .= ")";
- if ($classes) {
- $tmp = "(&$tmp(|";
- for my $class (@$classes) {
- $tmp .= "(objectclass=$class)";
- }
- $tmp .= "))";
- }
+ return "$res)";
+};
- if ($filter) {
- $filter = "($filter)" if $filter !~ m/^\(.*\)$/;
- $filter = "(&${filter}${tmp})"
+my $query_objects = sub {
+ my ($ldap, $base_dn, $custom_filter, $classes, $attributes, $search_attrs) = @_;
+
+ # build filter from given class and attribute list
+ my $class_filter = &$build_filter(sub { "(objectclass=$_[0])" }, $classes) if defined($classes);
+ my $attr_filter = &$build_filter(sub { "($_[0]=*)" }, $attributes) if defined($attributes);
+
+ # $class_filter is always defined
+ my $filter;
+ if (defined($class_filter) && defined($attr_filter)) {
+ $filter = "(&${class_filter}${attr_filter})";
} else {
- $filter = $tmp;
+ $filter = $class_filter || $attr_filter;
+ }
+
+ # combine custom (user-supplied) filter and internal one using AND
+ if ($custom_filter) {
+ $custom_filter = "($custom_filter)" if $custom_filter !~ m/^\(.*\)$/;
+
+ if ($filter) {
+ $filter = "(& {${custom_filter}${filter})";
+ } else {
+ $filter = $custom_filter;
+ }
}
my $page = Net::LDAP::Control::Paged->new(size => 900);
@@ -131,40 +143,23 @@ sub query_users {
scope => "subtree",
filter => $filter,
control => [ $page ],
- attrs => [ @$attributes, 'memberOf'],
+ attrs => $search_attrs,
);
my $cookie;
my $err;
- my $users = [];
+ my $objs = [];
while(1) {
-
my $mesg = $ldap->search(@args);
# stop on error
if ($mesg->code) {
- $err = "ldap user search error: " . $mesg->error;
+ $err = $mesg->error;
last;
}
- #foreach my $entry ($mesg->entries) { $entry->dump; }
- foreach my $entry ($mesg->entries) {
- my $user = {
- dn => $entry->dn,
- attributes => {},
- groups => [$entry->get_value('memberOf')],
- };
-
- foreach my $attr (@$attributes) {
- my $vals = [$entry->get_value($attr)];
- if (scalar(@$vals)) {
- $user->{attributes}->{$attr} = $vals;
- }
- }
-
- push @$users, $user;
- }
+ push @$objs, $mesg->entries;
# Get cookie from paged control
my ($resp) = $mesg->control(LDAP_CONTROL_PAGED) or last;
@@ -181,93 +176,68 @@ sub query_users {
$page->cookie($cookie);
$page->size(0);
$ldap->search(@args);
- $err = "LDAP user query unsuccessful" if !$err;
+ $err = "query unsuccessful" if !$err;
}
- die $err if $err;
+ die "$err\n" if $err;
+ return $objs;
+};
- return $users;
-}
-
-sub query_groups {
- my ($ldap, $base_dn, $classes, $filter, $group_name_attr) = @_;
+sub query_users {
+ my ($ldap, $filter, $attributes, $base_dn, $classes) = @_;
- my $tmp = "(|";
- for my $class (@$classes) {
- $tmp .= "(objectclass=$class)";
- }
- $tmp .= ")";
+ my $search_attrs = [ @$attributes, 'memberOf' ];
+ my $objs = &$query_objects($ldap, $base_dn, $filter, $classes, $attributes, $search_attrs);
+
+ my @users = map {
+ my $entry = $_;
+ my $user = {
+ dn => $entry->dn,
+ attributes => {},
+ groups => [$entry->get_value('memberOf')],
+ };
+
+ foreach my $attr (@$attributes) {
+ my $vals = [$entry->get_value($attr)];
+ if (scalar(@$vals)) {
+ $user->{attributes}->{$attr} = $vals;
+ }
+ }
- if ($filter) {
- $filter = "($filter)" if $filter !~ m/^\(.*\)$/;
- $filter = "(&${filter}${tmp})"
- } else {
- $filter = $tmp;
- }
+ $user
+ } @$objs;
- my $page = Net::LDAP::Control::Paged->new(size => 100);
+ return \@users;
+}
- my $attrs = [ 'member', 'uniqueMember' ];
- push @$attrs, $group_name_attr if $group_name_attr;
- my @args = (
- base => $base_dn,
- scope => "subtree",
- filter => $filter,
- control => [ $page ],
- attrs => $attrs,
- );
+sub query_groups {
+ my ($ldap, $base_dn, $classes, $filter, $group_name_attr) = @_;
- my $cookie;
- my $err;
- my $groups = [];
+ my $search_attrs = [ 'member', 'uniqueMember' ];
+ push @$search_attrs, $group_name_attr if $group_name_attr;
- while(1) {
+ my $objs = &$query_objects($ldap, $base_dn, $filter, $classes, undef, $search_attrs);
- my $mesg = $ldap->search(@args);
+ my @groups = map {
+ my $entry = $_;
+ my $group = {
+ dn => $entry->dn,
+ members => [],
+ };
- # stop on error
- if ($mesg->code) {
- $err = "ldap group search error: " . $mesg->error;
- last;
+ my $members = [$entry->get_value('member')];
+ if (!scalar(@$members)) {
+ $members = [$entry->get_value('uniqueMember')];
}
-
- foreach my $entry ( $mesg->entries ) {
- my $group = {
- dn => $entry->dn,
- members => []
- };
- my $members = [$entry->get_value('member')];
- if (!scalar(@$members)) {
- $members = [$entry->get_value('uniqueMember')];
- }
- $group->{members} = $members;
- if ($group_name_attr && (my $name = $entry->get_value($group_name_attr))) {
- $group->{name} = $name;
- }
- push @$groups, $group;
+ $group->{members} = $members;
+ if ($group_name_attr && (my $name = $entry->get_value($group_name_attr))) {
+ $group->{name} = $name;
}
- # Get cookie from paged control
- my ($resp) = $mesg->control(LDAP_CONTROL_PAGED) or last;
- $cookie = $resp->cookie;
-
- last if (!defined($cookie) || !length($cookie));
-
- # Set cookie in paged control
- $page->cookie($cookie);
- }
-
- if ($cookie) {
- # We had an abnormal exit, so let the server know we do not want any more
- $page->cookie($cookie);
- $page->size(0);
- $ldap->search(@args);
- $err = "LDAP group query unsuccessful" if !$err;
- }
-
- die $err if $err;
+ $group
+ } @$objs;
- return $groups;
+ return \@groups;
}
1;
--
2.41.0
More information about the pve-devel
mailing list