Skip to content
Extraits de code Groupes Projets
Non vérifiée Valider a865b62e rédigé par Eugen Rochko's avatar Eugen Rochko Validation de GitHub
Parcourir les fichiers

Rate limit by user instead of IP when API user is authenticated (#5923)

* Fix #668 - Rate limit by user instead of IP when API user is authenticated

* Fix code style issue

* Use request decorator provided by Doorkeeper
parent 84cebad4
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -44,7 +44,8 @@ module RateLimitHeaders
end
def api_throttle_data
request.env['rack.attack.throttle_data']['api']
request.env['rack.attack.throttle_data']['throttle_authenticated_api'] ||
request.env['rack.attack.throttle_data']['throttle_unauthenticated_api']
end
def request_time
......
# frozen_string_literal: true
class Rack::Attack
class Request
def authenticated_token
return @token if defined?(@token)
@token = Doorkeeper::OAuth::Token.authenticate(
Doorkeeper::Grape::AuthorizationDecorator.new(self),
*Doorkeeper.configuration.access_token_methods
)
end
def authenticated_user_id
authenticated_token&.resource_owner_id
end
def unauthenticated?
!authenticated_user_id
end
def api_request?
path.start_with?('/api')
end
def web_request?
!api_request?
end
end
PROTECTED_PATHS = %w(
/auth/sign_in
/auth
/auth/password
).freeze
PROTECTED_PATHS_REGEX = Regexp.union(PROTECTED_PATHS.map { |path| /\A#{Regexp.escape(path)}/ })
# Always allow requests from localhost
# (blocklist & throttles are skipped)
Rack::Attack.safelist('allow from localhost') do |req|
......@@ -8,24 +43,16 @@ class Rack::Attack
'127.0.0.1' == req.ip || '::1' == req.ip
end
# Rate limits for the API
throttle('api', limit: 300, period: 5.minutes) do |req|
req.ip if req.path =~ /\A\/api\/v/
end
# Rate limit logins
throttle('login', limit: 5, period: 5.minutes) do |req|
req.ip if req.path == '/auth/sign_in' && req.post?
throttle('throttle_authenticated_api', limit: 300, period: 5.minutes) do |req|
req.api_request? && req.authenticated_user_id
end
# Rate limit sign-ups
throttle('register', limit: 5, period: 5.minutes) do |req|
req.ip if req.path == '/auth' && req.post?
throttle('throttle_unauthenticated_api', limit: 300, period: 5.minutes) do |req|
req.ip if req.api_request? && req.unauthenticated?
end
# Rate limit forgotten passwords
throttle('reminder', limit: 5, period: 5.minutes) do |req|
req.ip if req.path == '/auth/password' && req.post?
throttle('protected_paths', limit: 5, period: 5.minutes) do |req|
req.ip if req.post? && req.path =~ PROTECTED_PATHS_REGEX
end
self.throttled_response = lambda do |env|
......
......@@ -34,7 +34,7 @@ describe ApplicationController do
let(:start_time) { DateTime.new(2017, 1, 1, 12, 0, 0).utc }
before do
request.env['rack.attack.throttle_data'] = { 'api' => { limit: 100, count: 20, period: 10 } }
request.env['rack.attack.throttle_data'] = { 'throttle_authenticated_api' => { limit: 100, count: 20, period: 10 } }
travel_to start_time do
get 'show'
end
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter