From c3484ab49ccb4eeddfc60be77c1064a717210af4 Mon Sep 17 00:00:00 2001 From: Nicholas van Oudtshoorn Date: Wed, 20 Mar 2024 17:06:01 +0800 Subject: [PATCH] Update Koha::Middleware::RealIP with an option to automatically detect all CloudFlare proxies --- Koha/Middleware/RealIP.pm | 45 ++++++++++++++++++- .../bug_36304-add_trustcloudlfare_syspref.pl | 18 ++++++++ installer/data/mysql/mandatory/sysprefs.sql | 1 + .../admin/preferences/web_services.pref | 6 +++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_36304-add_trustcloudlfare_syspref.pl diff --git a/Koha/Middleware/RealIP.pm b/Koha/Middleware/RealIP.pm index fc9f280ff6..647d7c9a4e 100644 --- a/Koha/Middleware/RealIP.pm +++ b/Koha/Middleware/RealIP.pm @@ -104,10 +104,51 @@ the trusted proxies given to Koha. =cut sub get_trusted_proxies { + my $trustcloudflare = C4::Context->preference('TrustCloudFlare'); my $proxies_conf = C4::Context->config('koha_trusted_proxies'); - return unless $proxies_conf; - my @trusted_proxies_ip = split( / /, $proxies_conf ); + return unless (($trustcloudflare eq '1') || $proxies_conf); + my @trusted_proxies = (); + + if ($trustcloudflare eq '1') { + # Get the list of CloudFlare proxies from their api, and add them to the trusted_proxies + my $ua = LWP::UserAgent->new(); + my $response = $ua->get('https://api.cloudflare.com/client/v4/ips'); + if ( $response->is_success ) { + my $json = decode_json( $response->decoded_content ); + if (exists( $json->{'result'})) { + if (exists( $json->{'result'}->{'ipv4_cidrs'} ) ) { + my $masks = $json->{'result'}->{'ipv4_cidrs'}; + for my $item( @{$masks} ) { + my $finalmask = Net::Netmask->new2($item); + if ($finalmask) { + push(@trusted_proxies, $finalmask); + } + else { + warn "$Net::Netmask::error"; + } + } + } + if (exists( $json->{'result'}->{'ipv6_cidrs'} ) ) { + my $masks = $json->{'result'}->{'ipv6_cidrs'}; + for my $item( @{$masks} ) { + my $finalmask = Net::Netmask->new2($item); + if ($finalmask) { + push(@trusted_proxies, $finalmask); + } + else { + warn "$Net::Netmask::error"; + } + } + } + } + } + else { + warn "Could not get CloudFlare ip list"; + } + } + + my @trusted_proxies_ip = split( / /, $proxies_conf ); foreach my $ip (@trusted_proxies_ip){ my $mask = Net::Netmask->new2($ip); if ($mask){ diff --git a/installer/data/mysql/atomicupdate/bug_36304-add_trustcloudlfare_syspref.pl b/installer/data/mysql/atomicupdate/bug_36304-add_trustcloudlfare_syspref.pl new file mode 100644 index 0000000000..79752e3e41 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_36304-add_trustcloudlfare_syspref.pl @@ -0,0 +1,18 @@ +use Modern::Perl; + +return { + bug_number => "36304", + description => "A single line description", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + # Do you stuffs here + $dbh->do( + q{ INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('TrustCloudFlare', '0', NULL, 'If enabled, cloudflare is considered a trusted proxy, and CF_CONNECTING_IP is used to determine the real IP.', 'YesNo') } + ); + + say $out "Added new system preference 'TrustCloudFlare'"; + + }, +}; diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index 4057841a34..bd7867cd85 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -780,6 +780,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('TransferWhenCancelAllWaitingHolds','0',NULL,'Transfer items when cancelling all waiting holds','YesNo'), ('TranslateNotices','0',NULL, 'Allow notices to be translated','YesNo'), ('TrapHoldsOnOrder','1',NULL,'If enabled, Koha will trap holds for on order items ( notforloan < 0 )','YesNo'), +('TrustCloudFlare', '0', NULL, 'If enabled, cloudflare is considered a trusted proxy, and CF_CONNECTING_IP is used to determine the real IP.', 'YesNo'), ('TwoFactorAuthentication', 'disabled', 'enforced|enabled|disabled', 'Enables two-factor authentication', 'Choice'), ('UNIMARCAuthorityField100','afrey50 ba0',NULL,'Define the contents of UNIMARC authority control field 100 position 08-35','Textarea'), ('UNIMARCAuthorsFacetsSeparator',', ',NULL,'UNIMARC authors facets separator','short'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/web_services.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/web_services.pref index 1fb5c99916..36719ff8b4 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/web_services.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/web_services.pref @@ -5,6 +5,12 @@ Web services: - pref: 'AccessControlAllowOrigin' class: Text - "." + - + - pref: 'TrustCloudFlare' + choices: + 1: "Enable" + 0: "Disable" + - "cloudflare as a trusted proxy." REST API: - - pref: RESTBasicAuth -- 2.34.1