Skip to content

Commit

Permalink
Item11621: Improve redirecting for http/https sites
Browse files Browse the repository at this point in the history
 - Redirect all scripts in the {AuthScripts} list.  They will need https
   for authentication.
 - Monkeypatch the TemplateLogin login manager to redirect to https
   whenver forceAuthenticaiton is called.  The https session may already
   be authenticated.
  • Loading branch information
gac410 committed Mar 28, 2017
1 parent b2451e0 commit 5c4fda0
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 107 deletions.
17 changes: 14 additions & 3 deletions data/System/HttpsRedirectPlugin.txt
@@ -1,4 +1,4 @@
%META:TOPICINFO{author="ProjectContributor" date="1458439803" format="1.1" version="1.2"}%
%META:TOPICINFO{author="ProjectContributor" date="1490669264" format="1.1" version="1.2"}%
%META:TOPICPARENT{name="Plugins"}%
---+!! !HttpsRedirectPlugin
<!--
Expand All @@ -15,6 +15,16 @@ The HTTPS redirect plug-in is designed to help you run a web site where guest us
Simply activate the plug-in from =configure= to take advantage of its functionality.
Once enabled it will force authenticated users to use HTTPS by redirecting them to HTTPS URL if needed. Guests will be redirected to HTTPS only when accessing the login screen.

Redirect happens on the following conditions:
* Request for the login script.
* Request for any script listed in ={AuthScripts}=
* Any request that triggers the LoginManager::TemplateLogin::forceAuthentication() event.

Note tht as of this release, only the !TemplateLogin method is supported for
forceAuthentication based redirects.

Be sure to set the https:// URL in ={PermittedRedirectHostUrls}=.

---++ Installation Instructions

%$INSTALL_INSTRUCTIONS%
Expand All @@ -24,11 +34,12 @@ Once enabled it will force authenticated users to use HTTPS by redirecting them
Many thanks to the following sponsors for supporting this work:
* http://slion.net

| Plugin Author(s): | Foswiki:Main.StephaneLenclud |
| Copyright: | &copy; 2008-2009 St&eacute;phaneLenclud, 2011-2016 Foswiki Contributors |
| Plugin Author(s): | Foswiki:Main.StephaneLenclud Foswiki:Main.GeorgeClark |
| Copyright: | &copy; 2008-2009 St&eacute;phaneLenclud, 2011-2017 Foswiki Contributors |
| License: | [[http://www.gnu.org/licenses/gpl.html][GPL (Gnu General Public License)]] |
| Plugin Version: | %$VERSION% |
| Change History: | <!-- versions below in reverse order -->&nbsp; |
| 26 Mar 2017 | v1.3 Foswikitask:Item11621 - Redirect auth scripts and forceAuthentication events. |
| 19 mar 2016 | v1.2 Foswikitask:Item14030 - Use new version strings, remove non-utf8 characters from topic. Other minor cleanup. |
| 28 Mar 2011 | v1.1 Foswikitask:Item10551 - fixed a problem where foswiki scripts would produce no output if run from CLI |
| 28 Apr 2009 | v1.0 First actually working version for Foswiki |
Expand Down
206 changes: 102 additions & 104 deletions lib/Foswiki/Plugins/HttpsRedirectPlugin.pm
@@ -1,68 +1,29 @@
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details, published at
# http://www.gnu.org/copyleft/gpl.html
# See bottom of file for notices

=pod
---+ package Foswiki::Plugins::HttpsRedirectPlugin
To interact with Foswiki use ONLY the official API functions
in the Foswiki::Func module. Do not reference any functions or
variables elsewhere in Foswiki, as these are subject to change
without prior warning, and your plugin may suddenly stop
working.
For increased performance, all handlers except initPlugin are
disabled below. *To enable a handler* remove the leading DISABLE_ from
the function name. For efficiency and clarity, you should comment out or
delete the whole of handlers you don't use before you release your
plugin.
__NOTE:__ When developing a plugin it is important to remember that
Foswiki is tolerant of plugins that do not compile. In this case,
the failure will be silent but the plugin will not be available.
See [[%SYSTEMWEB%.Plugins#FAILEDPLUGINS]] for error messages.
__NOTE:__ Defining deprecated handlers will cause the handlers to be
listed in [[%SYSTEMWEB%.Plugins#FAILEDPLUGINS]]. See
[[%SYSTEMWEB%.Plugins#Handlig_deprecated_functions]]
for information on regarding deprecated handlers that are defined for
compatibility with older Foswiki versions.
__NOTE:__ When writing handlers, keep in mind that these may be invoked
on included topics. For example, if a plugin generates links to the current
topic, these need to be generated before the afterCommonTagsHandler is run,
as at that point in the rendering loop we have lost the information that we
the text had been included from another topic.
Intercept any http: requests that should be done over https
and redirect the requests to an https: URL
* Any request to login
* Requests to any script in the ={AuthScripts}= list
* Any request that triggers a forceAuthentication event.
=cut

package Foswiki::Plugins::HttpsRedirectPlugin;

# Always use strict to enforce variable scoping
use strict;
use warnings;

require Foswiki::Func; # The plugins API
require Foswiki::Plugins; # For the API version
use Foswiki::Func; # The plugins API
use Foswiki::Plugins; # For the API version

our $VERSION = '1.2';
our $RELEASE = '19 Mar 2016';
our $VERSION = '1.3';
our $RELEASE = '26 Mar 2017';

# Short description of this plugin
# One line description, is shown in the %SYSTEMWEB%.TextFormattingRules topic:
our $SHORTDESCRIPTION = 'Redirect authenticated users to HTTPS url.';

# You must set $NO_PREFS_IN_TOPIC to 0 if you want your plugin to use preferences
# stored in the plugin topic.
our $SHORTDESCRIPTION = 'Redirect authenticated users to HTTPS url.';
our $NO_PREFS_IN_TOPIC = 1;

# Name of this Plugin, only used in this module
Expand All @@ -72,12 +33,37 @@ our $debug = 0;

=pod
---++ earlyInitPlugin
Determines if TemplateLogin is in use. If it is, enable a hook that
monkey-patches TemplateLogin::forceAuthentication. This hook will force
a redirect to https if any page is accessed that would require authentication.
=cut

sub earlyInitPlugin {
return if !$Foswiki::cfg{Plugins}{HttpsRedirectPlugin}{Enabled};
return undef
unless (
$Foswiki::cfg{LoginManager} eq 'Foswiki::LoginManager::TemplateLogin' );
require Foswiki::Plugins::HttpsRedirectPlugin::CoreHooks;
Foswiki::Plugins::HttpsRedirectPlugin::CoreHooks::hook();
return undef;
}

=pod
---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
* =$topic= - the name of the topic in the current CGI query
* =$web= - the name of the web in the current CGI query
* =$user= - the login name of the user
* =$installWeb= - the name of the web the plugin is installed in
Redirects requests to https:
* Any request to login
* Requests to any ={AuthScripts}=
* Any authenticated requests.
=cut

sub initPlugin {
Expand All @@ -90,74 +76,86 @@ sub initPlugin {
return 0;
}

# Example code of how to get a preference value, register a variable handler
# and register a RESTHandler. (remove code you do not need)

# Set plugin preferences in LocalSite.cfg, like this:
# $Foswiki::cfg{Plugins}{HttpsRedirectPlugin}{ExampleSetting} = 1;
# Always provide a default in case the setting is not defined in
# LocalSite.cfg. See %SYSTEMWEB%.Plugins for help in adding your plugin
# configuration to the =configure= interface.
$debug = $Foswiki::cfg{Plugins}{HttpsRedirectPlugin}{Debug} || 0;

my $query = Foswiki::Func::getCgiQuery();

return 1 if $query->secure(); # Nothing needed if already secure
return 1
if Foswiki::Func::getContext()->{'command_line'}; #Not needed for CLI

if (Foswiki::Func::isGuest) {

#If we are guest, force HTTPS on login
if ( Foswiki::Func::getContext()
->{'login'} ) #If we are on the login script
{
my $actionRegex =
'\b' . Foswiki::Func::getRequestObject()->action() . '\b';

#Build up our URL
my $query = Foswiki::Func::getCgiQuery();
my $url = $query->url() . $query->path_info();
if ( $query->query_string() ) {
$url .= '?' . $query->query_string();
}

unless ( $url =~ /^https/ ) #Unless we are already using HTTPS
{

#Redirect to HTTPS URL and quite
$url =~ s/^http/https/;
Foswiki::Func::writeDebug("HTTPS redirect to: $url")
if ($debug);
Foswiki::Func::redirectCgiQuery( $query, $url );

#$Foswiki::Plugins::SESSION->finish();
#exit(0);
}
#If we are guest, force HTTPS on login, or any script that requires authentication.
if (
Foswiki::Func::getContext()
->{'login'} #If we are on the login script
|| $Foswiki::cfg{AuthScripts} =~ m/$actionRegex/
)
{
_redirectRequest($query);
}

}
else {
# Force redirect on all requests
_redirectRequest($query);

#If the user is no guest always force HTTPS
}

#Get our URL
my $query = Foswiki::Func::getCgiQuery();
my $url = $query->url() . $query->path_info();
if ( $query->query_string() ) {
$url .= '?' . $query->query_string();
}
# Plugin correctly initialized
return 1;
}

#Unless we are already using HTTPS, or running from CLI
unless ( $url =~ /^https/
or Foswiki::Func::getContext()->{'command_line'} )
{
=pod
---++ Private _redirectRequest($query)
#Redirect to HTTPS URL and quite
$url =~ s/^http/https/;
Foswiki::Func::writeDebug("HTTPS redirect to: $url") if ($debug);
Foswiki::Func::redirectCgiQuery( $query, $url );
Convert the URL to https: and redirect.
#$Foswiki::Plugins::SESSION->finish();
#exit(0);
}
}
=cut

sub _redirectRequest {
my $query = shift;

# Plugin correctly initialized
return 1;
#Get our URL
my $url = $query->url() . $query->path_info();
if ( $query->query_string() ) {
$url .= '?' . $query->query_string();
}

#Redirect to HTTPS URL
$url =~ s/^http/https/;
$url = Foswiki::decode_utf8($url) if $Foswiki::UNICODE;
Foswiki::Func::writeDebug("HTTPS redirect to: $url") if ($debug);
Foswiki::Func::redirectCgiQuery( $query, $url );
}

1;
__END__
Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Copyright (C) 2008-2017 Foswiki Contributors. Foswiki Contributors
are listed in the AUTHORS file in the root of this distribution.
NOTE: Please extend that file, not this notice.
Additional copyrights may apply to some or all of the code in this
file as follows:
Copyright (C) 2013 Modell Aachen GmbH, http://modell-aachen.de
Author: Jan Krueger
Copyright (C) 1999-2007 Peter Thoeny, peter@thoeny.org
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details, published at
http://www.gnu.org/copyleft/gpl.html
78 changes: 78 additions & 0 deletions lib/Foswiki/Plugins/HttpsRedirectPlugin/CoreHooks.pm
@@ -0,0 +1,78 @@
# See bottom of file for notices

package Foswiki::Plugins::HttpsRedirectPlugin::CoreHooks;

use strict;
use warnings;
use Assert;
use Foswiki::Plugins::HttpsRedirectPlugin;

my $hooked;
my $oldforceAuthentication;

sub hook {

# Prevent nasties on FastCGI/mod_perl
# If the hooks were applied twice, the $old... variables would end up
# containing the hooks themselves and we'd get ourselves stuck in an
# infinite loop...
return if defined $hooked;

# Overwrite the normal Foswiki functions for adding zones.
# This is, sadly, necessary if we want to have the ability to
# magically let through all zone code added directly by plugins
# (e.g. JQueryPlugin's prefs object).

$oldforceAuthentication =
\&Foswiki::LoginManager::TemplateLogin::forceAuthentication;
undef *Foswiki::LoginManager::TemplateLogin::forceAuthentication;
*Foswiki::LoginManager::TemplateLogin::forceAuthentication =
\&Foswiki::Plugins::HttpsRedirectPlugin::CoreHooks::forceAuthentication;

$hooked = 1;
return;
}

sub forceAuthentication {

my $query = Foswiki::Func::getCgiQuery();

# No need to redirect if already a secure request.
return $oldforceAuthentication->(@_) if $query->secure();

Foswiki::Plugins::HttpsRedirectPlugin::_redirectRequest($query);
}

1;
__DATA__
Foswiki - The Free and Open Source Wiki, http://foswiki.org/
Copyright (C) 2008-2017 Foswiki Contributors. Foswiki Contributors
are listed in the AUTHORS file in the root of this distribution.
NOTE: Please extend that file, not this notice.
Additional copyrights may apply to some or all of the code in this
file as follows:
Copyright (C) 2013 Modell Aachen GmbH, http://modell-aachen.de
Author: Jan Krueger
Copyright (C) 1999-2007 Peter Thoeny, peter@thoeny.org
and TWiki Contributors. All Rights Reserved. TWiki Contributors
are listed in the AUTHORS file in the root of this distribution.
Based on parts of Ward Cunninghams original Wiki and JosWiki.
Copyright (C) 1998 Markus Peter - SPiN GmbH (warpi@spin.de)
Some changes by Dave Harris (drh@bhresearch.co.uk) incorporated
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. For
more details read LICENSE in the root of this distribution.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
As per the GPL, removal of this notice is prohibited.
1 change: 1 addition & 0 deletions lib/Foswiki/Plugins/HttpsRedirectPlugin/MANIFEST
@@ -1,3 +1,4 @@
data/System/HttpsRedirectPlugin.txt 0644
lib/Foswiki/Plugins/HttpsRedirectPlugin.pm 0644
lib/Foswiki/Plugins/HttpsRedirectPlugin/Config.spec 0664
lib/Foswiki/Plugins/HttpsRedirectPlugin/CoreHooks.pm 0664

0 comments on commit 5c4fda0

Please sign in to comment.