-
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
v6.2 auto-load prevents specific middleware placement #459
Comments
Hi @zarqman, Thank you for the detailed issue report! How are you inserting |
@grzuy, appreciate the quick response. As added background, part of our auth process dynamically affects Rack::Attack's rate limits. Because of that tight relationship, we use the following to assure everything remains adjacent. From config.middleware.use Rack::Attack
config.middleware.insert_before Rack::Attack, Authenticator::PartOne
config.middleware.insert_after Rack::Attack, Authenticator::PartTwo |
From reading the issue description, I didn't get what the problem with this:
Can you elaborate more what is the problem with second no-op |
@fatkodima, there are a few reasons we'd rather not have duplicate copies of Rack::Attack in the middleware stack:
Are you open to adding something like the |
I would rather prefer to revert to original explicit need to include rack-attack middleware, than introducing any more flags or parameters. But let's wait for @grzuy thoughts. |
moving forward, is there any way we can configure Rack::Attack to not auto-load? Thank you! |
@zarqman Aside from these 4 listed concerns, is your custom "2 step authentication" still working with rack-attack
|
@grzuy Correct, no other changes in 6.2 have broken anything else. |
Agree with @fatkodima I would prefer not to add a new setting/flag for this. Not sure how we would eventually let users set a config option before even loading the gem... Feels like we could end up with something too "hacky" and brittle. I don't think "Revert to original explicit need to include rack-attack middleware" is the way to go either. To put this issue into perspective, I think the most feasible option so far, if we end up addressing this, is the |
for what it's worth, Rack::Timeout is doing something similar with the |
Hi, I just wanted to add one more case here ^^ I first encountered this problem and reported it in #457 and by lack of better option, decided to lock the version below 6.2 to avoid the trouble. And now I have the same problem again on another project where I need to have one middleware inserted after Rack::Attack (because it's slow and needs to be protected) and I can't again figure out how to do that cleanly. I totally understand the default to silently add the middleware the the end and for me the best fix here would also be something like: # Gemfile
gem 'rack-attack', require: 'rack/attack/base' # application.rb
config.middleware.use Rack::Attack Or small variant: # Gemfile
gem 'rack-attack', require: false # application.rb
require 'rack/attack/base'
config.middleware.use Rack::Attack For people who prefer to keep the require where it's used or conditionally load it, stuff like that. Basically a way to NOT require the rails autoload code and manually insert the middleware where we want. If this is something you are open to, I can submit a PR. Also for the record there's more people interested in this outside of these issues ^^ #491 |
@jarthod We found a way around this. It's super hacky, and a directly supported path with an alternate # in application.rb, where you'd add any other middleware:
initializer 'run after engine initializers' do
config.middleware.insert_after Rack::Attack, SomeLastMiddleware
end It's also possible to relocate Rack::Attack itself, but requires a more advanced hack: initializer 'run after engine initializers' do
class Dummy ; end
config.middleware.swap Rack::Attack, Dummy
config.middleware.delete Dummy
config.middleware.insert_after ActionDispatch::DebugExceptions, Rack::Attack
end The rename/swap is required because all delete ops are processed after everything else. Deleting Rack::Attack directly will delete all copies, including the newly added one. |
Thanks @zarqman! That's what I was starting to do indeed, I'm gonna use this workaround until some decision is reached about a potential future cleaner solution. |
Is there still a possibility that this might be solved in a future version? We have a use case where one of the middlewares does takes some actions on particular requests to track and record them, which is fine for most cases but if a user is being rate-limited then it would negate the performance gains offered by rack attack since the middleware would run before rack attack. We can use one of the suggested workarounds for now but it'd be really useful to have the option to load and initialize the Rack::Attack middleware manually if required. |
I just happened to come across this thread. I'm not encountering the problem, but I think if you want to skip the railtie initializer inserting the middleware automatically (eg: so you can insert it manually into a different position) then I think you should be able to do disable with this one-liner rather than fighting to undo its effects afterwards? # Put this anywhere in application.rb
Rack::Attack::Railtie.initializers.clear More nuance will be needed if this gem ever starts using other initialisers that we don't want to skip, but it should work fine for now. |
Thanks @robotfelix clearing the initializers works perfectly to resolve my issue in #667. |
Upon upgrading to 6.2.1 (from 6.1.0), we end up with Rack::Attack twice in our middleware stack.
Actual behavior:
Expected behavior:
As you can see, our specific case involves a two-phase authentication middleware stack that is specifically designed to surround Rack::Attack, so we cannot move Rack::Attack to the end of the stack, where it installs itself by default.
I see that 6.2.1 was intended to turn the second instance into a no-op, but we'd much prefer avoiding the double load to begin with.
Given the need to configure Rack::Attack anyway, one could argue against auto-loading the middleware. However, I'd like to instead propose a couple of ways to allow disabling the auto-load for advanced configurations like ours, while preserving it as the new default behavior.
Add a config option
Rack::Attack.auto_load = true
. Defaults to true. When false, the initializer would skip the auto-load.Rework the gem's default require by moving most of lib/rack/attack.rb into a new file. Replace the original file with nothing but:
This would allow advanced configurations to set the Gemfile as
which would implicitly disable the auto-load railtie.
Either way preserves your new default while adding a path for more specific configuration for those of us with apps with advanced middleware configurations.
Are you open to either of the above solutions? If at least one is acceptable, I'm happy to prepare a PR accordingly if that'd be helpful.
FWIW, either of the above would also allow the removal of the already-called condition (
return ... if ... env["rack.attack.called"]
) added in #457, which I think may break/prevent PR #442.The text was updated successfully, but these errors were encountered: