Bug 23019: Add ImportBatchesProfile schema and set is_boolean to parse_items column
[koha.git] / Koha / Middleware / RealIP.pm
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     #X-Forwarded-For: <client>, <proxy1>, <proxy2>
85     my $real_ip = shift @forwarded_for;
86     my @unconfirmed = ( @forwarded_for, $remote_addr );
87
88     while (my $addr = pop @unconfirmed) {
89         my $has_matched = 0;
90         foreach my $netmask (@$trusted_proxies) {
91             $has_matched++, last if $netmask->match($addr);
92         }
93         $real_ip = $addr, last unless $has_matched;
94     }
95
96     return $real_ip;
97 }
98
99 =head2 get_trusted_proxies
100
101 This method returns an arrayref of Net::Netmask objects for all
102 the trusted proxies given to Koha.
103
104 =cut
105
106 sub get_trusted_proxies {
107     my $proxies_conf = C4::Context->config('koha_trusted_proxies');
108     return unless $proxies_conf;
109     my @trusted_proxies_ip = split( / /, $proxies_conf );
110     my @trusted_proxies = ();
111     foreach my $ip (@trusted_proxies_ip){
112         my $mask = Net::Netmask->new2($ip);
113         if ($mask){
114             push(@trusted_proxies,$mask);
115         }
116         else {
117             warn "$Net::Netmask::error";
118         }
119     }
120     return \@trusted_proxies;
121 }
122
123
124 =head1 AUTHORS
125
126 Kyle M Hall <kyle@bywatersolutions.com>
127
128 =cut
129
130 1;