From a0fcc8ff20fe57bf442402ba227954ffb33a2175 Mon Sep 17 00:00:00 2001 From: Dylan William Hardison Date: Thu, 15 Oct 2015 18:58:09 -0400 Subject: Bug 1196626 - log all authenticated requests --- Bugzilla.pm | 39 ++++++++++++++++++++++++ Bugzilla/Attachment/PatchReader.pm | 9 ++++++ Bugzilla/Config/Admin.pm | 6 ++++ Bugzilla/Search.pm | 1 + Bugzilla/WebService/Bug.pm | 14 +++++++++ attachment.cgi | 4 +++ show_bug.cgi | 5 +++ template/en/default/admin/params/admin.html.tmpl | 4 ++- userprefs.cgi | 9 ++++++ 9 files changed, 90 insertions(+), 1 deletion(-) diff --git a/Bugzilla.pm b/Bugzilla.pm index fa95128d1..b14b92e0d 100644 --- a/Bugzilla.pm +++ b/Bugzilla.pm @@ -594,6 +594,45 @@ sub switch_to_main_db { return $class->dbh_main; } +sub log_user_request { + my ($class, $bug_id, $attach_id, $action) = @_; + + return unless Bugzilla->params->{log_user_requests}; + + my $cgi = $class->cgi; + my $user_id = $class->user->id; + my $request_url = $cgi->request_uri // ''; + my $method = $cgi->request_method; + my $user_agent = $cgi->user_agent // ''; + my $script_name = $cgi->script_name; + my $server = "web"; + + if ($script_name =~ /rest\.cgi/) { + $server = $script_name =~ /BzAPI/ ? "bzapi" : "rest"; + } + elsif ($script_name =~ /xmlrpc\.cgi/) { + $server = "xmlrpc"; + } + elsif ($script_name =~ /jsonrpc\.cgi/) { + $server = "jsonrpc"; + } + + my @params = ($user_id, remote_ip(), $user_agent, $request_url, $method, $bug_id, $attach_id, $action, $server); + foreach my $param (@params) { + trick_taint($param) if defined $param; + } + + eval { + local $class->request_cache->{dbh}; + $class->switch_to_main_db(); + $class->dbh->do("INSERT INTO user_request_log + (user_id, ip_address, user_agent, request_url, + method, timestamp, bug_id, attach_id, action, server) + VALUES (?, ?, ?, ?, ?, NOW(), ?, ?, ?, ?)", undef, @params); + }; + warn $@ if $@; +} + sub is_shadow_db { my $class = shift; return $class->request_cache->{dbh} != $class->dbh_main; diff --git a/Bugzilla/Attachment/PatchReader.pm b/Bugzilla/Attachment/PatchReader.pm index 1ab14f386..2c1647736 100644 --- a/Bugzilla/Attachment/PatchReader.pm +++ b/Bugzilla/Attachment/PatchReader.pm @@ -38,6 +38,9 @@ sub process_diff { if ($format eq 'raw') { require Bugzilla::PatchReader::DiffPrinter::raw; $last_reader->sends_data_to(new Bugzilla::PatchReader::DiffPrinter::raw()); + + Bugzilla->log_user_request($attachment->bug_id, $attachment->id, "attachment-get") + if Bugzilla->user->id; # Actually print out the patch. print $cgi->header(-type => 'text/plain', -expires => '+3M'); @@ -93,6 +96,12 @@ sub process_interdiff { my $lc = Bugzilla->localconfig; my $vars = {}; + if (Bugzilla->user->id) { + foreach my $attachment ($old_attachment, $new_attachment) { + Bugzilla->log_user_request($attachment->bug_id, $attachment->id, "attachment-get"); + } + } + # Encode attachment data as utf8 if it's going to be displayed in a HTML # page using the UTF-8 encoding. if ($format ne 'raw' && Bugzilla->params->{'utf8'}) { diff --git a/Bugzilla/Config/Admin.pm b/Bugzilla/Config/Admin.pm index 769e3170b..b0c0bad9a 100644 --- a/Bugzilla/Config/Admin.pm +++ b/Bugzilla/Config/Admin.pm @@ -63,6 +63,12 @@ sub get_param_list { type => 't', default => 10, checker => \&check_numeric + }, + + { + name => 'log_user_requests', + type => 'b', + default => 0, }); return @param_list; } diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index 46d959c3c..ff0db1baa 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -787,6 +787,7 @@ sub data { return $self->{data} if $self->{data}; my $dbh = Bugzilla->dbh; + Bugzilla->log_user_request(undef, undef, "search") if Bugzilla->user->id; # If all fields belong to the 'bugs' table, there is no need to split # the original query into two pieces. Else we override the 'fields' # argument to first get bug IDs based on the search criteria defined diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index d0fe8465f..d7a1d8f9b 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -458,6 +458,11 @@ sub get { $self->_add_update_tokens($params, \@bugs, \@hashes); + if (Bugzilla->user->id) { + foreach my $bug (@bugs) { + Bugzilla->log_user_request($bug->id, undef, 'bug-get'); + } + } return { bugs => \@hashes, faults => \@faults }; } @@ -1196,6 +1201,7 @@ sub attachments { } my %attachments; + my @log_attachments; foreach my $attach (@{Bugzilla::Attachment->new_from_list($attach_ids)}) { Bugzilla::Bug->check($attach->bug_id); if ($attach->isprivate && !Bugzilla->user->is_insider) { @@ -1203,10 +1209,18 @@ sub attachments { object => 'attachment', attach_id => $attach->id}); } + push @log_attachments, $attach; + $attachments{$attach->id} = $self->_attachment_to_hash($attach, $params); } + if (Bugzilla->user->id) { + foreach my $attachment (@log_attachments) { + Bugzilla->log_user_request($attachment->bug_id, $attachment->id, "attachment-get"); + } + } + return { bugs => \%bugs, attachments => \%attachments }; } diff --git a/attachment.cgi b/attachment.cgi index 78023560d..104ee0ca8 100755 --- a/attachment.cgi +++ b/attachment.cgi @@ -435,6 +435,8 @@ sub view { } } } + Bugzilla->log_user_request($attachment->bug_id, $attachment->id, "attachment-get") + if Bugzilla->user->id; print $cgi->header(-type=>"$contenttype; name=\"$filename\"", -content_disposition=> "$disposition; filename=\"$filename\"", -content_length => $attachment->datasize); @@ -669,6 +671,8 @@ sub edit { $vars->{'attachment'} = $attachment; $vars->{'attachments'} = $bugattachments; + Bugzilla->log_user_request($attachment->bug_id, $attachment->id, "attachment-get") + if Bugzilla->user->id; print $cgi->header(); # Generate and return the UI (HTML page) from the appropriate template. diff --git a/show_bug.cgi b/show_bug.cgi index 06d17e352..fbcf4e828 100755 --- a/show_bug.cgi +++ b/show_bug.cgi @@ -133,6 +133,11 @@ foreach ($cgi->param("excludefield")) { $vars->{'displayfields'} = \%displayfields; +if ($user->id) { + foreach my $bug_id (@bugids) { + Bugzilla->log_user_request($bug_id, undef, 'bug-get'); + } +} print $cgi->header($format->{'ctype'}); $template->process($format->{'template'}, $vars) diff --git a/template/en/default/admin/params/admin.html.tmpl b/template/en/default/admin/params/admin.html.tmpl index f84dbc701..df0580783 100644 --- a/template/en/default/admin/params/admin.html.tmpl +++ b/template/en/default/admin/params/admin.html.tmpl @@ -40,5 +40,7 @@ "will ever happen." last_visit_keep_days => "This option controls how many days $terms.Bugzilla will " _ - "remember when users visit specific ${terms.bugs}."} + "remember when users visit specific ${terms.bugs}.", + + log_user_requests => "This option controls logging of authenticated requests in the user_request_log table"} %] diff --git a/userprefs.cgi b/userprefs.cgi index 6c6a246ff..bd1bb8ab7 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -853,6 +853,12 @@ sub SaveApiKey { revoked => $revoked, }); $api_key->update(); + if ($revoked) { + Bugzilla->log_user_request(undef, undef, 'api-key-revoke') + } + else { + Bugzilla->log_user_request(undef, undef, 'api-key-unrevoke') + } } } } @@ -912,6 +918,7 @@ sub MfaApiKey { revoked => 0, }); $api_key->update(); + Bugzilla->log_user_request(undef, undef, 'api-key-unrevoke'); $dbh->bz_commit_transaction; } } @@ -926,6 +933,8 @@ sub _create_api_key { description => $description, }); + Bugzilla->log_user_request(undef, undef, 'api-key-create'); + # As a security precaution, we always sent out an e-mail when # an API key is created my $template = Bugzilla->template_inner($user->setting('lang')); -- cgit v1.2.3-24-g4f1b