diff options
Diffstat (limited to 'Bugzilla/Auth')
-rw-r--r-- | Bugzilla/Auth/Login.pm | 2 | ||||
-rw-r--r-- | Bugzilla/Auth/Login/Cookie.pm | 79 | ||||
-rw-r--r-- | Bugzilla/Auth/Persist/Cookie.pm | 33 |
3 files changed, 87 insertions, 27 deletions
diff --git a/Bugzilla/Auth/Login.pm b/Bugzilla/Auth/Login.pm index 42ce51c62..7e03778b3 100644 --- a/Bugzilla/Auth/Login.pm +++ b/Bugzilla/Auth/Login.pm @@ -17,7 +17,7 @@ package Bugzilla::Auth::Login; 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 de9188c64..62a6c58a9 100644 --- a/Bugzilla/Auth/Login/Cookie.pm +++ b/Bugzilla/Auth/Login/Cookie.pm @@ -21,13 +21,15 @@ use base qw(Bugzilla::Auth::Login); use Bugzilla::Constants; use Bugzilla::Util; +use Bugzilla::Error; 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. @@ -35,24 +37,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 @@ -76,13 +89,43 @@ sub get_login_info { WHERE cookie = ?", undef, $login_cookie); return { user_id => $user_id }; } + elsif (i_am_webservice()) { + ThrowUserError('invalid_cookies_or_token'); + } } - # Either the he cookie is invalid, or we got no cookie. We don't want - # to ever return AUTH_LOGINFAILED, because we don't want Bugzilla to - # actually throw an error when it gets a bad cookie. It should just - # look like there was no cookie to begin with. + # Either the cookie or token is invalid and we are not authenticating + # via a webservice, or we did not receive a cookie or token. We don't + # want to ever return AUTH_LOGINFAILED, because we don't want Bugzilla to + # actually throw an error when it gets a bad cookie or token. It should just + # look like there was no cookie or token to begin with. 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 (!i_am_webservice()) { + 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 ace474635..c1d133772 100644 --- a/Bugzilla/Auth/Persist/Cookie.pm +++ b/Bugzilla/Auth/Persist/Cookie.pm @@ -36,6 +36,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 { @@ -107,6 +109,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; @@ -120,16 +123,24 @@ 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); + + # Make sure that @login_cookies is not empty to not break SQL statements. + push(@login_cookies, '') unless @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 @@ -138,12 +149,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()"); } |