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

(-)a/C4/Auth.pm (+2 lines)
Lines 57-62 BEGIN { Link Here
57
        else            { exit }
57
        else            { exit }
58
    }
58
    }
59
59
60
    C4::Context->set_remote_address;
61
60
    $debug     = $ENV{DEBUG};
62
    $debug     = $ENV{DEBUG};
61
    @ISA       = qw(Exporter);
63
    @ISA       = qw(Exporter);
62
    @EXPORT    = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions);
64
    @EXPORT    = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions);
(-)a/C4/Context.pm (+20 lines)
Lines 1099-1104 sub temporary_directory { Link Here
1099
    return C4::Context->config('tmp_path') || File::Spec->tmpdir;
1099
    return C4::Context->config('tmp_path') || File::Spec->tmpdir;
1100
}
1100
}
1101
1101
1102
=head3 set_remote_address
1103
1104
set_remote_address should be called at the beginning of every script
1105
that is *not* running under plack in order to the REMOTE_ADDR environment
1106
variable to be set correctly.
1107
1108
=cut
1109
1110
sub set_remote_address {
1111
    if ( C4::Context->config('koha_trusted_proxies') ) {
1112
        require CGI;
1113
        my $cgi    = CGI->new;
1114
        my $header = $cgi->http('HTTP_X_FORWARDED_FOR');
1115
1116
        if ($header) {
1117
            require Koha::Middleware::RealIP;
1118
            $ENV{REMOTE_ADDR} = Koha::Middleware::RealIP::get_real_ip( $ENV{REMOTE_ADDR}, $header );
1119
        }
1120
    }
1121
}
1102
1122
1103
1;
1123
1;
1104
1124
(-)a/C4/Installer/PerlDependencies.pm (+5 lines)
Lines 908-913 our $PERL_DEPS = { Link Here
908
        required => '1',
908
        required => '1',
909
        min_ver  => '0.37',
909
        min_ver  => '0.37',
910
    },
910
    },
911
    'Net::Netmask' => {
912
        'usage'    => 'Koha X-Forwarded-For support',
913
        'required' => '0',
914
        'min_ver'  => '1.9022',
915
    },
911
    'Net::Z3950::SimpleServer' => {
916
    'Net::Z3950::SimpleServer' => {
912
        'usage'    => 'Z39.50 responder',
917
        'usage'    => 'Z39.50 responder',
913
        'required' => '0',
918
        'required' => '0',
(-)a/Koha/Middleware/RealIP.pm (+120 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
=head1 METHODS
30
31
=head2 prepare_app
32
33
This method generates and stores the list of trusted ip's as Netmask objects
34
at the time Plack starts up, obviating the need to regerenate them on each request.
35
36
=cut
37
38
sub prepare_app {
39
    my $self = shift;
40
    $self->trusted_proxy( get_trusted_proxies() );
41
}
42
43
=head2 call
44
45
This method is called for each request, and will ensure the correct remote address
46
is set in the REMOTE_ADDR environment variable.
47
48
=cut
49
50
sub call {
51
    my $self = shift;
52
    my $env  = shift;
53
54
    if ( $env->{HTTP_X_FORWARDED_FOR} ) {
55
        my @trusted_proxy = $self->trusted_proxy ? @{ $self->trusted_proxy } : undef;
56
57
        if (@trusted_proxy) {
58
            my $addr = get_real_ip( $env->{REMOTE_ADDR}, $env->{HTTP_X_FORWARDED_FOR}, \@trusted_proxy );
59
            $ENV{REMOTE_ADDR} = $addr;
60
            $env->{REMOTE_ADDR} = $addr;
61
        }
62
    }
63
64
    return $self->app->($env);
65
}
66
67
=head2 get_real_ip
68
69
my $address = get_real_ip( $remote_addres, $x_forwarded_for_header );
70
71
This method takes the current remote address and the x-forwarded-for header string,
72
determines the correct external ip address, and returns it.
73
74
=cut
75
76
sub get_real_ip {
77
    my ( $remote_addr, $header ) = @_;
78
79
    my @forwarded_for = $header =~ /([^,\s]+)/g;
80
    return $remote_addr unless @forwarded_for;
81
82
    my $trusted_proxies = get_trusted_proxies();
83
84
    my @unconfirmed = ( @forwarded_for, $remote_addr );
85
86
    my $real_ip;
87
    while (my $addr = pop @unconfirmed) {
88
        my $has_matched = 0;
89
        foreach my $netmask (@$trusted_proxies) {
90
            $has_matched++, last if $netmask->match($addr);
91
        }
92
        $real_ip = $addr, last unless $has_matched;
93
    }
94
95
    return $real_ip;
96
}
97
98
=head2 get_trusted_proxies
99
100
This method returns an arrayref of Net::Netmask objects for all
101
the trusted proxies given to Koha.
102
103
=cut
104
105
sub get_trusted_proxies {
106
    my $proxies_conf = C4::Context->config('koha_trusted_proxies');
107
    return unless $proxies_conf;
108
    my @trusted_proxies_ip = split( / /, $proxies_conf );
109
    my @trusted_proxies = map { Net::Netmask->new($_) } @trusted_proxies_ip;
110
    return \@trusted_proxies;
111
}
112
113
114
=head1 AUTHORS
115
116
Kyle M Hall <kyle@bywatersolutions.com>
117
118
=cut
119
120
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> <!-- may be repeated to include all servers on your cluster -->
355
     <server>localhost:9200</server> <!-- may be repeated to include all servers on your cluster -->
(-)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 (-1 / +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>__ELASTICSEARCH_SERVERS__</server>
171
     <server>__ELASTICSEARCH_SERVERS__</server>
167
- 

Return to bug 23068