From 1e6df24d6cbf44c865805712e6a15ecc601273aa Mon Sep 17 00:00:00 2001 From: Jesse Weaver Date: Fri, 13 May 2016 16:27:22 -0600 Subject: [PATCH] Bug 16520: Allow per-VirtualHost environment variables with Plack This allows OVERRIDE_SYSPREF_* and others to work properly. Test plan: 1) Add the following line to your plack.psgi (near the bottom, just above "mount ..."): enable "+Koha::Middleware::Plack"; 2) Load the OPAC advanced search page (under Plack). The title should read "Koha online catalog" (or whatever your LibraryName syspref contains). 3) Add the following to your Apache configuration: RequestHeader add X-Koha-SetEnv "OVERRIDE_SYSPREF_LibraryName Potato\, Potato" 4) Restart Apache. 5) Refresh. The title should now read "Potato, Potato online catalog". Signed-off-by: Tomas Cohen Arazi Signed-off-by: Kyle M Hall Signed-off-by: Brendan Gallagher --- Koha/Middleware/SetEnv.pm | 122 ++++++++++++++++++++++++++++++++++++ debian/templates/plack.psgi | 5 +- misc/plack/koha.psgi | 3 + 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 Koha/Middleware/SetEnv.pm diff --git a/Koha/Middleware/SetEnv.pm b/Koha/Middleware/SetEnv.pm new file mode 100644 index 0000000000..6cf334da7e --- /dev/null +++ b/Koha/Middleware/SetEnv.pm @@ -0,0 +1,122 @@ +package Koha::Middleware::SetEnv; + +# Copyright 2016 ByWater Solutions and the Koha Dev Team +# +# This file is part of Koha. +# +# Koha 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 3 of the License, or +# (at your option) any later version. +# +# Koha 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. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use parent qw(Plack::Middleware); + +use Plack::Request; + +=head1 NAME + +Koha::Middleware::SetEnv - Plack middleware to allow SetEnv through proxied headers + +=head1 SYNOPSIS + + builder { + ... + enable "Koha::Middleware::SetEnv"; + ... + } + + + SetEnv MEMCACHED_NAMESPACE "localhost:11211" + RequestHeader add X-Koha-SetEnv "MEMCACHED_NAMESPACE localhost:11211" + +=head1 DESCRIPTION + +This module adds a Plack middleware to convert C request headers to actual +environment variables. + +This is needed because Plackified Koha is currently connected to Apache via an HTTP proxy, and +Cs are not passed through. Koha uses SetEnvs to pass memcached settings and per-virtualhost +styles, search limits and syspref overrides. + +=head1 CAVEATS + +Due to how HTTP headers are combined, if you want to set a value with an embedded comma, it must be +escaped: + + SetEnv OVERRIDE_SYSPREF_LibraryName "The Best, Truly the Best, Koha Library" + RequestHeader add X-Koha-SetEnv "OVERRIDE_SYSPREF_LibraryName The Best\, Truly the Best\, Koha Library" + +=head1 NOTES + +This system was designed to use a single header for reasons of security. We have no way of knowing +whether a given request header was set by Apache or the original client, so we have to clear any +relevant headers before Apache starts adding them. This is only really practical for a single header +name. + +=cut + +my $allowed_setenvs = qr/^( + MEMCACHED_SERVERS | + MEMCACHED_NAMESPACE | + OVERRIDE_SYSPREF_(\w+) | + OVERRIDE_SYSPREF_NAMES | + OPAC_CSS_OVERRIDE | + OPAC_SEARCH_LIMIT | + OPAC_LIMIT_OVERRIDE +)\ /x; + +sub call { + my ( $self, $env ) = @_; + my $req = Plack::Request->new($env); + + # First, we split the result only on unescaped commas. + my @setenv_headers = split /(?header('X-Koha-SetEnv') || ''; + + # Then, these need to be mapped to key-value pairs, and commas removed. + my %setenvs = map { + # The syntax of this is a bit awkward because you can't use return inside a map (it + # returns from the enclosing function). + if (!/$allowed_setenvs/) { + warn "Forbidden/incorrect X-Koha-SetEnv: $_"; + + (); + } else { + my ( $key, $value ) = /(\w+) (.*)/; + $value =~ s/\\,/,/g; + + ( $key, $value ); + } + } @setenv_headers; + + # Finally, everything is shoved into the $env. + $env = { + %$env, + %setenvs + }; + + # We also add the MEMCACHED_ settings to the actual environment, to make sure any early + # initialization of Koha::Cache correctly sets up a memcached connection. + foreach my $special_var ( qw( MEMCACHED_SERVERS MEMCACHED_NAMESPACE ) ) { + $ENV{$special_var} = $setenvs{$special_var} if defined $setenvs{$special_var}; + } + + return $self->app->($env); +} + +=head1 AUTHOR + +Jesse Weaver, Ejweaver@bywatersolutions.comE + +=cut + +1; diff --git a/debian/templates/plack.psgi b/debian/templates/plack.psgi index baf0c5e85c..235e56d844 100644 --- a/debian/templates/plack.psgi +++ b/debian/templates/plack.psgi @@ -24,6 +24,7 @@ use Plack::Builder; use Plack::App::CGIBin; use Plack::App::Directory; use Plack::App::URLMap; +use Plack::Request; use Mojo::Server::PSGI; @@ -67,11 +68,13 @@ my $apiv1 = builder { }; builder { - enable "ReverseProxy"; enable "Plack::Middleware::Static"; + # + is required so Plack doesn't try to prefix Plack::Middleware:: + enable "+Koha::Middleware::SetEnv"; mount '/opac' => $opac; mount '/intranet' => $intranet; mount '/api/v1/app.pl' => $apiv1; + }; diff --git a/misc/plack/koha.psgi b/misc/plack/koha.psgi index 330335dcb6..a66b2ec360 100644 --- a/misc/plack/koha.psgi +++ b/misc/plack/koha.psgi @@ -95,6 +95,9 @@ builder { path => qr{^/(intranet|opac)-tmpl/}, root => "$ENV{INTRANETDIR}/koha-tmpl/"; + # + is required so Plack doesn't try to prefix Plack::Middleware:: + enable "+Koha::Middleware::SetEnv"; + mount "/cgi-bin/koha" => $app; mount "/" => $home; -- 2.39.5