зеркало из https://github.com/mozilla/pjs.git
Fix for bug 226754: 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.
This commit is contained in:
Родитель
ddab364f3c
Коммит
89fefb09e2
|
@ -1,243 +0,0 @@
|
|||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
# Dan Mosedale <dmose@mozilla.org>
|
||||
# Joe Robins <jmrobins@tgix.com>
|
||||
# Dave Miller <justdave@syndicomm.com>
|
||||
# Christopher Aillon <christopher@aillon.com>
|
||||
# Gervase Markham <gerv@gerv.net>
|
||||
# Christian Reis <kiko@async.com.br>
|
||||
# Bradley Baetz <bbaetz@acm.org>
|
||||
|
||||
package Bugzilla::Auth::CGI;
|
||||
|
||||
use strict;
|
||||
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Util;
|
||||
|
||||
sub login {
|
||||
my ($class, $type) = @_;
|
||||
|
||||
# 'NORMAL' logins depend on the 'requirelogin' param
|
||||
if ($type == LOGIN_NORMAL) {
|
||||
$type = Param('requirelogin') ? LOGIN_REQUIRED : LOGIN_OPTIONAL;
|
||||
}
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
|
||||
# First, try the actual login method against form variables
|
||||
my $username = $cgi->param("Bugzilla_login");
|
||||
my $passwd = $cgi->param("Bugzilla_password");
|
||||
|
||||
my $authmethod = Param("loginmethod");
|
||||
my ($authres, $userid, $extra, $info) =
|
||||
Bugzilla::Auth->authenticate($username, $passwd);
|
||||
|
||||
if ($authres == AUTH_OK) {
|
||||
# Login via username/password was correct and valid, so create
|
||||
# and send out the login cookies
|
||||
my $ipaddr = $cgi->remote_addr;
|
||||
unless ($cgi->param('Bugzilla_restrictlogin') ||
|
||||
Param('loginnetmask') == 32) {
|
||||
$ipaddr = Bugzilla::Auth::get_netaddr($ipaddr);
|
||||
}
|
||||
|
||||
# The IP address is valid, at least for comparing with itself in a
|
||||
# subsequent login
|
||||
trick_taint($ipaddr);
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("INSERT INTO logincookies (userid, ipaddr) VALUES (?, ?)",
|
||||
undef,
|
||||
$userid, $ipaddr);
|
||||
my $logincookie = $dbh->selectrow_array("SELECT LAST_INSERT_ID()");
|
||||
|
||||
# Remember cookie only if admin has told so
|
||||
# or admin didn't forbid it and user told to remember.
|
||||
if ((Param('rememberlogin') eq 'on') ||
|
||||
((Param('rememberlogin') ne 'off') &&
|
||||
($cgi->param('Bugzilla_remember') eq 'on'))) {
|
||||
$cgi->send_cookie(-name => 'Bugzilla_login',
|
||||
-value => $userid,
|
||||
-expires => 'Fri, 01-Jan-2038 00:00:00 GMT');
|
||||
$cgi->send_cookie(-name => 'Bugzilla_logincookie',
|
||||
-value => $logincookie,
|
||||
-expires => 'Fri, 01-Jan-2038 00:00:00 GMT');
|
||||
|
||||
}
|
||||
else {
|
||||
$cgi->send_cookie(-name => 'Bugzilla_login',
|
||||
-value => $userid);
|
||||
$cgi->send_cookie(-name => 'Bugzilla_logincookie',
|
||||
-value => $logincookie);
|
||||
|
||||
}
|
||||
|
||||
# compat code. The cookie value is used for logouts, and that
|
||||
# isn't generic yet.
|
||||
$::COOKIE{'Bugzilla_logincookie'} = $logincookie;
|
||||
}
|
||||
elsif ($authres == AUTH_NODATA) {
|
||||
# No data from the form, so try to login via cookies
|
||||
$username = $cgi->cookie("Bugzilla_login");
|
||||
$passwd = $cgi->cookie("Bugzilla_logincookie");
|
||||
|
||||
require Bugzilla::Auth::Cookie;
|
||||
my $authmethod = "Cookie";
|
||||
|
||||
($authres, $userid, $extra) =
|
||||
Bugzilla::Auth::Cookie->authenticate($username, $passwd);
|
||||
|
||||
# If the data for the cookie was incorrect, then treat that as
|
||||
# NODATA. This could occur if the user's IP changed, for example.
|
||||
# Give them un-loggedin access if allowed (checked below)
|
||||
$authres = AUTH_NODATA if $authres == AUTH_LOGINFAILED;
|
||||
}
|
||||
|
||||
# Now check the result
|
||||
|
||||
# An error may have occurred with the login mechanism
|
||||
if ($authres == AUTH_ERROR) {
|
||||
ThrowCodeError("auth_err",
|
||||
{ authmethod => lc($authmethod),
|
||||
userid => $userid,
|
||||
auth_err_tag => $extra,
|
||||
info => $info
|
||||
});
|
||||
}
|
||||
|
||||
# We can load the page if the login was ok, or there was no data
|
||||
# but a login wasn't required
|
||||
if ($authres == AUTH_OK ||
|
||||
($authres == AUTH_NODATA && $type == LOGIN_OPTIONAL)) {
|
||||
|
||||
# login succeded, so we're done
|
||||
return $userid;
|
||||
}
|
||||
|
||||
# No login details were given, but we require a login if the
|
||||
# page does
|
||||
if ($authres == AUTH_NODATA && $type == LOGIN_REQUIRED) {
|
||||
# Throw up the login page
|
||||
|
||||
print Bugzilla->cgi->header();
|
||||
|
||||
my $template = Bugzilla->template;
|
||||
$template->process("account/auth/login.html.tmpl",
|
||||
{ 'target' => $cgi->url(-relative=>1),
|
||||
'form' => \%::FORM,
|
||||
'mform' => \%::MFORM,
|
||||
'caneditaccount' => Bugzilla::Auth->can_edit,
|
||||
}
|
||||
)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
# This seems like as good as time as any to get rid of old
|
||||
# crufty junk in the logincookies table. Get rid of any entry
|
||||
# that hasn't been used in a month.
|
||||
Bugzilla->dbh->do("DELETE FROM logincookies " .
|
||||
"WHERE TO_DAYS(NOW()) - TO_DAYS(lastused) > 30");
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
# The username/password may be wrong
|
||||
# Don't let the user know whether the username exists or whether
|
||||
# the password was just wrong. (This makes it harder for a cracker
|
||||
# to find account names by brute force)
|
||||
if ($authres == AUTH_LOGINFAILED) {
|
||||
ThrowUserError("invalid_username_or_password");
|
||||
}
|
||||
|
||||
# The account may be disabled
|
||||
if ($authres == AUTH_DISABLED) {
|
||||
# Clear the cookie
|
||||
|
||||
$cgi->send_cookie(-name => 'Bugzilla_login',
|
||||
-expires => "Tue, 15-Sep-1998 21:49:00 GMT");
|
||||
$cgi->send_cookie(-name => 'Bugzilla_logincookie',
|
||||
-expires => "Tue, 15-Sep-1998 21:49:00 GMT");
|
||||
|
||||
# and throw a user error
|
||||
ThrowUserError("account_disabled",
|
||||
{'disabled_reason' => $extra});
|
||||
}
|
||||
|
||||
# If we get here, then we've run out of options, which shouldn't happen
|
||||
ThrowCodeError("authres_unhandled",
|
||||
{ authres => $authres,
|
||||
type => $type,
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
sub logout {
|
||||
my ($class, $user) = @_;
|
||||
|
||||
if ($user) {
|
||||
# Even though we know the userid must match, we still check it in the
|
||||
# SQL as a sanity check, since there is no locking here, and if
|
||||
# the user logged out from two machines simulataniously, while someone
|
||||
# else 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
|
||||
my $dbh = Bugzilla->dbh;
|
||||
$dbh->do("DELETE FROM logincookies WHERE cookie = ? AND userid = ?",
|
||||
undef, $::COOKIE{"Bugzilla_logincookie"}, $user->id);
|
||||
}
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
$cgi->send_cookie(-name => "Bugzilla_login",
|
||||
-expires => "Tue, 15-Sep-1998 21:49:00 GMT");
|
||||
$cgi->send_cookie(-name => "Bugzilla_logincookie",
|
||||
-expires => "Tue, 15-Sep-1998 21:49:00 GMT");
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Auth::CGI - CGI-based logins for Bugzilla
|
||||
|
||||
=head1 SUMMARY
|
||||
|
||||
This is a L<login module|Bugzilla::Auth/"LOGIN"> for Bugzilla. Users connecting
|
||||
from a CGI script use this module to authenticate. Logouts are also handled here.
|
||||
|
||||
=head1 BEHAVIOUR
|
||||
|
||||
Users are first authenticated against the default authentication handler,
|
||||
using the CGI parameters I<Bugzilla_login> and I<Bugzilla_password>.
|
||||
|
||||
If no data is present for that, then cookies are tried, using
|
||||
L<Bugzilla::Auth::Cookie>.
|
||||
|
||||
When a logout is performed, we take care of removing the relevant
|
||||
logincookie database entry and effectively deleting the client cookie.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Bugzilla::Auth>
|
|
@ -1,119 +0,0 @@
|
|||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
# Dan Mosedale <dmose@mozilla.org>
|
||||
# Joe Robins <jmrobins@tgix.com>
|
||||
# Dave Miller <justdave@syndicomm.com>
|
||||
# Christopher Aillon <christopher@aillon.com>
|
||||
# Gervase Markham <gerv@gerv.net>
|
||||
# Christian Reis <kiko@async.com.br>
|
||||
# Bradley Baetz <bbaetz@acm.org>
|
||||
|
||||
package Bugzilla::Auth::Cookie;
|
||||
|
||||
use strict;
|
||||
|
||||
use Bugzilla::Auth;
|
||||
use Bugzilla::Config;
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Util;
|
||||
|
||||
sub authenticate {
|
||||
my ($class, $login, $login_cookie) = @_;
|
||||
|
||||
return (AUTH_NODATA) unless defined $login && defined $login_cookie;
|
||||
|
||||
my $cgi = Bugzilla->cgi;
|
||||
|
||||
my $ipaddr = $cgi->remote_addr();
|
||||
my $netaddr = Bugzilla::Auth::get_netaddr($ipaddr);
|
||||
|
||||
# Anything goes for these params - they're just strings which
|
||||
# we're going to verify against the db
|
||||
trick_taint($login);
|
||||
trick_taint($login_cookie);
|
||||
trick_taint($ipaddr);
|
||||
|
||||
my $query = "SELECT profiles.userid, profiles.disabledtext " .
|
||||
"FROM logincookies, profiles " .
|
||||
"WHERE logincookies.cookie=? AND " .
|
||||
" logincookies.userid=profiles.userid AND " .
|
||||
" logincookies.userid=? AND " .
|
||||
" (logincookies.ipaddr=?";
|
||||
if (defined $netaddr) {
|
||||
trick_taint($netaddr);
|
||||
$query .= " OR logincookies.ipaddr=?";
|
||||
}
|
||||
$query .= ")";
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my ($userid, $disabledtext) = $dbh->selectrow_array($query, undef,
|
||||
$login_cookie,
|
||||
$login,
|
||||
$ipaddr,
|
||||
$netaddr);
|
||||
|
||||
return (AUTH_DISABLED, $userid, $disabledtext)
|
||||
if ($disabledtext);
|
||||
|
||||
if ($userid) {
|
||||
# If we logged in successfully, then update the lastused time on the
|
||||
# login cookie
|
||||
$dbh->do("UPDATE logincookies SET lastused=NULL WHERE cookie=?",
|
||||
undef,
|
||||
$login_cookie);
|
||||
|
||||
# compat code. The cookie value is used for logouts, and that
|
||||
# isn't generic yet. Detaint it so that its usable
|
||||
detaint_natural($::COOKIE{'Bugzilla_logincookie'});
|
||||
|
||||
return (AUTH_OK, $userid);
|
||||
}
|
||||
|
||||
# If we get here, then the login failed.
|
||||
return (AUTH_LOGINFAILED);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Bugzilla::Cookie - cookie authentication for Bugzilla
|
||||
|
||||
=head1 SUMMARY
|
||||
|
||||
This is an L<authentication module|Bugzilla::Auth/"AUTHENTICATION"> for
|
||||
Bugzilla, which logs the user in using a persistent cookie stored in the
|
||||
C<logincookies> table.
|
||||
|
||||
The actual password is not stored in the cookie; only the userid and a
|
||||
I<logincookie> (which is used to reverify the login without requiring the
|
||||
password to be sent over the network) are. These I<logincookies> are
|
||||
restricted to certain IP addresses as a security meaure. The exact
|
||||
restriction can be specified by the admin via the C<loginnetmask> parameter.
|
||||
|
||||
This module does not ever send a cookie (It has no way of knowing when a user
|
||||
is successfully logged in). Instead L<Bugzilla::Auth::CGI> handles this.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Bugzilla::Auth>, L<Bugzilla::Auth::CGI>
|
|
@ -46,6 +46,10 @@ use base qw(Exporter);
|
|||
LOGIN_OPTIONAL
|
||||
LOGIN_NORMAL
|
||||
LOGIN_REQUIRED
|
||||
|
||||
LOGOUT_ALL
|
||||
LOGOUT_CURRENT
|
||||
LOGOUT_KEEP_CURRENT
|
||||
);
|
||||
|
||||
@Bugzilla::Constants::EXPORT_OK = qw(contenttypes);
|
||||
|
@ -83,7 +87,7 @@ use constant CONTROLMAPSHOWN => 1;
|
|||
use constant CONTROLMAPDEFAULT => 2;
|
||||
use constant CONTROLMAPMANDATORY => 3;
|
||||
|
||||
# See Bugzilla::Auth for docs for these
|
||||
# See Bugzilla::Auth for docs on AUTH_*, LOGIN_* and LOGOUT_*
|
||||
|
||||
use constant AUTH_OK => 0;
|
||||
use constant AUTH_NODATA => 1;
|
||||
|
@ -95,6 +99,10 @@ use constant LOGIN_OPTIONAL => 0;
|
|||
use constant LOGIN_NORMAL => 1;
|
||||
use constant LOGIN_REQUIRED => 2;
|
||||
|
||||
use constant LOGOUT_ALL => 0;
|
||||
use constant LOGOUT_CURRENT => 1;
|
||||
use constant LOGOUT_KEEP_CURRENT => 2;
|
||||
|
||||
use constant contenttypes =>
|
||||
{
|
||||
"html" => "text/html" ,
|
||||
|
|
Загрузка…
Ссылка в новой задаче