summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/Auth/Login/Cookie.pm11
-rw-r--r--Bugzilla/User/Session.pm48
-rw-r--r--template/en/default/account/prefs/prefs.html.tmpl6
-rw-r--r--template/en/default/account/prefs/sessions.html.tmpl56
-rwxr-xr-xuserprefs.cgi53
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 });