]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 180642 - Move authentication code into a module
authorbbaetz%acm.org <>
Sat, 22 Mar 2003 12:47:09 +0000 (12:47 +0000)
committerbbaetz%acm.org <>
Sat, 22 Mar 2003 12:47:09 +0000 (12:47 +0000)
r=gerv, justdave
a=justdave

25 files changed:
Bugzilla.pm
Bugzilla/Auth.pm [new file with mode: 0644]
Bugzilla/Auth/CGI.pm [new file with mode: 0644]
Bugzilla/Auth/Cookie.pm [new file with mode: 0644]
Bugzilla/Auth/DB.pm [new file with mode: 0644]
Bugzilla/Auth/LDAP.pm [new file with mode: 0644]
Bugzilla/Config.pm
Bugzilla/Constants.pm
Bugzilla/DB.pm
Bugzilla/Token.pm
CGI.pl
Token.pm
checksetup.pl
createaccount.cgi
defparams.pl
editusers.cgi
t/Support/Files.pm
template/en/default/account/auth/ldap-error.html.tmpl [new file with mode: 0644]
template/en/default/account/auth/login.html.tmpl [moved from template/en/default/account/login.html.tmpl with 68% similarity]
template/en/default/admin/products/groupcontrol/confirm-edit.html.tmpl
template/en/default/bug/process/confirm-duplicate.html.tmpl
template/en/default/bug/process/midair.html.tmpl
template/en/default/global/code-error.html.tmpl
template/en/default/global/confirm-user-match.html.tmpl
template/en/default/global/user-error.html.tmpl

index 366acb163923ed2ad9fdfd42fe32c6873100d2ca..cded650d7df659f6cd73c9368ea522aa8b872d5f 100644 (file)
@@ -24,10 +24,13 @@ package Bugzilla;
 
 use strict;
 
+use Bugzilla::Auth;
 use Bugzilla::CGI;
 use Bugzilla::Config;
+use Bugzilla::Constants;
 use Bugzilla::DB;
 use Bugzilla::Template;
+use Bugzilla::User;
 
 my $_template;
 sub template {
@@ -43,6 +46,60 @@ sub cgi {
     return $_cgi;
 }
 
+my $_user;
+sub user {
+    my $class = shift;
+    return $_user;
+}
+
+sub login {
+    my ($class, $type) = @_;
+
+    # Avoid double-logins, which may confuse the auth code
+    # (double cookies, odd compat code settings, etc)
+    # This is particularly important given the munging for
+    # $::COOKIE{'Bugzilla_login'} from a userid to a loginname
+    # (for backwards compat)
+    if (defined $_user) {
+        return $_user->{id};
+    }
+
+    $type = LOGIN_NORMAL unless defined $type;
+
+    # For now, we can only log in from a cgi
+    # One day, we'll be able to log in via apache auth, an email message's
+    # PGP signature, and so on
+
+    use Bugzilla::Auth::CGI;
+    my $userid = Bugzilla::Auth::CGI->login($type);
+    if ($userid) {
+        $_user = new Bugzilla::User($userid);
+
+        # Compat stuff
+        $::userid = $userid;
+        &::ConfirmGroup($userid);
+
+        # Evil compat hack. The cookie stores the id now, not the name, but
+        # old code still looks at this to get the current user's email
+        # so it needs to be set.
+        $::COOKIE{'Bugzilla_login'} = $_user->{email};
+
+        $::vars->{'user'} = &::GetUserInfo($userid);
+    } else {
+        # Old compat stuff
+
+        $::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 $userid || 0;
+}
+
 my $_dbh;
 my $_dbh_main;
 my $_dbh_shadow;
@@ -93,6 +150,7 @@ sub switch_to_main_db {
 # Per process cleanup
 sub _cleanup {
     undef $_cgi;
+    undef $_user;
 
     # See bug 192531. If we don't clear the possibly active statement handles,
     # then when this is called from the END block, it happens _before_ the
@@ -192,6 +250,16 @@ The current C<cgi> object. Note that modules should B<not> be using this in
 general. Not all Bugzilla actions are cgi requests. Its useful as a convenience
 method for those scripts/templates which are only use via CGI, though.
 
+=item C<user>
+
+The current L<Bugzilla::User>. C<undef> if there is no currently logged in user
+or if the login code has not yet been run.
+
+=item C<login>
+
+Logs in a user, returning the userid, or C<0> if there is no logged in user. 
+See L<Bugzilla::Auth>.
+
 =item C<dbh>
 
 The current database handle. See L<DBI>.
diff --git a/Bugzilla/Auth.pm b/Bugzilla/Auth.pm
new file mode 100644 (file)
index 0000000..902ae0f
--- /dev/null
@@ -0,0 +1,214 @@
+# -*- 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): Bradley Baetz <bbaetz@acm.org>
+
+package Bugzilla::Auth;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Constants;
+
+# 'inherit' from the main loginmethod
+BEGIN {
+    my $loginmethod = Param("loginmethod");
+    require "Bugzilla/Auth/" . $loginmethod . ".pm";
+
+    our @ISA;
+    push (@ISA, "Bugzilla::Auth::" . $loginmethod);
+}
+
+# PRIVATE
+
+# Returns the network address for a given ip
+sub get_netaddr {
+    my $ipaddr = shift;
+
+    # Check for a valid IPv4 addr which we know how to parse
+    if (!$ipaddr || $ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
+        return undef;
+    }
+
+    my $addr = unpack("N", pack("CCCC", split(/\./, $ipaddr)));
+
+    my $maskbits = Param('loginnetmask');
+
+    $addr >>= (32-$maskbits);
+    $addr <<= (32-$maskbits);
+    return join(".", unpack("CCCC", pack("N", $addr)));
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth - Authentication handling for Bugzilla users
+
+=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).
+
+The handlers for the various types 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>
+then use those methods to do the authentication.
+
+I<Bugzilla::Auth> itself inherits from the default authentication handler,
+identified by the I<loginmethod> param.
+
+=head1 METHODS
+
+C<Bugzilla::Auth> contains several helper methods to be used by
+authentication or login modules.
+
+=over 4
+
+=item C<Bugzilla::Auth::get_netaddr($ipaddr)>
+
+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
+order to restrict weak authentication methods (such as cookies) to only some
+addresses.
+
+=back
+
+=head1 AUTHENTICATION
+
+Authentication modules check a users's credentials (username, password, etc) to
+verify who the user is.
+
+=head2 METHODS
+
+=over 4
+
+=item C<authenticate($username, $pass)>
+
+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.
+
+The first 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.
+
+=over 4
+
+=item C<AUTH_OK>
+
+Authentication succeeded. The second variable is the userid of the new user.
+
+=item 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.
+
+=item C<AUTH_ERROR>
+
+An error occurred when trying to use the login mechanism. The second return
+value may contain the Bugzilla userid, but will probably be C<undef>,
+signifiying that the userid is unknown. The third value is a tag describing
+the error used by the authentication error templates to print a description
+to the user. The optional fourth argument is a hashref of values used as part
+of the tag's error descriptions.
+
+This error template must have a name/location of
+I<account/auth/C<lc(authentication-type)>-error.html.tmpl>.
+
+=item C<AUTH_LOGINFAILED>
+
+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 second 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.
+
+The third 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 fourth argument, to be used by the tag to give more detailed 
+information.
+
+=item C<AUTH_DISABLED>
+
+The user successfully logged in, but their account has been disabled. The
+second argument in the returned array is the userid, and the third 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.
+
+=back
+
+=item C<can_edit>
+
+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
+through the Bugzilla user interface. Forgotten passwords can also be
+retrieved through the L<Token interface|Token>.
+
+=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::CGI|Bugzilla::Auth::CGI> logs in users
+from CGI scripts, first by trying database authentication against the
+Bugzilla C<profiles> table, and then by trying cookies as a fallback.
+
+A login module consists of a single method, C<login>, which takes a C<$type>
+argument, using constants found in C<Bugzilla::Constants>.
+
+=over 4
+
+=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.
+
+=back
+
+The login module uses various authentication modules to try to authenticate
+a user, and returns 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
+module to prompt the user for this data.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth::CGI>, L<Bugzilla::Auth::Cookie>, L<Bugzilla::Auth::DB>
diff --git a/Bugzilla/Auth/CGI.pm b/Bugzilla/Auth/CGI.pm
new file mode 100644 (file)
index 0000000..b7c2e6c
--- /dev/null
@@ -0,0 +1,195 @@
+# -*- 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::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 = 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()");
+        my $cookiepath = Param("cookiepath");
+        print "Set-Cookie: Bugzilla_login=$userid ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
+        print "Set-Cookie: Bugzilla_logincookie=$logincookie ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
+
+        # 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) {
+        $::vars->{'authmethod'} = lc($authmethod);
+        $::vars->{'userid'} = $userid;
+        $::vars->{'auth_err_tag'} = $extra;
+        $::vars->{'info'} = $info;
+
+        &::ThrowCodeError("auth_err");
+    }
+
+    # 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 "Content-Type: text/html\n\n";
+
+        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
+        my $cookiepath = Param("cookiepath");
+        print "Set-Cookie: Bugzilla_login= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT\n";
+        print "Set-Cookie: Bugzilla_logincookie= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT\n";
+        # 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,
+                      }
+                     );
+
+}
+
+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.
+
+=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>.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth>
diff --git a/Bugzilla/Auth/Cookie.pm b/Bugzilla/Auth/Cookie.pm
new file mode 100644 (file)
index 0000000..7dd2967
--- /dev/null
@@ -0,0 +1,119 @@
+# -*- 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>
diff --git a/Bugzilla/Auth/DB.pm b/Bugzilla/Auth/DB.pm
new file mode 100644 (file)
index 0000000..55e4bc7
--- /dev/null
@@ -0,0 +1,102 @@
+# -*- 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::DB;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Constants;
+use Bugzilla::Util;
+
+sub authenticate {
+    my ($class, $username, $passwd) = @_;
+
+    return (AUTH_NODATA) unless defined $username && defined $passwd;
+
+    my $dbh = Bugzilla->dbh;
+
+    # We're just testing against the db, so any value is ok
+    trick_taint($username);
+
+    # Retrieve the user's ID and crypted password from the database.
+    my $sth = $dbh->prepare_cached("SELECT userid,cryptpassword,disabledtext " .
+                                   "FROM profiles " .
+                                   "WHERE login_name=?");
+    my ($userid, $realcryptpwd, $disabledtext) =
+      $dbh->selectrow_array($sth,
+                            undef,
+                            $username);
+
+    # If the user doesn't exist, return now
+    return (AUTH_LOGINFAILED) unless defined $userid;
+
+    # OK, now authenticate the user
+
+    # 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);
+
+    # Make sure the passwords match or return an error
+    return (AUTH_LOGINFAILED, $userid) unless
+      ($enteredCryptedPassword eq $realcryptpwd);
+
+    # Now we know that the user has logged in successfully,
+    # so delete any password tokens for them
+    require Token;
+    Token::DeletePasswordTokens("user logged in");
+
+    # The user may have had their account disabled
+    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);
+}
+
+sub can_edit { return 1; }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::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>
diff --git a/Bugzilla/Auth/LDAP.pm b/Bugzilla/Auth/LDAP.pm
new file mode 100644 (file)
index 0000000..4570bdd
--- /dev/null
@@ -0,0 +1,185 @@
+# -*- 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::LDAP;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Constants;
+
+use Net::LDAP;
+
+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;
+
+    # We need to bind anonymously to the LDAP server.  This is
+    # because we need to get the Distinguished Name of the user trying
+    # to log in.  Some servers (such as iPlanet) allow you to have unique
+    # uids spread out over a subtree of an area (such as "People"), so
+    # 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");
+    }
+
+    my $LDAPport = "389";  # default LDAP port
+    if($LDAPserver =~ /:/) {
+        ($LDAPserver, $LDAPport) = split(":",$LDAPserver);
+    }
+    my $LDAPconn = Net::LDAP->new($LDAPserver, port => $LDAPport, version => 3);
+    if(!$LDAPconn) {
+        return (AUTH_ERROR, undef, "connect_failed");
+    }
+
+    my $mesg;
+    if (Param("LDAPbinddn")) {
+        my ($LDAPbinddn,$LDAPbindpass) = split(":",Param("LDAPbinddn"));
+        $mesg = $LDAPconn->bind($LDAPbinddn, password => $LDAPbindpass);
+    }
+    else {
+        $mesg = $LDAPconn->bind();
+    }
+    if($mesg->code) {
+        return (AUTH_ERROR, undef,
+                "connect_failed",
+                { errstr => $mesg->err });
+    }
+
+    # We've got our anonymous bind;  let's look up this user.
+    $mesg = $LDAPconn->search( base   => Param("LDAPBaseDN"),
+                               scope  => "sub",
+                               filter => Param("LDAPuidattribute") . "=$username",
+                               attrs  => ['dn'],
+                             );
+    return (AUTH_LOGINFAILED, undef, "lookup_failure")
+        unless $mesg->count;
+
+    # Now we get the DN from this search.
+    my $userDN = $mesg->shift_entry->dn;
+
+    # Now we attempt to bind as the specified user.
+    $mesg = $LDAPconn->bind( $userDN, password => $passwd);
+
+    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",
+                             );
+    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 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");
+        }
+        &::InsertNewUser($username, $userRealName);
+
+        my ($userid, $disabledtext) = $dbh->selectrow_array($sth,
+                                                            undef,
+                                                            $username);
+        return (AUTH_ERROR, $userid, "no_userid")
+          unless $userid;
+    }
+
+    # 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);
+}
+
+sub can_edit { return 0; }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::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://bugzilla.mozilla.org/> 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>
index 6a34396be91be5a566a453b86260c6d07170b5d8..c1f3e9103dccb2c6a8f9288787222f891672fd28 100644 (file)
@@ -186,6 +186,11 @@ sub UpdateParams {
         $param{'useentrygroupdefault'} = $param{'usebuggroupsentry'};
     }
 
+    # Modularise auth code
+    if (exists $param{'useLDAP'} && !exists $param{'loginmethod'}) {
+        $param{'loginmethod'} = $param{'useLDAP'} ? "LDAP" : "DB";
+    }
+
     # --- DEFAULTS FOR NEW PARAMS ---
 
     foreach my $item (@param_list) {
index 70773e036ec756187a811a0718bc6ac9eca2f1a9..5e6b5365d44b47338afac5edc32f3736ae4d914c 100644 (file)
@@ -36,7 +36,17 @@ use base qw(Exporter);
     CONTROLMAPSHOWN
     CONTROLMAPDEFAULT
     CONTROLMAPMANDATORY
-    );
+
+    AUTH_OK
+    AUTH_NODATA
+    AUTH_ERROR
+    AUTH_LOGINFAILED
+    AUTH_DISABLED
+
+    LOGIN_OPTIONAL
+    LOGIN_NORMAL
+    LOGIN_REQUIRED
+);
    
 
 # CONSTANTS
@@ -72,5 +82,16 @@ use constant CONTROLMAPSHOWN => 1;
 use constant CONTROLMAPDEFAULT => 2;
 use constant CONTROLMAPMANDATORY => 3;
 
-1;
+# See Bugzilla::Auth for docs for these
 
+use constant AUTH_OK => 0;
+use constant AUTH_NODATA => 1;
+use constant AUTH_ERROR => 2;
+use constant AUTH_LOGINFAILED => 3;
+use constant AUTH_DISABLED => 4;
+
+use constant LOGIN_OPTIONAL => 0;
+use constant LOGIN_NORMAL => 1;
+use constant LOGIN_REQUIRED => 2;
+
+1;
index 29935928dee24ecd46212c84648ac8c1cb675294..1d2e966140284c610e3d56a72d520e8c7fa2cec3 100644 (file)
@@ -61,8 +61,6 @@ our @SQLStateStack = ();
 sub SendSQL {
     my ($str) = @_;
 
-    require Bugzilla;
-
     $_current_sth = Bugzilla->dbh->prepare($str);
 
     $_current_sth->execute;
@@ -79,8 +77,6 @@ sub SqlQuote {
     # Backwards compat code
     return "''" if not defined $str;
 
-    require Bugzilla;
-
     my $res = Bugzilla->dbh->quote($str);
 
     trick_taint($res);
@@ -156,6 +152,7 @@ sub _connect {
                            $db_pass,
                            { RaiseError => 1,
                              PrintError => 0,
+                             ShowErrorStatement => 1,
                              HandleError => \&_handle_error,
                              FetchHashKeyName => 'NAME_lc',
                              TaintIn => 1,
index c8132b8048b5792346707bdd71ca9c065b0309b6..97d2da41d93ad5abb7f52ca8cdbdfb12d73f741a 100644 (file)
@@ -237,16 +237,17 @@ sub Cancel {
     &::SendSQL("UNLOCK TABLES");
 }
 
-sub HasPasswordToken {
-    # Returns a password token if the user has one.
-    
-    my ($userid) = @_;
-    
-    &::SendSQL("SELECT token FROM tokens 
-                WHERE userid = $userid AND tokentype = 'password' LIMIT 1");
-    my ($token) = &::FetchSQLData();
-    
-    return $token;
+sub DeletePasswordTokens {
+    my ($userid, $reason) = @_;
+
+    my $dbh = Bugzilla->dbh;
+    my $sth = $dbh->prepare("SELECT token " .
+                            "FROM tokens " .
+                            "WHERE userid=? AND tokentype='password'");
+    $sth->execute($userid);
+    while (my $token = $sth->fetchrow_array) {
+        Token::Cancel($token, "user_logged_in");
+    }
 }
 
 sub HasEmailChangeToken {
diff --git a/CGI.pl b/CGI.pl
index 4765a7a00684ef06c5c775ab3d9be437df4c326d..8ce589ced5493e74cedbcf000b1e3bb7bed495f7 100644 (file)
--- a/CGI.pl
+++ b/CGI.pl
@@ -34,12 +34,7 @@ use lib ".";
 
 use Bugzilla::Util;
 use Bugzilla::Config;
-
-# commented out the following snippet of code. this tosses errors into the
-# CGI if you are perl 5.6, and doesn't if you have perl 5.003. 
-# We want to check for the existence of the LDAP modules here.
-# eval "use Mozilla::LDAP::Conn";
-# my $have_ldap = $@ ? 0 : 1;
+use Bugzilla::Constants;
 
 # Shut up misguided -w warnings about "used only once".  For some reason,
 # "use vars" chokes on me when I try it here.
@@ -202,82 +197,8 @@ sub PasswordForLogin {
     return $result;
 }
 
-sub get_netaddr {
-    my ($ipaddr) = @_;
-
-    # Check for a valid IPv4 addr which we know how to parse
-    if (!$ipaddr || $ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
-        return undef;
-    }
-
-    my $addr = unpack("N", pack("CCCC", split(/\./, $ipaddr)));
-
-    my $maskbits = Param('loginnetmask');
-
-    $addr >>= (32-$maskbits);
-    $addr <<= (32-$maskbits);
-    return join(".", unpack("CCCC", pack("N", $addr)));
-}
-
-my $login_cookie_set = 0;
-# If quietly_check_login is called with no arguments and logins are
-# required, it will prompt for a login.
 sub quietly_check_login {
-    if (Param('requirelogin') && !(@_)) {
-        return confirm_login();
-    }
-    $::disabledreason = '';
-    my $userid = 0;
-    my $ipaddr = $ENV{'REMOTE_ADDR'};
-    my $netaddr = get_netaddr($ipaddr);
-    if (defined $::COOKIE{"Bugzilla_login"} &&
-        defined $::COOKIE{"Bugzilla_logincookie"}) {
-        my $query = "SELECT profiles.userid," .
-                " profiles.login_name, " .
-                " profiles.disabledtext " .
-                " FROM profiles, logincookies WHERE logincookies.cookie = " .
-                SqlQuote($::COOKIE{"Bugzilla_logincookie"}) .
-                " AND profiles.userid = logincookies.userid AND" .
-                " profiles.login_name = " .
-                SqlQuote($::COOKIE{"Bugzilla_login"}) .
-                " AND (logincookies.ipaddr = " .
-                SqlQuote($ipaddr);
-        if (defined $netaddr) {
-            $query .= " OR logincookies.ipaddr = " . SqlQuote($netaddr);
-        }
-        $query .= ")";
-        SendSQL($query);
-
-        my @row;
-        if (MoreSQLData()) {
-            ($userid, my $loginname, my $disabledtext) = FetchSQLData();
-            if ($userid > 0) {
-                if ($disabledtext eq '') {
-                    $::COOKIE{"Bugzilla_login"} = $loginname; # Makes sure case
-                                                              # is in
-                                                              # canonical form.
-                    # We've just verified that this is ok
-                    detaint_natural($::COOKIE{"Bugzilla_logincookie"});
-                } else {
-                    $::disabledreason = $disabledtext;
-                    $userid = 0;
-                }
-            }
-        }
-    }
-    # if 'who' is passed in, verify that it's a good value
-    if ($::FORM{'who'}) {
-        my $whoid = DBname_to_id($::FORM{'who'});
-        delete $::FORM{'who'} unless $whoid;
-    }
-    if (!$userid) {
-        delete $::COOKIE{"Bugzilla_login"};
-    }
-                    
-    $::userid = $userid;
-    ConfirmGroup($userid);
-    $vars->{'user'} = GetUserInfo($::userid);
-    return $userid;
+    return Bugzilla->login($_[0] ? LOGIN_OPTIONAL : LOGIN_NORMAL);
 }
 
 # Populate a hash with information about this user. 
@@ -351,281 +272,7 @@ sub MailPassword {
 }
 
 sub confirm_login {
-    my ($nexturl) = (@_);
-
-# Uncommenting the next line can help debugging...
-#    print "Content-type: text/plain\n\n";
-
-    # I'm going to reorganize some of this stuff a bit.  Since we're adding
-    # a second possible validation method (LDAP), we need to move some of this
-    # to a later section.  -Joe Robins, 8/3/00
-    my $enteredlogin = "";
-    my $realcryptpwd = "";
-    my $userid;
-
-    # If the form contains Bugzilla login and password fields, use Bugzilla's 
-    # built-in authentication to authenticate the user (otherwise use LDAP below).
-    if (defined $::FORM{"Bugzilla_login"} && defined $::FORM{"Bugzilla_password"}) {
-        # Make sure the user's login name is a valid email address.
-        $enteredlogin = $::FORM{"Bugzilla_login"};
-        CheckEmailSyntax($enteredlogin);
-
-        # Retrieve the user's ID and crypted password from the database.
-        SendSQL("SELECT userid, cryptpassword FROM profiles 
-                 WHERE login_name = " . SqlQuote($enteredlogin));
-        ($userid, $realcryptpwd) = FetchSQLData();
-
-        # Make sure the user exists or throw an error (but do not admit it was a username
-        # error to make it harder for a cracker to find account names by brute force).
-        $userid || ThrowUserError("invalid_username_or_password");
-
-        # If this is a new user, generate a password, insert a record
-        # into the database, and email their password to them.
-        if ( defined $::FORM{"PleaseMailAPassword"} && !$userid ) {
-            # Ensure the new login is valid
-            if(!ValidateNewUser($enteredlogin)) {
-                ThrowUserError("account_exists");
-            }
-
-            my $password = InsertNewUser($enteredlogin, "");
-            MailPassword($enteredlogin, $password);
-            
-            $vars->{'login'} = $enteredlogin;
-            
-            print "Content-Type: text/html\n\n";
-            $template->process("account/created.html.tmpl", $vars)
-              || ThrowTemplateError($template->error());                 
-        }
-
-        # Otherwise, authenticate the user.
-        else {
-            # Get the salt from the user's crypted password.
-            my $salt = $realcryptpwd;
-
-            # Using the salt, crypt the password the user entered.
-            my $enteredCryptedPassword = crypt( $::FORM{"Bugzilla_password"} , $salt );
-
-            # Make sure the passwords match or throw an error.
-            ($enteredCryptedPassword eq $realcryptpwd)
-              || ThrowUserError("invalid_username_or_password");
-
-            # If the user has successfully logged in, delete any password tokens
-            # lying around in the system for them.
-            use Token;
-            my $token = Token::HasPasswordToken($userid);
-            while ( $token ) {
-                Token::Cancel($token, 'user_logged_in');
-                $token = Token::HasPasswordToken($userid);
-            }
-        }
-
-     } elsif (Param("useLDAP") &&
-              defined $::FORM{"LDAP_login"} &&
-              defined $::FORM{"LDAP_password"}) {
-       # If we're using LDAP for login, we've got an entirely different
-       # set of things to check.
-
-# see comment at top of file near eval
-       # First, if we don't have the LDAP modules available to us, we can't
-       # do this.
-#       if(!$have_ldap) {
-#         print "Content-type: text/html\n\n";
-#         PutHeader("LDAP not enabled");
-#         print "The necessary modules for LDAP login are not installed on ";
-#         print "this machine.  Please send mail to ".Param("maintainer");
-#         print " and notify him of this problem.\n";
-#         PutFooter();
-#         exit;
-#       }
-
-       # Next, we need to bind anonymously to the LDAP server.  This is
-       # because we need to get the Distinguished Name of the user trying
-       # to log in.  Some servers (such as iPlanet) allow you to have unique
-       # uids spread out over a subtree of an area (such as "People"), so
-       # 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 "") {
-         print "Content-type: text/html\n\n";
-         PutHeader("LDAP server not defined");
-         print "The LDAP server for authentication has not been defined.  ";
-         print "Please contact ".Param("maintainer")." ";
-         print "and notify him of this problem.\n";
-         PutFooter();
-         exit;
-       }
-
-       my $LDAPport = "389";  #default LDAP port
-       if($LDAPserver =~ /:/) {
-         ($LDAPserver, $LDAPport) = split(":",$LDAPserver);
-       }
-       my $LDAPconn = new Mozilla::LDAP::Conn($LDAPserver,$LDAPport);
-       if(!$LDAPconn) {
-         print "Content-type: text/html\n\n";
-         PutHeader("Unable to connect to LDAP server");
-         print "I was unable to connect to the LDAP server for user ";
-         print "authentication.  Please contact ".Param("maintainer");
-         print " and notify him of this problem.\n";
-         PutFooter();
-         exit;
-       }
-
-       # 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
-       if ( ! $::FORM{"LDAP_password"} ) {
-         print "Content-type: text/html\n\n";
-         PutHeader("Login Failed");
-         print "You did not provide a password.\n";
-         print "Please click <b>Back</b> and try again.\n";
-         PutFooter();
-         exit;
-       }
-
-       # We've got our anonymous bind;  let's look up this user.
-       my $dnEntry = $LDAPconn->search(Param("LDAPBaseDN"),"subtree","uid=".$::FORM{"LDAP_login"});
-       if(!$dnEntry) {
-         print "Content-type: text/html\n\n";
-         PutHeader("Login Failed");
-         print "The username or password you entered is not valid.\n";
-         print "Please click <b>Back</b> and try again.\n";
-         PutFooter();
-         exit;
-       }
-
-       # Now we get the DN from this search.  Once we've got that, we're
-       # done with the anonymous bind, so we close it.
-       my $userDN = $dnEntry->getDN;
-       $LDAPconn->close;
-
-       # Now we attempt to bind as the specified user.
-       $LDAPconn = new Mozilla::LDAP::Conn($LDAPserver,$LDAPport,$userDN,$::FORM{"LDAP_password"});
-       if(!$LDAPconn) {
-         print "Content-type: text/html\n\n";
-         PutHeader("Login Failed");
-         print "The username or password you entered is not valid.\n";
-         print "Please click <b>Back</b> and try again.\n";
-         PutFooter();
-         exit;
-       }
-
-       # And now we're going to repeat the search, so that we can get the
-       # mail attribute for this user.
-       my $userEntry = $LDAPconn->search(Param("LDAPBaseDN"),"subtree","uid=".$::FORM{"LDAP_login"});
-       if(!$userEntry->exists(Param("LDAPmailattribute"))) {
-         print "Content-type: text/html\n\n";
-         PutHeader("LDAP authentication error");
-         print "I was unable to retrieve the ".Param("LDAPmailattribute");
-         print " attribute from the LDAP server.  Please contact ";
-         print Param("maintainer")." and notify him of this error.\n";
-         PutFooter();
-         exit;
-       }
-
-       # Mozilla::LDAP::Entry->getValues returns an array for the attribute
-       # requested, even if there's only one entry.
-       $enteredlogin = ($userEntry->getValues(Param("LDAPmailattribute")))[0];
-
-       # We're going to need the cryptpwd for this user from the database
-       # so that we can set the cookie below, even though we're not going
-       # to use it for authentication.
-       $realcryptpwd = PasswordForLogin($enteredlogin);
-
-       # If we don't get a result, then we've got a user who isn't in
-       # Bugzilla's database yet, so we've got to add them.
-       if($realcryptpwd eq "") {
-         # We'll want the user's name for this.
-         my $userRealName = ($userEntry->getValues("displayName"))[0];
-         if($userRealName eq "") {
-           $userRealName = ($userEntry->getValues("cn"))[0];
-         }
-         InsertNewUser($enteredlogin, $userRealName);
-         $realcryptpwd = PasswordForLogin($enteredlogin);
-       }
-     } # end LDAP authentication
-
-     # And now, if we've logged in via either method, then we need to set
-     # the cookies.
-     if($enteredlogin ne "") {
-       $::COOKIE{"Bugzilla_login"} = $enteredlogin;
-       my $ipaddr = $ENV{'REMOTE_ADDR'};
-
-       # Unless we're restricting the login, or restricting would have no
-       # effect, loosen the IP which we record in the table
-       unless ($::FORM{'Bugzilla_restrictlogin'} ||
-               Param('loginnetmask') == 32) {
-           $ipaddr = get_netaddr($ipaddr);
-           $ipaddr = $ENV{'REMOTE_ADDR'} unless defined $ipaddr;
-       }
-       SendSQL("insert into logincookies (userid,ipaddr) values (@{[DBNameToIdAndCheck($enteredlogin)]}, @{[SqlQuote($ipaddr)]})");
-       SendSQL("select LAST_INSERT_ID()");
-       my $logincookie = FetchOneColumn();
-
-       $::COOKIE{"Bugzilla_logincookie"} = $logincookie;
-       my $cookiepath = Param("cookiepath");
-       if ($login_cookie_set == 0) {
-           $login_cookie_set = 1;
-           print "Set-Cookie: Bugzilla_login= " . url_quote($enteredlogin) . " ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
-           print "Set-Cookie: Bugzilla_logincookie=$logincookie ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
-       }
-    }
-
-    # If anonymous logins are disabled, quietly_check_login will force
-    # the user to log in by calling confirm_login() when called by any 
-    # code that does not call it with an argument. When confirm_login
-    # calls quietly_check_login, it must not result in confirm_login
-    # being called back.
-    $userid = quietly_check_login('do_not_recurse_here');
-
-    if (!$userid) {
-        if ($::disabledreason) {
-            my $cookiepath = Param("cookiepath");
-            print "Set-Cookie: Bugzilla_login= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT
-Set-Cookie: Bugzilla_logincookie= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT
-Content-type: text/html
-
-";
-            $vars->{'disabled_reason'} = $::disabledreason;
-            ThrowUserError("account_disabled");
-        }
-        
-        if (!defined $nexturl || $nexturl eq "") {
-            # Sets nexturl to be argv0, stripping everything up to and
-            # including the last slash (or backslash on Windows).
-            $0 =~ m:([^/\\]*)$:;
-            $nexturl = $1;
-        }
-        
-        $vars->{'target'} = $nexturl;
-        $vars->{'form'} = \%::FORM;
-        $vars->{'mform'} = \%::MFORM;
-        
-        print "Content-type: text/html\n\n";
-        $template->process("account/login.html.tmpl", $vars)
-          || 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.
-        if (Bugzilla->dbwritesallowed) {
-            SendSQL("DELETE FROM logincookies " .
-                    "WHERE TO_DAYS(NOW()) - TO_DAYS(lastused) > 30");
-        }
-
-        exit;
-    }
-
-    # Update the timestamp on our logincookie, so it'll keep on working.
-    if (Bugzilla->dbwritesallowed) {
-        SendSQL("UPDATE logincookies SET lastused = null " .
-                "WHERE cookie = $::COOKIE{'Bugzilla_logincookie'}");
-    }
-    ConfirmGroup($userid);
-    return $userid;
+    return Bugzilla->login(LOGIN_REQUIRED);
 }
 
 sub PutHeader {
@@ -659,15 +306,20 @@ sub ThrowCodeError {
   ($vars->{'error'}, my $extra_vars, my $unlock_tables) = (@_);
 
   SendSQL("UNLOCK TABLES") if $unlock_tables;
-  
-  # Copy the extra_vars into the vars hash 
-  foreach my $var (keys %$extra_vars) {
-      $vars->{$var} = $extra_vars->{$var};
+
+  # If we don't have this test here, then the %@extra_vars vivifies
+  # the hashref, and then setting $vars->{'variables'} uses an empty hashref
+  # so the error template prints out a bogus header for the empty hash
+  if (defined $extra_vars) {
+      # Copy the extra_vars into the vars hash 
+      foreach my $var (keys %$extra_vars) {
+          $vars->{$var} = $extra_vars->{$var};
+      }
+
+      # We may one day log something to file here also.
+      $vars->{'variables'} = $extra_vars;
   }
   
-  # We may one day log something to file here also.
-  $vars->{'variables'} = $extra_vars;
-  
   print "Content-type: text/html\n\n" if !$vars->{'header_done'};
   $template->process("global/code-error.html.tmpl", $vars)
     || ThrowTemplateError($template->error());
index c8132b8048b5792346707bdd71ca9c065b0309b6..97d2da41d93ad5abb7f52ca8cdbdfb12d73f741a 100644 (file)
--- a/Token.pm
+++ b/Token.pm
@@ -237,16 +237,17 @@ sub Cancel {
     &::SendSQL("UNLOCK TABLES");
 }
 
-sub HasPasswordToken {
-    # Returns a password token if the user has one.
-    
-    my ($userid) = @_;
-    
-    &::SendSQL("SELECT token FROM tokens 
-                WHERE userid = $userid AND tokentype = 'password' LIMIT 1");
-    my ($token) = &::FetchSQLData();
-    
-    return $token;
+sub DeletePasswordTokens {
+    my ($userid, $reason) = @_;
+
+    my $dbh = Bugzilla->dbh;
+    my $sth = $dbh->prepare("SELECT token " .
+                            "FROM tokens " .
+                            "WHERE userid=? AND tokentype='password'");
+    $sth->execute($userid);
+    while (my $token = $sth->fetchrow_array) {
+        Token::Cancel($token, "user_logged_in");
+    }
 }
 
 sub HasEmailChangeToken {
index 6c3fc57b7bca04219311f65db2e794d5581ceee1..a8ea7b1e1e6babd0f28f92a60a33bff5cb9b9a24 100755 (executable)
@@ -674,28 +674,6 @@ EOF
     }
 }
 
-###########################################################################
-# Global Utility Library
-###########################################################################
-
-# globals.pl clears the PATH, but File::Find uses Cwd::cwd() instead of
-# Cwd::getcwd(), which we need to do because `pwd` isn't in the path - see
-# http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2001-09/msg00115.html
-# As a workaround, since we only use File::Find in checksetup, which doesn't
-# run in taint mode anyway, preserve the path...
-my $origPath = $::ENV{'PATH'};
-
-# Use the Bugzilla utility library for various functions.  We do this
-# here rather than at the top of the file so globals.pl doesn't define
-# localconfig variables for us before we get a chance to check for
-# their existence and create them if they don't exist.  Also, globals.pl
-# removes $ENV{'path'}, which we need in order to run `which mysql` above.
-require "globals.pl";
-
-# ...and restore it. This doesn't change tainting, so this will still cause
-# errors if this script ever does run with -T.
-$::ENV{'PATH'} = $origPath;
-
 ###########################################################################
 # Check data directory
 ###########################################################################
@@ -1215,6 +1193,33 @@ if ($my_webservergroup) {
     chmod 01777, 'graphs';
 }
 
+###########################################################################
+# Global Utility Library
+###########################################################################
+
+# This is done here, because some modules require params to be set up, which
+# won't have happened earlier.
+
+# The only use for loading globals.pl is for Crypt(), which should at some
+# point probably be factored out into Bugzilla::Auth::*
+
+# globals.pl clears the PATH, but File::Find uses Cwd::cwd() instead of
+# Cwd::getcwd(), which we need to do because `pwd` isn't in the path - see
+# http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2001-09/msg00115.html
+# As a workaround, since we only use File::Find in checksetup, which doesn't
+# run in taint mode anyway, preserve the path...
+my $origPath = $::ENV{'PATH'};
+
+# Use the Bugzilla utility library for various functions.  We do this
+# here rather than at the top of the file so globals.pl doesn't define
+# localconfig variables for us before we get a chance to check for
+# their existence and create them if they don't exist.  Also, globals.pl
+# removes $ENV{'path'}, which we need in order to run `which mysql` above.
+require "globals.pl";
+
+# ...and restore it. This doesn't change tainting, so this will still cause
+# errors if this script ever does run with -T.
+$::ENV{'PATH'} = $origPath;
 
 ###########################################################################
 # Check MySQL setup
@@ -1300,6 +1305,16 @@ my $dbh = DBI->connect($connectstring, $my_db_user, $my_db_pass)
 
 END { $dbh->disconnect if $dbh }
 
+###########################################################################
+# Check for LDAP
+###########################################################################
+
+if (Param('loginmethod') eq 'LDAP') {
+    my $netLDAP = have_vers("Net::LDAP", 0);
+    if (!$netLDAP && !$silent) {
+        print "If you wish to use LDAP authentication, then you must install Net::LDAP\n\n";
+    }
+}
 
 ###########################################################################
 # Check GraphViz setup
index 4ce347fcf5a28ca6f8cfb3cc21536bcd3e04103d..0550f42b9026c9b14d17f28abdbc187aa8966e20 100755 (executable)
@@ -40,11 +40,11 @@ use vars qw(
 ConnectToDatabase();
 
 # If we're using LDAP for login, then we can't create a new account here.
-if(Param('useLDAP')) {
+unless (Bugzilla::Auth->can_edit) {
   # Just in case someone already has an account, let them get the correct
   # footer on the error message
   quietly_check_login();
-  ThrowUserError("ldap_cant_create_account");
+  ThrowUserError("auth_cant_create_account");
 }
 
 # Clear out the login cookies.  Make people log in again if they create an
index f75ead4b275c96ce3be84dfc5e05f6100791a0f0..31a7786ac69c766eac4f29b5270663ab83c9efbb 100644 (file)
@@ -123,6 +123,31 @@ sub check_netmask {
     return "";
 }
 
+sub check_loginmethod {
+    # doeditparams traverses the list of params, and for each one it checks,
+    # then updates. This means that if one param checker wants to look at 
+    # other params, it must be below that other one. So you can't have two 
+    # params mutually dependant on each other.
+    # This means that if someone clears the LDAP config params after setting
+    # the login method as LDAP, we won't notice, but all logins will fail.
+    # So don't do that.
+
+    my ($method, $entry) = @_;
+    my $res = check_multi($method, $entry);
+    return $res if $res;
+    if ($method eq 'DB') {
+        # No params
+    } elsif ($method eq 'LDAP') {
+        eval "require Net::LDAP";
+        return "Error requiring Net::LDAP: '$@'" if $@;
+        return "LDAP servername is missing" unless Param("LDAPserver");
+        return "LDAPBaseDN is empty" unless Param("LDAPBaseDN");
+    } else {
+        return "Unknown loginmethod '$method' in check_loginmethod";
+    }
+    return "";
+}
+
 # OK, here are the parameter definitions themselves.
 #
 # Each definition is a hash with keys:
@@ -322,16 +347,6 @@ sub check_netmask {
    checker => \&check_shadowdb
   },
 
-  {
-   name => 'useLDAP',
-   desc => 'Turn this on to use an LDAP directory for user authentication ' .
-           'instead of the Bugzilla database.  (User profiles will still be ' .
-           'stored in the database, and will match against the LDAP user by ' .
-           'email address.)',
-   type => 'b',
-   default => 0
-  },
-
   {
    name => 'LDAPserver',
    desc => 'The name (and optionally port) of your LDAP server. (e.g. ' .
@@ -340,6 +355,16 @@ sub check_netmask {
    default => ''
   },
 
+  {
+   name => 'LDAPbinddn',
+   desc => 'If your LDAP server requires that you use a binddn and password ' .
+           'instead of binding anonymously, enter it here ' .
+           '(e.g. cn=default,cn=user:password). ' .
+           'Leave this empty for the normal case of an anonymous bind.',
+   type => 't',
+   default => ''
+  },
+
   {
    name => 'LDAPBaseDN',
    desc => 'The BaseDN for authenticating users against. (e.g. ' .
@@ -348,6 +373,13 @@ sub check_netmask {
    default => ''
   },
 
+  {
+   name => 'LDAPuidattribute',
+   desc => 'The name of the attribute containing the user\'s login name.',
+   type => 't',
+   default => 'uid'
+  },
+
   {
    name => 'LDAPmailattribute',
    desc => 'The name of the attribute of a user in your directory that ' .
@@ -356,6 +388,29 @@ sub check_netmask {
    default => 'mail'
   },
 
+  {
+   name => 'loginmethod',
+   desc => 'The type of login authentication to use:
+            <dl>
+              <dt>DB</dt>
+              <dd>
+                Bugzilla\'s builtin authentication. This is the most common
+                choice.
+              </dd>
+              <dt>LDAP</dt>
+              <dd>
+                LDAP authentication using an LDAP server. This method is
+                experimental; please see the Bugzilla documentation for more
+                information. Using this method requires additional parameters
+                to be set above.
+              </dd>
+             </dl>',
+   type => 's',
+   choices => [ 'DB', 'LDAP' ],
+   default => 'DB',
+   checker => \&check_loginmethod
+  },
+
   {
    name => 'mostfreqthreshold',
    desc => 'The minimum number of duplicates a bug needs to show up on the ' .
index cc6be6665ba3a6f39b16e24d7005806c768796c2..fee00a4e08bef544f9b50bc14a1def268aeb5ed8 100755 (executable)
@@ -110,8 +110,8 @@ sub EmitFormElements ($$$$)
     if ($editall) {
         print "</TR><TR>\n";
         print "  <TH ALIGN=\"right\">Password:</TH>\n";
-        if(Param('useLDAP')) {
-          print "  <TD><FONT COLOR=RED>This site is using LDAP for authentication!</FONT></TD>\n";
+        if(!Bugzilla::Auth->can_edit) {
+          print "  <TD><FONT COLOR=RED>This site's authentication method does not allow password changes through Bugzilla!</FONT></TD>\n";
         } else {
           print qq|
             <TD><INPUT TYPE="PASSWORD" SIZE="16" MAXLENGTH="16" NAME="password" VALUE=""><br>
@@ -357,7 +357,7 @@ if ($action eq 'list') {
         }
         print "</TR>";
     }
-    if ($editall && !Param('useLDAP')) {
+    if ($editall && Bugzilla::Auth->can_edit) {
         print "<TR>\n";
         my $span = $candelete ? 3 : 2;
         print qq{
@@ -391,9 +391,8 @@ if ($action eq 'add') {
         exit;
     }
 
-    if(Param('useLDAP')) {
-      print "This site is using LDAP for authentication.  To add a new user, ";
-      print "please contact the LDAP administrators.";
+    if(!Bugzilla::Auth->can_edit) {
+      print "The authentication mechanism you are using does not permit accounts to be created from Bugzilla";
       PutTrailer();
       exit;
     }
@@ -429,9 +428,8 @@ if ($action eq 'new') {
         exit;
     }
 
-    if(Param('useLDAP')) {
-      print "This site is using LDAP for authentication.  To add a new user, ";
-      print "please contact the LDAP administrators.";
+    if (!Bugzilla::Auth->can_edit) {
+      print "This site's authentication mechanism does not allow new users to be added.";
       PutTrailer();
       exit;
     }
@@ -791,7 +789,7 @@ if ($action eq 'update') {
 
 
     # Update the database with the user's new password if they changed it.
-    if ( !Param('useLDAP') && $editall && $password ) {
+    if ( Bugzilla::Auth->can_edit && $editall && $password ) {
         my $passworderror = ValidatePassword($password);
         if ( !$passworderror ) {
             my $cryptpassword = SqlQuote(Crypt($password));
index 108f6541a89a4aa359bcb9f18d4c19cc8c3354b6..e822346d0eae2cb117b422d5051b5f5ec55cf4ad 100644 (file)
@@ -29,12 +29,13 @@ package Support::Files;
 @additional_files = ();
 %exclude_deps = (
     'XML::Parser' => ['importxml.pl'],
+    'Net::LDAP' => ['Bugzilla/Auth/LDAP.pm'],
 );
 
 
-# XXX - this file should be rewritten to use File::Find or similar
+# XXX - this file should really be rewritten to use File::Find or similar
 $file = '*';
-@files = (glob($file), glob('Bugzilla/*.pm'));
+@files = (glob($file), glob('Bugzilla/*.pm'), glob('Bugzilla/*/*.pm'));
 
 sub have_pkg {
     my ($pkg) = @_;
diff --git a/template/en/default/account/auth/ldap-error.html.tmpl b/template/en/default/account/auth/ldap-error.html.tmpl
new file mode 100644 (file)
index 0000000..7615fb3
--- /dev/null
@@ -0,0 +1,48 @@
+[%# 1.0@bugzilla.org %]
+[%# 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): Bradley Baetz <bbaetz@acm.org>
+  #%]
+
+[%# INTERFACE:
+  # auth_err_tag: string. The tag for the error
+  # info: hash. Additional variables which may be used when printing details
+  #   of the error.
+  #%]
+
+[% SWITCH auth_err_tag %]
+  [% CASE "cannot_retreive_attr" %]
+    The specified LDAP attribute [% info.attr FILTER html %] was not found.
+
+  [% CASE "connect_failed" %]
+    An error occurred while trying to connect to the LDAP server.
+    [% IF info.errstr %]
+      The error from the server was: <tt>[% info.errstr FILTER html %]</tt>.
+    [% END %]
+
+  [% CASE "no_userid" %]
+    Bugzilla created a new account for you, but then could not find the
+    new userid.
+
+  [% CASE "server_not_defined" %]
+    The LDAP server for authentication has not been defined.
+    
+  [% CASE %]
+    Unhandled authentication error: [% auth_err_tag FILTER html %]
+
+[% END %]
similarity index 68%
rename from template/en/default/account/login.html.tmpl
rename to template/en/default/account/auth/login.html.tmpl
index 7d6e298d2b079b2cc978c0e41db570aef98cbad0..6dbd6531f4527475dfaf84221d125c067fb78a74 100644 (file)
 %]
 
 <p>
-  I need a legitimate 
-  [% Param('useLDAP') ? "LDAP username" : "email address" %]
-  and password to continue.
-</p>  
+  I need a legitimate login and password to continue.
+</p>
 
 <form action="[% target %]" method="POST">
   <table>
     <tr>
-      [% IF Param("useLDAP") %]
-        <td align="right">
-          <b>Username:</b>
-        </td>
-        <td>
-          <input size="10" name="LDAP_login">
-        </td>
-      </tr>
-      <tr>
-        <td align="right">
-          <b>Password:</b>
-        </td>
-        <td>
-          <input type="password" size="10" name="LDAP_password">
-        </td>
-      [% ELSE %]
-        <td align="right">
-          <b>E-mail address:</b>
-        </td>
-        <td>
-          <input size="35" name="Bugzilla_login">
-        </td>
-      </tr>
-      <tr>
-        <td align="right">
-          <b>Password:</b>
-        </td>
-        <td>
-          <input type="password" size="35" name="Bugzilla_password">
-        </td>
-      [% END %]
+      <td align="right">
+        <b>Login:</b>
+      </td>
+      <td>
+        <input size="35" name="Bugzilla_login">
+      </td>
+    </tr>
+    <tr>
+      <td align="right">
+        <b>Password:</b>
+      </td>
+      <td>
+        <input type="password" size="35" name="Bugzilla_password">
+      </td>
     [% IF Param('loginnetmask') < 32 %]
       <tr>
         <td align="right">
     </tr>
   </table>
   
-  [% PROCESS "global/hidden-fields.html.tmpl"   
-     exclude="^(Bugzilla|LDAP)_(login|password)$" %]
+  [% PROCESS "global/hidden-fields.html.tmpl"
+     exclude="^Bugzilla_(login|password|restrictlogin)$" %]
 
   <input type="submit" name="GoAheadAndLogIn" value="Login">
 </form>
 
 [%# Allow the user to create a new account, or request a token to change 
-  # their password (unless we are using LDAP, in which case the user must 
-  # use LDAP to change it).
+  # their password, assuming that our auth method allows that.
   #%]
   
-[% UNLESS Param("useLDAP") %]
+[% IF caneditaccount %]
   <hr>
 
   [% IF Param("createemailregexp") %]
index 85f89e6e8440cc96aad471ac1ecab6b362b6d933..cf8fcca9cf018645f65da09ff388c787b2059997 100644 (file)
@@ -36,7 +36,7 @@ group '[% group.name FILTER html %]' impacts [% group.count %] bugs for which th
 [% END %]
 <form method="post" >
 
-  [% PROCESS "global/hidden-fields.html.tmpl" exclude="^(Bugzilla|LDAP)_(login|password)$" %]
+  [% PROCESS "global/hidden-fields.html.tmpl" exclude="^Bugzilla_(login|password)$" %]
 
   <br>
      Click "Continue" to proceed with the change including the changes 
index 22ae57b75790432cc44c968aadc3cd756188b78b..72472a83b5c60482fdd4e6293c498bd461bf9437 100644 (file)
@@ -52,7 +52,7 @@
     
 <form method="post" action="process_bug.cgi">
 
-[% PROCESS "global/hidden-fields.html.tmpl" exclude="^(Bugzilla|LDAP)_(login|password)$" %]
+[% PROCESS "global/hidden-fields.html.tmpl" exclude="^Bugzilla_(login|password)$" %]
 
 <p>
   <input type="radio" name="confirm_add_duplicate" value="1"> 
index 85a5c1fffa196edb1b19dee849b703421121d8e6..e3698a64012232233b87b9064fe8e413c405cb69 100644 (file)
@@ -65,7 +65,7 @@ You have the following choices:
 <ul>
   <li>
     <form method="post" action="process_bug.cgi">
-      [% PROCESS "global/hidden-fields.html.tmpl" exclude="^(Bugzilla|LDAP)_(login|password)$" %]
+      [% PROCESS "global/hidden-fields.html.tmpl" exclude="^Bugzilla_(login|password)$" %]
       <input type="submit" value="Submit my changes anyway">
         This will cause all of the above changes to be overwritten
         [% ", except for the added comment(s)" IF comments.size > start_at %].
index a29cb1e1cd2d3b4dbabb90a940972d48fdaac6ca..b35bbb0642dc48550129e90d5b1b6d5c38beffdb 100644 (file)
     Attachment #[% attachid 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 == "authres_unhandled" %]
+    An authorization handler return value was not handled by the login code.
+
   [% ELSIF error == "bug_error" %]
     Trying to retrieve bug [% bug.bug_id %] returned the error
     [% bug.error FILTER html %]
index 92fa47a53d61d6a093ab9553cc2e4f89f37bdc22..037f7385c175c49898b6997c63abe2f709f71f7b 100644 (file)
 
 [% IF matchsuccess == 1 %]
 
-  [% PROCESS "global/hidden-fields.html.tmpl" exclude="^(Bugzilla|LDAP)_(login|password)$" %]
+  [% PROCESS "global/hidden-fields.html.tmpl" exclude="^Bugzilla_(login|password)$" %]
 
   <p>
     <input type="submit" value="Continue">
index 89f8cb7f30507e2a6f02449a970be1b632a4711b..11899fe70e49f65432169377d361263bc89949ed 100644 (file)
     Bug aliases cannot be longer than 20 characters.
     Please choose a shorter alias.
 
+  [% ELSIF error == "auth_cant_create_account" %]
+    [% title = "Can't create accounts" %]
+    This site is using an authentication scheme which does not permit
+    account creation. Please contact an administrator to get a new account
+    created.
+
   [% ELSIF error == "authorization_failure" %]
     [% title = "Authorization Failed" %]
     You are not allowed to [% action %].
   [% ELSIF error == "invalid_username_or_password" %]
     [% title = "Invalid Username Or Password" %]
     The username or password you entered is not valid.
-                    
-  [% ELSIF error == "ldap_cant_create_account" %]
-    [% title = "Can't create LDAP accounts" %]
-    This site is using LDAP for authentication.  Please contact 
-    an LDAP administrator to get a new account created.
      
   [% ELSIF error == "login_needed_for_password_change" %]
     [% title = "Login Name Required" %]