View | Details | Raw Unified | Return to bug 23068
Collapse All | Expand All

(-)a/C4/Context.pm (+20 lines)
Lines 1078-1083 sub temporary_directory { Link Here
1078
    return C4::Context->config('tmp_path') || File::Spec->tmpdir;
1078
    return C4::Context->config('tmp_path') || File::Spec->tmpdir;
1079
}
1079
}
1080
1080
1081
=head3 set_remote_address
1082
1083
set_remote_address should be called at the beginning of every script
1084
that is *not* running under plack in order to the REMOTE_ADDR environment
1085
variable to be set correctly.
1086
1087
=cut
1088
1089
sub set_remote_address {
1090
    if ( C4::Context->config('koha_trusted_proxies') ) {
1091
        require CGI;
1092
        my $cgi    = CGI->new;
1093
        my $header = $cgi->http('HTTP_X_FORWARDED_FOR');
1094
1095
        if ($header) {
1096
            require Koha::Middleware::RealIP;
1097
            $ENV{REMOTE_ADDR} = Koha::Middleware::RealIP::get_real_ip( $ENV{REMOTE_ADDR}, $header );
1098
        }
1099
    }
1100
}
1081
1101
1082
1;
1102
1;
1083
1103
(-)a/Koha/Middleware/RealIP.pm (+118 lines)
Line 0 Link Here
1
package Koha::Middleware::RealIP;
2
3
# Copyright 2019 ByWater Solutions and the Koha Dev Team
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use parent qw(Plack::Middleware);
23
24
use C4::Context;
25
26
use Net::Netmask;
27
use Plack::Util::Accessor qw( trusted_proxy );
28
29
=head3 prepare_app
30
31
This method generates and stores the list of trusted ip's as Netmask objects
32
at the time Plack starts up, obviating the need to regerenate them on each request.
33
34
=cut
35
36
sub prepare_app {
37
    my $self = shift;
38
    $self->trusted_proxy( get_trusted_proxies() );
39
}
40
41
=head3 call
42
43
This method is called for each request, and will ensure the correct remote address
44
is set in the REMOTE_ADDR environment variable.
45
46
=cut
47
48
sub call {
49
    my $self = shift;
50
    my $env  = shift;
51
52
    if ( $env->{HTTP_X_FORWARDED_FOR} ) {
53
        my @trusted_proxy = @{ $self->trusted_proxy } if $self->trusted_proxy;
54
55
        if (@trusted_proxy) {
56
            my $addr = get_real_ip( $env->{REMOTE_ADDR}, $env->{HTTP_X_FORWARDED_FOR}, \@trusted_proxy );
57
            $ENV{REMOTE_ADDR} = $addr;
58
            $env->{REMOTE_ADDR} = $addr;
59
        }
60
    }
61
62
    return $self->app->($env);
63
}
64
65
=head3 get_real_ip
66
67
my $address = get_real_ip( $remote_addres, $x_forwarded_for_header );
68
69
This method takes the current remote address and the x-forwarded-for header string,
70
determines the correct external ip address, and returns it.
71
72
=cut
73
74
sub get_real_ip {
75
    my ( $remote_addr, $header ) = @_;
76
77
    my @forwarded_for = $header =~ /([^,\s]+)/g;
78
    return $remote_addr unless @forwarded_for;
79
80
    my $trusted_proxies = get_trusted_proxies();
81
82
    my @unconfirmed = ( @forwarded_for, $remote_addr );
83
84
    my $real_ip;
85
    while (my $addr = pop @unconfirmed) {
86
        my $has_matched = 0;
87
        foreach my $netmask (@$trusted_proxies) {
88
            $has_matched++, last if $netmask->match($addr);
89
        }
90
        $real_ip = $addr, last unless $has_matched;
91
    }
92
93
    return $real_ip;
94
}
95
96
=head3 get_trusted_proxies
97
98
This method returns an arrayref of Net::Netmask objects for all
99
the trusted proxies given to Koha.
100
101
=cut
102
103
sub get_trusted_proxies {
104
    my $proxies_conf = C4::Context->config('koha_trusted_proxies');
105
    return unless $proxies_conf;
106
    my @trusted_proxies_ip = split( / /, $proxies_conf );
107
    my @trusted_proxies = map { Net::Netmask->new($_) } @trusted_proxies_ip;
108
    return \@trusted_proxies;
109
}
110
111
112
=head1 AUTHORS
113
114
Kyle M Hall <kyle@bywatersolutions.com>
115
116
=cut
117
118
1;
(-)a/debian/templates/koha-conf-site.xml.in (+5 lines)
Lines 345-350 __END_SRU_PUBLICSERVER__ Link Here
345
 <plack_max_requests>50</plack_max_requests>
345
 <plack_max_requests>50</plack_max_requests>
346
 <plack_workers>2</plack_workers>
346
 <plack_workers>2</plack_workers>
347
347
348
 <!-- Configuration for X-Forwarded-For -->
349
 <!--
350
 <koha_trusted_proxies>1.2.3.4 2.3.4.5 3.4.5.6</koha_trusted_proxies>
351
 -->
352
348
 <!-- Elasticsearch Configuration -->
353
 <!-- Elasticsearch Configuration -->
349
 <elasticsearch>
354
 <elasticsearch>
350
     <server>localhost:9200</server>
355
     <server>localhost:9200</server>
(-)a/debian/templates/plack.psgi (+2 lines)
Lines 68-75 my $apiv1 = builder { Link Here
68
builder {
68
builder {
69
    enable "ReverseProxy";
69
    enable "ReverseProxy";
70
    enable "Plack::Middleware::Static";
70
    enable "Plack::Middleware::Static";
71
71
    # + is required so Plack doesn't try to prefix Plack::Middleware::
72
    # + is required so Plack doesn't try to prefix Plack::Middleware::
72
    enable "+Koha::Middleware::SetEnv";
73
    enable "+Koha::Middleware::SetEnv";
74
    enable "+Koha::Middleware::RealIP";
73
75
74
    mount '/opac'          => $opac;
76
    mount '/opac'          => $opac;
75
    mount '/intranet'      => $intranet;
77
    mount '/intranet'      => $intranet;
(-)a/etc/koha-conf.xml (+5 lines)
Lines 161-166 __PAZPAR2_TOGGLE_XML_POST__ Link Here
161
 <plack_max_requests>50</plack_max_requests>
161
 <plack_max_requests>50</plack_max_requests>
162
 <plack_workers>2</plack_workers>
162
 <plack_workers>2</plack_workers>
163
163
164
 <!-- Configuration for X-Forwarded-For -->
165
 <!--
166
 <koha_trusted_proxies>1.2.3.4 2.3.4.5 3.4.5.6</koha_trusted_proxies>
167
 -->
168
164
 <!-- Elasticsearch Configuration -->
169
 <!-- Elasticsearch Configuration -->
165
 <elasticsearch>
170
 <elasticsearch>
166
     <server>localhost:9200</server>
171
     <server>localhost:9200</server>
(-)a/offline_circ/process.pl (+2 lines)
Lines 24-29 use CGI qw ( -utf8 ); Link Here
24
use C4::Auth;
24
use C4::Auth;
25
use C4::Circulation;
25
use C4::Circulation;
26
26
27
C4::Context->set_remote_address;
28
27
my $query = CGI->new;
29
my $query = CGI->new;
28
30
29
my ($template, $loggedinuser, $cookie) = get_template_and_user({
31
my ($template, $loggedinuser, $cookie) = get_template_and_user({
(-)a/svc/cataloguing/metasearch (+2 lines)
Lines 23-28 use C4::Service; Link Here
23
use Encode qw( encode_utf8 );
23
use Encode qw( encode_utf8 );
24
use Koha::MetaSearcher;
24
use Koha::MetaSearcher;
25
25
26
C4::Context->set_remote_address;
27
26
my ( $query, $response ) = C4::Service->init( catalogue => 1 );
28
my ( $query, $response ) = C4::Service->init( catalogue => 1 );
27
29
28
my ( $query_string, $servers ) = C4::Service->require_params( 'q', 'servers' );
30
my ( $query_string, $servers ) = C4::Service->require_params( 'q', 'servers' );
(-)a/tools/background-job-progress.pl (+2 lines)
Lines 29-34 use C4::BackgroundJob; Link Here
29
use CGI::Cookie; # need to check cookies before
29
use CGI::Cookie; # need to check cookies before
30
                 # having CGI parse the POST request
30
                 # having CGI parse the POST request
31
31
32
C4::Context->set_remote_address;
33
32
my $input = CGI->new;
34
my $input = CGI->new;
33
my %cookies = CGI::Cookie->fetch;
35
my %cookies = CGI::Cookie->fetch;
34
my ($auth_status, $sessionID) = check_cookie_auth($cookies{'CGISESSID'}->value, { tools => '*' });
36
my ($auth_status, $sessionID) = check_cookie_auth($cookies{'CGISESSID'}->value, { tools => '*' });
(-)a/tools/batchMod.pl (+2 lines)
Lines 41-46 use Koha::Items; Link Here
41
use Koha::ItemTypes;
41
use Koha::ItemTypes;
42
use Koha::Patrons;
42
use Koha::Patrons;
43
43
44
C4::Context->set_remote_address;
45
44
my $input = new CGI;
46
my $input = new CGI;
45
my $dbh = C4::Context->dbh;
47
my $dbh = C4::Context->dbh;
46
my $error        = $input->param('error');
48
my $error        = $input->param('error');
(-)a/tools/batch_record_modification.pl (+2 lines)
Lines 34-39 use Koha::Biblios; Link Here
34
use Koha::MetadataRecord::Authority;
34
use Koha::MetadataRecord::Authority;
35
use Koha::Virtualshelves;
35
use Koha::Virtualshelves;
36
36
37
C4::Context->set_remote_address;
38
37
my $input = new CGI;
39
my $input = new CGI;
38
our $dbh = C4::Context->dbh;
40
our $dbh = C4::Context->dbh;
39
my $op = $input->param('op') // q|form|;
41
my $op = $input->param('op') // q|form|;
(-)a/tools/manage-marc-import.pl (+2 lines)
Lines 37-42 use C4::BackgroundJob; Link Here
37
use C4::Labels::Batch;
37
use C4::Labels::Batch;
38
use Koha::BiblioFrameworks;
38
use Koha::BiblioFrameworks;
39
39
40
C4::Context->set_remote_address;
41
40
my $script_name = "/cgi-bin/koha/tools/manage-marc-import.pl";
42
my $script_name = "/cgi-bin/koha/tools/manage-marc-import.pl";
41
43
42
my $input = new CGI;
44
my $input = new CGI;
(-)a/tools/stage-marc-import.pl (+2 lines)
Lines 43-48 use C4::BackgroundJob; Link Here
43
use C4::MarcModificationTemplates;
43
use C4::MarcModificationTemplates;
44
use Koha::Plugins;
44
use Koha::Plugins;
45
45
46
C4::Context->set_remote_address;
47
46
my $input = new CGI;
48
my $input = new CGI;
47
49
48
my $fileID                     = $input->param('uploadedfileid');
50
my $fileID                     = $input->param('uploadedfileid');
(-)a/tools/upload-cover-image.pl (-1 / +2 lines)
Lines 49-54 use C4::Images; Link Here
49
use Koha::UploadedFiles;
49
use Koha::UploadedFiles;
50
use C4::Log;
50
use C4::Log;
51
51
52
C4::Context->set_remote_address;
53
52
my $debug = 1;
54
my $debug = 1;
53
55
54
my $input = new CGI;
56
my $input = new CGI;
55
- 

Return to bug 23068