4 # Copyright 2020 Prosentient Systems
6 # This file is part of Koha.
8 # Koha is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # Koha is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with Koha; if not, see <http://www.gnu.org/licenses>.
23 use Test::More tests => 11;
27 use_ok("Koha::Middleware::RealIP");
29 my ($remote_address,$x_forwarded_for_header,$address);
31 subtest "No X-Forwarded-For header" => sub {
33 $remote_address = "1.1.1.1";
34 $x_forwarded_for_header = "";
35 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
36 is($address,'1.1.1.1',"There is no X-Forwarded-For header, so just use the remote address");
39 subtest "No configuration" => sub {
41 $remote_address = "2.2.2.2";
42 $x_forwarded_for_header = "1.1.1.1";
43 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
44 is($address,'2.2.2.2',"No trusted proxies available, so don't trust 2.2.2.2 as a proxy, instead use it as the remote address");
47 subtest "Bad configuration" => sub {
49 $remote_address = "1.1.1.1";
50 $x_forwarded_for_header = "2.2.2.2,3.3.3.3";
51 t::lib::Mocks::mock_config('koha_trusted_proxies', 'bad configuration');
53 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
54 } ["could not parse bad","could not parse configuration"],"Warn on misconfigured koha_trusted_proxies";
55 is($address,'1.1.1.1',"koha_trusted_proxies is misconfigured so ignore the X-Forwarded-For header");
57 $remote_address = "1.1.1.1";
58 $x_forwarded_for_header = "2.2.2.2";
59 t::lib::Mocks::mock_config('koha_trusted_proxies', 'bad 1.1.1.1');
61 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
62 } "could not parse bad","Warn on partially misconfigured koha_trusted_proxies";
63 is($address,'2.2.2.2',"koha_trusted_proxies contains an invalid value but still includes one correct value, which is relevant, so use X-Forwarded-For header");
66 subtest "Fail proxy isn't trusted" => sub {
68 $remote_address = "2.2.2.2";
69 $x_forwarded_for_header = "1.1.1.1";
70 t::lib::Mocks::mock_config('koha_trusted_proxies', '3.3.3.3');
71 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
72 is($address,'2.2.2.2',"The 2.2.2.2 proxy isn't in our trusted list, so use it as the remote address");
75 subtest "The most recent proxy is trusted but the proxy before it is not trusted" => sub {
77 $remote_address = "3.3.3.3";
78 $x_forwarded_for_header = "1.1.1.1, 2.2.2.2";
79 t::lib::Mocks::mock_config('koha_trusted_proxies', '3.3.3.3');
80 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
81 is($address,'2.2.2.2',"We trust 3.3.3.3, but we don't trust 2.2.2.2, so use 2.2.2.2 as the remote address");
84 subtest "Success one proxy" => sub {
86 $remote_address = "2.2.2.2";
87 $x_forwarded_for_header = "1.1.1.1";
88 t::lib::Mocks::mock_config('koha_trusted_proxies', '2.2.2.2');
89 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
90 is($address,'1.1.1.1',"Trust proxy (2.2.2.2), so use the client IP from the X-Forwarded-For header for the remote address");
93 subtest "Success multiple proxies" => sub {
95 $remote_address = "2.2.2.2";
96 $x_forwarded_for_header = "1.1.1.1,3.3.3.3";
97 t::lib::Mocks::mock_config('koha_trusted_proxies', '2.2.2.2 3.3.3.3');
98 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
99 is($address,'1.1.1.1',"Trust multiple proxies (2.2.2.2 and 3.3.3.3), so use the X-Forwaded-For <client> portion for the remote address");
102 subtest "Test alternative configuration styles" => sub {
104 $remote_address = "2.2.2.2";
105 $x_forwarded_for_header = "1.1.1.1";
106 t::lib::Mocks::mock_config('koha_trusted_proxies', '2.2.2.0/24');
107 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
108 is($address,'1.1.1.1',"Trust proxy (2.2.2.2) using CIDR notation, so use the X-Forwarded-For header for the remote address");
110 $remote_address = "2.2.2.2";
111 $x_forwarded_for_header = "1.1.1.1";
112 t::lib::Mocks::mock_config('koha_trusted_proxies', '2.2.2');
113 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
114 is($address,'1.1.1.1',"Trust proxy (2.2.2.2) using abbreviated notation, so use the X-Forwarded-For header for the remote address");
116 $remote_address = "2.2.2.2";
117 $x_forwarded_for_header = "1.1.1.1";
118 t::lib::Mocks::mock_config('koha_trusted_proxies', '2.2.2.0:255.255.255.0');
119 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
120 is($address,'1.1.1.1',"Trust proxy (2.2.2.2) using an IP address and netmask separated by a colon, so use the X-Forwarded-For header for the remote address");
123 subtest "Client IP is properly processed even if it is in koha_trusted_proxies" => sub {
124 $remote_address = "1.1.1.2";
125 $x_forwarded_for_header = "1.1.1.1";
126 t::lib::Mocks::mock_config('koha_trusted_proxies', '1.1.1.0/24');
127 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address, $x_forwarded_for_header );
128 is($address,'1.1.1.1',"The X-Forwarded-For value matches the koha_trusted_proxies, but there is no proxy specified");
132 subtest "IPv6 support" => sub {
133 my ($remote_address,$x_forwarded_for_header,$address);
134 require Net::Netmask;
135 if (Net::Netmask->VERSION < 1.9104){
136 $remote_address = "2001:db8:1234:5678:abcd:1234:abcd:1234";
137 $x_forwarded_for_header = "2.2.2.2";
138 t::lib::Mocks::mock_config( 'koha_trusted_proxies', '2001:db8:1234:5678::/64' );
141 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address,
142 $x_forwarded_for_header );
144 "could not parse 2001:db8:1234:5678::/64",
145 "Warn on IPv6 koha_trusted_proxies";
148 '2001:db8:1234:5678:abcd:1234:abcd:1234',
149 "Unable to parse IPv6 address for trusted proxy, so ignore the X-Forwarded-For header"
153 $remote_address = "2001:db8:1234:5678:abcd:1234:abcd:1234";
154 $x_forwarded_for_header = "2.2.2.2";
155 t::lib::Mocks::mock_config( 'koha_trusted_proxies', '2001:db8:1234:5678::/64' );
157 $address = Koha::Middleware::RealIP::get_real_ip( $remote_address,$x_forwarded_for_header );
158 is($address,'2.2.2.2',"Trust proxy (2001:db8:1234:5678:abcd:1234:abcd:1234) using IPv6 CIDR notation, so use the X-Forwarded-For header for the remote address");