From 81c9b27a7f29db1719b831a771d3a0df09595ba6 Mon Sep 17 00:00:00 2001 From: Molly Struve Date: Fri, 8 May 2020 09:16:49 -0500 Subject: [PATCH] Track IPs and API Tokens for Throttled Requets, Send Retry After Header (#7735) --- config/initializers/rack/attack.rb | 13 +++++++------ spec/initializers/rack/attack_spec.rb | 18 +++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/config/initializers/rack/attack.rb b/config/initializers/rack/attack.rb index 71bd91124..d8ce200ff 100644 --- a/config/initializers/rack/attack.rb +++ b/config/initializers/rack/attack.rb @@ -1,37 +1,38 @@ +Rack::Attack.throttled_response_retry_after_header = true + class Rack::Attack throttle("search_throttle", limit: 5, period: 1) do |request| if request.path.starts_with?("/search/") && request.env["HTTP_FASTLY_CLIENT_IP"].present? + Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) request.env["HTTP_FASTLY_CLIENT_IP"].to_s end end throttle("api_throttle", limit: 3, period: 1) do |request| if request.path.starts_with?("/api/") && request.get? && request.env["HTTP_FASTLY_CLIENT_IP"].present? + Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) request.env["HTTP_FASTLY_CLIENT_IP"].to_s end end throttle("api_write_throttle", limit: 1, period: 1) do |request| if request.path.starts_with?("/api/") && (request.put? || request.post? || request.delete?) + Honeycomb.add_field("user_api_key", request.env["HTTP_API_KEY"]) request.env["HTTP_API_KEY"] end end throttle("site_hits", limit: 100, period: 2) do |request| if request.env["HTTP_FASTLY_CLIENT_IP"].present? + Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) request.env["HTTP_FASTLY_CLIENT_IP"].to_s end end throttle("message_throttle", limit: 2, period: 1) do |request| if request.path.starts_with?("/messages") && request.post? && request.env["HTTP_FASTLY_CLIENT_IP"].present? + Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) request.env["HTTP_FASTLY_CLIENT_IP"].to_s end end - - track("request_tracking") do |request| - if request.env["HTTP_FASTLY_CLIENT_IP"].present? - Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) - end - end end diff --git a/spec/initializers/rack/attack_spec.rb b/spec/initializers/rack/attack_spec.rb index c781255df..8c61db2e5 100644 --- a/spec/initializers/rack/attack_spec.rb +++ b/spec/initializers/rack/attack_spec.rb @@ -6,6 +6,7 @@ describe Rack::Attack, type: :request, throttle: true do cache_db = ActiveSupport::Cache::RedisStore.new(redis_url) allow(Rails).to receive(:cache) { cache_db } cache_db.data.flushdb + allow(Honeycomb).to receive(:add_field) end describe "search_throttle" do @@ -21,6 +22,8 @@ describe Rack::Attack, type: :request, throttle: true do valid_responses.each { |r| expect(r).not_to eq(429) } expect(throttled_response).to eq(429) expect(new_ip_response).not_to eq(429) + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "5.6.7.8").exactly(11).times + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "1.1.1.1").exactly(2).times end end end @@ -37,6 +40,8 @@ describe Rack::Attack, type: :request, throttle: true do valid_responses.each { |r| expect(r).not_to eq(429) } expect(throttled_response).to eq(429) expect(new_ip_response).not_to eq(429) + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "5.6.7.8").exactly(7).times + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "1.1.1.1").exactly(2).times end end end @@ -58,6 +63,8 @@ describe Rack::Attack, type: :request, throttle: true do expect(valid_response).not_to eq(429) expect(throttled_response).to eq(429) expect(new_api_response).not_to eq(429) + expect(Honeycomb).to have_received(:add_field).with("user_api_key", api_secret.secret).exactly(2).times + expect(Honeycomb).to have_received(:add_field).with("user_api_key", another_api_secret.secret) end end end @@ -93,16 +100,9 @@ describe Rack::Attack, type: :request, throttle: true do valid_responses.each { |r| expect(r).not_to eq(429) } expect(throttled_response).to eq(429) expect(new_api_response).not_to eq(429) + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "5.6.7.8").exactly(6).times + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "1.1.1.1").exactly(2).times end end end - - describe "request_tracking" do - it "adds fastly client IP to Honeycomb span" do - allow(Honeycomb).to receive(:add_field) - get api_articles_path, headers: { "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" } - - expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "5.6.7.8") - end - end end