mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
b5350cccf7
We have a built-in bruteforce protection for built-in users. When users are being created from LDAP on-the-fly, these limits cannot apply, as we do not have a user object yet. Instead, we can provide a more generous throttler to block attempts
55 lines
1.4 KiB
Ruby
55 lines
1.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module OpenProject
|
|
module RateLimiting
|
|
module_function
|
|
|
|
def active_rules
|
|
@active_rules ||= []
|
|
end
|
|
|
|
def default_rules
|
|
@default_rules ||= [
|
|
LostPassword,
|
|
APIV3,
|
|
Login
|
|
]
|
|
end
|
|
|
|
def set_defaults!
|
|
Rack::Attack.clear_configuration
|
|
Rack::Attack.throttled_responder = ->(request) { OpenProject::RateLimiting.throttled_response(request) }
|
|
Rack::Attack.blocklisted_responder = ->(request) { OpenProject::RateLimiting.blocklisted_response(request) }
|
|
|
|
@active_rules = []
|
|
default_rules.each do |rule|
|
|
apply(rule)
|
|
end
|
|
end
|
|
|
|
def apply(rule)
|
|
unless rule < OpenProject::RateLimiting::Base
|
|
raise ArgumentError.new("Rules need to subclass OpenProject::RateLimiting::Base")
|
|
end
|
|
|
|
active_rules << rule.new.apply! if rule.enabled?
|
|
end
|
|
|
|
def throttled_response(request)
|
|
matched = request.env["rack.attack.matched"]
|
|
rule = find_rule(matched)
|
|
rule ? rule.response(request) : Base.new.response(request)
|
|
end
|
|
|
|
def blocklisted_response(request)
|
|
matched = request.env["rack.attack.matched"]
|
|
rule = find_rule(matched)
|
|
rule ? rule.blocked_response : [403, {}, ["Forbidden\n"]]
|
|
end
|
|
|
|
def find_rule(matched)
|
|
active_rules.find { |r| matched == r.rule_name || matched.start_with?("#{r.rule_name}/") }
|
|
end
|
|
end
|
|
end
|