From 860785f00757a47e0e3ace973444ba5ad6d9c174 Mon Sep 17 00:00:00 2001
From: DJ Mountney <david@twkie.net>
Date: Mon, 27 Jun 2016 12:43:28 -0700
Subject: [PATCH] Make Rack::Request use our trusted proxies when filtering IP
 addresses

This allows us to control the trusted proxies while deployed in a private network. Normally Rack::Request will trust all private IPs as trusted proxies, which can caue problems if your users are connection on you network via private IP ranges.

Normally in a rails app this is handled by action_dispatch request, but rack_attack is specifically using the Rack::Request object instead.
---
 CHANGELOG                                 |  1 +
 config/initializers/trusted_proxies.rb    | 13 +++++++++++++
 spec/initializers/trusted_proxies_spec.rb | 12 ++++++++----
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 764df7cf55a..286e2815de7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,7 @@ v 8.10.0 (unreleased)
   - Wrap code blocks on Activies and Todos page. !4783 (winniehell)
   - Align flash messages with left side of page content !4959 (winniehell)
   - Display last commit of deleted branch in push events !4699 (winniehell)
+  - Apply the trusted_proxies config to the rack request object for use with rack_attack
   - Add Sidekiq queue duration to transaction metrics.
   - Let Workhorse serve format-patch diffs
   - Make images fit to the size of the viewport !4810
diff --git a/config/initializers/trusted_proxies.rb b/config/initializers/trusted_proxies.rb
index d256a16d42b..df4a933e22f 100644
--- a/config/initializers/trusted_proxies.rb
+++ b/config/initializers/trusted_proxies.rb
@@ -1,3 +1,16 @@
+# Override Rack::Request to make use of the same list of trusted_proxies
+# as the ActionDispatch::Request object. This is necessary for libraries
+# like rack_attack where they don't use ActionDispatch, and we want them
+# to block/throttle requests on private networks.
+# Rack Attack specific issue: https://github.com/kickstarter/rack-attack/issues/145 
+module Rack
+  class Request
+    def trusted_proxy?(ip)
+      Rails.application.config.action_dispatch.trusted_proxies.any? { |proxy| proxy === ip }
+    end
+  end
+end
+
 Rails.application.config.action_dispatch.trusted_proxies = (
   [ '127.0.0.1', '::1' ] + Array(Gitlab.config.gitlab.trusted_proxies)
 ).map { |proxy| IPAddr.new(proxy) }
diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb
index 4bb149f25ff..14c8df954a6 100644
--- a/spec/initializers/trusted_proxies_spec.rb
+++ b/spec/initializers/trusted_proxies_spec.rb
@@ -6,14 +6,16 @@ describe 'trusted_proxies', lib: true do
       set_trusted_proxies([])
     end
 
-    it 'preserves private IPs as remote_ip' do
+    it 'preserves private IPs' do
       request = stub_request('HTTP_X_FORWARDED_FOR' => '10.1.5.89')
       expect(request.remote_ip).to eq('10.1.5.89')
+      expect(request.ip).to eq('10.1.5.89')
     end
 
-    it 'filters out localhost from remote_ip' do
+    it 'filters out localhost' do
       request = stub_request('HTTP_X_FORWARDED_FOR' => '1.1.1.1, 10.1.5.89, 127.0.0.1')
       expect(request.remote_ip).to eq('10.1.5.89')
+      expect(request.ip).to eq('10.1.5.89')
     end
   end
 
@@ -22,9 +24,10 @@ describe 'trusted_proxies', lib: true do
       set_trusted_proxies([ "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" ])
     end
 
-    it 'filters out private and local IPs from remote_ip' do
+    it 'filters out private and local IPs' do
       request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 10.1.5.89, 127.0.0.1')
       expect(request.remote_ip).to eq('1.1.1.1')
+      expect(request.ip).to eq('1.1.1.1')
     end
   end
 
@@ -33,9 +36,10 @@ describe 'trusted_proxies', lib: true do
       set_trusted_proxies([ "60.98.25.47" ])
     end
 
-    it 'filters out proxy IP from remote_ip' do
+    it 'filters out proxy IP' do
       request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 60.98.25.47, 127.0.0.1')
       expect(request.remote_ip).to eq('1.1.1.1')
+      expect(request.ip).to eq('1.1.1.1')
     end
   end
 
-- 
GitLab