Bug 300410: Bugzilla::Auth needs to be restructured to not require a BEGIN block

Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=myk
This commit is contained in:
mkanat%bugzilla.org 2006-05-12 02:41:22 +00:00
Родитель 1624ad9d41
Коммит 8b54c5771a
35 изменённых файлов: 1521 добавлений и 532 удалений

Просмотреть файл

@ -26,7 +26,7 @@ package Bugzilla;
use strict;
use Bugzilla::Auth;
use Bugzilla::Auth::Login::WWW;
use Bugzilla::Auth::Persist::Cookie;
use Bugzilla::CGI;
use Bugzilla::Config;
use Bugzilla::Constants;
@ -160,7 +160,13 @@ sub sudo_request {
sub login {
my ($class, $type) = @_;
my $authenticated_user = Bugzilla::Auth::Login::WWW->login($type);
my $authorizer = new Bugzilla::Auth();
$type = LOGIN_REQUIRED if Bugzilla->cgi->param('GoAheadAndLogIn');
if (!defined $type || $type == LOGIN_NORMAL) {
$type = Param('requirelogin') ? LOGIN_REQUIRED : LOGIN_NORMAL;
}
my $authenticated_user = $authorizer->login($type);
# At this point, we now know if a real person is logged in.
# We must now check to see if an sudo session is in progress.
@ -200,14 +206,15 @@ sub logout {
return unless user->id;
$option = LOGOUT_CURRENT unless defined $option;
Bugzilla::Auth::Login::WWW->logout($_user, $option);
Bugzilla::Auth::Persist::Cookie->logout({type => $option});
Bugzilla->logout_request() unless $option eq LOGOUT_KEEP_CURRENT;
}
sub logout_user {
my ($class, $user) = @_;
# When we're logging out another user we leave cookies alone, and
# therefore avoid calling Bugzilla->logout() directly.
Bugzilla::Auth::Login::WWW->logout($user, LOGOUT_ALL);
Bugzilla::Auth::Persist::Cookie->logout({user => $user});
}
# just a compatibility front-end to logout_user that gets a user by id

Просмотреть файл

@ -19,40 +19,181 @@
#
# Contributor(s): Bradley Baetz <bbaetz@acm.org>
# Erik Stambaugh <erik@dasbistro.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth;
use strict;
use fields qw(
_info_getter
_verifier
_persister
);
use Bugzilla::Config;
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Config;
use Bugzilla::Auth::Login::Stack;
use Bugzilla::Auth::Verify::Stack;
use Bugzilla::Auth::Persist::Cookie;
# The verification method that was successfully used upon login, if any
my $current_verify_class = undef;
use Switch;
# 'inherit' from the main verify method
BEGIN {
for my $verifyclass (split /,\s*/, Param("user_verify_class")) {
if ($verifyclass =~ /^([A-Za-z0-9_\.\-]+)$/) {
$verifyclass = $1;
} else {
die "Badly-named user_verify_class '$verifyclass'";
}
require "Bugzilla/Auth/Verify/" . $verifyclass . ".pm";
}
sub new {
my ($class, $params) = @_;
my $self = fields::new($class);
$params ||= {};
$params->{Login} ||= Param('user_info_class') . ',Cookie';
$params->{Verify} ||= Param('user_verify_class');
$self->{_info_getter} = new Bugzilla::Auth::Login::Stack($params->{Login});
$self->{_verifier} = new Bugzilla::Auth::Verify::Stack($params->{Verify});
# If we ever have any other login persistence methods besides cookies,
# this could become more configurable.
$self->{_persister} = new Bugzilla::Auth::Persist::Cookie();
return $self;
}
# PRIVATE
sub login {
my ($self, $type) = @_;
my $dbh = Bugzilla->dbh;
# A number of features, like password change requests, require the DB
# verification method to be on the list.
sub has_db {
for (split (/[\s,]+/, Param("user_verify_class"))) {
if (/^DB$/) {
return 1;
# Get login info from the cookie, form, environment variables, etc.
my $login_info = $self->{_info_getter}->get_login_info();
if ($login_info->{failure}) {
return $self->_handle_login_result($login_info, $type);
}
# Now verify his username and password against the DB, LDAP, etc.
if ($self->{_info_getter}->{successful}->requires_verification) {
$login_info = $self->{_verifier}->check_credentials($login_info);
if ($login_info->{failure}) {
return $self->_handle_login_result($login_info, $type);
}
$login_info =
$self->{_verifier}->{successful}->create_or_update_user($login_info);
}
else {
$login_info = $self->{_verifier}->create_or_update_user($login_info);
}
if ($login_info->{failure}) {
return $self->_handle_login_result($login_info, $type);
}
# Make sure the user isn't disabled.
my $user = $login_info->{user};
if ($user->disabledtext) {
return $self->_handle_login_result({ failure => AUTH_DISABLED,
user => $user }, $type);
}
$user->set_authorizer($self);
return $self->_handle_login_result($login_info, $type);
}
sub can_change_password {
my ($self) = @_;
my $verifier = $self->{_verifier}->{successful};
$verifier ||= $self->{_verifier};
my $getter = $self->{_info_getter}->{successful};
$getter = $self->{_info_getter}
if (!$getter || $getter->isa('Bugzilla::Auth::Login::Cookie'));
return $verifier->can_change_password &&
$getter->user_can_create_account;
}
sub can_login {
my ($self) = @_;
return $self->{_info_getter}->can_login;
}
sub can_logout {
my ($self) = @_;
my $getter = $self->{_info_getter}->{successful};
# If there's no successful getter, we're not logged in, so of
# course we can't log out!
return 0 unless $getter;
return $getter->can_logout;
}
sub user_can_create_account {
my ($self) = @_;
my $verifier = $self->{_verifier}->{successful};
$verifier ||= $self->{_verifier};
my $getter = $self->{_info_getter}->{successful};
$getter = $self->{_info_getter}
if (!$getter || $getter->isa('Bugzilla::Auth::Login::Cookie'));
return $verifier->user_can_create_account
&& $getter->user_can_create_account;
}
sub can_change_email {
return $_[0]->user_can_create_account;
}
sub _handle_login_result {
my ($self, $result, $login_type) = @_;
my $dbh = Bugzilla->dbh;
my $user = $result->{user};
my $fail_code = $result->{failure};
if (!$fail_code) {
if ($self->{_info_getter}->{successful}->requires_persistence) {
$self->{_persister}->persist_login($user);
}
}
return 0;
else {
switch ($fail_code) {
case AUTH_ERROR {
ThrowCodeError($result->{error}, $result->{details});
}
case AUTH_NODATA {
if ($login_type == LOGIN_REQUIRED) {
# 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.
$dbh->do("DELETE FROM logincookies WHERE " .
$dbh->sql_to_days('NOW()') . " - " .
$dbh->sql_to_days('lastused') . " > 30");
$self->{_info_getter}->fail_nodata($self);
}
# Otherwise, we just return the "default" user.
$user = Bugzilla->user;
}
# 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)
case [AUTH_LOGINFAILED, AUTH_NO_SUCH_USER] {
ThrowUserError("invalid_username_or_password");
}
# The account may be disabled
case AUTH_DISABLED {
$self->{_persister}->logout();
# XXX This is NOT a good way to do this, architecturally.
$self->{_persister}->clear_browser_cookies();
# and throw a user error
ThrowUserError("account_disabled",
{'disabled_reason' => $result->{user}->disabledtext});
}
# If we get here, then we've run out of options, which
# shouldn't happen.
else {
ThrowCodeError("authres_unhandled",
{ value => $fail_code });
}
}
}
return $user;
}
# Returns the network address for a given IP
@ -72,84 +213,174 @@ sub get_netaddr {
return "0.0.0.0" if ($maskbits == 0);
$addr >>= (32-$maskbits);
$addr <<= (32-$maskbits);
return join(".", unpack("CCCC", pack("N", $addr)));
}
# This is a replacement for the inherited authenticate function
# go through each of the available methods for each function
sub authenticate {
my $class = shift;
my @args = @_;
my @firstresult = ();
my @result = ();
my $current_verify_method;
for my $method (split /,\s*/, Param("user_verify_class")) {
$current_verify_method = $method;
$method = "Bugzilla::Auth::Verify::" . $method;
@result = $method->authenticate(@args);
@firstresult = @result unless @firstresult;
if (($result[0] != AUTH_NODATA)&&($result[0] != AUTH_LOGINFAILED)) {
unshift @result, ($current_verify_method);
return @result;
}
}
@result = @firstresult;
# no auth match
# see if we can set $current to the first verify method that
# will allow a new login
my $chosen_verify_method;
for my $method (split /,\s*/, Param("user_verify_class")) {
$current_verify_method = $method;
$method = "Bugzilla::Auth::Verify::" . $method;
if ($method->can_edit('new')) {
$chosen_verify_method = $method;
}
}
unshift @result, $chosen_verify_method;
return @result;
}
sub can_edit {
my ($class, $type) = @_;
if ($current_verify_class) {
return $current_verify_class->can_edit($type);
}
# $current_verify_class will not be set if the user isn't logged in. That
# happens when the user is trying to create a new account, which (for now)
# is hard-coded to work with DB.
elsif (has_db) {
return Bugzilla::Auth::Verify::DB->can_edit($type);
}
return 0;
}
1;
__END__
=head1 NAME
Bugzilla::Auth - Authentication handling for Bugzilla users
Bugzilla::Auth - An object that authenticates the login credentials for
a user.
=head1 DESCRIPTION
Handles authentication for Bugzilla users.
Authentication from Bugzilla involves two sets of modules. One set is
used to obtain the data (from CGI, email, etc), and the other set uses
this data to authenticate against the datasource (the Bugzilla DB, LDAP,
cookies, etc).
used to obtain the username/password (from CGI, email, etc), and the
other set uses this data to authenticate against the datasource
(the Bugzilla DB, LDAP, PAM, etc.).
Modules for obtaining the data are located under L<Bugzilla::Auth::Login>, and
modules for authenticating are located in L<Bugzilla::Auth::Verify>.
Modules for obtaining the username/password are subclasses of
L<Bugzilla::Auth::Login>, and modules for authenticating are subclasses
of L<Bugzilla::Auth::Verify>.
=head1 AUTHENTICATION ERROR CODES
Whenever a method in the C<Bugzilla::Auth> family fails in some way,
it will return a hashref containing at least a single key called C<failure>.
C<failure> will point to an integer error code, and depending on the error
code the hashref may contain more data.
The error codes are explained here below.
=head2 C<AUTH_NODATA>
Insufficient login data was provided by the user. This may happen in several
cases, such as cookie authentication when the cookie is not present.
=head2 C<AUTH_ERROR>
An error occurred when trying to use the login mechanism.
The hashref will also contain an C<error> element, which is the name
of an error from C<template/en/default/global/code-error.html> --
the same type of error that would be thrown by
L<Bugzilla::Error::ThrowCodeError>.
The hashref *may* contain an element called C<details>, which is a hashref
that should be passed to L<Bugzilla::Error::ThrowCodeError> as the
various fields to be used in the error message.
=head2 C<AUTH_LOGINFAILED>
An incorrect username or password was given.
=head2 C<AUTH_NO_SUCH_USER>
This is an optional more-specific version of C<AUTH_LOGINFAILED>.
Modules should throw this error when they discover that the
requested user account actually does not exist, according to them.
That is, for example, L<Bugzilla::Auth::Verify::LDAP> would throw
this if the user didn't exist in LDAP.
The difference between C<AUTH_NO_SUCH_USER> and C<AUTH_LOGINFAILED>
should never be communicated to the user, for security reasons.
=head2 C<AUTH_DISABLED>
The user successfully logged in, but their account has been disabled.
Usually this is throw only by C<Bugzilla::Auth::login>.
=head1 LOGIN TYPES
The C<login> function (below) can do different types of login, depending
on what constant you pass into it:
=head2 C<LOGIN_OPTIONAL>
A login is never required to access this data. Attempting to login is
still useful, because this allows the page to be personalised. Note that
an incorrect login will still trigger an error, even though the lack of
a login will be OK.
=head2 C<LOGIN_NORMAL>
A login may or may not be required, depending on the setting of the
I<requirelogin> parameter. This is the default if you don't specify a
type.
=head2 C<LOGIN_REQUIRED>
A login is always required to access this data.
=head1 METHODS
These are methods that can be called on a C<Bugzilla::Auth> object
itself.
=head2 Login
=over 4
=item C<login($type)>
Description: Logs a user in. For more details on how this works
internally, see the section entitled "STRUCTURE."
Params: $type - One of the Login Types from above.
Returns: An authenticated C<Bugzilla::User>. Or, if the type was
not C<LOGIN_REQUIRED>, then we return an
empty C<Bugzilla::User> if no login data was passed in.
=back
=head2 Info Methods
These are methods that give information about the Bugzilla::Auth object.
=over 4
=item C<can_change_password>
Description: Tells you whether or not the current login system allows
changing passwords.
Params: None
Returns: C<true> if users and administrators should be allowed to
change passwords, C<false> otherwise.
=item C<can_login>
Description: Tells you whether or not the current login system allows
users to log in through the web interface.
Params: None
Returns: C<true> if users can log in through the web interface,
C<false> otherwise.
=item C<can_logout>
Description: Tells you whether or not the current login system allows
users to log themselves out.
Params: None
Returns: C<true> if users can log themselves out, C<false> otherwise.
If a user isn't logged in, we always return C<false>.
=item C<user_can_create_account>
Description: Tells you whether or not users are allowed to manually create
their own accounts, based on the current login system in use.
Note that this doesn't check the C<createemailregexp>
parameter--you have to do that by yourself in your code.
Params: None
Returns: C<true> if users are allowed to create new Bugzilla accounts,
C<false> otherwise.
=item C<can_change_email>
Description: Whether or not the current login system allows users to
change their own email address.
Params: None
Returns: C<true> if users can change their own email address,
C<false> otherwise.
=back
=head1 CLASS FUNCTIONS
C<Bugzilla::Auth> contains several helper methods to be used by
authentication or login modules.
@ -164,162 +395,118 @@ only some addresses.
=back
=head1 AUTHENTICATION
=head1 STRUCTURE
Authentication modules check a user's credentials (username, password,
etc) to verify who the user is. The methods that C<Bugzilla::Auth> uses for
authentication are wrappers that check all configured modules (via the
C<Param('user_info_class')> and C<Param('user_verify_class')>) in sequence.
This section is mostly interesting to developers who want to implement
a new authentication type. It describes the general structure of the
Bugzilla::Auth family, and how the C<login> function works.
=head2 METHODS
A C<Bugzilla::Auth> object is essentially a collection of a few other
objects: the "Info Getter," the "Verifier," and the "Persistence
Mechanism."
They are used inside the C<login> function in the following order:
=head2 The Info Getter
This is a C<Bugzilla::Auth::Login> object. Basically, it gets the
username and password from the user, somehow. Or, it just gets enough
information to uniquely identify a user, and passes that on down the line.
(For example, a C<user_id> is enough to uniquely identify a user,
even without a username and password.)
Some Info Getters don't require any verification. For example, if we got
the C<user_id> from a Cookie, we don't need to check the username and
password.
If an Info Getter returns only a C<user_id> and no username/password,
then it MUST NOT require verification. If an Info Getter requires
verfication, then it MUST return at least a C<username>.
=head2 The Verifier
This verifies that the username and password are valid.
It's possible that some methods of verification don't require a password.
=head2 The Persistence Mechanism
This makes it so that the user doesn't have to log in on every page.
Normally this object just sends a cookie to the user's web browser,
as that's the most common method of "login persistence."
=head2 Other Things We Do
After we verify the username and password, sometimes we automatically
create an account in the Bugzilla database, for certain authentication
types. We use the "Account Source" to get data about the user, and
create them in the database. (Or, if their data has changed since the
last time they logged in, their data gets updated.)
=head2 The C<$login_data> Hash
All of the C<Bugzilla::Auth::Login> and C<Bugzilla::Auth::Verify>
methods take an argument called C<$login_data>. This is basically
a hash that becomes more and more populated as we go through the
C<login> function.
All C<Bugzilla::Auth::Login> and C<Bugzilla::Auth::Verify> methods
also *return* the C<$login_data> structure, when they succeed. They
may have added new data to it.
For all C<Bugzilla::Auth::Login> and C<Bugzilla::Auth::Verify> methods,
the rule is "you must return the same hashref you were passed in." You can
modify the hashref all you want, but you can't create a new one. The only
time you can return a new one is if you're returning some error code
instead of the C<$login_data> structure.
Each C<Bugzilla::Auth::Login> or C<Bugzilla::Auth::Verify> method
explains in its documentation which C<$login_data> elements are
required by it, and which are set by it.
Here are all of the elements that *may* be in C<$login_data>:
=over 4
=item C<authenticate($username, $pass)>
=item C<user_id>
This method is passed a username and a password, and returns a list
containing up to four return values, depending on the results of the
authentication.
A Bugzilla C<user_id> that uniquely identifies a user.
The first return value is the name of the class that generated the results
constined in the remaining return values. The second return value is one of
the status codes defined in L<Bugzilla::Constants|Bugzilla::Constants> and
described below. The rest of the return values are status code-specific
and are explained in the status code descriptions.
=item C<username>
=item C<AUTH_OK>
The username that was provided by the user.
Authentication succeeded. The third variable is the userid of the new
user.
=item C<bz_username>
=item C<AUTH_NODATA>
The username of this user inside of Bugzilla. Sometimes this differs from
C<username>.
Insufficient login data was provided by the user. This may happen in several
cases, such as cookie authentication when the cookie is not present.
=item C<password>
=item C<AUTH_ERROR>
The password provided by the user.
An error occurred when trying to use the login mechanism. The third return
value may contain the Bugzilla userid, but will probably be C<undef>,
signifiying that the userid is unknown. The fourth value is a tag describing
the error used by the authentication error templates to print a description
to the user. The optional fifth argument is a hashref of values used as part
of the tag's error descriptions.
=item C<realname>
This error template must have a name/location of
I<account/auth/C<lc(authentication-type)>-error.html.tmpl>.
The real name of the user.
=item C<AUTH_LOGINFAILED>
=item C<extern_id>
An incorrect username or password was given. Note that for security reasons,
both cases return the same error code. However, in the case of a valid
username, the third argument may be the userid. The authentication
mechanism may not always be able to discover the userid if the password is
not known, so whether or not this argument is present is implementation
specific. For security reasons, the presence or lack of a userid value should
not be communicated to the user.
Some string that uniquely identifies the user in an external account
source. If this C<extern_id> already exists in the database with
a different username, the username will be *changed* to be the
username specified in this C<$login_data>.
The fourth argument is an optional tag from the authentication server
describing the error. The tag can be used by a template to inform the user
about the error. Similar to C<AUTH_ERROR>, an optional hashref may be
present as a fifth argument, to be used by the tag to give more detailed
information.
That is, let's my extern_id is C<mkanat>. I already have an account
in Bugzilla with the username of C<mkanat@foo.com>. But this time,
when I log in, I have an extern_id of C<mkanat> and a C<username>
of C<mkanat@bar.org>. So now, Bugzilla will automatically change my
username to C<mkanat@bar.org> instead of C<mkanat@foo.com>.
=item C<AUTH_DISABLED>
=item C<user>
The user successfully logged in, but their account has been disabled.
The third argument in the returned array is the userid, and the fourth
is some text explaining why the account was disabled. This text would
typically come from the C<disabledtext> field in the C<profiles> table.
Note that this argument is a string, not a tag.
=item C<current_verify_class>
This scalar gets populated with the full name (eg.,
C<Bugzilla::Auth::Verify::DB>) of the verification method being used by the
current user. If no user is logged in, it will contain the name of the first
method that allows new users, if any. Otherwise, it carries an undefined
value.
=item C<can_edit>
This determines if the user's account details can be modified. It returns a
reference to a hash with the keys C<userid>, C<login_name>, and C<realname>,
which determine whether their respective profile values may be altered, and
C<new>, which determines if new accounts may be created.
Each user verification method (chosen with C<Param('user_verify_class')> has
its own set of can_edit values. Calls to can_edit return the appropriate
values for the current user's login method.
If a user is not logged in, C<can_edit> will contain the values of the first
verify method that allows new users to be created, if available. Otherwise it
returns an empty hash.
A L<Bugzilla::User> object representing the authenticated user.
Note that C<Bugzilla::Auth::login> may modify this object at various points.
=back
=head1 LOGINS
A login module can be used to try to log in a Bugzilla user in a
particular way. For example,
L<Bugzilla::Auth::Login::WWW::CGI|Bugzilla::Auth::Login::WWW::CGI>
logs in users from CGI scripts, first by using form variables, and then
by trying cookies as a fallback.
The login interface consists of the following methods:
=over 4
=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:
=item C<LOGIN_OPTIONAL>
A login is never required to access this data. Attempting to login is
still useful, because this allows the page to be personalised. Note that
an incorrect login will still trigger an error, even though the lack of
a login will be OK.
=item C<LOGIN_NORMAL>
A login may or may not be required, depending on the setting of the
I<requirelogin> parameter.
=item C<LOGIN_REQUIRED>
A login is always required to access this data.
=item C<logout>, which takes a C<Bugzilla::User> argument for the user
being logged out, and an C<$option> argument. Possible values for
C<$option> include:
=item C<LOGOUT_CURRENT>
Log out the user and invalidate his currently registered session.
=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
L<Bugzilla::Auth::Login::WWW::CGI>, L<Bugzilla::Auth::Login::WWW::CGI::Cookie>, L<Bugzilla::Auth::Verify::DB>

Просмотреть файл

@ -0,0 +1,125 @@
# -*- 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.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Login;
use strict;
use fields qw();
# 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
# that particular type of login method cannot log out.
use constant can_logout => 1;
use constant can_login => 1;
use constant requires_persistence => 1;
use constant requires_verification => 1;
use constant user_can_create_account => 0;
sub new {
my ($class) = @_;
my $self = fields::new($class);
return $self;
}
1;
__END__
=head1 NAME
Bugzilla::Auth::Login - Gets username/password data from the user.
=head1 DESCRIPTION
Bugzilla::Auth::Login is used to get information that uniquely identifies
a user and allows us to authorize their Bugzilla access.
It is mostly an abstract class, requiring subclasses to implement
most methods.
Note that callers outside of the C<Bugzilla::Auth> package should never
create this object directly. Just create a C<Bugzilla::Auth> object
and call C<login> on it.
=head1 LOGIN METHODS
These are methods that have to do with getting the actual login data
from the user or handling a login somehow.
These methods are abstract -- they MUST be implemented by a subclass.
=over 4
=item C<get_login_info()>
Description: Gets a username/password from the user, or some other
information that uniquely identifies them.
Params: None
Returns: A C<$login_data> hashref. (See L<Bugzilla::Auth> for details.)
The hashref MUST contain: C<user_id> *or* C<username>
If this is a login method that requires verification,
the hashref MUST contain C<password>.
The hashref MAY contain C<realname> and C<extern_id>.
=item C<fail_nodata()>
Description: This function is called when Bugzilla doesn't get
a username/password and the login type is C<LOGIN_REQUIRED>
(See L<Bugzilla::Auth> for a description of C<LOGIN_REQUIRED>).
That is, this handles C<AUTH_NODATA> in that situation.
This function MUST stop CGI execution when it is complete.
That is, it must call C<exit> or C<ThrowUserError> or some
such thing.
Params: None
Returns: Never Returns.
=back
=head1 INFO METHODS
These are methods that describe the capabilities of this
C<Bugzilla::Auth::Login> object. These are all no-parameter
methods that return either C<true> or C<false>.
=over 4
=item C<can_logout>
Whether or not users can log out if they logged in using this
object. Defaults to C<true>.
=item C<can_login>
Whether or not users can log in through the web interface using
this object. Defaults to C<true>.
=item C<requires_persistence>
Whether or not we should send the user a cookie if they logged in with
this method. Defaults to C<true>.
=item C<requires_verification>
Whether or not we should check the username/password that we
got from this login method. Defaults to C<true>.
=item C<user_can_create_account>
Whether or not users can create accounts, if this login method is
currently being used by the system. Defaults to C<false>.
=back

Просмотреть файл

@ -0,0 +1,73 @@
# -*- 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>
# Erik Stambaugh <erik@dasbistro.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Login::CGI;
use strict;
use base qw(Bugzilla::Auth::Login);
use constant user_can_create_account => 1;
use Bugzilla::Config;
use Bugzilla::Constants;
use Bugzilla::Util;
use Bugzilla::User;
sub get_login_info {
my ($self) = @_;
my $cgi = Bugzilla->cgi;
my $username = trim($cgi->param("Bugzilla_login"));
my $password = $cgi->param("Bugzilla_password");
$cgi->delete('Bugzilla_login', 'Bugzilla_password');
if (!defined $username || !defined $password) {
return { failure => AUTH_NODATA };
}
return { username => $username, password => $password };
}
sub fail_nodata {
my ($self) = @_;
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
# Redirect to SSL if required
if (Param('sslbase') ne '' and Param('ssl') ne 'never') {
$cgi->require_https(Param('sslbase'));
}
print $cgi->header();
$template->process("account/auth/login.html.tmpl",
{ 'target' => $cgi->url(-relative=>1) })
|| ThrowTemplateError($template->error());
exit;
}
1;

Просмотреть файл

@ -0,0 +1,83 @@
# -*- 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.
#
# Contributor(s): Bradley Baetz <bbaetz@acm.org>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Login::Cookie;
use strict;
use base qw(Bugzilla::Auth::Login);
use Bugzilla::Auth;
use Bugzilla::Constants;
use Bugzilla::User;
use Bugzilla::Util;
use constant requires_persistence => 0;
use constant requires_verification => 0;
use constant can_login => 0;
# Note that Cookie never consults the Verifier, it always assumes
# it has a valid DB account or it fails.
sub get_login_info {
my ($self) = @_;
my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh;
my $ip_addr = $cgi->remote_addr();
my $net_addr = Bugzilla::Auth::get_netaddr($ip_addr);
my $login_cookie = $cgi->cookie("Bugzilla_logincookie");
my $user_id = $cgi->cookie("Bugzilla_login");
if ($login_cookie && $user_id) {
# Anything goes for these params - they're just strings which
# we're going to verify against the db
trick_taint($ip_addr);
trick_taint($login_cookie);
detaint_natural($user_id);
my $query = "SELECT userid
FROM logincookies
WHERE logincookies.cookie = ?
AND logincookies.userid = ?
AND (logincookies.ipaddr = ?";
# If we have a network block that's allowed to use this cookie,
# as opposed to just a single IP.
my @params = ($login_cookie, $user_id, $ip_addr);
if (defined $net_addr) {
trick_taint($net_addr);
$query .= " OR logincookies.ipaddr = ?";
push(@params, $net_addr);
}
$query .= ")";
# If the cookie is valid, return a valid username.
if ($dbh->selectrow_array($query, undef, @params)) {
# If we logged in successfully, then update the lastused
# time on the login cookie
$dbh->do("UPDATE logincookies SET lastused = NOW()
WHERE cookie = ?", undef, $login_cookie);
return { user_id => $user_id };
}
}
# 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 cokie to begin with.
return { failure => AUTH_NODATA };
}
1;

Просмотреть файл

@ -0,0 +1,54 @@
# -*- 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): Erik Stambaugh <erik@dasbistro.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Login::Env;
use strict;
use base qw(Bugzilla::Auth::Login);
use Bugzilla::Config;
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::User;
use constant can_logout => 0;
use constant can_login => 0;
use constant requires_verification => 0;
sub get_login_info {
my ($self) = @_;
my $dbh = Bugzilla->dbh;
my $env_id = $ENV{Param("auth_env_id")} || '';
my $env_email = $ENV{Param("auth_env_email")} || '';
my $env_realname = $ENV{Param("auth_env_realname")} || '';
return { failure => AUTH_NODATA } if !$env_email;
return { username => $env_email, extern_id => $env_id,
realname => $env_realname };
}
sub fail_nodata {
ThrowCodeError('env_no_email');
}
1;

Просмотреть файл

@ -0,0 +1,87 @@
# -*- 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): Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Login::Stack;
use strict;
use base qw(Bugzilla::Auth::Login);
use fields qw(
_stack
successful
);
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
my $list = shift;
$self->{_stack} = [];
foreach my $login_method (split(',', $list)) {
require "Bugzilla/Auth/Login/${login_method}.pm";
push(@{$self->{_stack}},
"Bugzilla::Auth::Login::$login_method"->new(@_));
}
return $self;
}
sub get_login_info {
my $self = shift;
my $result;
foreach my $object (@{$self->{_stack}}) {
$result = $object->get_login_info(@_);
$self->{successful} = $object;
last if !$result->{failure};
# So that if none of them succeed, it's undef.
$self->{successful} = undef;
}
return $result;
}
sub fail_nodata {
my $self = shift;
# We fail from the bottom of the stack.
my @reverse_stack = reverse @{$self->{_stack}};
foreach my $object (@reverse_stack) {
# We pick the first object that actually has the method
# implemented.
if ($object->can('fail_nodata')) {
$object->fail_nodata(@_);
}
}
}
sub can_login {
my ($self) = @_;
# We return true if any method can log in.
foreach my $object (@{$self->{_stack}}) {
return 1 if $object->can_login;
}
return 0;
}
sub user_can_create_account {
my ($self) = @_;
# We return true if any method allows users to create accounts.
foreach my $object (@{$self->{_stack}}) {
return 1 if $object->user_can_create_account;
}
return 0;
}
1;

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,153 @@
# -*- 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>
# Erik Stambaugh <erik@dasbistro.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Persist::Cookie;
use strict;
use fields qw();
use Bugzilla::Config;
use Bugzilla::Constants;
use Bugzilla::Util;
use Bugzilla::User;
use List::Util qw(first);
sub new {
my ($class) = @_;
my $self = fields::new($class);
return $self;
}
sub persist_login {
my ($self, $user) = @_;
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
my $ip_addr = $cgi->remote_addr;
unless ($cgi->param('Bugzilla_restrictlogin') ||
Param('loginnetmask') == 32)
{
# XXX I don't like this subclass being dependent upon its parent.
$ip_addr = Bugzilla::Auth::get_netaddr($ip_addr);
}
# The IP address is valid, at least for comparing with itself in a
# subsequent login
trick_taint($ip_addr);
my $login_cookie =
Bugzilla::Token::GenerateUniqueToken('logincookies', 'cookie');
$dbh->do("INSERT INTO logincookies (cookie, userid, ipaddr, lastused)
VALUES (?, ?, ?, NOW())",
undef, $login_cookie, $user->id, $ip_addr);
# 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') &&
$cgi->param('Bugzilla_remember') eq 'on') )
{
$cgi->send_cookie(-name => 'Bugzilla_login',
-value => $user->id,
-expires => 'Fri, 01-Jan-2038 00:00:00 GMT');
$cgi->send_cookie(-name => 'Bugzilla_logincookie',
-value => $login_cookie,
-expires => 'Fri, 01-Jan-2038 00:00:00 GMT');
}
else {
$cgi->send_cookie(-name => 'Bugzilla_login',
-value => $user->id);
$cgi->send_cookie(-name => 'Bugzilla_logincookie',
-value => $login_cookie);
}
}
sub logout {
my ($self, $param) = @_;
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
$param = {} unless $param;
my $user = $param->{user} || Bugzilla->user;
my $type = $param->{type} || LOGOUT_ALL;
if ($type == LOGOUT_ALL) {
$dbh->do("DELETE FROM logincookies WHERE userid = ?",
undef, $user->id);
return;
}
# 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 $cookie = first {$_->name eq 'Bugzilla_logincookie'}
@{$cgi->{'Bugzilla_cookie_list'}};
my $login_cookie;
if ($cookie) {
$login_cookie = $cookie->value;
}
else {
$login_cookie = $cgi->cookie("Bugzilla_logincookie");
}
trick_taint($login_cookie);
# 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
# as a sanity check, since there is no locking here, and if the user
# logged out from two machines simultaneously, 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
if ($type == LOGOUT_KEEP_CURRENT) {
$dbh->do("DELETE FROM logincookies WHERE cookie != ? AND userid = ?",
undef, $login_cookie, $user->id);
} elsif ($type == LOGOUT_CURRENT) {
$dbh->do("DELETE FROM logincookies WHERE cookie = ? AND userid = ?",
undef, $login_cookie, $user->id);
} else {
die("Invalid type $type supplied to logout()");
}
if ($type != LOGOUT_KEEP_CURRENT) {
clear_browser_cookies();
}
}
sub clear_browser_cookies {
my $cgi = Bugzilla->cgi;
$cgi->remove_cookie('Bugzilla_login');
$cgi->remove_cookie('Bugzilla_logincookie');
}
1;

Просмотреть файл

Просмотреть файл

@ -0,0 +1,223 @@
# -*- 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.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Verify;
use strict;
use fields qw();
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::User;
use Bugzilla::Util;
use constant user_can_create_account => 1;
sub new {
my ($class, $login_type) = @_;
my $self = fields::new($class);
return $self;
}
sub can_change_password {
return $_[0]->can('change_password');
}
sub create_or_update_user {
my ($self, $params) = @_;
my $dbh = Bugzilla->dbh;
my $extern_id = $params->{extern_id};
my $username = $params->{bz_username} || $params->{username};
my $password = $params->{password} || '*';
my $real_name = $params->{realname} || '';
my $user_id = $params->{user_id};
# A passed-in user_id always overrides anything else, for determining
# what account we should return.
if (!$user_id) {
my $username_user_id = login_to_id($username || '');
my $extern_user_id;
if ($extern_id) {
trick_taint($extern_id);
$extern_user_id = $dbh->selectrow_array('SELECT userid
FROM profiles WHERE extern_id = ?', undef, $extern_id);
}
# If we have both a valid extern_id and a valid username, and they are
# not the same id, then we have a conflict.
if ($username_user_id && $extern_user_id
&& $username_user_id ne $extern_user_id)
{
my $extern_name = Bugzilla::User->new($extern_user_id)->login;
return { failure => AUTH_ERROR, error => "extern_id_conflict",
details => {extern_id => $extern_id,
extern_user => $extern_name,
username => $username} };
}
# If we have a valid username, but no valid id,
# then we have to create the user. This happens when we're
# passed only a username, and that username doesn't exist already.
if ($username && !$username_user_id && !$extern_user_id) {
validate_email_syntax($username)
|| return { failure => AUTH_ERROR,
error => 'auth_invalid_email',
details => {addr => $username} };
insert_new_user($username, $real_name, $password);
$username_user_id = login_to_id($username);
}
# If we have a valid username id and an extern_id, but no valid
# extern_user_id, then we have to set the user's extern_id.
if ($extern_id && $username_user_id && !$extern_user_id) {
$dbh->do('UPDATE profiles SET extern_id = ? WHERE userid = ?',
undef, $extern_id, $username_user_id);
}
# Finally, at this point, one of these will give us a valid user id.
$user_id = $extern_user_id || $username_user_id;
}
# If we still don't have a valid user_id, then we weren't passed
# enough information in $params, and we should die right here.
ThrowCodeError('bad_arg', {argument => 'params', function =>
'Bugzilla::Auth::Verify::create_or_update_user'})
unless $user_id;
my $user = new Bugzilla::User($user_id);
# Now that we have a valid User, we need to see if any data has to be
# updated.
if ($username && $user->login ne $username) {
validate_email_syntax($username)
|| return { failure => AUTH_ERROR, error => 'auth_invalid_email',
details => {addr => $username} };
$dbh->do('UPDATE profiles SET login_name = ? WHERE userid = ?',
$username, $user->id);
}
if ($real_name && $user->realname ne $real_name) {
$dbh->do('UPDATE profiles SET realname = ? WHERE userid = ?',
undef, $real_name, $user->id);
}
return { user => $user };
}
1;
__END__
=head1 NAME
Bugzilla::Auth::Verify - An object that verifies usernames and passwords.
=head1 DESCRIPTION
Bugzilla::Auth::Verify provides the "Verifier" part of the Bugzilla
login process. (For details, see the "STRUCTURE" section of
L<Bugzilla::Auth>.)
It is mostly an abstract class, requiring subclasses to implement
most methods.
Note that callers outside of the C<Bugzilla::Auth> package should never
create this object directly. Just create a C<Bugzilla::Auth> object
and call C<login> on it.
=head1 VERIFICATION METHODS
These are the methods that have to do with the actual verification.
Subclasses MUST implement these methods.
=over 4
=item C<check_credentials($login_data)>
Description: Checks whether or not a username is valid.
Params: $login_data - A C<$login_data> hashref, as described in
L<Bugzilla::Auth>.
This C<$login_data> hashref MUST contain
C<username>, and SHOULD also contain
C<password>.
Returns: A C<$login_data> hashref with C<bz_username> set. This
method may also set C<realname>. It must avoid changing
anything that is already set.
=back
=head1 MODIFICATION METHODS
These are methods that change data in the actual authentication backend.
These methods are optional, they do not have to be implemented by
subclasses.
=over 4
=item C<create_or_update_user($login_data)>
Description: Automatically creates a user account in the database
if it doesn't already exist, or updates the account
data if C<$login_data> contains newer information.
Params: $login_data - A C<$login_data> hashref, as described in
L<Bugzilla::Auth>.
This C<$login_data> hashref MUST contain
either C<user_id>, C<bz_username>, or
C<username>. If both C<username> and C<bz_username>
are specified, C<bz_username> is used as the
login name of the user to create in the database.
It MAY also contain C<extern_id>, in which
case it still MUST contain C<bz_username> or
C<username>.
It MAY contain C<password> and C<realname>.
Returns: A hashref with one element, C<user>, which is a
L<Bugzilla::User> object. May also return a login error
as described in L<Bugzilla::Auth>.
Note: This method is not abstract, it is actually implemented
and creates accounts in the Bugzilla database. Subclasses
should probably all call the C<Bugzilla::Auth::Verify>
version of this function at the end of their own
C<create_or_update_user>.
=item C<change_password($user, $password)>
Description: Modifies the user's password in the authentication backend.
Params: $user - A L<Bugzilla::User> object representing the user
whose password we want to change.
$password - The user's new password.
Returns: Nothing.
=back
=head1 INFO METHODS
These are methods that describe the capabilities of this object.
These are all no-parameter methods that return either C<true> or
C<false>.
=over 4
=item C<user_can_create_account>
Whether or not users can manually create accounts in this type of
account source. Defaults to C<true>.
=back

Просмотреть файл

@ -28,97 +28,51 @@
# Erik Stambaugh <erik@dasbistro.com>
package Bugzilla::Auth::Verify::DB;
use strict;
use base qw(Bugzilla::Auth::Verify);
use Bugzilla::Config;
use Bugzilla::Constants;
use Bugzilla::Token;
use Bugzilla::Util;
use Bugzilla::User;
my $edit_options = {
'new' => 1,
'userid' => 0,
'login_name' => 1,
'realname' => 1,
};
sub check_credentials {
my ($self, $login_data) = @_;
my $dbh = Bugzilla->dbh;
sub can_edit {
my ($class, $type) = @_;
return $edit_options->{$type};
}
my $username = $login_data->{username};
my $user_id = login_to_id($username);
sub authenticate {
my ($class, $username, $passwd) = @_;
return { failure => AUTH_NO_SUCH_USER } unless $user_id;
return (AUTH_NODATA) unless defined $username && defined $passwd;
$login_data->{bz_username} = $username;
my $password = $login_data->{password};
my $userid = Bugzilla::User::login_to_id($username);
return (AUTH_LOGINFAILED) unless $userid;
trick_taint($username);
my ($real_password_crypted) = $dbh->selectrow_array(
"SELECT cryptpassword FROM profiles WHERE userid = ?",
undef, $user_id);
return (AUTH_LOGINFAILED, $userid)
unless $class->check_password($userid, $passwd);
# Using the internal crypted password as the salt,
# crypt the password the user entered.
my $entered_password_crypted = crypt($password, $real_password_crypted);
return { failure => AUTH_LOGINFAILED }
if $entered_password_crypted ne $real_password_crypted;
# The user's credentials are okay, so delete any outstanding
# password tokens they may have generated.
require Bugzilla::Token;
Bugzilla::Token::DeletePasswordTokens($userid, "user_logged_in");
Bugzilla::Token::DeletePasswordTokens($user_id, "user_logged_in");
# Account may have been disabled
my $disabledtext = $class->get_disabled($userid);
return (AUTH_DISABLED, $userid, $disabledtext)
if $disabledtext ne '';
return (AUTH_OK, $userid);
}
sub get_disabled {
my ($class, $userid) = @_;
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare_cached("SELECT disabledtext FROM profiles " .
"WHERE userid=?");
my ($text) = $dbh->selectrow_array($sth, undef, $userid);
return $text;
}
sub check_password {
my ($class, $userid, $passwd) = @_;
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare_cached("SELECT cryptpassword FROM profiles " .
"WHERE userid=?");
my ($realcryptpwd) = $dbh->selectrow_array($sth, undef, $userid);
# Get the salt from the user's crypted password.
my $salt = $realcryptpwd;
# Using the salt, crypt the password the user entered.
my $enteredCryptedPassword = crypt($passwd, $salt);
return $enteredCryptedPassword eq $realcryptpwd;
return $login_data;
}
sub change_password {
my ($class, $userid, $password) = @_;
my ($self, $user, $password) = @_;
my $dbh = Bugzilla->dbh;
my $cryptpassword = bz_crypt($password);
$dbh->do("UPDATE profiles SET cryptpassword = ? WHERE userid = ?",
undef, $cryptpassword, $userid);
$dbh->do("UPDATE profiles SET cryptpassword = ? WHERE userid = ?",
undef, $cryptpassword, $user->id);
}
1;
__END__
=head1 NAME
Bugzilla::Auth::Verify::DB - database authentication for Bugzilla
=head1 SUMMARY
This is an L<authentication module|Bugzilla::Auth/"AUTHENTICATION"> for
Bugzilla, which logs the user in using the password stored in the C<profiles>
table. This is the most commonly used authentication module.
=head1 SEE ALSO
L<Bugzilla::Auth>

Просмотреть файл

@ -26,39 +26,30 @@
# Christian Reis <kiko@async.com.br>
# Bradley Baetz <bbaetz@acm.org>
# Erik Stambaugh <erik@dasbistro.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Verify::LDAP;
use strict;
use base qw(Bugzilla::Auth::Verify);
use fields qw(
ldap
);
use Bugzilla::Config;
use Bugzilla::Constants;
use Bugzilla::User;
use Bugzilla::Error;
use Net::LDAP;
my $edit_options = {
'new' => 0,
'userid' => 0,
'login_name' => 0,
'realname' => 0,
};
use constant DEFAULT_PORT => 389;
use constant DEFAULT_SSL_PORT => 636;
sub can_edit {
my ($class, $type) = @_;
return $edit_options->{$type};
}
use constant admin_can_create_account => 0;
use constant user_can_create_account => 0;
sub authenticate {
my ($class, $username, $passwd) = @_;
# If no password was provided, then fail the authentication.
# While it may be valid to not have an LDAP password, when you
# bind without a password (regardless of the binddn value), you
# will get an anonymous bind. I do not know of a way to determine
# whether a bind is anonymous or not without making changes to the
# LDAP access control settings
return (AUTH_NODATA) unless $username && $passwd;
sub check_credentials {
my ($self, $params) = @_;
my $dbh = Bugzilla->dbh;
# We need to bind anonymously to the LDAP server. This is
# because we need to get the Distinguished Name of the user trying
@ -67,151 +58,108 @@ sub authenticate {
# just appending the Base DN to the uid isn't sufficient to get the
# user's DN. For servers which don't work this way, there will still
# be no harm done.
my $LDAPserver = Param("LDAPserver");
if ($LDAPserver eq "") {
return (AUTH_ERROR, undef, "server_not_defined");
$self->_bind_ldap_anonymously();
# Now, we verify that the user exists, and get a LDAP Distinguished
# Name for the user.
my $username = $params->{username};
my $dn_result = $self->ldap->search(_bz_search_params($username),
attrs => ['dn']);
return { failure => AUTH_ERROR, error => "ldap_search_error",
details => {errstr => $dn_result->error, username => $username}
} if $dn_result->code;
return { failure => AUTH_NO_SUCH_USER } if !$dn_result->count;
my $dn = $dn_result->shift_entry->dn;
# Check the password.
my $pw_result = $self->ldap->bind($dn, password => $params->{password});
return { failure => AUTH_LOGINFAILED } if $pw_result->code;
# And now we fill in the user's details.
my $detail_result = $self->ldap->search(_bz_search_params($username));
return { failure => AUTH_ERROR, error => "ldap_search_error",
details => {errstr => $detail_result->error, username => $username}
} if $detail_result->code;
my $user_entry = $detail_result->shift_entry;
my $mail_attr = Param("LDAPmailattribute");
if (!$user_entry->exists($mail_attr)) {
return { failure => AUTH_ERROR,
error => "ldap_cannot_retreive_attr",
details => {attr => $mail_attr} };
}
my $LDAPport = "389"; # default LDAP port
my $LDAPprotocol = "ldap";
$params->{bz_username} = $user_entry->get_value($mail_attr);
$params->{realname} ||= $user_entry->get_value("displayName");
$params->{realname} ||= $user_entry->get_value("cn");
if ($LDAPserver =~ /(ldap|ldaps):\/\/(.*)/) {
# ldap(s)://server(:port)
$LDAPprotocol = $1;
my $serverpart = $2;
if ($serverpart =~ /:/) {
# ldap(s)://server:port
($LDAPserver, $LDAPport) = split(":", $serverpart);
} else {
# ldap(s)://server
$LDAPserver = $serverpart;
if ($LDAPprotocol eq "ldaps") {
$LDAPport = "636";
}
}
} elsif ($LDAPserver =~ /:/) {
# server:port
($LDAPserver, $LDAPport) = split(":", $LDAPserver);
}
return $params;
}
sub _bz_search_params {
my ($username) = @_;
return (base => Param("LDAPBaseDN"),
scope => "sub",
filter => '(&(' . Param("LDAPuidattribute") . "=$username)"
. Param("LDAPfilter") . ')');
}
my $LDAPconn = Net::LDAP->new("$LDAPprotocol://$LDAPserver:$LDAPport", version => 3);
if(!$LDAPconn) {
return (AUTH_ERROR, undef, "connect_failed");
}
my $mesg;
sub _bind_ldap_anonymously {
my ($self) = @_;
my $bind_result;
if (Param("LDAPbinddn")) {
my ($LDAPbinddn,$LDAPbindpass) = split(":",Param("LDAPbinddn"));
$mesg = $LDAPconn->bind($LDAPbinddn, password => $LDAPbindpass);
$bind_result =
$self->ldap->bind($LDAPbinddn, password => $LDAPbindpass);
}
else {
$mesg = $LDAPconn->bind();
}
if($mesg->code) {
return (AUTH_ERROR, undef,
"connect_failed",
{ errstr => $mesg->error });
$bind_result = $self->ldap->bind();
}
ThrowCodeError("ldap_bind_failed", {errstr => $bind_result->error})
if $bind_result->code;
}
# We've got our anonymous bind; let's look up this user.
$mesg = $LDAPconn->search( base => Param("LDAPBaseDN"),
scope => "sub",
filter => '(&(' . Param("LDAPuidattribute") . "=$username)" . Param("LDAPfilter") . ')',
attrs => ['dn'],
);
return (AUTH_LOGINFAILED, undef, "lookup_failure")
unless $mesg->count;
# We can't just do this in new(), because we're not allowed to throw any
# error from anywhere under Bugzilla::Auth::new -- otherwise we
# could create a situation where the admin couldn't get to editparams
# to fix his mistake. (Because Bugzilla->login always calls
# Bugzilla::Auth->new, and almost every page calls Bugzilla->login.)
sub ldap {
my ($self) = @_;
return $self->{ldap} if $self->{ldap};
# Now we get the DN from this search.
my $userDN = $mesg->shift_entry->dn;
my $server = Param("LDAPserver");
ThrowCodeError("ldap_server_not_defined") unless $server;
# Now we attempt to bind as the specified user.
$mesg = $LDAPconn->bind( $userDN, password => $passwd);
my $port = DEFAULT_PORT;
my $protocol = "ldap";
return (AUTH_LOGINFAILED) if $mesg->code;
# And now we're going to repeat the search, so that we can get the
# mail attribute for this user.
$mesg = $LDAPconn->search( base => Param("LDAPBaseDN"),
scope => "sub",
filter => '(&(' . Param("LDAPuidattribute") . "=$username)" . Param("LDAPfilter") . ')',
);
my $user_entry = $mesg->shift_entry if !$mesg->code && $mesg->count;
if(!$user_entry || !$user_entry->exists(Param("LDAPmailattribute"))) {
return (AUTH_ERROR, undef,
"cannot_retreive_attr",
{ attr => Param("LDAPmailattribute") });
}
# get the mail attribute
$username = $user_entry->get_value(Param("LDAPmailattribute"));
# OK, so now we know that the user is valid. Lets try finding them in the
# Bugzilla database
# XXX - should this part be made more generic, and placed in
# Bugzilla::Auth? Lots of login mechanisms may have to do this, although
# until we actually get some more, its hard to know - BB
my $dbh = Bugzilla->dbh;
my $sth = $dbh->prepare_cached("SELECT userid, disabledtext " .
"FROM profiles " .
"WHERE " .
$dbh->sql_istrcmp('login_name', '?'));
my ($userid, $disabledtext) =
$dbh->selectrow_array($sth,
undef,
$username);
# If the user doesn't exist, then they need to be added
unless ($userid) {
# We'll want the user's name for this.
my $userRealName = $user_entry->get_value("displayName");
if($userRealName eq "") {
$userRealName = $user_entry->get_value("cn");
if ($server =~ /(ldap|ldaps):\/\/(.*)/) {
# ldap(s)://server(:port)
$protocol = $1;
my $server_part = $2;
if ($server_part =~ /:/) {
# ldap(s)://server:port
($server, $port) = split(":", $server_part);
} else {
# ldap(s)://server
$server = $server_part;
if ($protocol eq "ldaps") {
$port = DEFAULT_SSL_PORT;
}
}
insert_new_user($username, $userRealName);
($userid, $disabledtext) = $dbh->selectrow_array($sth,
undef,
$username);
return (AUTH_ERROR, $userid, "no_userid")
unless $userid;
} elsif ($server =~ /:/) {
# server:port
($server, $port) = split(":", $server);
}
# we're done, so disconnect
$LDAPconn->unbind;
# Test for disabled account
return (AUTH_DISABLED, $userid, $disabledtext)
if $disabledtext ne '';
# If we get to here, then the user is allowed to login, so we're done!
return (AUTH_OK, $userid);
my $conn_string = "$protocol://$server:$port";
$self->{ldap} = new Net::LDAP($conn_string)
|| ThrowCodeError("ldap_connect_failed", { server => $conn_string });
return $self->{ldap};
}
1;
__END__
=head1 NAME
Bugzilla::Auth::Verify::LDAP - LDAP based authentication for Bugzilla
This is an L<authentication module|Bugzilla::Auth/"AUTHENTICATION"> for
Bugzilla, which logs the user in using an LDAP directory.
=head1 DISCLAIMER
B<This module is experimental>. It is poorly documented, and not very flexible.
Search L<http:E<sol>E<sol>bugzilla.mozilla.orgE<sol>> for a list of known LDAP bugs.
None of the core Bugzilla developers, nor any of the large installations, use
this module, and so it has received less testing. (In fact, this iteration
hasn't been tested at all)
Patches are accepted.
=head1 SEE ALSO
L<Bugzilla::Auth>

Просмотреть файл

@ -0,0 +1,81 @@
# -*- 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.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Auth::Verify::Stack;
use strict;
use base qw(Bugzilla::Auth::Verify);
use fields qw(
_stack
successful
);
sub new {
my $class = shift;
my $list = shift;
my $self = $class->SUPER::new(@_);
$self->{_stack} = [];
foreach my $verify_method (split(',', $list)) {
require "Bugzilla/Auth/Verify/${verify_method}.pm";
push(@{$self->{_stack}},
"Bugzilla::Auth::Verify::$verify_method"->new(@_));
}
return $self;
}
sub can_change_password {
my ($self) = @_;
# We return true if any method can change passwords.
foreach my $object (@{$self->{_stack}}) {
return 1 if $object->can_change_password;
}
return 0;
}
sub check_credentials {
my $self = shift;
my $result;
foreach my $object (@{$self->{_stack}}) {
$result = $object->check_credentials(@_);
$self->{successful} = $object;
last if !$result->{failure};
# So that if none of them succeed, it's undef.
$self->{successful} = undef;
}
# Returns the result at the bottom of the stack if they all fail.
return $result;
}
sub create_or_update_user {
my $self = shift;
my $result;
foreach my $object (@{$self->{_stack}}) {
$result = $object->create_or_update_user(@_);
last if !$result->{failure};
}
# Returns the result at the bottom of the stack if they all fail.
return $result;
}
sub user_can_create_account {
my ($self) = @_;
# We return true if any method allows the user to create an account.
foreach my $object (@{$self->{_stack}}) {
return 1 if $object->user_can_create_account;
}
return 0;
}
1;

Просмотреть файл

@ -43,6 +43,7 @@ use base qw(Exporter);
AUTH_ERROR
AUTH_LOGINFAILED
AUTH_DISABLED
AUTH_NO_SUCH_USER
USER_PASSWORD_MIN_LENGTH
USER_PASSWORD_MAX_LENGTH
@ -144,6 +145,7 @@ use constant AUTH_NODATA => 1;
use constant AUTH_ERROR => 2;
use constant AUTH_LOGINFAILED => 3;
use constant AUTH_DISABLED => 4;
use constant AUTH_NO_SUCH_USER => 5;
# The minimum and maximum lengths a password must have.
use constant USER_PASSWORD_MIN_LENGTH => 3;

Просмотреть файл

@ -155,17 +155,17 @@ sub disabledtext { $_[0]->{'disabledtext'}; }
sub is_disabled { $_[0]->disabledtext ? 1 : 0; }
sub showmybugslink { $_[0]->{showmybugslink}; }
sub set_flags {
my $self = shift;
while (my $key = shift) {
$self->{'flags'}->{$key} = shift;
}
sub set_authorizer {
my ($self, $authorizer) = @_;
$self->{authorizer} = $authorizer;
}
sub get_flag {
my $self = shift;
my $key = shift;
return $self->{'flags'}->{$key};
sub authorizer {
my ($self) = @_;
if (!$self->{authorizer}) {
require Bugzilla::Auth;
$self->{authorizer} = new Bugzilla::Auth();
}
return $self->{authorizer};
}
# Generate a string to identify the user by name + login if the user
@ -1505,6 +1505,17 @@ which to identify the user. Currently the part of the user's email address
before the at sign (@), but that could change, especially if we implement
usernames not dependent on email address.
=item C<authorizer>
This is the L<Bugzilla::Auth> object that the User logged in with.
If the user hasn't logged in yet, a new, empty Bugzilla::Auth() object is
returned.
=item C<set_authorizer($authorizer)>
Sets the L<Bugzilla::Auth> object to be returned by C<authorizer()>.
Should only be called by C<Bugzilla::Auth::login>, for the most part.
=item C<queries>
Returns an array of the user's named queries, sorted in a case-insensitive
@ -1718,21 +1729,6 @@ When called with one argument:
Returns C<1> if the user can bless the group with that name, returns
C<0> otherwise.
=item C<set_flags>
=item C<get_flag>
User flags are template-accessible user status information, stored in the form
of a hash. For an example of use, when the current user is authenticated in
such a way that they are allowed to log out, the 'can_logout' flag is set to
true (1). The template then checks this flag before displaying the "Log Out"
link.
C<set_flags> is called with any number of key,value pairs. Flags for each key
will be set to the specified value.
C<get_flag> is called with a single key name, which returns the associated
value.
=item C<wants_bug_mail>
Returns true if the user wants mail for a given bug change.

Просмотреть файл

@ -49,7 +49,7 @@ my $vars = {};
print $cgi->header();
# If we're using LDAP for login, then we can't create a new account here.
unless (Bugzilla::Auth->can_edit('new')) {
unless (Bugzilla->user->authorizer->user_can_create_account) {
ThrowUserError("auth_cant_create_account");
}

Просмотреть файл

@ -53,15 +53,7 @@ my $template = Bugzilla->template;
my $vars = {};
my $buffer = $cgi->query_string();
if ($cgi->param("GoAheadAndLogIn")) {
# We got here from a login page, probably from relogin.cgi. We better
# make sure the password is legit.
Bugzilla->login(LOGIN_REQUIRED);
} else {
Bugzilla->login();
}
my $user = Bugzilla->user;
my $user = Bugzilla->login();
my $userid = $user->id;
# Backwards compatibility hack -- if there are any of the old QUERY_*

Просмотреть файл

@ -75,8 +75,7 @@ elsif ($action eq 'begin-sudo') {
# and password.
# We only need to do this for authentication methods that involve Bugzilla
# directly obtaining a login (i.e. normal CGI login), as opposed to other
# methods (like Environment vars login). We assume that if a user can log
# out, they can also log in:
# methods (like Environment vars login).
# First, record if Bugzilla_login and Bugzilla_password were provided
my $credentials_provided;
@ -92,7 +91,7 @@ elsif ($action eq 'begin-sudo') {
# At this point, the user is logged in. However, if they used a method
# where they could have provided a username/password (i.e. CGI), but they
# did not provide a username/password, then throw an error.
if ($user->get_flag('can_logout') && !$credentials_provided) {
if ($user->authorizer->can_login && !$credentials_provided) {
ThrowUserError('sudo_password_required',
{ target_login => $cgi->param('target_login'),
reason => $cgi->param('reason')});

Просмотреть файл

@ -37,11 +37,7 @@ my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $vars = {};
if ($cgi->param('GoAheadAndLogIn')) {
Bugzilla->login(LOGIN_REQUIRED);
} else {
Bugzilla->login();
}
Bugzilla->login();
# Editable, 'single' HTML bugs are treated slightly specially in a few places
my $single = !$cgi->param('format')

Просмотреть файл

Просмотреть файл

@ -79,7 +79,7 @@
[%# For now, password change requests only apply to the DB
# verification method #%]
[% IF has_db != 0 %]
[% IF user.authorizer.can_change_password %]
<td>[ <a href="index.cgi?GoAheadAndLogIn=1#forgot">Forgot my Password</a> ]</td>
[% END %]
</tr>

Просмотреть файл

@ -22,7 +22,6 @@
[%# INTERFACE:
# target: string. URL to go to after login.
# has_db: true if DB is one of the available authentication mechanisms
#%]
[% PROCESS global/variables.none.tmpl %]
@ -100,9 +99,7 @@
# their password, assuming that our auth method allows that.
#%]
[% IF caneditaccount %]
[% IF Param("createemailregexp") %]
[% IF Param("createemailregexp") && user.authorizer.user_can_create_account %]
<hr>
<p>
@ -111,10 +108,7 @@
</p>
[% END %]
[%# For now, password change requests only apply to the DB
# verification method #%]
[% IF has_db != 0 %]
[% IF user.authorizer.can_change_password %]
<hr>
<a name="forgot"></a>
@ -126,10 +120,6 @@
<input size="35" name="loginname">
<input type="submit" value="Submit Request">
</form>
[% END %]
<hr>
[% END %]
[% PROCESS global/footer.html.tmpl %]

Просмотреть файл

@ -42,20 +42,21 @@
<tr>
<td colspan="2"><hr></td>
</tr>
[% IF user.authorizer.can_change_password %]
<tr>
<th align="right">New password:</th>
<td>
<input type="password" name="new_password1">
</td>
</tr>
<tr>
<th align="right">New password:</th>
<td>
<input type="password" name="new_password1">
</td>
</tr>
<tr>
<th align="right">Re-enter new password:</th>
<td>
<input type="password" name="new_password2">
</td>
</tr>
<tr>
<th align="right">Re-enter new password:</th>
<td>
<input type="password" name="new_password2">
</td>
</tr>
[% END %]
<tr>
<th align="right">Your real name (optional, but encouraged):</th>
@ -64,7 +65,7 @@
</td>
</tr>
[% IF Param('allowemailchange') %]
[% IF user.authorizer.can_change_email && Param('allowemailchange') %]
[% IF login_change_date %]
[% IF new_login_name %]
<tr>

Просмотреть файл

@ -76,7 +76,7 @@
are impersonating them.
</p>
[% IF user.get_flag("can_logout") %]
[% IF user.authorizer.can_login %]
<p>
Finally, enter your [% terms.Bugzilla %] password:
<input type="hidden" name="Bugzilla_login" value="

Просмотреть файл

@ -48,15 +48,23 @@
Attachment #[% attach_id FILTER html %] ([% description FILTER html %])
is already obsolete.
[% ELSIF error == "auth_err" %]
[% title = "Internal Authentication Error" %]
[%# Authentication errors are in a template depending on the auth method,
for pluggability.
#%]
[% INCLUDE "account/auth/$authmethod-error.html.tmpl" %]
[% ELSIF error == "auth_invalid_email" %]
[% title = "Invalid Email Address" %]
We received an email address (<b>[% addr FILTER html %]</b>)
that didn't pass our syntax checking for a legal email address,
when trying to create or update your account.
[% IF default %]
A legal address must contain exactly one '@',
and at least one '.' after the @.
[% ELSE %]
[%+ Param('emailregexpdesc') %]
[% END %]
It must also not contain any of these special characters:
<tt>\ ( ) &amp; &lt; &gt; , ; : &quot; [ ]</tt>, or any whitespace.</tt>
[% ELSIF error == "authres_unhandled" %]
An authorization handler return value was not handled by the login code.
The result value of [% value FILTER html %] was not handled by
the login code.
[% ELSIF error == "bad_page_cgi_id" %]
[% title = "Invalid Page ID" %]
@ -103,10 +111,27 @@
[% ELSIF error == "cookies_need_value" %]
Every cookie must have a value.
[% ELSIF error == "env_no_email" %]
[% terms.Bugzilla %] did not receive an email address from the
environment.
[% IF Param("auth_env_email") %]
This means that the '[% Param("auth_env_email") FILTER html %]'
environment variable was empty or did not exist.
[% ELSE %]
You need to set the "auth_env_email" environment variable to
the name of the environment variable that will contain the
user's email address.
[% END %]
[% ELSIF error == "extension_invalid" %]
An error occured processing hook [% name FILTER html %] in
extension [% extension FILTER html %].
[% ELSIF error == "extern_id_conflict" %]
The external ID '[% extern_id FILTER html %]' already exists
in the database for '[% username FILTER html %]', but your
account source says that '[% extern_user FILTER html %]' has that ID.
[% ELSIF error == "field_type_mismatch" %]
Cannot seem to handle <code>[% field FILTER html %]</code>
and <code>[% type FILTER html %]</code> together.
@ -247,6 +272,19 @@
given.
[% END %]
[% ELSIF error == "ldap_bind_failed" %]
Failed to bind to the LDAP server. The error message was:
<code>[% errstr FILTER html %]</code>
[% ELSIF error == "ldap_cannot_retreive_attr" %]
The specified LDAP attribute [% attr FILTER html %] was not found.
[% ELSIF error == "ldap_connect_failed" %]
Could not connect to the LDAP server <code>[% server FILTER html %]</code>.
[% ELSIF error == "ldap_server_not_defined" %]
The LDAP server for authentication has not been defined.
[% ELSIF error == "missing_bug_id" %]
No [% terms.bug %] ID was given.

Просмотреть файл

@ -57,7 +57,7 @@
[% IF user.login %]
[% ' | <a href="sanitycheck.cgi">Sanity&nbsp;check</a>'
IF user.groups.tweakparams %]
[% IF user.get_flag('can_logout') %]
[% IF user.authorizer.can_logout %]
| <a href="relogin.cgi">Log&nbsp;out</a>&nbsp;
[% ELSE %]
| Logged&nbsp;in&nbsp;as&nbsp;
@ -70,10 +70,13 @@
[% user.login FILTER html %]
[% END %]
[% ELSE %]
[% IF Param('createemailregexp') %]
[% IF Param('createemailregexp')
&& user.authorizer.user_can_create_account %]
| <a href="createaccount.cgi">New&nbsp;Account</a>
[% END %]
| <a href="index.cgi?GoAheadAndLogIn=1">Log&nbsp;In</a>
[% IF user.authorizer.can_login %]
| <a href="index.cgi?GoAheadAndLogIn=1">Log&nbsp;In</a>
[% END %]
[% END %]
</div>
</div>

Просмотреть файл

@ -1339,10 +1339,6 @@
[% title = "Wrong Token" %]
That token cannot be used to change your password.
[% ELSIF error == "extern_id_conflict" %]
[% title = "Extern ID Conflict" %]
Someone with a different external ID has that address.
[% ELSIF error == "wrong_token_for_confirming_email_change" %]
[% title = "Wrong Token" %]
That token cannot be used to change your email address.

Просмотреть файл

@ -69,12 +69,12 @@ function addSidebar() {
<li id="report"><a href="report.cgi">Summary reports and charts</a></li>
[% IF user.id %]
<li id="userprefs"><a href="userprefs.cgi">Change password or user preferences</a></li>
[% IF user.get_flag('can_logout') %]
[% IF user.authorizer.can_logout %]
<li id="logout"><a href="relogin.cgi">Log out [% user.login FILTER html %]</a></li>
[% END %]
[% ELSE %]
[% ELSIF user.authorizer.can_login %]
[% PROCESS "account/auth/login-small.html.tmpl" %]
[% IF Param('createemailregexp') %]
[% IF Param('createemailregexp') && user.authorizer.user_can_create_account %]
<li id="account"><a href="createaccount.cgi">Open a new [% terms.Bugzilla %] account</a></li>
[% END %]
[% END %]

Просмотреть файл

@ -97,7 +97,7 @@ function normal_keypress_handler( aEvent ) {
[%- IF user.groups.tweakparams %]
<text class="text-link" onclick="load_relative_url('sanitycheck.cgi')" value="sanity check"/>
[%- END %]
[%- IF user.get_flag('can_logout') %]
[%- IF user.authorizer.can_logout %]
<text class="text-link" onclick="load_relative_url('relogin.cgi')" value="log out [% user.login FILTER html %]"/>
[%- END %]
<separator class="thin"/>

Просмотреть файл

@ -104,7 +104,7 @@ if ( $::action eq 'reqpw' ) {
|| ThrowUserError("login_needed_for_password_change");
# check verification methods
unless (Bugzilla::Auth->has_db) {
unless (Bugzilla->user->authorizer->can_change_password) {
ThrowUserError("password_change_requests_not_allowed");
}

Просмотреть файл

@ -50,7 +50,8 @@ sub DoAccount {
($vars->{'realname'}) = $dbh->selectrow_array(
"SELECT realname FROM profiles WHERE userid = ?", undef, $user->id);
if(Param('allowemailchange')) {
if(Param('allowemailchange')
&& Bugzilla->user->authorizer->can_change_email) {
my @token = $dbh->selectrow_array(
"SELECT tokentype, issuedate + " .
$dbh->sql_interval(3, 'DAY') . ", eventdata