summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorByron Jones <bjones@mozilla.com>2013-01-23 09:27:03 +0100
committerByron Jones <bjones@mozilla.com>2013-01-23 09:27:03 +0100
commitf2a29007f96f33da77440cd10f475c2af946573e (patch)
treecc8d4772bf7ab8eac52cfe5f5646c125c983e7c1
parent3c50104166023a136d0e4cee22322904521eae87 (diff)
downloadbugzilla-f2a29007f96f33da77440cd10f475c2af946573e.tar.gz
bugzilla-f2a29007f96f33da77440cd10f475c2af946573e.tar.xz
Bug 812433: create a report for auditing bugzilla security group membership
-rw-r--r--extensions/BMO/Extension.pm6
-rw-r--r--extensions/BMO/lib/Reports.pm100
-rw-r--r--extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl11
-rw-r--r--extensions/BMO/template/en/default/pages/email_queue.html.tmpl2
-rw-r--r--extensions/BMO/template/en/default/pages/group_admins.html.tmpl2
-rw-r--r--extensions/BMO/template/en/default/pages/group_members.html.tmpl97
-rw-r--r--extensions/BMO/template/en/default/pages/group_members.json.tmpl32
-rw-r--r--extensions/BMO/template/en/default/pages/group_membership.html.tmpl2
-rw-r--r--extensions/BMO/template/en/default/pages/user_activity.html.tmpl2
-rw-r--r--extensions/BMO/web/styles/reports.css10
10 files changed, 248 insertions, 16 deletions
diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm
index c35e5688f..2681b9a41 100644
--- a/extensions/BMO/Extension.pm
+++ b/extensions/BMO/Extension.pm
@@ -62,7 +62,8 @@ use Bugzilla::Extension::BMO::Reports qw(user_activity_report
group_admins_report
email_queue_report
release_tracking_report
- group_membership_report);
+ group_membership_report
+ group_members_report);
our $VERSION = '0.1';
@@ -180,6 +181,9 @@ sub page_before_template {
elsif ($page eq 'group_membership.html' or $page eq 'group_membership.txt') {
group_membership_report($page, $vars);
}
+ elsif ($page eq 'group_members.html' or $page eq 'group_members.json') {
+ group_members_report($vars);
+ }
elsif ($page eq 'email_queue.html') {
email_queue_report($vars);
}
diff --git a/extensions/BMO/lib/Reports.pm b/extensions/BMO/lib/Reports.pm
index ce307d9ff..cf663dcd9 100644
--- a/extensions/BMO/lib/Reports.pm
+++ b/extensions/BMO/lib/Reports.pm
@@ -13,6 +13,7 @@ use Bugzilla::Extension::BMO::Data qw($cf_disabled_flags);
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Field;
+use Bugzilla::Group;
use Bugzilla::User;
use Bugzilla::Util qw(trim detaint_natural trick_taint correct_urlbase);
@@ -28,7 +29,8 @@ our @EXPORT_OK = qw(user_activity_report
group_admins_report
email_queue_report
release_tracking_report
- group_membership_report);
+ group_membership_report
+ group_members_report);
sub user_activity_report {
my ($vars) = @_;
@@ -559,9 +561,9 @@ sub group_admins_report {
my $dbh = Bugzilla->dbh;
my $user = Bugzilla->user;
- $user->in_group('editusers')
- || ThrowUserError('auth_failure', { group => 'editusers',
- action => 'run',
+ ($user->in_group('editusers') || $user->in_group('infrasec'))
+ || ThrowUserError('auth_failure', { group => 'editusers',
+ action => 'run',
object => 'group_admins' });
my $query = "
@@ -598,8 +600,8 @@ sub group_membership_report {
my $cgi = Bugzilla->cgi;
($user->in_group('editusers') || $user->in_group('infrasec'))
- || ThrowUserError('auth_failure', { group => 'editusers',
- action => 'run',
+ || ThrowUserError('auth_failure', { group => 'editusers',
+ action => 'run',
object => 'group_admins' });
my $who = $cgi->param('who');
@@ -693,6 +695,92 @@ sub group_membership_report {
$vars->{'users'} = \@users;
}
+sub group_members_report {
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+ my $cgi = Bugzilla->cgi;
+
+ ($user->in_group('editusers') || $user->in_group('infrasec'))
+ || ThrowUserError('auth_failure', { group => 'editusers',
+ action => 'run',
+ object => 'group_admins' });
+
+ my $include_disabled = $cgi->param('include_disabled') ? 1 : 0;
+ $vars->{'include_disabled'} = $include_disabled;
+
+ # don't allow all groups, to avoid putting pain on the servers
+ my @group_names =
+ sort
+ grep { !/^(?:bz_.+|canconfirm|editbugs|everyone)$/ }
+ map { lc($_->name) }
+ Bugzilla::Group->get_all;
+ unshift(@group_names, '');
+ $vars->{'groups'} = \@group_names;
+
+ # load selected group
+ my $group = lc(trim($cgi->param('group') // ''));
+ $group = '' unless grep { $_ eq $group } @group_names;
+ return if $group eq '';
+ my $group_obj = Bugzilla::Group->new({ name => $group });
+ $vars->{'group'} = $group;
+
+ # direct members
+ my @types = (
+ {
+ name => 'direct',
+ members => _filter_userlist($group_obj->members_direct, $include_disabled),
+ },
+ );
+
+ # indirect members, by group
+ foreach my $member_group (sort @{ $group_obj->grant_direct(GROUP_MEMBERSHIP) }) {
+ push @types, {
+ name => $member_group->name,
+ members => _filter_userlist($member_group->members_direct, $include_disabled),
+ },
+ }
+
+ # make it easy for the template to detect an empty group
+ my $has_members = 0;
+ foreach my $type (@types) {
+ $has_members += scalar(@{ $type->{members} });
+ last if $has_members;
+ }
+ @types = () unless $has_members;
+
+ if (@types) {
+ # add last-login
+ my $user_ids = join(',', map { map { $_->id } @{ $_->{members} } } @types);
+ my $tokens = $dbh->selectall_hashref("
+ SELECT profiles.userid,
+ (SELECT DATEDIFF(curdate(), logincookies.lastused) lastseen
+ FROM logincookies
+ WHERE logincookies.userid = profiles.userid
+ ORDER BY lastused DESC
+ LIMIT 1) lastseen
+ FROM profiles
+ WHERE userid IN ($user_ids)",
+ 'userid');
+ foreach my $type (@types) {
+ foreach my $member (@{ $type->{members} }) {
+ $member->{lastseen} =
+ defined $tokens->{$member->id}->{lastseen}
+ ? $tokens->{$member->id}->{lastseen}
+ : '>' . MAX_LOGINCOOKIE_AGE;
+ }
+ }
+ }
+
+ $vars->{'types'} = \@types;
+}
+
+sub _filter_userlist {
+ my ($list, $include_disabled) = @_;
+ $list = [ grep { $_->is_enabled } @$list ] unless $include_disabled;
+ return [ sort { lc($a->identity) cmp lc($b->identity) } @$list ];
+}
+
sub email_queue_report {
my ($vars, $filter) = @_;
my $dbh = Bugzilla->dbh;
diff --git a/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl b/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl
index dae7f9108..35644c1e4 100644
--- a/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl
+++ b/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl
@@ -24,19 +24,22 @@
<a href="[% urlbase FILTER none %]page.cgi?id=release_tracking_report.html">Release Tracking Report</a>
</strong> - For triaging release-train flag information.
</li>
- [% IF user.in_group('editusers') %]
+ [% IF user.in_group('editusers') || user.in_group('infrasec') %]
<li>
<strong>
<a href="[% urlbase FILTER none %]page.cgi?id=group_admins.html">Group Admins</a>
- </strong> - Group Admins Report
+ </strong> - Lists the administrators of each group.
</li>
- [% END %]
- [% IF user.in_group('editusers') || user.in_group('infrasec') %]
<li>
<strong>
<a href="[% urlbase FILTER none %]page.cgi?id=group_membership.html">Group Membership Report</a>
</strong> - Lists the groups a user is a member of.
</li>
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=group_members.html">Group Members Report</a>
+ </strong> - Lists the users of groups.
+ </li>
[% END %]
[% IF user.in_group('admin') || user.in_group('infra') %]
<li>
diff --git a/extensions/BMO/template/en/default/pages/email_queue.html.tmpl b/extensions/BMO/template/en/default/pages/email_queue.html.tmpl
index 0e4a37551..5c7970506 100644
--- a/extensions/BMO/template/en/default/pages/email_queue.html.tmpl
+++ b/extensions/BMO/template/en/default/pages/email_queue.html.tmpl
@@ -15,7 +15,7 @@
<p><i>[% jobs.size FILTER none %] email(s) in the queue.</i></p>
- <table id="report" cellspacing="0" border="0">
+ <table id="report" class="hover" cellspacing="0" border="0">
<tr id="report-header">
<th>Insert Time</th>
<th>Run Time</th>
diff --git a/extensions/BMO/template/en/default/pages/group_admins.html.tmpl b/extensions/BMO/template/en/default/pages/group_admins.html.tmpl
index 1afcdb0b8..01bb744c4 100644
--- a/extensions/BMO/template/en/default/pages/group_admins.html.tmpl
+++ b/extensions/BMO/template/en/default/pages/group_admins.html.tmpl
@@ -25,7 +25,7 @@
%]
[% IF groups.size > 0 %]
- <table border="0" cellspacing="0" id="report" width="100%">
+ <table border="0" cellspacing="0" id="report" class="hover" width="100%">
<tr id="report-header">
<th align="left">Name</th>
<th align="left">Admins</th>
diff --git a/extensions/BMO/template/en/default/pages/group_members.html.tmpl b/extensions/BMO/template/en/default/pages/group_members.html.tmpl
new file mode 100644
index 000000000..daf4d5b0d
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/group_members.html.tmpl
@@ -0,0 +1,97 @@
+[%# 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.
+ #%]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Group Members Report"
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+%]
+
+<form method="GET" action="page.cgi">
+ <input type="hidden" name="id" value="group_members.html">
+
+ <table id="parameters">
+ <tr>
+ <th>Group</th>
+ <td>
+ <select name="group">
+ [% FOREACH group_name = groups %]
+ <option value="[% group_name FILTER html %]"
+ [% "selected" IF group_name == group %]>
+ [% group_name FILTER html %]</option>
+ [% END %]
+ </select>
+ <input type="checkbox" name="include_disabled" id="include_disabled"
+ value="1" [% "checked" IF include_disabled %]>
+ <label for="include_disabled">
+ Include disabled users
+ </label>
+ <input type="submit" value="Generate">
+ </td>
+ </tr>
+ </table>
+</form>
+
+[% IF group != '' %]
+
+ <p>
+ Members of the <b>[% group FILTER html %]</b> group:
+ </p>
+
+ [% IF types.size > 0 %]
+ <table border="0" cellspacing="0" id="report" class="nohover" width="100%">
+ <tr id="report-header">
+ <th>Type</th>
+ <th>Count</th>
+ <th>Members</th>
+ <th class="right">Last Seen (days ago)</th>
+ </tr>
+
+ [% FOREACH type = types %]
+ [% count = loop.count() %]
+ <tr class="report_item [% count % 2 == 1 ? "report_row_odd" : "report_row_even" %]">
+ <td valign="top">
+ [% "via&nbsp;" UNLESS type.name == 'direct' %]
+ [% type.name FILTER html %]
+ </td>
+ <td valign="top" align="right">
+ [% type.members.size FILTER html %]
+ </td>
+ <td valign="top" width="100%" colspan="2">
+ <table cellspacing="0" class="hoverrow">
+ [% FOREACH member = type.members %]
+ <tr>
+ <td width="100%">
+ <a href="editusers.cgi?action=edit&amp;userid=[% member.id FILTER none %]"
+ target="_blank">
+ <span [% 'class="bz_inactive"' UNLESS member.is_enabled %]>
+ [% member.name FILTER html %] &lt;[% member.email FILTER email FILTER html %]&gt;
+ </span>
+ </a>
+ </td>
+ <td align="right" nowrap>
+ [% member.lastseen FILTER html %]
+ </td>
+ </tr>
+ [% END %]
+ </table>
+ </td>
+ </tr>
+ [% END %]
+ </table>
+
+ <a href="page.cgi?id=group_members.json&amp;group=[% group FILTER uri %]
+ [% IF include_disabled %]&amp;include_disabled=1[% END %]">JSON</a>
+ [% ELSE %]
+ <p>
+ <i>This group is empty.</i>
+ </p>
+ [% END %]
+
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/group_members.json.tmpl b/extensions/BMO/template/en/default/pages/group_members.json.tmpl
new file mode 100644
index 000000000..f80fc8c5f
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/group_members.json.tmpl
@@ -0,0 +1,32 @@
+[%# 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.
+ #%]
+
+[
+ [% SET count = 0 %]
+ [% FOREACH type = types %]
+ [% SET count = count + type.members.size %]
+ [% END %]
+ [% SET i = 0 %]
+ [% FOREACH type = types %]
+ [% FOREACH member = type.members %]
+ [% SET i = i + 1 %]
+ { "login": "[% member.login FILTER email FILTER js %]",
+ [% IF type.name == "direct" %]
+ "membership": "direct",
+ [% ELSE %]
+ "membership": "indirect",
+ "group": [% type.name FILTER js %]",
+ [% END %]
+ [% IF include_disabled %]
+ "disabled": "[% member.is_enabled ? "false" : "true" %]",
+ [% END %]
+ "lastseen": "[% member.lastseen FILTER js %]"
+ }[% "," UNLESS i == count %]
+ [% END %]
+ [% END %]
+]
diff --git a/extensions/BMO/template/en/default/pages/group_membership.html.tmpl b/extensions/BMO/template/en/default/pages/group_membership.html.tmpl
index 2680c7da2..32484b13f 100644
--- a/extensions/BMO/template/en/default/pages/group_membership.html.tmpl
+++ b/extensions/BMO/template/en/default/pages/group_membership.html.tmpl
@@ -48,7 +48,7 @@
[% IF users.size %]
- <table border="0" cellspacing="0" id="report" width="100%">
+ <table border="0" cellspacing="0" id="report" class="hover" width="100%">
[% FOREACH u = users %]
<tr>
<th colspan="3">[% u.user.identity FILTER html %]</th>
diff --git a/extensions/BMO/template/en/default/pages/user_activity.html.tmpl b/extensions/BMO/template/en/default/pages/user_activity.html.tmpl
index 377d7c244..f299b862b 100644
--- a/extensions/BMO/template/en/default/pages/user_activity.html.tmpl
+++ b/extensions/BMO/template/en/default/pages/user_activity.html.tmpl
@@ -106,7 +106,7 @@
[% IF operations.size > 0 %]
<br>
- <table border="1" cellpadding="4" cellspacing="0" id="report">
+ <table border="1" cellpadding="4" cellspacing="0" id="report" class="hover">
<tr id="report-header">
[% IF who_count > 1 %]
<th>Who</th>
diff --git a/extensions/BMO/web/styles/reports.css b/extensions/BMO/web/styles/reports.css
index 2a6bc54fc..7ad0df241 100644
--- a/extensions/BMO/web/styles/reports.css
+++ b/extensions/BMO/web/styles/reports.css
@@ -23,6 +23,10 @@
text-align: left;
}
+#report th.right {
+ text-align: right;
+}
+
#report th.sorted {
text-decoration: underline;
}
@@ -41,7 +45,7 @@
color: #000000;
}
-#report tr:hover {
+#report.hover tr:hover {
background-color: #ccccff;
}
@@ -56,3 +60,7 @@
.disabled {
color: #888888;
}
+
+.hoverrow tr:hover {
+ background-color: #ccccff;
+}