From 6cc6d9730a234c2cc27869f9b9388ab61de9c460 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 6 Apr 2016 17:27:52 +0200 Subject: Delete dead code --- lib/gitlab/backend/grack_auth.rb | 53 +--------------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index cdcaae8094c..e2363b91265 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -36,10 +36,7 @@ module Grack lfs_response = Gitlab::Lfs::Router.new(project, @user, @request).try_call return lfs_response unless lfs_response.nil? - if project && authorized_request? - # Tell gitlab-workhorse the request is OK, and what the GL_ID is - render_grack_auth_ok - elsif @user.nil? && !@ci + if @user.nil? && !@ci unauthorized else render_not_found @@ -141,36 +138,6 @@ module Grack user end - def authorized_request? - return true if @ci - - case git_cmd - when *Gitlab::GitAccess::DOWNLOAD_COMMANDS - if !Gitlab.config.gitlab_shell.upload_pack - false - elsif user - Gitlab::GitAccess.new(user, project).download_access_check.allowed? - elsif project.public? - # Allow clone/fetch for public projects - true - else - false - end - when *Gitlab::GitAccess::PUSH_COMMANDS - if !Gitlab.config.gitlab_shell.receive_pack - false - elsif user - # Skip user authorization on upload request. - # It will be done by the pre-receive hook in the repository. - true - else - false - end - else - false - end - end - def git_cmd if @request.get? @request.params['service'] @@ -197,24 +164,6 @@ module Grack end end - def render_grack_auth_ok - repo_path = - if @request.path_info =~ /^([\w\.\/-]+)\.wiki\.git/ - ProjectWiki.new(project).repository.path_to_repo - else - project.repository.path_to_repo - end - - [ - 200, - { "Content-Type" => "application/json" }, - [JSON.dump({ - 'GL_ID' => Gitlab::ShellEnv.gl_id(@user), - 'RepoPath' => repo_path, - })] - ] - end - def render_not_found [404, { "Content-Type" => "text/plain" }, ["Not Found"]] end -- cgit v1.2.1 From 91226c200151461b21e85cc8c85a103c93d6a17f Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 6 Apr 2016 17:52:12 +0200 Subject: Move workhorse protocol code into lib --- lib/gitlab/workhorse.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index c3ddd4c2680..5b2982e4994 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -6,6 +6,13 @@ module Gitlab SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data' class << self + def git_http_ok(repository, user) + { + 'GL_ID' => Gitlab::ShellEnv.gl_id(user), + 'RepoPath' => repository.path_to_repo, + } + end + def send_git_blob(repository, blob) params = { 'RepoPath' => repository.path_to_repo, -- cgit v1.2.1 From b1ffc9f0fee16251899e5a2efbc78c4781ef4902 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 29 Apr 2016 18:58:55 +0200 Subject: Make CI/Oauth/rate limiting reusable --- lib/api/session.rb | 8 ++- lib/gitlab/auth.rb | 107 ++++++++++++++++++++++++++++++++++----- lib/gitlab/backend/grack_auth.rb | 2 +- 3 files changed, 102 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/api/session.rb b/lib/api/session.rb index cc646895914..e308ccc3004 100644 --- a/lib/api/session.rb +++ b/lib/api/session.rb @@ -11,8 +11,12 @@ module API # Example Request: # POST /session post "/session" do - auth = Gitlab::Auth.new - user = auth.find(params[:email] || params[:login], params[:password]) + user, _ = Gitlab::Auth.find( + params[:email] || params[:login], + params[:password], + project: nil, + ip: request.ip + ) return unauthorized! unless user present user, with: Entities::UserLogin diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 30509528b8b..32e903905ad 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -1,17 +1,100 @@ module Gitlab class Auth - def find(login, password) - user = User.by_login(login) - - # If no user is found, or it's an LDAP server, try LDAP. - # LDAP users are only authenticated via LDAP - if user.nil? || user.ldap_user? - # Second chance - try LDAP authentication - return nil unless Gitlab::LDAP::Config.enabled? - - Gitlab::LDAP::Authentication.login(login, password) - else - user if user.valid_password?(password) + class << self + def find(login, password, project:, ip:) + raise "Must provide an IP for rate limiting" if ip.nil? + + user, type = nil, nil + + if valid_ci_request?(login, password, project) + type = :ci + elsif user = find_by_master_or_ldap(login, password) + type = :master_or_ldap + elsif user = oauth_access_token_check(login, password) + type = :oauth + end + + rate_limit!(ip, success: !!user || (type == :ci), login: login) + [user, type] + end + + def find_by_master_or_ldap(login, password) + user = User.by_login(login) + + # If no user is found, or it's an LDAP server, try LDAP. + # LDAP users are only authenticated via LDAP + if user.nil? || user.ldap_user? + # Second chance - try LDAP authentication + return nil unless Gitlab::LDAP::Config.enabled? + + Gitlab::LDAP::Authentication.login(login, password) + else + user if user.valid_password?(password) + end + end + + private + + def valid_ci_request?(login, password, project) + matched_login = /(?^[a-zA-Z]*-ci)-token$/.match(login) + + return false unless project && matched_login.present? + + underscored_service = matched_login['service'].underscore + + if underscored_service == 'gitlab_ci' + project && project.valid_build_token?(password) + elsif Service.available_services_names.include?(underscored_service) + # We treat underscored_service as a trusted input because it is included + # in the Service.available_services_names whitelist. + service_method = "#{underscored_service}_service" + service = project.send(service_method) + + service && service.activated? && service.valid_token?(password) + end + end + + def oauth_access_token_check(login, password) + if login == "oauth2" && password.present? + token = Doorkeeper::AccessToken.by_token(password) + token && token.accessible? && User.find_by(id: token.resource_owner_id) + end + end + + def rate_limit!(ip, success:, login:) + # If the user authenticated successfully, we reset the auth failure count + # from Rack::Attack for that IP. A client may attempt to authenticate + # with a username and blank password first, and only after it receives + # a 401 error does it present a password. Resetting the count prevents + # false positives from occurring. + # + # Otherwise, we let Rack::Attack know there was a failed authentication + # attempt from this IP. This information is stored in the Rails cache + # (Redis) and will be used by the Rack::Attack middleware to decide + # whether to block requests from this IP. + + config = Gitlab.config.rack_attack.git_basic_auth + return unless config.enabled + + if success + # A successful login will reset the auth failure count from this IP + Rack::Attack::Allow2Ban.reset(ip, config) + else + banned = Rack::Attack::Allow2Ban.filter(ip, config) do + # Unless the IP is whitelisted, return true so that Allow2Ban + # increments the counter (stored in Rails.cache) for the IP + if config.ip_whitelist.include?(ip) + false + else + true + end + end + + if banned + Rails.logger.info "IP #{ip} failed to login " \ + "as #{login} but has been temporarily banned from Git auth" + end + end end end end diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index e2363b91265..b263a27d4d3 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -95,7 +95,7 @@ module Grack end def authenticate_user(login, password) - user = Gitlab::Auth.new.find(login, password) + user, _ = Gitlab::Auth.new.find_by_master_or_ldap(login, password) unless user user = oauth_access_token_check(login, password) -- cgit v1.2.1 From d1f5019511a1dc630e97f99bdb1f6b9fe6b02bba Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 2 May 2016 13:19:39 +0200 Subject: Use correct auth finder --- lib/api/session.rb | 7 +------ lib/gitlab/backend/grack_auth.rb | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/api/session.rb b/lib/api/session.rb index e308ccc3004..1156aab8cc2 100644 --- a/lib/api/session.rb +++ b/lib/api/session.rb @@ -11,12 +11,7 @@ module API # Example Request: # POST /session post "/session" do - user, _ = Gitlab::Auth.find( - params[:email] || params[:login], - params[:password], - project: nil, - ip: request.ip - ) + user = Gitlab::Auth.find_by_master_or_ldap(params[:email] || params[:login], params[:password]) return unauthorized! unless user present user, with: Entities::UserLogin diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index b263a27d4d3..3462c2dcfbc 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -95,7 +95,7 @@ module Grack end def authenticate_user(login, password) - user, _ = Gitlab::Auth.new.find_by_master_or_ldap(login, password) + user = Gitlab::Auth.new.find_by_master_or_ldap(login, password) unless user user = oauth_access_token_check(login, password) -- cgit v1.2.1 From 9ce099429972726da22253407d98ae8aa1ef167b Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 2 May 2016 13:21:59 +0200 Subject: Rubocop and whitespace --- lib/gitlab/workhorse.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 5b2982e4994..f9ceee142d7 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -36,9 +36,9 @@ module Gitlab "git-archive:#{encode(params)}", ] end - + protected - + def encode(hash) Base64.urlsafe_encode64(JSON.dump(hash)) end -- cgit v1.2.1 From 3dc276b367fe88c3c1026371d275d6078611f625 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 3 May 2016 11:46:14 +0200 Subject: Remove parallel assignment --- lib/gitlab/auth.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 32e903905ad..0479006f993 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -4,7 +4,8 @@ module Gitlab def find(login, password, project:, ip:) raise "Must provide an IP for rate limiting" if ip.nil? - user, type = nil, nil + user = nil + type = nil if valid_ci_request?(login, password, project) type = :ci -- cgit v1.2.1 From fea591e5c5796235d28eeec4d27759f87fa9d8e2 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 2 Jun 2016 13:42:18 +0200 Subject: Rename finder to find_in_gitlab_or_ldap --- lib/api/session.rb | 2 +- lib/gitlab/auth.rb | 4 ++-- lib/gitlab/backend/grack_auth.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/api/session.rb b/lib/api/session.rb index 1156aab8cc2..56e69b2366f 100644 --- a/lib/api/session.rb +++ b/lib/api/session.rb @@ -11,7 +11,7 @@ module API # Example Request: # POST /session post "/session" do - user = Gitlab::Auth.find_by_master_or_ldap(params[:email] || params[:login], params[:password]) + user = Gitlab::Auth.find_in_gitlab_or_ldap(params[:email] || params[:login], params[:password]) return unauthorized! unless user present user, with: Entities::UserLogin diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 0479006f993..d156fa2978d 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -9,7 +9,7 @@ module Gitlab if valid_ci_request?(login, password, project) type = :ci - elsif user = find_by_master_or_ldap(login, password) + elsif user = find_in_gitlab_or_ldap(login, password) type = :master_or_ldap elsif user = oauth_access_token_check(login, password) type = :oauth @@ -19,7 +19,7 @@ module Gitlab [user, type] end - def find_by_master_or_ldap(login, password) + def find_in_gitlab_or_ldap(login, password) user = User.by_login(login) # If no user is found, or it's an LDAP server, try LDAP. diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 3462c2dcfbc..492ffb138a3 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -95,7 +95,7 @@ module Grack end def authenticate_user(login, password) - user = Gitlab::Auth.new.find_by_master_or_ldap(login, password) + user = Gitlab::Auth.new.find_in_gitlab_or_ldap(login, password) unless user user = oauth_access_token_check(login, password) -- cgit v1.2.1 From 3ffa494ffe06105d6e36a46df52e8a842be0ab69 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 3 Jun 2016 14:57:34 +0200 Subject: =?UTF-8?q?Changes=20after=20more=20review=20from=20R=C3=A9my?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/gitlab/auth.rb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index d156fa2978d..672642ebfbe 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -1,22 +1,23 @@ module Gitlab class Auth + Result = Struct.new(:user, :type) + class << self def find(login, password, project:, ip:) raise "Must provide an IP for rate limiting" if ip.nil? - user = nil - type = nil + result = Result.new if valid_ci_request?(login, password, project) - type = :ci - elsif user = find_in_gitlab_or_ldap(login, password) - type = :master_or_ldap - elsif user = oauth_access_token_check(login, password) - type = :oauth + result.type = :ci + elsif result.user = find_in_gitlab_or_ldap(login, password) + result.type = :gitlab_or_ldap + elsif result.user = oauth_access_token_check(login, password) + result.type = :oauth end - rate_limit!(ip, success: !!user || (type == :ci), login: login) - [user, type] + rate_limit!(ip, success: !!result.user || (result.type == :ci), login: login) + result end def find_in_gitlab_or_ldap(login, password) @@ -67,7 +68,7 @@ module Gitlab # from Rack::Attack for that IP. A client may attempt to authenticate # with a username and blank password first, and only after it receives # a 401 error does it present a password. Resetting the count prevents - # false positives from occurring. + # false positives. # # Otherwise, we let Rack::Attack know there was a failed authentication # attempt from this IP. This information is stored in the Rails cache @@ -78,15 +79,14 @@ module Gitlab return unless config.enabled if success - # A successful login will reset the auth failure count from this IP Rack::Attack::Allow2Ban.reset(ip, config) else banned = Rack::Attack::Allow2Ban.filter(ip, config) do - # Unless the IP is whitelisted, return true so that Allow2Ban - # increments the counter (stored in Rails.cache) for the IP if config.ip_whitelist.include?(ip) + # Don't increment the ban counter for this IP false else + # Increment the ban counter for this IP true end end -- cgit v1.2.1 From fa35aea3ddf1093db26f8b7fec78175a5f88af7a Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 3 Jun 2016 17:07:40 +0200 Subject: Refactor Gitlab::Auth rate limiting --- lib/gitlab/auth.rb | 36 +++++++++++------------------------ lib/gitlab/auth/rate_limiter.rb | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 lib/gitlab/auth/rate_limiter.rb (limited to 'lib') diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 672642ebfbe..dd6ba84c973 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -1,5 +1,5 @@ module Gitlab - class Auth + module Auth Result = Struct.new(:user, :type) class << self @@ -64,34 +64,20 @@ module Gitlab end def rate_limit!(ip, success:, login:) - # If the user authenticated successfully, we reset the auth failure count - # from Rack::Attack for that IP. A client may attempt to authenticate - # with a username and blank password first, and only after it receives - # a 401 error does it present a password. Resetting the count prevents - # false positives. - # - # Otherwise, we let Rack::Attack know there was a failed authentication - # attempt from this IP. This information is stored in the Rails cache - # (Redis) and will be used by the Rack::Attack middleware to decide - # whether to block requests from this IP. - - config = Gitlab.config.rack_attack.git_basic_auth - return unless config.enabled + rate_limiter = IpRateLimiter.new(ip) + return unless rate_limiter.enabled? if success - Rack::Attack::Allow2Ban.reset(ip, config) + # Repeated login 'failures' are normal behavior for some Git clients so + # it is important to reset the ban counter once the client has proven + # they are not a 'bad guy'. + rate_limiter.reset! else - banned = Rack::Attack::Allow2Ban.filter(ip, config) do - if config.ip_whitelist.include?(ip) - # Don't increment the ban counter for this IP - false - else - # Increment the ban counter for this IP - true - end - end + # Register a login failure so that Rack::Attack can block the next + # request from this IP if needed. + rate_limiter.register_fail!(ip, config) - if banned + if rate_limiter.banned? Rails.logger.info "IP #{ip} failed to login " \ "as #{login} but has been temporarily banned from Git auth" end diff --git a/lib/gitlab/auth/rate_limiter.rb b/lib/gitlab/auth/rate_limiter.rb new file mode 100644 index 00000000000..4be9f6d0efe --- /dev/null +++ b/lib/gitlab/auth/rate_limiter.rb @@ -0,0 +1,42 @@ +module Gitlab + module Auth + class IpRateLimiter + attr_reader :ip + + def initialize(ip) + @ip = ip + @banned = false + end + + def enabled? + config.enabled + end + + def reset! + Rack::Attack::Allow2Ban.reset(ip, config) + end + + def register_fail! + # Allow2Ban.filter will return false if this IP has not failed too often yet + @banned = Rack::Attack::Allow2Ban.filter(ip, config) do + # If we return false here, the failure for this IP is ignored by Allow2Ban + ignore_failure? + end + end + + def banned? + @banned + end + + private + + def config + Gitlab.config.rack_attack.git_basic_auth + end + + def ignore_failure? + config.ip_whitelist.exclude?(ip) + end + end + end +end -- cgit v1.2.1 From 1fab583266af0904dfc29facfe4551e37c06342a Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 3 Jun 2016 17:08:44 +0200 Subject: Remove instances of Auth.new --- lib/gitlab/backend/grack_auth.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 492ffb138a3..9e09d2e118d 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -95,7 +95,7 @@ module Grack end def authenticate_user(login, password) - user = Gitlab::Auth.new.find_in_gitlab_or_ldap(login, password) + user = Gitlab::Auth.find_in_gitlab_or_ldap(login, password) unless user user = oauth_access_token_check(login, password) -- cgit v1.2.1 From 03bec6b0e943a3a047fd8f6185f71a976c02506c Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 3 Jun 2016 17:14:13 +0200 Subject: Argh mixed up all the negatives --- lib/gitlab/auth/rate_limiter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/auth/rate_limiter.rb b/lib/gitlab/auth/rate_limiter.rb index 4be9f6d0efe..1089bc9f89e 100644 --- a/lib/gitlab/auth/rate_limiter.rb +++ b/lib/gitlab/auth/rate_limiter.rb @@ -20,7 +20,7 @@ module Gitlab # Allow2Ban.filter will return false if this IP has not failed too often yet @banned = Rack::Attack::Allow2Ban.filter(ip, config) do # If we return false here, the failure for this IP is ignored by Allow2Ban - ignore_failure? + ip_can_be_banned? end end @@ -34,7 +34,7 @@ module Gitlab Gitlab.config.rack_attack.git_basic_auth end - def ignore_failure? + def ip_can_be_banned? config.ip_whitelist.exclude?(ip) end end -- cgit v1.2.1 From 3f3b036defe4f22656f945f341c1d7da06d5543c Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 3 Jun 2016 17:23:34 +0200 Subject: Use public_send --- lib/gitlab/auth.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index dd6ba84c973..bd129d7216a 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -49,8 +49,7 @@ module Gitlab elsif Service.available_services_names.include?(underscored_service) # We treat underscored_service as a trusted input because it is included # in the Service.available_services_names whitelist. - service_method = "#{underscored_service}_service" - service = project.send(service_method) + service = project.public_send("#{underscored_service}_service") service && service.activated? && service.valid_token?(password) end -- cgit v1.2.1 From 07f49626d01ddffcd127e937c528b74b8248043b Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 6 Jun 2016 17:40:26 +0200 Subject: Fix tests --- lib/gitlab/auth.rb | 42 +++++++++++++++++++------------------- lib/gitlab/auth/ip_rate_limiter.rb | 42 ++++++++++++++++++++++++++++++++++++++ lib/gitlab/auth/rate_limiter.rb | 42 -------------------------------------- 3 files changed, 63 insertions(+), 63 deletions(-) create mode 100644 lib/gitlab/auth/ip_rate_limiter.rb delete mode 100644 lib/gitlab/auth/rate_limiter.rb (limited to 'lib') diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index bd129d7216a..076e2af7d38 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -35,6 +35,27 @@ module Gitlab end end + def rate_limit!(ip, success:, login:) + rate_limiter = Gitlab::Auth::IpRateLimiter.new(ip) + return unless rate_limiter.enabled? + + if success + # Repeated login 'failures' are normal behavior for some Git clients so + # it is important to reset the ban counter once the client has proven + # they are not a 'bad guy'. + rate_limiter.reset! + else + # Register a login failure so that Rack::Attack can block the next + # request from this IP if needed. + rate_limiter.register_fail! + + if rate_limiter.banned? + Rails.logger.info "IP #{ip} failed to login " \ + "as #{login} but has been temporarily banned from Git auth" + end + end + end + private def valid_ci_request?(login, password, project) @@ -61,27 +82,6 @@ module Gitlab token && token.accessible? && User.find_by(id: token.resource_owner_id) end end - - def rate_limit!(ip, success:, login:) - rate_limiter = IpRateLimiter.new(ip) - return unless rate_limiter.enabled? - - if success - # Repeated login 'failures' are normal behavior for some Git clients so - # it is important to reset the ban counter once the client has proven - # they are not a 'bad guy'. - rate_limiter.reset! - else - # Register a login failure so that Rack::Attack can block the next - # request from this IP if needed. - rate_limiter.register_fail!(ip, config) - - if rate_limiter.banned? - Rails.logger.info "IP #{ip} failed to login " \ - "as #{login} but has been temporarily banned from Git auth" - end - end - end end end end diff --git a/lib/gitlab/auth/ip_rate_limiter.rb b/lib/gitlab/auth/ip_rate_limiter.rb new file mode 100644 index 00000000000..1089bc9f89e --- /dev/null +++ b/lib/gitlab/auth/ip_rate_limiter.rb @@ -0,0 +1,42 @@ +module Gitlab + module Auth + class IpRateLimiter + attr_reader :ip + + def initialize(ip) + @ip = ip + @banned = false + end + + def enabled? + config.enabled + end + + def reset! + Rack::Attack::Allow2Ban.reset(ip, config) + end + + def register_fail! + # Allow2Ban.filter will return false if this IP has not failed too often yet + @banned = Rack::Attack::Allow2Ban.filter(ip, config) do + # If we return false here, the failure for this IP is ignored by Allow2Ban + ip_can_be_banned? + end + end + + def banned? + @banned + end + + private + + def config + Gitlab.config.rack_attack.git_basic_auth + end + + def ip_can_be_banned? + config.ip_whitelist.exclude?(ip) + end + end + end +end diff --git a/lib/gitlab/auth/rate_limiter.rb b/lib/gitlab/auth/rate_limiter.rb deleted file mode 100644 index 1089bc9f89e..00000000000 --- a/lib/gitlab/auth/rate_limiter.rb +++ /dev/null @@ -1,42 +0,0 @@ -module Gitlab - module Auth - class IpRateLimiter - attr_reader :ip - - def initialize(ip) - @ip = ip - @banned = false - end - - def enabled? - config.enabled - end - - def reset! - Rack::Attack::Allow2Ban.reset(ip, config) - end - - def register_fail! - # Allow2Ban.filter will return false if this IP has not failed too often yet - @banned = Rack::Attack::Allow2Ban.filter(ip, config) do - # If we return false here, the failure for this IP is ignored by Allow2Ban - ip_can_be_banned? - end - end - - def banned? - @banned - end - - private - - def config - Gitlab.config.rack_attack.git_basic_auth - end - - def ip_can_be_banned? - config.ip_whitelist.exclude?(ip) - end - end - end -end -- cgit v1.2.1