aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrédéric Buclin <LpSolit@netscape.net>2017-10-09 20:42:12 +0200
committerFrédéric Buclin <LpSolit@netscape.net>2017-10-09 20:43:37 +0200
commitceefacd41df24ddb2c41e235a01938f479e40a22 (patch)
tree8fe5be1a8110d5659b364045a9fdbd5d7ac79beb
parent08fa219c0ae361c351271ec47b2efa2daa97b902 (diff)
downloadbugs-ceefacd41df24ddb2c41e235a01938f479e40a22.tar
bugs-ceefacd41df24ddb2c41e235a01938f479e40a22.tar.gz
bugs-ceefacd41df24ddb2c41e235a01938f479e40a22.tar.bz2
bugs-ceefacd41df24ddb2c41e235a01938f479e40a22.tar.xz
bugs-ceefacd41df24ddb2c41e235a01938f479e40a22.zip
Bug 899: Sync Bugzilla groups with LDAP groups
-rw-r--r--extensions/Mageia/Config.pm6
-rw-r--r--extensions/Mageia/Extension.pm17
-rw-r--r--extensions/Mageia/lib/Util.pm100
-rwxr-xr-xextensions/Mageia/sync_LDAP_groups.pl27
-rw-r--r--extensions/Mageia/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl27
5 files changed, 175 insertions, 2 deletions
diff --git a/extensions/Mageia/Config.pm b/extensions/Mageia/Config.pm
index ce0eae39d..492bdab11 100644
--- a/extensions/Mageia/Config.pm
+++ b/extensions/Mageia/Config.pm
@@ -14,6 +14,12 @@ use warnings;
use constant NAME => 'Mageia';
use constant REQUIRED_MODULES => [
+ # Required to sync LDAP groups with Bugzilla groups.
+ {
+ package => 'perl-ldap',
+ module => 'Net::LDAP',
+ version => 0
+ }
];
use constant OPTIONAL_MODULES => [
diff --git a/extensions/Mageia/Extension.pm b/extensions/Mageia/Extension.pm
index 982a3bdb7..0c5efb02c 100644
--- a/extensions/Mageia/Extension.pm
+++ b/extensions/Mageia/Extension.pm
@@ -18,7 +18,7 @@ use Bugzilla::Bug qw(LogActivityEntry);
use Bugzilla::Field qw(get_field_id);
use Bugzilla::User qw();
use Bugzilla::User::Setting qw(add_setting);
-use Bugzilla::Extension::Mageia::Util qw(compare_datetimes);
+use Bugzilla::Extension::Mageia::Util qw(compare_datetimes sync_ldap_groups_check);
use Email::Address;
use Encode qw(encode);
@@ -136,6 +136,21 @@ sub mailer_before_send {
}
}
+sub sanitycheck_check {
+ my ($self, $args) = @_;
+ &{$args->{status}}('ldap_check_group_membership');
+ sync_ldap_groups_check($args->{status});
+}
+
+sub sanitycheck_repair {
+ my ($self, $args) = @_;
+ if (Bugzilla->cgi->param('sync_ldap_groups')) {
+ &{$args->{status}}('ldap_repair_start');
+ sync_ldap_groups_check($args->{status}, 1);
+ &{$args->{status}}('ldap_repair_end');
+ }
+}
+
sub template_before_process {
my ($self, $args) = @_;
_inline_history($args) if $args->{file} eq 'bug/comments.html.tmpl';
diff --git a/extensions/Mageia/lib/Util.pm b/extensions/Mageia/lib/Util.pm
index 60447fa28..11f4fcaf6 100644
--- a/extensions/Mageia/lib/Util.pm
+++ b/extensions/Mageia/lib/Util.pm
@@ -11,9 +11,17 @@ use 5.10.1;
use strict;
use warnings;
+use Bugzilla::Auth::Verify::LDAP;
+use Bugzilla::Group;
+use Bugzilla::User;
+use Bugzilla::Util qw(diff_arrays);
+
use parent qw(Exporter);
-our @EXPORT = qw(compare_datetimes);
+our @EXPORT = qw(compare_datetimes sync_ldap_groups_check);
+
+# Use Mageia Robot user ID = 2122 for LDAP groups sync.
+use constant LDAP_SYNC_USER_ID => 2122;
# This file can be loaded by your extension via
# "use Bugzilla::Extension::Mageia::Util". You can put functions
@@ -41,4 +49,94 @@ sub compare_datetimes {
return 0;
}
+sub sync_ldap_groups_check {
+ my ($status, $repair) = @_;
+ my $ldap = Bugzilla::Auth::Verify::LDAP->new();
+ $ldap->_bind_ldap_for_search;
+
+ my $result = $ldap->ldap->search(
+ base => 'ou=Group,dc=mageia,dc=org',
+ filter => '(objectClass=groupOfNames)',
+ attrs => ['cn', 'member']
+ );
+
+ if ($result->is_error) {
+ &$status('ldap_sync_alert', { ldap_error => $result->error }, 'alert');
+ return;
+ }
+
+ my (%groups, %users);
+ my $dbh = Bugzilla->dbh;
+
+ my %bz_groups = map { $_->name => $_ } grep { $_->name =~ /^mga-/ } Bugzilla::Group->get_all;
+
+ foreach my $ldap_group ($result->entries) {
+ my $group = $ldap_group->get_value('cn');
+ next unless $bz_groups{$group};
+
+ $groups{$group} = {};
+
+ foreach my $user ($ldap_group->get_value('member')) {
+ unless (exists $users{$user}) {
+ my $result = $ldap->ldap->search(
+ base => $user,
+ scope => 'base',
+ filter => '(objectClass=inetOrgPerson)',
+ attrs => ['uid', 'mail']
+ );
+ if ($result->is_error) {
+ &$status('ldap_sync_alert', { ldap_error => $result->error }, 'alert');
+ next;
+ }
+
+ # Some entries are not valid user accounts.
+ my $ldap_user = $result->entry(0) or next;
+ my $uid = $ldap_user->get_value('uid');
+ my $mail = $ldap_user->get_value('mail');
+ # Some accounts lack an email address. They cannot log into Bugzilla.
+ next unless $uid && $mail;
+
+ # Ignore the LDAP account if it does not exist in Bugzilla.
+ my $bz_user = Bugzilla::User->new({ extern_id => $uid }) or next;
+ $users{$user} = $bz_user;
+ }
+ $groups{$group}->{$users{$user}->extern_id} = $users{$user};
+ }
+ }
+
+ my $current_user = Bugzilla->user;
+ my $ldap_sync_needs_repair = 0;
+
+ if ($repair) {
+ # We need to log in as a super user in order to update group memberships.
+ # Bugzilla needs a valid user ID to log changes, though.
+ my $super_user = Bugzilla::User->super_user;
+ $super_user->{userid} = LDAP_SYNC_USER_ID;
+ Bugzilla->set_user($super_user);
+ }
+
+ foreach my $group (sort keys %groups) {
+ my %members = map { $_->extern_id => $_ } @{$bz_groups{$group}->members_direct};
+ my ($removed, $added) = diff_arrays([keys %members], [keys %{$groups{$group}}]);
+ if ($repair) {
+ foreach my $old_user (@$removed) {
+ $members{$old_user}->set_groups({ remove => [$group] });
+ $members{$old_user}->update;
+ }
+
+ foreach my $new_user (@$added) {
+ $groups{$group}->{$new_user}->set_groups({ add => [$group] });
+ $groups{$group}->{$new_user}->update;
+ }
+ }
+ elsif (@$removed || @$added) {
+ &$status('ldap_sync_group_mismatch_alert', { group => $group, old_users => $removed, new_users => $added }, 'alert');
+ $ldap_sync_needs_repair = 1;
+ }
+ }
+ # Restore the original user.
+ Bugzilla->set_user($current_user) if $repair;
+ &$status('ldap_sync_repair_link') if $ldap_sync_needs_repair;
+}
+
1;
diff --git a/extensions/Mageia/sync_LDAP_groups.pl b/extensions/Mageia/sync_LDAP_groups.pl
new file mode 100755
index 000000000..77a99ee9a
--- /dev/null
+++ b/extensions/Mageia/sync_LDAP_groups.pl
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -T
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+use 5.14.0;
+use strict;
+use warnings;
+
+use lib qw(. lib);
+
+use Bugzilla;
+BEGIN { Bugzilla->extensions() }
+use Bugzilla::Extension::Mageia::Util qw(sync_ldap_groups_check);
+
+# See Status() in sanitycheck.cgi.
+sub status {
+ my ($san_tag, $vars, $alert) = @_;
+ return unless $alert && $san_tag eq 'ldap_sync_alert';
+
+ say 'LDAP error: ' . $vars->{ldap_error};
+}
+
+sync_ldap_groups_check(\&status, 1);
diff --git a/extensions/Mageia/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl b/extensions/Mageia/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl
new file mode 100644
index 000000000..19155048b
--- /dev/null
+++ b/extensions/Mageia/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl
@@ -0,0 +1,27 @@
+[%# This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ #
+ # This Source Code Form is "Incompatible With Secondary Licenses", as
+ # defined by the Mozilla Public License, v. 2.0.
+ #%]
+
+[% IF san_tag == "ldap_check_group_membership" %]
+ Checking group membership for LDAP groups.
+[% ELSIF san_tag == "ldap_repair_start" %]
+ OK, now fixing Bugzilla group memberships based on LDAP groups.
+[% ELSIF san_tag == "ldap_repair_end" %]
+ Bugzilla group memberships synchronization completed.
+[% ELSIF san_tag == "ldap_sync_alert" %]
+ LDAP error: [% ldap_error FILTER html %]
+[% ELSIF san_tag == "ldap_sync_group_mismatch_alert" %]
+ Group [% group FILTER html %] is out of sync:<br>
+ - [% old_users.size %] users are no longer in this group and should be removed:
+ [%+ old_users.join(", ") FILTER html %].<br>
+ - [% new_users.size %] users are not yet in this group and should be added:
+ [%+ new_users.join(", ") FILTER html %].
+[% ELSIF san_tag == "ldap_sync_repair_link" %]
+ <a href="sanitycheck.cgi?sync_ldap_groups=1&amp;token=
+ [%- issue_hash_token(['sanitycheck']) FILTER uri %]">Synchronize Bugzilla groups
+ with LDAP groups (LDAP -> Bugzilla).</a>
+[% END %]