aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbugreport%peshkin.net <>2004-08-11 20:53:43 +0000
committerbugreport%peshkin.net <>2004-08-11 20:53:43 +0000
commitd306c2edbbc171d5345b3378bd76ed5b69984316 (patch)
tree9810bba5d11c730fd4412a962dfd263655793470
parentBug 251669: add an option to show users in a drop down menu instead of a text... (diff)
downloadbugzilla-d306c2edbbc171d5345b3378bd76ed5b69984316.tar.gz
bugzilla-d306c2edbbc171d5345b3378bd76ed5b69984316.tar.bz2
bugzilla-d306c2edbbc171d5345b3378bd76ed5b69984316.zip
Bug 241903: Add Environment Variable Authentication for apache auth and SSO
patch by erik r=joel a=justdave
-rw-r--r--Bugzilla/Auth/Login/WWW.pm10
-rw-r--r--Bugzilla/Auth/Login/WWW/CGI.pm3
-rw-r--r--Bugzilla/Auth/Login/WWW/Env.pm182
-rw-r--r--Bugzilla/User.pm29
-rwxr-xr-xchecksetup.pl5
-rw-r--r--defparams.pl39
-rw-r--r--template/en/default/global/useful-links.html.tmpl8
-rw-r--r--template/en/default/index.html.tmpl4
-rw-r--r--template/en/default/sidebar.xul.tmpl2
9 files changed, 276 insertions, 6 deletions
diff --git a/Bugzilla/Auth/Login/WWW.pm b/Bugzilla/Auth/Login/WWW.pm
index def68df63..8b7724bef 100644
--- a/Bugzilla/Auth/Login/WWW.pm
+++ b/Bugzilla/Auth/Login/WWW.pm
@@ -36,6 +36,12 @@ sub login_class {
return $current_login_class;
}
+# can_logout determines if a user may log out
+sub can_logout {
+ return 1 if (login_class && login_class->can_logout);
+ return 0;
+}
+
sub login {
my ($class, $type) = @_;
@@ -64,6 +70,8 @@ sub login {
if ($userid) {
$user = new Bugzilla::User($userid);
+ $user->set_flags('can_logout' => $class->can_logout);
+
# Compat stuff
$::userid = $userid;
} else {
@@ -74,7 +82,7 @@ sub login {
sub logout {
my ($class, $user, $option) = @_;
- if ($class->login_class) {
+ if (can_logout) {
$class->login_class->logout($user, $option);
}
}
diff --git a/Bugzilla/Auth/Login/WWW/CGI.pm b/Bugzilla/Auth/Login/WWW/CGI.pm
index fb00cd018..3b90ec6ad 100644
--- a/Bugzilla/Auth/Login/WWW/CGI.pm
+++ b/Bugzilla/Auth/Login/WWW/CGI.pm
@@ -186,6 +186,9 @@ sub login {
type => $type, });
}
+# This auth style allows the user to log out.
+sub can_logout { return 1; }
+
# Logs user out, according to the option provided; this consists of
# removing entries from logincookies for the specified $user.
sub logout {
diff --git a/Bugzilla/Auth/Login/WWW/Env.pm b/Bugzilla/Auth/Login/WWW/Env.pm
new file mode 100644
index 000000000..abd176315
--- /dev/null
+++ b/Bugzilla/Auth/Login/WWW/Env.pm
@@ -0,0 +1,182 @@
+# -*- 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>
+
+package Bugzilla::Auth::Login::WWW::Env;
+
+use strict;
+
+use Bugzilla::Config;
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+sub login {
+ my ($class, $type) = @_;
+
+ # XXX This does not currently work correctly with Param('requirelogin').
+ # Bug 253636 will hopefully see that param's needs taken care of in a
+ # parent module, but for the time being, this module does not honor
+ # the param in the way that CGI.pm does.
+
+ my $matched_userid = '';
+ my $matched_extern_id = '';
+ my $disabledtext = '';
+
+ my $dbh = Bugzilla->dbh;
+ my $sth;
+
+ # Gather the environment variables
+ my $env_id = $ENV{Param("auth_env_id")};
+ my $env_email = $ENV{Param("auth_env_email")};
+ my $env_realname = $ENV{Param("auth_env_realname")};
+
+ # allow undefined values to work with trick_taint
+ for ($env_id, $env_email, $env_realname) { $_ ||= '' };
+ # make sure the email field contains only a valid email address
+ my $emailregexp = Param("emailregexp");
+ $env_email =~ /($emailregexp)/;
+ $env_email = $1;
+ # untaint the remaining values
+ trick_taint($env_id);
+ trick_taint($env_realname);
+
+ if ($env_id | $env_email) {
+ # Look in the DB for the extern_id
+ if ($env_id) {
+
+ # Not having the email address defined but having an ID isn't
+ # allowed.
+ return undef unless $env_email;
+
+ $sth = $dbh->prepare("SELECT userid, disabledtext " .
+ "FROM profiles WHERE extern_id=?");
+ $sth->execute($env_id);
+ my $fetched = $sth->fetch;
+ if ($fetched) {
+ $matched_userid = $fetched->[0];
+ $disabledtext = $fetched->[1];
+ }
+ }
+
+ unless ($matched_userid) {
+ # There was either no match for the external ID given, or one was
+ # not present.
+ #
+ # Check to see if the email address is in there and has no
+ # external id assigned. We test for both the login name (which we
+ # also sent), and the id, so that we have a way of telling that we
+ # got something instead of a bunch of NULLs
+ $sth = $dbh->prepare("SELECT extern_id, userid, disabledtext " .
+ "FROM profiles WHERE login_name=?");
+ $sth->execute($env_email);
+
+ $sth->execute();
+ my $fetched = $sth->fetch();
+ if ($fetched) {
+ ($matched_extern_id, $matched_userid, $disabledtext) = @{$fetched};
+ }
+ if ($matched_userid) {
+ if ($matched_extern_id) {
+ # someone with a different external ID has that address!
+ ThrowUserError("extern_id_conflict");
+ }
+ else
+ {
+ # someone with no external ID used that address, time to
+ # add the ID!
+ $sth = $dbh->prepare("UPDATE profiles " .
+ "SET extern_id=? WHERE userid=?");
+ $sth->execute($env_id, $matched_userid);
+ }
+ }
+ else
+ {
+ # Need to create a new user with that email address. Note
+ # that cryptpassword has been filled in with '*', since the
+ # user has no DB password.
+ $sth = $dbh->prepare("INSERT INTO profiles ( " .
+ "login_name, cryptpassword, " .
+ "realname, disabledtext " .
+ ") VALUES ( ?, ?, ?, '' )");
+ $sth->execute($env_email, '*', $env_realname);
+ $sth = $dbh->prepare("SELECT last_insert_id()");
+ $sth->execute();
+ $matched_userid = $sth->fetch->[0];
+ }
+ }
+ }
+
+ # now that we hopefully have a username, we need to see if the data
+ # has to be updated
+ if ($matched_userid) {
+ $sth = $dbh->prepare("SELECT login_name, realname " .
+ "FROM profiles " .
+ "WHERE userid=?");
+ $sth->execute($matched_userid);
+ my $fetched = $sth->fetch;
+ my $username = $fetched->[0];
+ my $this_realname = $fetched->[1];
+ if ( ($username ne $env_email) ||
+ ($this_realname ne $env_realname) ) {
+
+ $sth = $dbh->prepare("UPDATE profiles " .
+ "SET login_name=?, " .
+ "realname=? " .
+ "WHERE userid=?");
+ $sth->execute($env_email,
+ ($env_realname || $this_realname),
+ $matched_userid);
+ $sth->execute;
+ }
+ }
+
+ # Now we throw an error if the user has been disabled
+ if ($disabledtext) {
+ ThrowUserError("account_disabled",
+ {'disabled_reason' => $disabledtext});
+ }
+
+ return $matched_userid;
+
+}
+
+# This auth style does not allow the user to log out.
+sub can_logout { return 0; }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Auth::Env - Environment Variable Authentication
+
+=head1 DESCRIPTION
+
+Many external user authentication systems supply login information to CGI
+programs via environment variables. This module checks to see if those
+variables are populated and, if so, assumes authentication was successful and
+returns the user's ID, having automatically created a new profile if
+necessary.
+
+=head1 SEE ALSO
+
+L<Bugzilla::Auth>
+
diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm
index a40450076..38453841b 100644
--- a/Bugzilla/User.pm
+++ b/Bugzilla/User.pm
@@ -79,6 +79,7 @@ sub _create {
'name' => '',
'login' => '',
'showmybugslink' => 0,
+ 'flags' => {},
};
bless ($self, $class);
return $self unless $cond && $val;
@@ -139,6 +140,19 @@ sub email { $_[0]->{login}; }
sub name { $_[0]->{name}; }
sub showmybugslink { $_[0]->{showmybugslink}; }
+sub set_flags {
+ my $self = shift;
+ while (my $key = shift) {
+ $self->{'flags'}->{$key} = shift;
+ }
+}
+
+sub get_flag {
+ my $self = shift;
+ my $key = shift;
+ return $self->{'flags'}->{$key};
+}
+
# Generate a string to identify the user by name + email if the user
# has a name or by email only if she doesn't.
sub identity {
@@ -1109,6 +1123,21 @@ all MySQL supported, this will go away.
Returns C<1> if the user can bless at least one group. Otherwise returns C<0>.
+=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.
+
=back
=head1 SEE ALSO
diff --git a/checksetup.pl b/checksetup.pl
index c42c23535..703358cec 100755
--- a/checksetup.pl
+++ b/checksetup.pl
@@ -1810,6 +1810,7 @@ $table{profiles} =
mybugslink tinyint not null default 1,
emailflags mediumtext,
refreshed_when datetime not null,
+ extern_id varchar(64) default null,
unique(login_name)';
@@ -3999,6 +4000,10 @@ if (GetFieldDef("group_group_map", "isbless")) {
ADD UNIQUE (member_id, grantor_id, grant_type)");
}
+# Allow profiles to optionally be linked to a unique identifier in an outside
+# login data source
+AddField("profiles", "extern_id", "varchar(64)");
+
# If you had to change the --TABLE-- definition in any way, then add your
# differential change code *** A B O V E *** this comment.
#
diff --git a/defparams.pl b/defparams.pl
index 86cc7f2d5..8260be978 100644
--- a/defparams.pl
+++ b/defparams.pl
@@ -435,6 +435,36 @@ sub find_languages {
default => '',
},
+ {
+ name => 'auth_env_id',
+ desc => 'Environment variable used by external authentication system ' .
+ 'to store a unique identifier for each user. Leave it blank ' .
+ 'if there isn\'t one or if this method of authentication ' .
+ 'is not being used.',
+ type => 't',
+ default => '',
+ },
+
+ {
+ name => 'auth_env_email',
+ desc => 'Environment variable used by external authentication system ' .
+ 'to store each user\'s email address. This is a required ' .
+ 'field for environmental authentication. Leave it blank ' .
+ 'if you are not going to use this feature.',
+ type => 't',
+ default => '',
+ },
+
+ {
+ name => 'auth_env_realname',
+ desc => 'Environment variable used by external authentication system ' .
+ 'to store the user\'s real name. Leave it blank if there ' .
+ 'isn\'t one or if this method of authentication is not being ' .
+ 'used.',
+ type => 't',
+ default => '',
+ },
+
# XXX in the future:
#
# user_verify_class and user_info_class should have choices gathered from
@@ -455,9 +485,14 @@ sub find_languages {
<dd>
Asks for username and password via CGI form interface.
</dd>
- </dl>',
+ <dt>Env</dt>
+ <dd>
+ Info for a pre-authenticated user is passed in system
+ environment variables.
+ </dd>
+ </dl>',
type => 's',
- choices => [ 'CGI' ],
+ choices => [ 'CGI', 'Env', 'Env,CGI' ],
default => 'CGI',
checker => \&check_multi
},
diff --git a/template/en/default/global/useful-links.html.tmpl b/template/en/default/global/useful-links.html.tmpl
index c04b60dd6..7e568372c 100644
--- a/template/en/default/global/useful-links.html.tmpl
+++ b/template/en/default/global/useful-links.html.tmpl
@@ -52,8 +52,12 @@
[% IF user.login %]
[% ' | <a href="sanitycheck.cgi">Sanity&nbsp;check</a>'
IF user.groups.tweakparams %]
- | <a href="relogin.cgi">Log&nbsp;out</a>&nbsp;
- [% user.login FILTER html %]
+ [% IF user.get_flag('can_logout') %]
+ | <a href="relogin.cgi">Log&nbsp;out</a>&nbsp;
+ [% ELSE %]
+ | Logged&nbsp;in&nbsp;as&nbsp;
+ [% END %]
+ [% user.login FILTER html %]
[% ELSE %]
[% IF Param('createemailregexp') %]
| <a href="createaccount.cgi">New&nbsp;Account</a>
diff --git a/template/en/default/index.html.tmpl b/template/en/default/index.html.tmpl
index 5422061fd..d31a51d89 100644
--- a/template/en/default/index.html.tmpl
+++ b/template/en/default/index.html.tmpl
@@ -66,7 +66,9 @@ function addSidebar() {
</p><p>
[% IF user.id %]
<a href="userprefs.cgi">Change password or user preferences</a><br>
- <a href="relogin.cgi">Logout [% user.login FILTER html %]</a><br>
+ [% IF user.get_flag('can_logout') %]
+ <a href="relogin.cgi">Logout [% user.login FILTER html %]</a><br>
+ [% END %]
[% ELSE %]
<a href="query.cgi?GoAheadAndLogIn=1">Log in to an existing account</a><br>
[% IF Param('createemailregexp') %]
diff --git a/template/en/default/sidebar.xul.tmpl b/template/en/default/sidebar.xul.tmpl
index 60ae33dbd..802fd9f23 100644
--- a/template/en/default/sidebar.xul.tmpl
+++ b/template/en/default/sidebar.xul.tmpl
@@ -95,7 +95,9 @@ 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') %]
<text class="text-link" onclick="load_relative_url('relogin.cgi')" value="logout [% user.login FILTER html %]"/>
+ [%- END %]
<separator class="thin"/>
[%- IF user.showmybugslink %]
[% filtered_username = user.login FILTER url_quote %]