Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/rack_attack.rb')
-rw-r--r--lib/gitlab/rack_attack.rb118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/gitlab/rack_attack.rb b/lib/gitlab/rack_attack.rb
new file mode 100644
index 00000000000..7c336153e32
--- /dev/null
+++ b/lib/gitlab/rack_attack.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: true
+
+# When adding new user-configurable throttles, remember to update the documentation
+# in doc/user/admin_area/settings/user_and_ip_rate_limits.md
+#
+# Integration specs for throttling can be found in:
+# spec/requests/rack_attack_global_spec.rb
+module Gitlab
+ module RackAttack
+ def self.configure(rack_attack)
+ # This adds some methods used by our throttles to the `Rack::Request`
+ rack_attack::Request.include(Gitlab::RackAttack::Request)
+ # Send the Retry-After header so clients (e.g. python-gitlab) can make good choices about delays
+ Rack::Attack.throttled_response_retry_after_header = true
+ # Configure the throttles
+ configure_throttles(rack_attack)
+
+ configure_user_allowlist
+ end
+
+ def self.configure_user_allowlist
+ @user_allowlist = nil
+ user_allowlist
+ end
+
+ def self.configure_throttles(rack_attack)
+ throttle_or_track(rack_attack, 'throttle_unauthenticated', Gitlab::Throttle.unauthenticated_options) do |req|
+ if !req.should_be_skipped? &&
+ Gitlab::Throttle.settings.throttle_unauthenticated_enabled &&
+ req.unauthenticated?
+ req.ip
+ end
+ end
+
+ throttle_or_track(rack_attack, 'throttle_authenticated_api', Gitlab::Throttle.authenticated_api_options) do |req|
+ if req.api_request? &&
+ Gitlab::Throttle.settings.throttle_authenticated_api_enabled
+ req.throttled_user_id([:api])
+ end
+ end
+
+ # Product analytics feature is in experimental stage.
+ # At this point we want to limit amount of events registered
+ # per application (aid stands for application id).
+ throttle_or_track(rack_attack, 'throttle_product_analytics_collector', limit: 100, period: 60) do |req|
+ if req.product_analytics_collector_request?
+ req.params['aid']
+ end
+ end
+
+ throttle_or_track(rack_attack, 'throttle_authenticated_web', Gitlab::Throttle.authenticated_web_options) do |req|
+ if req.web_request? &&
+ Gitlab::Throttle.settings.throttle_authenticated_web_enabled
+ req.throttled_user_id([:api, :rss, :ics])
+ end
+ end
+
+ throttle_or_track(rack_attack, 'throttle_unauthenticated_protected_paths', Gitlab::Throttle.protected_paths_options) do |req|
+ if req.post? &&
+ !req.should_be_skipped? &&
+ req.protected_path? &&
+ Gitlab::Throttle.protected_paths_enabled? &&
+ req.unauthenticated?
+ req.ip
+ end
+ end
+
+ throttle_or_track(rack_attack, 'throttle_authenticated_protected_paths_api', Gitlab::Throttle.protected_paths_options) do |req|
+ if req.post? &&
+ req.api_request? &&
+ req.protected_path? &&
+ Gitlab::Throttle.protected_paths_enabled?
+ req.throttled_user_id([:api])
+ end
+ end
+
+ throttle_or_track(rack_attack, 'throttle_authenticated_protected_paths_web', Gitlab::Throttle.protected_paths_options) do |req|
+ if req.post? &&
+ req.web_request? &&
+ req.protected_path? &&
+ Gitlab::Throttle.protected_paths_enabled?
+ req.throttled_user_id([:api, :rss, :ics])
+ end
+ end
+
+ rack_attack.safelist('throttle_bypass_header') do |req|
+ Gitlab::Throttle.bypass_header.present? &&
+ req.get_header(Gitlab::Throttle.bypass_header) == '1'
+ end
+ end
+
+ def self.throttle_or_track(rack_attack, throttle_name, *args, &block)
+ if track?(throttle_name)
+ rack_attack.track(throttle_name, *args, &block)
+ else
+ rack_attack.throttle(throttle_name, *args, &block)
+ end
+ end
+
+ def self.track?(name)
+ dry_run_config = ENV['GITLAB_THROTTLE_DRY_RUN'].to_s.strip
+
+ return false if dry_run_config.empty?
+ return true if dry_run_config == '*'
+
+ dry_run_config.split(',').map(&:strip).include?(name)
+ end
+
+ def self.user_allowlist
+ @user_allowlist ||= begin
+ list = UserAllowlist.new(ENV['GITLAB_THROTTLE_USER_ALLOWLIST'])
+ Gitlab::AuthLogger.info(gitlab_throttle_user_allowlist: list.to_a)
+ list
+ end
+ end
+ end
+end
+::Gitlab::RackAttack.prepend_if_ee('::EE::Gitlab::RackAttack')