-
Notifications
You must be signed in to change notification settings - Fork 337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to use multiple instances of middleware #442
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,36 @@ | ||||||||||||||
# frozen_string_literal: true | ||||||||||||||
|
||||||||||||||
require_relative "../spec_helper" | ||||||||||||||
|
||||||||||||||
describe "Middleware" do | ||||||||||||||
it "is used in Rails by default" do | ||||||||||||||
skip unless defined?(Rails) | ||||||||||||||
|
||||||||||||||
app = Class.new(Rails::Application) do | ||||||||||||||
config.eager_load = false | ||||||||||||||
config.logger = Logger.new(nil) # avoid creating the log/ directory automatically | ||||||||||||||
config.cache_store = :null_store # avoid creating tmp/ directory for cache | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
app.initialize! | ||||||||||||||
assert app.middleware.include?(Rack::Attack) | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
def app | ||||||||||||||
Rack::Builder.new do | ||||||||||||||
use Rack::Attack do | ||||||||||||||
blocklist_ip("1.2.3.4") | ||||||||||||||
end | ||||||||||||||
Comment on lines
+21
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we actually test that multiple instances of the middleware work together? Maybe I'm missing something but I tried adding a second middleware def app
Rack::Builder.new do
use Rack::Attack do
blocklist_ip("1.2.3.4")
end
use Rack::Attack do
blocklist_ip("4.3.2.1")
end
run lambda { |_env| [200, {}, ['Hello World']] }
end.to_app
end
it "can be configured via a block" do
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
assert_equal 403, last_response.status
get "/", {}, "REMOTE_ADDR" => "4.3.2.1"
assert_equal 403, last_response.status
end and it didn't work 🤔 thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Multiple instances on the same rack app are not working because of this guard clause rack-attack/lib/rack/attack.rb Line 105 in b6ce502
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ahh ok I see.. that was introduced to guarantee idempotency. But with this PR, that's no longer accurate. What I mean is that in the past it was safe to just have At this point I'm starting to doubt if the benefits of the PR are greater than its drawbacks, especially around generating confusion to end users and inflicting pain on them 🤔 Pros I see:
Cons I see:
WDYT? Please let me know your thoughts, I'm open to discussion and changing my mind 🙌 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is still a good direction. Ideally we retain compatibility with any existing configuration mechanism and redirect it to a per-instance configuration. I don't think the idempotency fix is correct. It seems like XY problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ioquatix Do you have suggestions how to proceed? I wish the middleware was not automatically added to rails apps some time ago 😐. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have time to provide detailed feedback until after RubyKaigi, but I can take a look then. Is it part of Rails' default stack? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, rack-attack/lib/rack/attack/railtie.rb Lines 11 to 15 in b6ce502
👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can introduce some configs so that you either get the old way to config + idempotency + the railtie, OR you get the new way to config rack attack with the block + ability to have multiple middlewares added + no railtie? What I mean is that I’m ok with both approaches, but I think the key here is not mixing both of them at the same time 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's fairly straight forward to configure using a Railtie, so we could have a default middleware which gets configured via Rails' own configuration system, but that doesn't mean we can't have non-global instances. |
||||||||||||||
|
||||||||||||||
run lambda { |_env| [200, {}, ['Hello World']] } | ||||||||||||||
end.to_app | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
it "can be configured via a block" do | ||||||||||||||
get "/", {}, "REMOTE_ADDR" => "1.2.3.4" | ||||||||||||||
assert_equal 403, last_response.status | ||||||||||||||
|
||||||||||||||
get "/", {}, "REMOTE_ADDR" => "4.3.2.1" | ||||||||||||||
assert_equal 200, last_response.status | ||||||||||||||
end | ||||||||||||||
end |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to make the final statement in this branch
configuration
, otherwise@configuration
gets set to the return value of the last statement in the block, which in my case was an instance ofThrottle
.Otherwise, this seems to work nicely, I've monkey patched this change into a project I'm working on it does the job wonderfully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @jellybob for the code review.
Ideally this problem would reveal in any new test case covering the new block argument.