Commit 8a06f991 authored by kiko%async.com.br's avatar kiko%async.com.br

Fix for bug 226764: Move InvalidateLogins into Bugzilla::Auth::CGI.

Consolidates the logout code into Bugzilla::Auth::CGI, and provides simple front-end wrappers in Bugzilla.pm for use in the CGIs we have. r=bbaetz, joel; a=justdave. Adds a set of constants to the logout() API which allow specifying "how much" we should log out -- all sessions, the current session, or all sessions but the current one. Fixes callsites to use this new API; cleans and documents things a bit while we're at it. Part I in the great COOKIE apocalypse.
parent a66d86a8
...@@ -83,33 +83,53 @@ sub login { ...@@ -83,33 +83,53 @@ sub login {
# so it needs to be set. # so it needs to be set.
$::COOKIE{'Bugzilla_login'} = $_user->login; $::COOKIE{'Bugzilla_login'} = $_user->login;
} else { } else {
# Old compat stuff logout_request();
undef $_user;
$::userid = 0;
delete $::COOKIE{'Bugzilla_login'};
delete $::COOKIE{'Bugzilla_logincookie'};
# NB - Can't delete from $cgi->cookie, so the cookie data will
# remain there
# People shouldn't rely on the cookie param for the username
# - use Bugzilla->user instead!
} }
return $_user; return $_user;
} }
sub logout { sub logout {
my ($class, $option) = @_;
if (! $_user) {
# If we're not logged in, go away
return;
}
$option = LOGOUT_CURRENT unless defined $option;
use Bugzilla::Auth::CGI;
Bugzilla::Auth::CGI->logout($_user, $option);
if ($option != LOGOUT_KEEP_CURRENT) {
Bugzilla::Auth::CGI->clear_browser_cookies();
logout_request();
}
}
sub logout_user {
my ($class, $user) = @_;
# When we're logging out another user we leave cookies alone, and
# therefore avoid calling logout() directly.
use Bugzilla::Auth::CGI; use Bugzilla::Auth::CGI;
# remove cookies and clean up database state Bugzilla::Auth::CGI->logout($user, LOGOUT_ALL);
Bugzilla::Auth::CGI->logout();
logout_request();
} }
# just a compatibility front-end to logout_user that gets a user by id
sub logout_user_by_id {
my ($class, $id) = @_;
my $user = new Bugzilla::User($id);
$class->logout_user($user);
}
# hack that invalidates credentials for a single request
sub logout_request { sub logout_request {
undef $_user; undef $_user;
$::userid = 0; $::userid = 0;
# XXX clean these up eventually
delete $::COOKIE{"Bugzilla_login"}; delete $::COOKIE{"Bugzilla_login"};
delete $::COOKIE{"Bugzilla_logincookie"}; # NB - Can't delete from $cgi->cookie, so the logincookie data will
# remain there; it's only used in Bugzilla::Auth::CGI->logout anyway
# People shouldn't rely on the cookie param for the username
# - use Bugzilla->user instead!
} }
my $_dbh; my $_dbh;
...@@ -264,7 +284,7 @@ method for those scripts/templates which are only use via CGI, though. ...@@ -264,7 +284,7 @@ method for those scripts/templates which are only use via CGI, though.
=item C<user> =item C<user>
The current L<Bugzilla::User>. C<undef> if there is no currently logged in user The current C<Bugzilla::User>. C<undef> if there is no currently logged in user
or if the login code has not yet been run. or if the login code has not yet been run.
=item C<login> =item C<login>
...@@ -273,15 +293,29 @@ Logs in a user, returning a C<Bugzilla::User> object, or C<undef> if there is ...@@ -273,15 +293,29 @@ Logs in a user, returning a C<Bugzilla::User> object, or C<undef> if there is
no logged in user. See L<Bugzilla::Auth|Bugzilla::Auth> and no logged in user. See L<Bugzilla::Auth|Bugzilla::Auth> and
L<Bugzilla::User|Bugzilla::User>. L<Bugzilla::User|Bugzilla::User>.
=item C<logout> =item C<logout($option)>
Logs out the current user, which involves invalidating user sessions and
cookies. Three options are available from
L<Bugzilla::Constants|Bugzilla::Constants>: LOGOUT_CURRENT (the
default), LOGOUT_ALL or LOGOUT_KEEP_CURRENT.
=item C<logout_user($user)>
Logs out the specified user (invalidating all his sessions), taking a
Bugzilla::User instance.
=item C<logout_by_id($id)>
Logs out the current user. Logs out the user with the id specified. This is a compatibility
function to be used in callsites where there is only a userid and no
Bugzilla::User instance.
=item C<logout_request> =item C<logout_request>
Essentially, causes calls to C<user> to return C<undef>. This has the Essentially, causes calls to C<Bugzilla->user> to return C<undef>. This has the
effect of logging out a user for the current request only; cookies and effect of logging out a user for the current request only; cookies and
database state are left intact. database sessions are left intact.
=item C<dbh> =item C<dbh>
......
...@@ -73,15 +73,18 @@ Bugzilla::Auth - Authentication handling for Bugzilla users ...@@ -73,15 +73,18 @@ Bugzilla::Auth - Authentication handling for Bugzilla users
Handles authentication for Bugzilla users. Handles authentication for Bugzilla users.
Authentication from Bugzilla involves two sets of modules. One set is used to Authentication from Bugzilla involves two sets of modules. One set is
obtain the data (from CGI, email, etc), and the other set uses this data to used to obtain the data (from CGI, email, etc), and the other set uses
authenticate against the datasource (the Bugzilla DB, LDAP, cookies, etc). this data to authenticate against the datasource (the Bugzilla DB, LDAP,
cookies, etc).
The handlers for the various types of authentication (DB/LDAP/cookies/etc) The handlers for the various types of authentication
provide the actual code for each specific method of authentication. (DB/LDAP/cookies/etc) provide the actual code for each specific method
of authentication.
The source modules (currently, only L<Bugzilla::Auth::CGI|Bugzilla::Auth::CGI> The source modules (currently, only
then use those methods to do the authentication. L<Bugzilla::Auth::CGI|Bugzilla::Auth::CGI>) then use those methods to do
the authentication.
I<Bugzilla::Auth> itself inherits from the default authentication handler, I<Bugzilla::Auth> itself inherits from the default authentication handler,
identified by the I<loginmethod> param. identified by the I<loginmethod> param.
...@@ -96,16 +99,16 @@ authentication or login modules. ...@@ -96,16 +99,16 @@ authentication or login modules.
=item C<Bugzilla::Auth::get_netaddr($ipaddr)> =item C<Bugzilla::Auth::get_netaddr($ipaddr)>
Given an ip address, this returns the associated network address, using Given an ip address, this returns the associated network address, using
C<Param('loginnetmask')> at the netmask. This can be used to obtain data in C<Param('loginnetmask')> as the netmask. This can be used to obtain data
order to restrict weak authentication methods (such as cookies) to only some in order to restrict weak authentication methods (such as cookies) to
addresses. only some addresses.
=back =back
=head1 AUTHENTICATION =head1 AUTHENTICATION
Authentication modules check a users's credentials (username, password, etc) to Authentication modules check a user's credentials (username, password,
verify who the user is. etc) to verify who the user is.
=head2 METHODS =head2 METHODS
...@@ -113,19 +116,21 @@ verify who the user is. ...@@ -113,19 +116,21 @@ verify who the user is.
=item C<authenticate($username, $pass)> =item C<authenticate($username, $pass)>
This method is passed a username and a password, and returns a list containing This method is passed a username and a password, and returns a list
up to four return values, depending on the results of the authentication. containing up to four return values, depending on the results of the
authentication.
The first return value is one of the status codes defined in The first return value is one of the status codes defined in
L<Bugzilla::Constants|Bugzilla::Constants> and described below. The rest of L<Bugzilla::Constants|Bugzilla::Constants> and described below. The
the return values are status code-specific and are explained in the status rest of the return values are status code-specific and are explained in
code descriptions. the status code descriptions.
=over 4 =over 4
=item C<AUTH_OK> =item C<AUTH_OK>
Authentication succeeded. The second variable is the userid of the new user. Authentication succeeded. The second variable is the userid of the new
user.
=item C<AUTH_NODATA> =item C<AUTH_NODATA>
...@@ -162,41 +167,52 @@ information. ...@@ -162,41 +167,52 @@ information.
=item C<AUTH_DISABLED> =item C<AUTH_DISABLED>
The user successfully logged in, but their account has been disabled. The The user successfully logged in, but their account has been disabled.
second argument in the returned array is the userid, and the third is some The second argument in the returned array is the userid, and the third
text explaining why the account was disabled. This text would typically come is some text explaining why the account was disabled. This text would
from the C<disabledtext> field in the C<profiles> table. Note that this typically come from the C<disabledtext> field in the C<profiles> table.
argument is a string, not a tag. Note that this argument is a string, not a tag.
=back =back
=item C<can_edit> =item C<can_edit>
This determines if the user's account details can be modified. If this This determines if the user's account details can be modified. If this
method returns a C<true> value, then accounts can be created and modified method returns a C<true> value, then accounts can be created and
through the Bugzilla user interface. Forgotten passwords can also be modified through the Bugzilla user interface. Forgotten passwords can
retrieved through the L<Token interface|Bugzilla::Token>. also be retrieved through the L<Token interface|Bugzilla::Token>.
=back =back
=head1 LOGINS =head1 LOGINS
A login module can be used to try to log in a Bugzilla user in a particular A login module can be used to try to log in a Bugzilla user in a
way. For example, L<Bugzilla::Auth::CGI|Bugzilla::Auth::CGI> logs in users particular way. For example, L<Bugzilla::Auth::CGI|Bugzilla::Auth::CGI>
from CGI scripts, first by trying database authentication against the logs in users from CGI scripts, first by using form variables, and then
Bugzilla C<profiles> table, and then by trying cookies as a fallback. by trying cookies as a fallback.
A login module consists of a single method, C<login>, which takes a C<$type> The login interface consists of the following methods:
argument, using constants found in C<Bugzilla::Constants>.
=item C<login>, which takes a C<$type> argument, using constants found in
C<Bugzilla::Constants>.
The login method may use various authentication modules (described
above) to try to authenticate a user, and should return the userid on
success, or C<undef> on failure.
When a login is required, but data is not present, it is the job of the
login method to prompt the user for this data.
The constants accepted by C<login> include the following:
=over 4 =over 4
=item C<LOGIN_OPTIONAL> =item C<LOGIN_OPTIONAL>
A login is never required to access this data. Attempting to login is still A login is never required to access this data. Attempting to login is
useful, because this allows the page to be personalised. Note that an still useful, because this allows the page to be personalised. Note that
incorrect login will still trigger an error, even though the lack of a login an incorrect login will still trigger an error, even though the lack of
will be OK. a login will be OK.
=item C<LOGIN_NORMAL> =item C<LOGIN_NORMAL>
...@@ -209,12 +225,30 @@ A login is always required to access this data. ...@@ -209,12 +225,30 @@ A login is always required to access this data.
=back =back
The login module uses various authentication modules to try to authenticate =item C<logout>, which takes a C<Bugzilla::User> argument for the user
a user, and returns the userid on success, or C<undef> on failure. being logged out, and an C<$option> argument. Possible values for
C<$option> include:
=over 4
=item C<LOGOUT_CURRENT>
When a login is required, but data is not present, it is the job of the login Log out the user and invalidate his currently registered session.
module to prompt the user for this data.
=item C<LOGOUT_ALL>
Log out the user, and invalidate all sessions the user has registered in
Bugzilla.
=item C<LOGOUT_KEEP_CURRENT>
Invalidate all sessions the user has registered excluding his current
session; this option should leave the user logged in. This is useful for
user-performed password changes.
=back
=head1 SEE ALSO =head1 SEE ALSO
L<Bugzilla::Auth::CGI>, L<Bugzilla::Auth::Cookie>, L<Bugzilla::Auth::DB> L<Bugzilla::Auth::CGI>, L<Bugzilla::Auth::Cookie>, L<Bugzilla::Auth::DB>
...@@ -34,6 +34,7 @@ use lib "."; ...@@ -34,6 +34,7 @@ use lib ".";
require "CGI.pl"; require "CGI.pl";
require "globals.pl"; require "globals.pl";
use Bugzilla;
use Bugzilla::User; use Bugzilla::User;
# Shut up misguided -w warnings about "used only once". "use vars" just # Shut up misguided -w warnings about "used only once". "use vars" just
...@@ -660,8 +661,7 @@ if ($action eq 'delete') { ...@@ -660,8 +661,7 @@ if ($action eq 'delete') {
SendSQL("DELETE FROM profiles SendSQL("DELETE FROM profiles
WHERE login_name=" . SqlQuote($user)); WHERE login_name=" . SqlQuote($user));
SendSQL("DELETE FROM logincookies Bugzilla->logout_user_by_id($userid);
WHERE userid=" . $userid);
print "User deleted.<BR>\n"; print "User deleted.<BR>\n";
PutTrailer($localtrailer); PutTrailer($localtrailer);
...@@ -818,7 +818,7 @@ if ($action eq 'update') { ...@@ -818,7 +818,7 @@ if ($action eq 'update') {
FROM profiles FROM profiles
WHERE login_name=" . SqlQuote($userold)); WHERE login_name=" . SqlQuote($userold));
my $userid = FetchOneColumn(); my $userid = FetchOneColumn();
InvalidateLogins($userid); Bugzilla->logout_user_by_id($userid);
print "Updated password.<BR>\n"; print "Updated password.<BR>\n";
} else { } else {
print "Did not update password: $passworderror<br>\n"; print "Did not update password: $passworderror<br>\n";
...@@ -838,7 +838,7 @@ if ($action eq 'update') { ...@@ -838,7 +838,7 @@ if ($action eq 'update') {
FROM profiles FROM profiles
WHERE login_name=" . SqlQuote($userold)); WHERE login_name=" . SqlQuote($userold));
my $userid = FetchOneColumn(); my $userid = FetchOneColumn();
InvalidateLogins($userid); Bugzilla->logout_user_by_id($userid);
print "Updated disabled text.<BR>\n"; print "Updated disabled text.<BR>\n";
} }
if ($editall && $user ne $userold) { if ($editall && $user ne $userold) {
......
...@@ -425,19 +425,6 @@ sub InsertNewUser { ...@@ -425,19 +425,6 @@ sub InsertNewUser {
return $password; return $password;
} }
# Removes all entries from logincookies for $userid, except for the
# optional $keep, which refers the logincookies.cookie primary key.
# (This is useful so that a user changing their password stays logged in)
sub InvalidateLogins {
my ($userid, $keep) = @_;
my $remove = "DELETE FROM logincookies WHERE userid = $userid";
if (defined $keep) {
$remove .= " AND cookie != " . SqlQuote($keep);
}
SendSQL($remove);
}
sub GenerateRandomPassword { sub GenerateRandomPassword {
my ($size) = @_; my ($size) = @_;
......
...@@ -201,7 +201,7 @@ sub changePassword { ...@@ -201,7 +201,7 @@ sub changePassword {
SendSQL("DELETE FROM tokens WHERE token = $::quotedtoken"); SendSQL("DELETE FROM tokens WHERE token = $::quotedtoken");
SendSQL("UNLOCK TABLES"); SendSQL("UNLOCK TABLES");
InvalidateLogins($userid); Bugzilla->logout_user_by_id($userid);
$vars->{'message'} = "password_changed"; $vars->{'message'} = "password_changed";
......
...@@ -26,6 +26,7 @@ use strict; ...@@ -26,6 +26,7 @@ use strict;
use lib qw(.); use lib qw(.);
use Bugzilla; use Bugzilla;
use Bugzilla::Constants;
require "CGI.pl"; require "CGI.pl";
...@@ -108,8 +109,9 @@ sub SaveAccount { ...@@ -108,8 +109,9 @@ sub SaveAccount {
SendSQL("UPDATE profiles SendSQL("UPDATE profiles
SET cryptpassword = $cryptedpassword SET cryptpassword = $cryptedpassword
WHERE userid = $userid"); WHERE userid = $userid");
# Invalidate all logins except for the current one # Invalidate all logins except for the current one
InvalidateLogins($userid, $cgi->cookie("Bugzilla_logincookie")); Bugzilla->logout(LOGOUT_KEEP_CURRENT);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment