summaryrefslogtreecommitdiffstats
path: root/Bugzilla/Auth
diff options
context:
space:
mode:
authorDave Lawrence <dlawrence@mozilla.com>2013-08-27 05:54:32 +0200
committerDave Lawrence <dlawrence@mozilla.com>2013-08-27 05:54:32 +0200
commit7450b47683d0aa972a522f5b70353e14269a95e6 (patch)
tree1c7908ede712092ac91b1508079e0b8dfebf67ec /Bugzilla/Auth
parent95aadcd21c9a56ef7d3478a2504980ea44f1bd9c (diff)
downloadbugzilla-7450b47683d0aa972a522f5b70353e14269a95e6.tar.gz
bugzilla-7450b47683d0aa972a522f5b70353e14269a95e6.tar.xz
Bug 893195 - Allow token based authentication for webservices
r=glob,a=sgreen
Diffstat (limited to 'Bugzilla/Auth')
-rw-r--r--Bugzilla/Auth/Login.pm2
-rw-r--r--Bugzilla/Auth/Login/Cookie.pm68
-rw-r--r--Bugzilla/Auth/Persist/Cookie.pm32
3 files changed, 79 insertions, 23 deletions
diff --git a/Bugzilla/Auth/Login.pm b/Bugzilla/Auth/Login.pm
index 33d63a425..ddc172689 100644
--- a/Bugzilla/Auth/Login.pm
+++ b/Bugzilla/Auth/Login.pm
@@ -9,7 +9,7 @@ package Bugzilla::Auth::Login;
use 5.10.1;
use strict;
-use fields qw();
+use fields qw(_login_token);
# Determines whether or not a user can logout. It's really a subroutine,
# but we implement it here as a constant. Override it in subclasses if
diff --git a/Bugzilla/Auth/Login/Cookie.pm b/Bugzilla/Auth/Login/Cookie.pm
index 56bc34f40..130fab8e3 100644
--- a/Bugzilla/Auth/Login/Cookie.pm
+++ b/Bugzilla/Auth/Login/Cookie.pm
@@ -20,7 +20,8 @@ use List::Util qw(first);
use constant requires_persistence => 0;
use constant requires_verification => 0;
use constant can_login => 0;
-use constant is_automatic => 1;
+
+sub is_automatic { return $_[0]->login_token ? 0 : 1; }
# Note that Cookie never consults the Verifier, it always assumes
# it has a valid DB account or it fails.
@@ -28,24 +29,35 @@ sub get_login_info {
my ($self) = @_;
my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh;
+ my ($user_id, $login_cookie);
- my $ip_addr = remote_ip();
- my $login_cookie = $cgi->cookie("Bugzilla_logincookie");
- my $user_id = $cgi->cookie("Bugzilla_login");
+ if (!Bugzilla->request_cache->{auth_no_automatic_login}) {
+ $login_cookie = $cgi->cookie("Bugzilla_logincookie");
+ $user_id = $cgi->cookie("Bugzilla_login");
- # If cookies cannot be found, this could mean that they haven't
- # been made available yet. In this case, look at Bugzilla_cookie_list.
- unless ($login_cookie) {
- my $cookie = first {$_->name eq 'Bugzilla_logincookie'}
- @{$cgi->{'Bugzilla_cookie_list'}};
- $login_cookie = $cookie->value if $cookie;
+ # If cookies cannot be found, this could mean that they haven't
+ # been made available yet. In this case, look at Bugzilla_cookie_list.
+ unless ($login_cookie) {
+ my $cookie = first {$_->name eq 'Bugzilla_logincookie'}
+ @{$cgi->{'Bugzilla_cookie_list'}};
+ $login_cookie = $cookie->value if $cookie;
+ }
+ unless ($user_id) {
+ my $cookie = first {$_->name eq 'Bugzilla_login'}
+ @{$cgi->{'Bugzilla_cookie_list'}};
+ $user_id = $cookie->value if $cookie;
+ }
}
- unless ($user_id) {
- my $cookie = first {$_->name eq 'Bugzilla_login'}
- @{$cgi->{'Bugzilla_cookie_list'}};
- $user_id = $cookie->value if $cookie;
+
+ # If no cookies were provided, we also look for a login token
+ # passed in the parameters of a webservice
+ my $token = $self->login_token;
+ if ($token && (!$login_cookie || !$user_id)) {
+ ($user_id, $login_cookie) = ($token->{'user_id'}, $token->{'login_token'});
}
+ my $ip_addr = remote_ip();
+
if ($login_cookie && $user_id) {
# Anything goes for these params - they're just strings which
# we're going to verify against the db
@@ -78,4 +90,32 @@ sub get_login_info {
return { failure => AUTH_NODATA };
}
+sub login_token {
+ my ($self) = @_;
+ my $input = Bugzilla->input_params;
+ my $usage_mode = Bugzilla->usage_mode;
+
+ return $self->{'_login_token'} if exists $self->{'_login_token'};
+
+ if ($usage_mode ne USAGE_MODE_XMLRPC
+ && $usage_mode ne USAGE_MODE_JSON
+ && $usage_mode ne USAGE_MODE_REST) {
+ return $self->{'_login_token'} = undef;
+ }
+
+ # Check if a token was passed in via requests for WebServices
+ my $token = trim(delete $input->{'Bugzilla_token'});
+ return $self->{'_login_token'} = undef if !$token;
+
+ my ($user_id, $login_token) = split('-', $token, 2);
+ if (!detaint_natural($user_id) || !$login_token) {
+ return $self->{'_login_token'} = undef;
+ }
+
+ return $self->{'_login_token'} = {
+ user_id => $user_id,
+ login_token => $login_token
+ };
+}
+
1;
diff --git a/Bugzilla/Auth/Persist/Cookie.pm b/Bugzilla/Auth/Persist/Cookie.pm
index 15a2d490e..9681bcea2 100644
--- a/Bugzilla/Auth/Persist/Cookie.pm
+++ b/Bugzilla/Auth/Persist/Cookie.pm
@@ -15,6 +15,8 @@ use Bugzilla::Constants;
use Bugzilla::Util;
use Bugzilla::Token;
+use Bugzilla::Auth::Login::Cookie qw(login_token);
+
use List::Util qw(first);
sub new {
@@ -86,6 +88,7 @@ sub logout {
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
+ my $input = Bugzilla->input_params;
$param = {} unless $param;
my $user = $param->{user} || Bugzilla->user;
my $type = $param->{type} || LOGOUT_ALL;
@@ -99,16 +102,23 @@ sub logout {
# The LOGOUT_*_CURRENT options require the current login cookie.
# If a new cookie has been issued during this run, that's the current one.
# If not, it's the one we've received.
+ my @login_cookies;
my $cookie = first {$_->name eq 'Bugzilla_logincookie'}
@{$cgi->{'Bugzilla_cookie_list'}};
- my $login_cookie;
if ($cookie) {
- $login_cookie = $cookie->value;
+ push(@login_cookies, $cookie->value);
}
else {
- $login_cookie = $cgi->cookie("Bugzilla_logincookie");
+ push(@login_cookies, $cgi->cookie("Bugzilla_logincookie"));
+ }
+
+ # If we are a webservice using a token instead of cookie
+ # then add that as well to the login cookies to delete
+ if (my $login_token = $user->authorizer->login_token) {
+ push(@login_cookies, $login_token->{'login_token'});
}
- trick_taint($login_cookie);
+
+ return if !@login_cookies;
# These queries use both the cookie ID and the user ID as keys. Even
# though we know the userid must match, we still check it in the SQL
@@ -117,12 +127,18 @@ sub logout {
# logged in and got the same cookie, we could be logging the other
# user out here. Yes, this is very very very unlikely, but why take
# chances? - bbaetz
+ map { trick_taint($_) } @login_cookies;
+ @login_cookies = map { $dbh->quote($_) } @login_cookies;
if ($type == LOGOUT_KEEP_CURRENT) {
- $dbh->do("DELETE FROM logincookies WHERE cookie != ? AND userid = ?",
- undef, $login_cookie, $user->id);
+ $dbh->do("DELETE FROM logincookies WHERE " .
+ $dbh->sql_in('cookie', \@login_cookies, 1) .
+ " AND userid = ?",
+ undef, $user->id);
} elsif ($type == LOGOUT_CURRENT) {
- $dbh->do("DELETE FROM logincookies WHERE cookie = ? AND userid = ?",
- undef, $login_cookie, $user->id);
+ $dbh->do("DELETE FROM logincookies WHERE " .
+ $dbh->sql_in('cookie', \@login_cookies) .
+ " AND userid = ?",
+ undef, $user->id);
} else {
die("Invalid type $type supplied to logout()");
}