Commit 8ecb3ad6 authored by mkanat%bugzilla.org's avatar mkanat%bugzilla.org

Bug 514913: Eliminate ssl="authenticated sessions"

Patch by Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat
parent 4671e0ff
...@@ -85,7 +85,6 @@ use constant SHUTDOWNHTML_EXIT_SILENTLY => [ ...@@ -85,7 +85,6 @@ use constant SHUTDOWNHTML_EXIT_SILENTLY => [
sub init_page { sub init_page {
(binmode STDOUT, ':utf8') if Bugzilla->params->{'utf8'}; (binmode STDOUT, ':utf8') if Bugzilla->params->{'utf8'};
if (${^TAINT}) { if (${^TAINT}) {
# Some environment variables are not taint safe # Some environment variables are not taint safe
delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
...@@ -94,6 +93,12 @@ sub init_page { ...@@ -94,6 +93,12 @@ sub init_page {
$ENV{'PATH'} = ''; $ENV{'PATH'} = '';
} }
# Because this function is run live from perl "use" commands of
# other scripts, we're skipping the rest of this function if we get here
# during a perl syntax check (perl -c, like we do during the
# 001compile.t test).
return if $^C;
# IIS prints out warnings to the webpage, so ignore them, or log them # IIS prints out warnings to the webpage, so ignore them, or log them
# to a file if the file exists. # to a file if the file exists.
if ($ENV{SERVER_SOFTWARE} && $ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i) { if ($ENV{SERVER_SOFTWARE} && $ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i) {
...@@ -108,18 +113,15 @@ sub init_page { ...@@ -108,18 +113,15 @@ sub init_page {
}; };
} }
do_ssl_redirect_if_required();
# If Bugzilla is shut down, do not allow anything to run, just display a # If Bugzilla is shut down, do not allow anything to run, just display a
# message to the user about the downtime and log out. Scripts listed in # message to the user about the downtime and log out. Scripts listed in
# SHUTDOWNHTML_EXEMPT are exempt from this message. # SHUTDOWNHTML_EXEMPT are exempt from this message.
# #
# Because this is code which is run live from perl "use" commands of other
# scripts, we're skipping this part if we get here during a perl syntax
# check -- runtests.pl compiles scripts without running them, so we
# need to make sure that this check doesn't apply to 'perl -c' calls.
#
# This code must go here. It cannot go anywhere in Bugzilla::CGI, because # This code must go here. It cannot go anywhere in Bugzilla::CGI, because
# it uses Template, and that causes various dependency loops. # it uses Template, and that causes various dependency loops.
if (!$^C && Bugzilla->params->{"shutdownhtml"} if (Bugzilla->params->{"shutdownhtml"}
&& lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1) && lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1)
{ {
# Allow non-cgi scripts to exit silently (without displaying any # Allow non-cgi scripts to exit silently (without displaying any
...@@ -318,14 +320,6 @@ sub login { ...@@ -318,14 +320,6 @@ sub login {
$class->set_user($authenticated_user); $class->set_user($authenticated_user);
} }
# We run after the login has completed since
# some of the checks in ssl_require_redirect
# look for Bugzilla->user->id to determine
# if redirection is required.
if (i_am_cgi() && ssl_require_redirect()) {
$class->cgi->require_https($class->params->{'sslbase'});
}
return $class->user; return $class->user;
} }
......
...@@ -65,17 +65,6 @@ sub fail_nodata { ...@@ -65,17 +65,6 @@ sub fail_nodata {
->faultstring('Login Required'); ->faultstring('Login Required');
} }
# If system is not configured to never require SSL connections
# we want to always redirect to SSL since passing usernames and
# passwords over an unprotected connection is a bad idea. If we
# get here then a login form will be provided to the user so we
# want this to be protected if possible.
if ($cgi->protocol ne 'https' && Bugzilla->params->{'sslbase'} ne ''
&& Bugzilla->params->{'ssl'} ne 'never')
{
$cgi->require_https(Bugzilla->params->{'sslbase'});
}
print $cgi->header(); print $cgi->header();
$template->process("account/auth/login.html.tmpl", $template->process("account/auth/login.html.tmpl",
{ 'target' => $cgi->url(-relative=>1) }) { 'target' => $cgi->url(-relative=>1) })
......
...@@ -89,11 +89,9 @@ sub persist_login { ...@@ -89,11 +89,9 @@ sub persist_login {
# Not a session cookie, so set an infinite expiry # Not a session cookie, so set an infinite expiry
$cookieargs{'-expires'} = 'Fri, 01-Jan-2038 00:00:00 GMT'; $cookieargs{'-expires'} = 'Fri, 01-Jan-2038 00:00:00 GMT';
} }
if (Bugzilla->params->{'ssl'} ne 'never' if (Bugzilla->params->{'ssl_redirect'}) {
&& Bugzilla->params->{'sslbase'} ne '') # Make these cookies only be sent to us by the browser during
{ # HTTPS sessions, if we're using SSL.
# Bugzilla->login will automatically redirect to https://,
# so it's safe to turn on the 'secure' bit.
$cookieargs{'-secure'} = 1; $cookieargs{'-secure'} = 1;
} }
......
...@@ -368,22 +368,23 @@ sub remove_cookie { ...@@ -368,22 +368,23 @@ sub remove_cookie {
'-value' => 'X'); '-value' => 'X');
} }
# Redirect to https if required sub redirect_to_https {
sub require_https { my $self = shift;
my ($self, $url) = @_; my $sslbase = Bugzilla->params->{'sslbase'};
# Do not create query string if data submitted via XMLRPC # If this is a POST, we don't want ?POSTDATA in the query string.
# since we want the data to be resubmitted over POST method. # We expect the client to re-POST, which may be a violation of
my $query = Bugzilla->usage_mode == USAGE_MODE_XMLRPC ? 0 : 1; # the HTTP spec, but the only time we're expecting it often is
# XMLRPC clients (SOAP::Lite at least) requires 301 to redirect properly # in the WebService, and WebService clients usually handle this
# and do not work with 302. # correctly.
my $status = Bugzilla->usage_mode == USAGE_MODE_XMLRPC ? 301 : 302; $self->delete('POSTDATA');
if (defined $url) { my $url = $sslbase . $self->url('-path_info' => 1, '-query' => 1,
$url .= $self->url('-path_info' => 1, '-query' => $query, '-relative' => 1); '-relative' => 1);
} else {
$url = $self->self_url; # XML-RPC clients (SOAP::Lite at least) require a 301 to redirect properly
$url =~ s/^http:/https:/i; # and do not work with 302. Our redirect really is permanent anyhow, so
} # it doesn't hurt to make it a 301.
print $self->redirect(-location => $url, -status => $status); print $self->redirect(-location => $url, -status => 301);
# When using XML-RPC with mod_perl, we need the headers sent immediately. # When using XML-RPC with mod_perl, we need the headers sent immediately.
$self->r->rflush if $ENV{MOD_PERL}; $self->r->rflush if $ENV{MOD_PERL};
exit; exit;
...@@ -459,13 +460,13 @@ effectively removing the cookie. ...@@ -459,13 +460,13 @@ effectively removing the cookie.
As its only argument, it takes the name of the cookie to expire. As its only argument, it takes the name of the cookie to expire.
=item C<require_https($baseurl)> =item C<redirect_to_https>
This routine redirects the client to a different location using the https protocol. This routine redirects the client to the https version of the page that
If the client is using XMLRPC, it will not retain the QUERY_STRING since XMLRPC uses POST. they're looking at, using the C<sslbase> parameter for the redirection.
It takes an optional argument which will be used as the base URL. If $baseurl Generally you should use L<Bugzilla::Util/do_ssl_redirect_if_required>
is not provided, the current URL is used. instead of calling this directly.
=item C<redirect_to_urlbase> =item C<redirect_to_urlbase>
......
...@@ -192,6 +192,11 @@ sub update_params { ...@@ -192,6 +192,11 @@ sub update_params {
$param->{'mail_delivery_method'} = $translation{$method}; $param->{'mail_delivery_method'} = $translation{$method};
} }
# Convert the old "ssl" parameter to the new "ssl_redirect" parameter.
# Both "authenticated sessions" and "always" turn on "ssl_redirect"
# when upgrading.
$param->{'ssl_redirect'} = 1 if $param->{'ssl'} ne 'never';
# --- DEFAULTS FOR NEW PARAMS --- # --- DEFAULTS FOR NEW PARAMS ---
_load_params unless %params; _load_params unless %params;
......
...@@ -68,10 +68,9 @@ sub get_param_list { ...@@ -68,10 +68,9 @@ sub get_param_list {
}, },
{ {
name => 'ssl', name => 'ssl_redirect',
type => 's', type => 'b',
choices => ['never', 'authenticated sessions', 'always'], default => 0
default => 'never'
}, },
......
...@@ -82,10 +82,7 @@ sub MessageToMTA { ...@@ -82,10 +82,7 @@ sub MessageToMTA {
# #
# We don't use correct_urlbase, because we want this URL to # We don't use correct_urlbase, because we want this URL to
# *always* be the same for this Bugzilla, in every email, # *always* be the same for this Bugzilla, in every email,
# and some emails we send when we're logged out (in which case # even if the admin changes the "ssl_redirect" parameter some day.
# some emails might get urlbase while the logged-in emails might
# get sslbase). Also, we want this to stay the same even if
# the admin changes the "ssl" parameter.
$email->header_set('X-Bugzilla-URL', Bugzilla->params->{'urlbase'}); $email->header_set('X-Bugzilla-URL', Bugzilla->params->{'urlbase'});
# We add this header to mark the mail as "auto-generated" and # We add this header to mark the mail as "auto-generated" and
......
...@@ -36,7 +36,7 @@ use base qw(Exporter); ...@@ -36,7 +36,7 @@ use base qw(Exporter);
html_quote url_quote xml_quote html_quote url_quote xml_quote
css_class_quote html_light_quote url_decode css_class_quote html_light_quote url_decode
i_am_cgi get_netaddr correct_urlbase i_am_cgi get_netaddr correct_urlbase
lsearch ssl_require_redirect use_attachbase lsearch do_ssl_redirect_if_required use_attachbase
diff_arrays diff_arrays
trim wrap_hard wrap_comment find_wrap_point trim wrap_hard wrap_comment find_wrap_point
format_time format_time_decimal validate_date format_time format_time_decimal validate_date
...@@ -264,60 +264,28 @@ sub i_am_cgi { ...@@ -264,60 +264,28 @@ sub i_am_cgi {
return exists $ENV{'SERVER_SOFTWARE'} ? 1 : 0; return exists $ENV{'SERVER_SOFTWARE'} ? 1 : 0;
} }
sub ssl_require_redirect { # This exists as a separate function from Bugzilla::CGI::redirect_to_https
my $method = shift; # because we don't want to create a CGI object during XML-RPC calls
# (doing so can mess up XML-RPC).
# If currently not in a protected SSL sub do_ssl_redirect_if_required {
# connection, determine if a redirection is return if !i_am_cgi();
# needed based on value in Bugzilla->params->{ssl}. return if !Bugzilla->params->{'ssl_redirect'};
# If we are already in a protected connection or
# sslbase is not set then no action is required.
if (uc($ENV{'HTTPS'}) ne 'ON'
&& $ENV{'SERVER_PORT'} != 443
&& Bugzilla->params->{'sslbase'} ne '')
{
# System is configured to never require SSL
# so no redirection is needed.
return 0
if Bugzilla->params->{'ssl'} eq 'never';
# System is configured to always require a SSL
# connection so we need to redirect.
return 1
if Bugzilla->params->{'ssl'} eq 'always';
# System is configured such that if we are inside
# of an authenticated session, then we need to make
# sure that all of the connections are over SSL. Non
# authenticated sessions SSL is not mandatory.
# For XMLRPC requests, if the method is User.login
# then we always want the connection to be over SSL
# if the system is configured for authenticated
# sessions since the user's username and password
# will be passed before the user is logged in.
return 1
if Bugzilla->params->{'ssl'} eq 'authenticated sessions'
&& (Bugzilla->user->id
|| (defined $method && $method eq 'User.login'));
}
return 0; my $sslbase = Bugzilla->params->{'sslbase'};
# If we're already running under SSL, never redirect.
return if uc($ENV{HTTPS} || '') eq 'ON';
# Never redirect if there isn't an sslbase.
return if !$sslbase;
Bugzilla->cgi->redirect_to_https();
} }
sub correct_urlbase { sub correct_urlbase {
my $ssl = Bugzilla->params->{'ssl'}; my $ssl = Bugzilla->params->{'ssl_redirect'};
return Bugzilla->params->{'urlbase'} if $ssl eq 'never'; my $urlbase = Bugzilla->params->{'urlbase'};
my $sslbase = Bugzilla->params->{'sslbase'}; my $sslbase = Bugzilla->params->{'sslbase'};
if ($sslbase) {
return $sslbase if $ssl eq 'always';
# Authenticated Sessions
return $sslbase if Bugzilla->user->id;
}
# Set to "authenticated sessions" but nobody's logged in, or return ($ssl && $sslbase) ? $sslbase : $urlbase;
# sslbase isn't set.
return Bugzilla->params->{'urlbase'};
} }
sub use_attachbase { sub use_attachbase {
...@@ -830,7 +798,7 @@ cookies) to only some addresses. ...@@ -830,7 +798,7 @@ cookies) to only some addresses.
=item C<correct_urlbase()> =item C<correct_urlbase()>
Returns either the C<sslbase> or C<urlbase> parameter, depending on the Returns either the C<sslbase> or C<urlbase> parameter, depending on the
current setting for the C<ssl> parameter. current setting for the C<ssl_redirect> parameter.
=item C<use_attachbase()> =item C<use_attachbase()>
......
...@@ -17,26 +17,12 @@ ...@@ -17,26 +17,12 @@
package Bugzilla::WebService::Server; package Bugzilla::WebService::Server;
use strict; use strict;
use Bugzilla::Util qw(ssl_require_redirect);
sub handle_login { sub handle_login {
my ($self, $class, $method, $full_method) = @_; my ($self, $class, $method, $full_method) = @_;
eval "require $class"; eval "require $class";
return if $class->login_exempt($method); return if $class->login_exempt($method);
Bugzilla->login(); Bugzilla->login();
# Even though we check for the need to redirect in
# Bugzilla->login() we check here again since Bugzilla->login()
# does not know what the current XMLRPC method is. Therefore
# ssl_require_redirect in Bugzilla->login() will have returned
# false if system was configured to redirect for authenticated
# sessions and the user was not yet logged in.
# So here we pass in the method name to ssl_require_redirect so
# it can then check for the extra case where the method equals
# User.login, which we would then need to redirect if not
# over a secure connection.
Bugzilla->cgi->require_https(Bugzilla->params->{'sslbase'})
if ssl_require_redirect($full_method);
} }
1; 1;
...@@ -100,13 +100,13 @@ ...@@ -100,13 +100,13 @@
<varlistentry> <varlistentry>
<term> <term>
ssl ssl_redirect
</term> </term>
<listitem> <listitem>
<para> <para>
Determines when Bugzilla will force HTTPS (SSL) connections, using If enabled, Bugzilla will force HTTPS (SSL) connections, by
the URL defined in <command>sslbase</command>. automatically redirecting any users who try to use a non-SSL
Options include "always", "never", and "authenticated sessions". connection.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -56,14 +56,6 @@ if ($cgi->param('logout')) { ...@@ -56,14 +56,6 @@ if ($cgi->param('logout')) {
# Main Body Execution # Main Body Execution
############################################################################### ###############################################################################
# Force to use HTTPS unless Bugzilla->params->{'ssl'} equals 'never'.
# This is required because the user may want to log in from here.
if ($cgi->protocol ne 'https' && Bugzilla->params->{'sslbase'} ne ''
&& Bugzilla->params->{'ssl'} ne 'never')
{
$cgi->require_https(Bugzilla->params->{'sslbase'});
}
# Return the appropriate HTTP response headers. # Return the appropriate HTTP response headers.
print $cgi->header(); print $cgi->header();
......
...@@ -28,12 +28,7 @@ ...@@ -28,12 +28,7 @@
[% login_target = "index.cgi" %] [% login_target = "index.cgi" %]
[% END %] [% END %]
[%# If SSL is in use, use 'sslbase', else use 'urlbase'. %] [% login_target = urlbase _ login_target %]
[% IF Param("sslbase") != "" && Param("ssl") != "never" %]
[% login_target = Param("sslbase") _ login_target %]
[% ELSE %]
[% login_target = Param("urlbase") _ login_target %]
[% END %]
<li id="mini_login_container[% qs_suffix %]"> <li id="mini_login_container[% qs_suffix %]">
<span class="separator">| </span> <span class="separator">| </span>
......
...@@ -42,8 +42,12 @@ ...@@ -42,8 +42,12 @@
sslbase => "The URL that is the common initial leading part of all HTTPS " _ sslbase => "The URL that is the common initial leading part of all HTTPS " _
"(SSL) $terms.Bugzilla URLs.", "(SSL) $terms.Bugzilla URLs.",
ssl => "Controls when $terms.Bugzilla should enforce sessions to use HTTPS by " _ ssl_redirect =>
"using <tt>sslbase</tt>.", "When this is enabled, $terms.Bugzilla will ensure that every page is"
_ " accessed over SSL, by redirecting any plain HTTP requests to HTTPS"
_ " using the <tt>sslbase</tt> parameter. Also, when this is enabled,"
_ " $terms.Bugzilla will send out links using <tt>sslbase</tt> in emails"
_ " instead of <tt>urlbase</tt>.",
cookiedomain => "The domain for $terms.Bugzilla cookies. Normally blank. " _ cookiedomain => "The domain for $terms.Bugzilla cookies. Normally blank. " _
"If your website is at 'www.foo.com', setting this to " _ "If your website is at 'www.foo.com', setting this to " _
......
...@@ -277,7 +277,8 @@ ...@@ -277,7 +277,8 @@
<legend>Note</legend> <legend>Note</legend>
<p> <p>
You need to You need to
<a href="[% IF Param('ssl') != 'never' %][% Param('sslbase') %][% END %]show_bug.cgi?id=[% bug.bug_id %]&amp;GoAheadAndLogIn=1">log in</a> <a href="show_bug.cgi?id=
[%- bug.bug_id %]&amp;GoAheadAndLogIn=1">log in</a>
before you can comment on or make changes to this [% terms.bug %]. before you can comment on or make changes to this [% terms.bug %].
</p> </p>
</fieldset> </fieldset>
......
...@@ -360,15 +360,7 @@ sub request_create_account { ...@@ -360,15 +360,7 @@ sub request_create_account {
$vars->{'email'} = $login_name . Bugzilla->params->{'emailsuffix'}; $vars->{'email'} = $login_name . Bugzilla->params->{'emailsuffix'};
$vars->{'expiration_ts'} = ctime(str2time($date) + MAX_TOKEN_AGE * 86400); $vars->{'expiration_ts'} = ctime(str2time($date) + MAX_TOKEN_AGE * 86400);
# When 'ssl' equals 'always' or 'authenticated sessions',
# we want this form to always be over SSL.
if ($cgi->protocol ne 'https' && Bugzilla->params->{'sslbase'} ne ''
&& Bugzilla->params->{'ssl'} ne 'never')
{
$cgi->require_https(Bugzilla->params->{'sslbase'});
}
print $cgi->header(); print $cgi->header();
$template->process('account/email/confirm-new.html.tmpl', $vars) $template->process('account/email/confirm-new.html.tmpl', $vars)
|| ThrowTemplateError($template->error()); || ThrowTemplateError($template->error());
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment