diff options
author | Dylan William Hardison <dylan@hardison.net> | 2015-08-24 20:04:19 +0200 |
---|---|---|
committer | Dylan William Hardison <dylan@hardison.net> | 2015-08-24 20:04:48 +0200 |
commit | d03b432557e0422d5b0dbd32e82d36d3f9a5b68a (patch) | |
tree | 062a315373e97c80804ffcdfde989612a50003fe | |
parent | 59f96419500ae8c1b87b06abb0a5cca9f165b030 (diff) | |
download | bugzilla-d03b432557e0422d5b0dbd32e82d36d3f9a5b68a.tar.gz bugzilla-d03b432557e0422d5b0dbd32e82d36d3f9a5b68a.tar.xz |
Bug 1192687 - add the ability for users to view and revoke existing sessions
-rw-r--r-- | Bugzilla/Auth/Login/Cookie.pm | 11 | ||||
-rw-r--r-- | Bugzilla/User/Session.pm | 48 | ||||
-rw-r--r-- | template/en/default/account/prefs/prefs.html.tmpl | 6 | ||||
-rw-r--r-- | template/en/default/account/prefs/sessions.html.tmpl | 56 | ||||
-rwxr-xr-x | userprefs.cgi | 53 |
5 files changed, 173 insertions, 1 deletions
diff --git a/Bugzilla/Auth/Login/Cookie.pm b/Bugzilla/Auth/Login/Cookie.pm index e1faa52d0..46024bca4 100644 --- a/Bugzilla/Auth/Login/Cookie.pm +++ b/Bugzilla/Auth/Login/Cookie.pm @@ -19,7 +19,7 @@ package Bugzilla::Auth::Login::Cookie; use strict; use base qw(Bugzilla::Auth::Login); -use fields qw(_login_token); +use fields qw(_login_token _cookie); use Bugzilla::Constants; use Bugzilla::Error; @@ -58,6 +58,8 @@ sub get_login_info { @{$cgi->{'Bugzilla_cookie_list'}}; $user_id = $cookie->value if $cookie; } + trick_taint($login_cookie) if $login_cookie; + $self->cookie($login_cookie); # If the call is for a web service, and an api token is provided, check # it is valid. @@ -155,4 +157,11 @@ sub login_token { }; } +sub cookie { + my ($self, $val) = @_; + $self->{_cookie} = $val if @_ > 1; + + return $self->{_cookie}; +} + 1; diff --git a/Bugzilla/User/Session.pm b/Bugzilla/User/Session.pm new file mode 100644 index 000000000..c547867d1 --- /dev/null +++ b/Bugzilla/User/Session.pm @@ -0,0 +1,48 @@ +# 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. + +package Bugzilla::User::Session; + +use 5.10.1; +use strict; + +use parent qw(Bugzilla::Object); + +##################################################################### +# Overriden Constants that are used as methods +##################################################################### + +use constant DB_TABLE => 'logincookies'; +use constant DB_COLUMNS => qw( + cookie + userid + lastused + ipaddr + id + restrict_ipaddr +); + +use constant UPDATE_COLUMNS => qw(); +use constant VALIDATORS => {}; +use constant LIST_ORDER => 'lastused DESC'; +use constant NAME_FIELD => 'cookie'; + +# turn off auditing and exclude these objects from memcached +use constant { AUDIT_CREATES => 0, + AUDIT_UPDATES => 0, + AUDIT_REMOVES => 0, + USE_MEMCACHED => 0 }; + +# Accessors +sub id { return $_[0]->{id} } +sub userid { return $_[0]->{userid} } +sub cookie { return $_[0]->{cookie} } +sub lastused { return $_[0]->{lastused} } +sub ipaddr { return $_[0]->{ipaddr} } +sub restrict_ipaddr { return $_[0]->{restrict_ipaddr} } + +1; diff --git a/template/en/default/account/prefs/prefs.html.tmpl b/template/en/default/account/prefs/prefs.html.tmpl index 9610752ed..679a3cb30 100644 --- a/template/en/default/account/prefs/prefs.html.tmpl +++ b/template/en/default/account/prefs/prefs.html.tmpl @@ -72,6 +72,12 @@ saveable => "1" }, { + name => "sessions", + label => "Sessions", + link => "userprefs.cgi?tab=sessions", + saveable => "1", + }, + { name => "apikey", label => "API Keys", link => "userprefs.cgi?tab=apikey", diff --git a/template/en/default/account/prefs/sessions.html.tmpl b/template/en/default/account/prefs/sessions.html.tmpl new file mode 100644 index 000000000..13257ef01 --- /dev/null +++ b/template/en/default/account/prefs/sessions.html.tmpl @@ -0,0 +1,56 @@ +[%# 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. + #%] + +[%# INTERFACE: + # sessions: array. Array of sessions this user has. + # session_max: int. Number of sessions that can be displayed at once. + # session_count: int. Total of number of sessions for the user. + # too_many_sessions: boolean. True if there are more than 20 sessions. + #%] + +<p>Here you can see your active [% terms.Bugzilla %] sessions. + You can logout these sessions, which means when you use [% terms.Bugzilla %] + from that location again you will have to log back in.</p> + +<p>Note that you may not logout your current session from this page. + You can use the "Logout" link from the top right menu for that.</p> + +<h3>Active Sessions</h3> + +[% IF too_many_sessions %] + <p>You have [% session_count FILTER html %] sessions. Display limited to most + recent [% session_max FILTER html %].</p> +[% END %] + +<p> + <input type="submit" name="session_logout_all" value="Log out all other sessions"> +</p> + +<table id="email_prefs"> + <tr class="column_header"> + <th>Last used</th> + <th>IP Address</th> + <th>IP Restriction</th> + <th>Logout</th> + </tr> + + [% FOREACH session IN sessions %] + <tr> + <td>[% session.lastused FILTER time %]</td> + <td>[% session.ipaddr OR "Unknown" FILTER html %]</td> + <td>[% session.restrict_ipaddr ? "Restricted" : "Unrestricted" FILTER html %] + <td> + [% IF session.current %] + <b>(current)</b> + [% ELSE %] + <input type="checkbox" name="session_logout_id" + value="[% session.id FILTER html %]"></td> + [% END %] + </tr> + [% END %] +</table>
\ No newline at end of file diff --git a/userprefs.cgi b/userprefs.cgi index 8f18de8c4..72a8dfb69 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -35,9 +35,12 @@ use Bugzilla::Util; use Bugzilla::Error; use Bugzilla::User; use Bugzilla::User::Setting qw(clear_settings_cache); +use Bugzilla::User::Session; use Bugzilla::User::APIKey; use Bugzilla::Token; +use constant SESSION_MAX => 20; + my $template = Bugzilla->template; local our $vars = {}; @@ -539,6 +542,51 @@ sub SaveSavedSearches { Bugzilla->memcached->clear({ table => 'profiles', id => $user->id }); } +sub SaveSessions { + my $cgi = Bugzilla->cgi; + my $dbh = Bugzilla->dbh; + my $user = Bugzilla->user; + + # Do it in a transaction. + $dbh->bz_start_transaction; + if ($cgi->param("session_logout_all")) { + my $info_getter = $user->authorizer && $user->authorizer->successful_info_getter(); + if ($info_getter->cookie) { + $dbh->do("DELETE FROM logincookies WHERE userid = ? AND cookie != ?", undef, + $user->id, $info_getter->cookie); + } + } + else { + my @logout_ids = $cgi->param('session_logout_id'); + my $sessions = Bugzilla::User::Session->new_from_list(\@logout_ids); + foreach my $session (@$sessions) { + $session->remove_from_db if $session->userid == $user->id; + } + } + + $dbh->bz_commit_transaction; +} + +sub DoSessions { + my $user = Bugzilla->user; + my $dbh = Bugzilla->dbh; + my $sessions = Bugzilla::User::Session->match({ userid => $user->id, LIMIT => SESSION_MAX + 1 }); + my $info_getter = $user->authorizer && $user->authorizer->successful_info_getter(); + + if ($info_getter) { + foreach my $session (@$sessions) { + $session->{current} = $info_getter->cookie eq $session->{cookie}; + } + } + my ($count) = $dbh->selectrow_array("SELECT count(*) FROM logincookies WHERE userid = ?", undef, + $user->id); + + $vars->{too_many_sessions} = @$sessions == SESSION_MAX + 1; + $vars->{sessions} = $sessions; + $vars->{session_count} = $count; + $vars->{session_max} = SESSION_MAX; + pop @$sessions if $vars->{too_many_sessions}; +} sub DoApiKey { my $user = Bugzilla->user; @@ -669,6 +717,11 @@ SWITCH: for ($current_tab_name) { DoApiKey(); last SWITCH; }; + /^sessions$/ && do { + SaveSessions() if $save_changes; + DoSessions(); + last SWITCH; + }; ThrowUserError("unknown_tab", { current_tab_name => $current_tab_name }); |