Skip to content

Commit 95fb9cd

Browse files
authored
Feat: disable rack attack config (#101)
* feat: update rack attack config * test: update rack attack test
1 parent c668d33 commit 95fb9cd

File tree

3 files changed

+94
-24
lines changed

3 files changed

+94
-24
lines changed

config/initializers/rack_attack.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,14 @@
66

77
# Enabled by default in production
88
# Can be deactivated with 'ENABLE_RACK_ATTACK=0'
9-
DecidimApp::RackAttack.apply_configuration if DecidimApp::RackAttack.rack_enabled?
9+
10+
DecidimApp::RackAttack.deactivate_decidim_throttling!
11+
12+
if DecidimApp::RackAttack.rack_enabled?
13+
DecidimApp::RackAttack.enable_rack_attack!
14+
DecidimApp::RackAttack.apply_configuration
15+
else
16+
DecidimApp::RackAttack.disable_rack_attack!
17+
end
18+
19+
DecidimApp::RackAttack.info!

lib/decidim_app/rack_attack.rb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,39 @@ module DecidimApp
44
module RackAttack
55
def self.rack_enabled?
66
setting = Rails.application.secrets.dig(:decidim, :rack_attack, :enabled)
7-
return setting == "1" if setting.present?
7+
return setting.to_s == "1" if setting.present?
88

99
Rails.env.production?
1010
end
1111

12-
def self.apply_configuration
12+
def self.info!
13+
Rails.logger.info("Rack::Attack is enabled: #{Rack::Attack.enabled}")
14+
Rails.logger.info("Rack::Attack Fail2ban is enabled: #{DecidimApp::RackAttack::Fail2ban.enabled?}")
15+
Rack::Attack.throttles.keys.each do |throttle|
16+
Rails.logger.info("Rack::Attack throttling registered: #{throttle}")
17+
end
18+
end
19+
20+
def self.enable_rack_attack!
21+
Rails.logger.info("Rack::Attack is now enabled")
1322
Rack::Attack.enabled = true
23+
end
1424

25+
def self.disable_rack_attack!
26+
Rails.logger.info("Rack::Attack is now disabled")
27+
Rack::Attack.enabled = false
28+
end
29+
30+
def self.deactivate_decidim_throttling!
1531
# Remove the original throttle from decidim-core
16-
# see https://github.com/decidim/decidim/blob/release/0.26-stable/decidim-core/config/initializers/rack_attack.rb#L19
32+
# see https://github.com/decidim/decidim/blob/release/0.27-stable/decidim-core/config/initializers/rack_attack.rb#L19
1733
DecidimApp::RackAttack::Throttling.deactivate_decidim_throttling! do
1834
Rails.logger.info("Deactivating 'requests by ip' from Decidim Core")
1935
Rack::Attack.throttles.delete("requests by ip")
2036
end
37+
end
2138

39+
def self.apply_configuration
2240
Rack::Attack.throttled_response_retry_after_header = true
2341

2442
Rack::Attack.throttled_responder = lambda do |request|

spec/lib/decidim_app/rack_attack_spec.rb

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,40 +62,76 @@
6262
end
6363
end
6464

65-
describe "#apply_configuration" do
65+
describe "#enable_rack_attack!" do
66+
before do
67+
described_class.enable_rack_attack!
68+
end
69+
70+
it "enables Rack::Attack" do
71+
expect(Rack::Attack.enabled).to be_truthy
72+
end
73+
end
74+
75+
describe "#disable_rack_attack!" do
6676
before do
67-
described_class.apply_configuration
68-
Rack::Attack.reset!
77+
described_class.disable_rack_attack!
6978
end
7079

80+
it "enables Rack::Attack" do
81+
expect(Rack::Attack.enabled).to be_falsey
82+
end
83+
end
84+
85+
describe "#deactivate_decidim_throttling!" do
86+
before do
87+
# Decidim throttling is deactivated by default in rails env test
88+
# https://github.com/decidim/decidim/blob/release/0.27-stable/decidim-core/config/initializers/rack_attack.rb#L19
89+
# so we add some keys to test the method
90+
Rack::Attack.throttle("limit confirmations attempts per code", limit: 5, period: 60.seconds) # added by module friendly_signup in decidim_app
91+
Rack::Attack.throttle("requests by ip", limit: 5, period: 60.seconds)
92+
described_class.deactivate_decidim_throttling!
93+
end
94+
95+
after do
96+
# delete the added keys
97+
Rack::Attack.throttles.delete("requests by ip")
98+
Rack::Attack.throttles.delete("limit confirmations attempts per code")
99+
end
100+
101+
it "deactivates Decidim throttling" do
102+
expect(Rack::Attack.throttles.keys.join).to include("limit confirmations attempts per code")
103+
expect(Rack::Attack.throttles.keys.join).not_to include("requests by ip")
104+
end
105+
end
106+
107+
describe "#apply_configuration" do
71108
describe "Throttling" do
72109
let(:headers) { { "REMOTE_ADDR" => "1.2.3.4", "decidim.current_organization" => organization } }
110+
let(:rack_max_requests) { 15 }
73111

74-
it "successful for 100 requests, then blocks the user" do
75-
100.times do
76-
get decidim.root_path, params: {}, headers: headers
77-
expect(response).to have_http_status(:ok)
78-
end
79-
80-
get decidim.root_path, params: {}, headers: headers
81-
expect(response).to have_http_status(:too_many_requests)
82-
expect(response.body).to include("Your connection has been slowed because server received too many requests.")
112+
before do
113+
allow(Rails.application.secrets).to receive(:dig).with(any_args).and_call_original
114+
allow(Rails.application.secrets).to receive(:dig).with(:decidim, :rack_attack, :throttle, :max_requests).and_return(rack_max_requests)
115+
described_class.apply_configuration
116+
Rack::Attack.reset!
117+
described_class.enable_rack_attack!
118+
end
83119

84-
travel_to(1.minute.from_now) do
85-
get decidim.root_path, params: {}, headers: headers
86-
expect(response).to have_http_status(:ok)
87-
end
120+
it "defines default period and max_requests" do
121+
expect(DecidimApp::RackAttack::Throttling.max_requests).to eq(rack_max_requests)
122+
expect(DecidimApp::RackAttack::Throttling.period).to eq(60)
88123
end
89124

90-
it "successful for 99 requests" do
91-
99.times do
125+
it "successful for 15 requests, then blocks the user" do
126+
rack_max_requests.times do
92127
get decidim.root_path, params: {}, headers: headers
93128
expect(response).to have_http_status(:ok)
129+
expect(response.body).not_to include("Your connection has been slowed because server received too many requests.")
94130
end
95131

96132
get decidim.root_path, params: {}, headers: headers
97-
expect(response.body).not_to include("Your connection has been slowed because server received too many requests.")
98-
expect(response).not_to have_http_status(:too_many_requests)
133+
expect(response).to have_http_status(:too_many_requests)
134+
expect(response.body).to include("Your connection has been slowed because server received too many requests.")
99135

100136
travel_to(1.minute.from_now) do
101137
get decidim.root_path, params: {}, headers: headers
@@ -107,6 +143,12 @@
107143
describe "Fail2Ban" do
108144
let(:headers) { { "REMOTE_ADDR" => "1.2.3.4", "decidim.current_organization" => organization } }
109145

146+
before do
147+
described_class.apply_configuration
148+
Rack::Attack.reset!
149+
described_class.enable_rack_attack!
150+
end
151+
110152
%w(/etc/passwd /wp-admin/index.php /wp-login/index.php SELECT CONCAT /.git/config).each do |path|
111153
it "blocks user for specific request : '#{path}'" do
112154
get "#{decidim.root_path}#{path}", params: {}, headers: headers

0 commit comments

Comments
 (0)