Skip to content

Commit

Permalink
Merge branch 'main' into instrument-fail2ban
Browse files Browse the repository at this point in the history
  • Loading branch information
santib authored Jun 27, 2024
2 parents d872acc + 427fdfa commit 83a1f41
Show file tree
Hide file tree
Showing 14 changed files with 169 additions and 125 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ end

### Cache store configuration

Throttle, allow2ban and fail2ban state is stored in a configurable cache (which defaults to `Rails.cache` if present), presumably backed by memcached or redis ([at least gem v3.0.0](https://rubygems.org/gems/redis)).
Throttle, track, allow2ban and fail2ban state is stored in a configurable cache (which defaults to `Rails.cache` if present), presumably backed by memcached or redis ([at least gem v3.0.0](https://rubygems.org/gems/redis)).

```ruby
# This is the default
Expand Down
2 changes: 1 addition & 1 deletion lib/rack/attack/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Configuration
end
end

attr_reader :safelists, :blocklists, :throttles, :anonymous_blocklists, :anonymous_safelists
attr_reader :safelists, :blocklists, :throttles, :tracks, :anonymous_blocklists, :anonymous_safelists
attr_accessor :blocklisted_responder, :throttled_responder, :throttled_response_retry_after_header

attr_reader :blocklisted_response, :throttled_response # Keeping these for backwards compatibility
Expand Down
15 changes: 7 additions & 8 deletions spec/acceptance/blocking_ip_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require_relative "../spec_helper"

describe "Blocking an IP" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist_ip("1.2.3.4")
end
Expand All @@ -26,21 +28,18 @@
end

it "notifies when the request is blocked" do
notified = false
notification_type = nil

ActiveSupport::Notifications.subscribe("blocklist.rack_attack") do |_name, _start, _finish, _id, payload|
notified = true
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/", {}, "REMOTE_ADDR" => "5.6.7.8"

refute notified
assert notifications.empty?

get "/", {}, "REMOTE_ADDR" => "1.2.3.4"

assert notified
assert_equal :blocklist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal :blocklist, notification[:request].env["rack.attack.match_type"]
end
end
34 changes: 16 additions & 18 deletions spec/acceptance/blocking_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require_relative "../spec_helper"

describe "#blocklist" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist do |request|
request.ip == "1.2.3.4"
Expand All @@ -22,27 +24,26 @@
end

it "notifies when the request is blocked" do
notification_matched = nil
notification_type = nil

ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload|
notification_matched = payload[:request].env["rack.attack.matched"]
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/", {}, "REMOTE_ADDR" => "5.6.7.8"

assert_nil notification_matched
assert_nil notification_type
assert notifications.empty?

get "/", {}, "REMOTE_ADDR" => "1.2.3.4"

assert_nil notification_matched
assert_equal :blocklist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_nil notification[:request].env["rack.attack.matched"]
assert_equal :blocklist, notification[:request].env["rack.attack.match_type"]
end
end

describe "#blocklist with name" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist("block 1.2.3.4") do |request|
request.ip == "1.2.3.4"
Expand All @@ -62,22 +63,19 @@
end

it "notifies when the request is blocked" do
notification_matched = nil
notification_type = nil

ActiveSupport::Notifications.subscribe("blocklist.rack_attack") do |_name, _start, _finish, _id, payload|
notification_matched = payload[:request].env["rack.attack.matched"]
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/", {}, "REMOTE_ADDR" => "5.6.7.8"

assert_nil notification_matched
assert_nil notification_type
assert notifications.empty?

get "/", {}, "REMOTE_ADDR" => "1.2.3.4"

assert_equal "block 1.2.3.4", notification_matched
assert_equal :blocklist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal "block 1.2.3.4", notification[:request].env["rack.attack.matched"]
assert_equal :blocklist, notification[:request].env["rack.attack.match_type"]
end
end
15 changes: 7 additions & 8 deletions spec/acceptance/blocking_subnet_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require_relative "../spec_helper"

describe "Blocking an IP subnet" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist_ip("1.2.3.4/31")
end
Expand All @@ -26,21 +28,18 @@
end

it "notifies when the request is blocked" do
notified = false
notification_type = nil

ActiveSupport::Notifications.subscribe("blocklist.rack_attack") do |_name, _start, _finish, _id, payload|
notified = true
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/", {}, "REMOTE_ADDR" => "5.6.7.8"

refute notified
assert notifications.empty?

get "/", {}, "REMOTE_ADDR" => "1.2.3.4"

assert notified
assert_equal :blocklist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal :blocklist, notification[:request].env["rack.attack.match_type"]
end
end
42 changes: 42 additions & 0 deletions spec/acceptance/fail2ban_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
require "timecop"

describe "fail2ban" do
let(:notifications) { [] }

before do
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new

Expand Down Expand Up @@ -75,4 +77,44 @@
assert_equal 200, last_response.status
end
end

it "notifies when the request is blocked" do
ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload|
notifications.push(payload)
end

get "/"

assert_equal 200, last_response.status
assert notifications.empty?

get "/private-place"

assert_equal 403, last_response.status
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal 'fail2ban pentesters', notification[:request].env["rack.attack.matched"]
assert_equal :blocklist, notification[:request].env["rack.attack.match_type"]

get "/"

assert_equal 200, last_response.status
assert notifications.empty?

get "/private-place"

assert_equal 403, last_response.status
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal 'fail2ban pentesters', notification[:request].env["rack.attack.matched"]
assert_equal :blocklist, notification[:request].env["rack.attack.match_type"]

get "/"

assert_equal 403, last_response.status
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal 'fail2ban pentesters', notification[:request].env["rack.attack.matched"]
assert_equal :blocklist, notification[:request].env["rack.attack.match_type"]
end
end
10 changes: 6 additions & 4 deletions spec/acceptance/safelisting_ip_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require_relative "../spec_helper"

describe "Safelist an IP" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist("admin") do |request|
request.path == "/admin"
Expand Down Expand Up @@ -42,15 +44,15 @@
end

it "notifies when the request is safe" do
notification_type = nil

ActiveSupport::Notifications.subscribe("safelist.rack_attack") do |_name, _start, _finish, _id, payload|
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/admin", {}, "REMOTE_ADDR" => "5.6.7.8"

assert_equal 200, last_response.status
assert_equal :safelist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal :safelist, notification[:request].env["rack.attack.match_type"]
end
end
28 changes: 14 additions & 14 deletions spec/acceptance/safelisting_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require_relative "../spec_helper"

describe "#safelist" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist do |request|
request.ip == "1.2.3.4"
Expand Down Expand Up @@ -38,23 +40,23 @@
end

it "notifies when the request is safe" do
notification_matched = nil
notification_type = nil

ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload|
notification_matched = payload[:request].env["rack.attack.matched"]
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/safe_space", {}, "REMOTE_ADDR" => "1.2.3.4"

assert_equal 200, last_response.status
assert_nil notification_matched
assert_equal :safelist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_nil notification[:request].env["rack.attack.matched"]
assert_equal :safelist, notification[:request].env["rack.attack.match_type"]
end
end

describe "#safelist with name" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist("block 1.2.3.4") do |request|
request.ip == "1.2.3.4"
Expand Down Expand Up @@ -90,18 +92,16 @@
end

it "notifies when the request is safe" do
notification_matched = nil
notification_type = nil

ActiveSupport::Notifications.subscribe("safelist.rack_attack") do |_name, _start, _finish, _id, payload|
notification_matched = payload[:request].env["rack.attack.matched"]
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/safe_space", {}, "REMOTE_ADDR" => "1.2.3.4"

assert_equal 200, last_response.status
assert_equal "safe path", notification_matched
assert_equal :safelist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal "safe path", notification[:request].env["rack.attack.matched"]
assert_equal :safelist, notification[:request].env["rack.attack.match_type"]
end
end
10 changes: 6 additions & 4 deletions spec/acceptance/safelisting_subnet_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require_relative "../spec_helper"

describe "Safelisting an IP subnet" do
let(:notifications) { [] }

before do
Rack::Attack.blocklist("admin") do |request|
request.path == "/admin"
Expand Down Expand Up @@ -36,15 +38,15 @@
end

it "notifies when the request is safe" do
notification_type = nil

ActiveSupport::Notifications.subscribe("safelist.rack_attack") do |_name, _start, _finish, _id, payload|
notification_type = payload[:request].env["rack.attack.match_type"]
notifications.push(payload)
end

get "/admin", {}, "REMOTE_ADDR" => "5.6.0.0"

assert_equal 200, last_response.status
assert_equal :safelist, notification_type
assert_equal 1, notifications.size
notification = notifications.pop
assert_equal :safelist, notification[:request].env["rack.attack.match_type"]
end
end
Loading

0 comments on commit 83a1f41

Please sign in to comment.