Merge branch 'git-http-blacklist' into 'master'
Git HTTP blacklist See merge request !1328
This commit is contained in:
commit
90e4b400ba
7 changed files with 102 additions and 3 deletions
|
@ -13,6 +13,7 @@ v 7.7.0
|
|||
- Show user SSH keys in admin area
|
||||
- Developer can push to protected branches option
|
||||
- Set project path instead of project name in create form
|
||||
- Block Git HTTP access after 10 failed authentication attempts
|
||||
-
|
||||
-
|
||||
- Updates to the messages returned by API (sponsored by O'Reilly Media)
|
||||
|
|
|
@ -366,7 +366,7 @@ GEM
|
|||
rack (1.5.2)
|
||||
rack-accept (0.4.5)
|
||||
rack (>= 0.4)
|
||||
rack-attack (2.3.0)
|
||||
rack-attack (4.2.0)
|
||||
rack
|
||||
rack-cors (0.2.9)
|
||||
rack-mini-profiler (0.9.0)
|
||||
|
|
|
@ -298,6 +298,20 @@ production: &base
|
|||
# ![Company Logo](http://www.companydomain.com/logo.png)
|
||||
# [Learn more about CompanyName](http://www.companydomain.com/)
|
||||
|
||||
rack_attack:
|
||||
git_basic_auth:
|
||||
# Whitelist requests from 127.0.0.1 for web proxies (NGINX/Apache) with incorrect headers
|
||||
# ip_whitelist: ["127.0.0.1"]
|
||||
#
|
||||
# Limit the number of Git HTTP authentication attempts per IP
|
||||
# maxretry: 10
|
||||
#
|
||||
# Reset the auth attempt counter per IP after 60 seconds
|
||||
# findtime: 60
|
||||
#
|
||||
# Ban an IP for one hour (3600s) after too many auth attempts
|
||||
# bantime: 3600
|
||||
|
||||
development:
|
||||
<<: *base
|
||||
|
||||
|
|
|
@ -171,6 +171,16 @@ Settings.satellites['timeout'] ||= 30
|
|||
#
|
||||
Settings['extra'] ||= Settingslogic.new({})
|
||||
|
||||
#
|
||||
# Rack::Attack settings
|
||||
#
|
||||
Settings['rack_attack'] ||= Settingslogic.new({})
|
||||
Settings.rack_attack['git_basic_auth'] ||= Settingslogic.new({})
|
||||
Settings.rack_attack.git_basic_auth['ip_whitelist'] ||= %w{127.0.0.1}
|
||||
Settings.rack_attack.git_basic_auth['maxretry'] ||= 10
|
||||
Settings.rack_attack.git_basic_auth['findtime'] ||= 1.minute
|
||||
Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour
|
||||
|
||||
#
|
||||
# Testing settings
|
||||
#
|
||||
|
|
12
config/initializers/rack_attack_git_basic_auth.rb
Normal file
12
config/initializers/rack_attack_git_basic_auth.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
unless Rails.env.test?
|
||||
# Tell the Rack::Attack Rack middleware to maintain an IP blacklist. We will
|
||||
# update the blacklist from Grack::Auth#authenticate_user.
|
||||
Rack::Attack.blacklist('Git HTTP Basic Auth') do |req|
|
||||
Rack::Attack::Allow2Ban.filter(req.ip, Gitlab.config.rack_attack.git_basic_auth) do
|
||||
# This block only gets run if the IP was not already banned.
|
||||
# Return false, meaning that we do not see anything wrong with the
|
||||
# request at this time
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
44
config/initializers/redis-store-fix-expiry.rb
Normal file
44
config/initializers/redis-store-fix-expiry.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Monkey-patch Redis::Store to make 'setex' and 'expire' work with namespacing
|
||||
|
||||
module Gitlab
|
||||
class Redis
|
||||
class Store
|
||||
module Namespace
|
||||
# Redis::Store#setex in redis-store 1.1.4 does not respect namespaces;
|
||||
# this new method does.
|
||||
def setex(key, expires_in, value, options=nil)
|
||||
namespace(key) { |key| super(key, expires_in, value) }
|
||||
end
|
||||
|
||||
# Redis::Store#expire in redis-store 1.1.4 does not respect namespaces;
|
||||
# this new method does.
|
||||
def expire(key, expires_in)
|
||||
namespace(key) { |key| super(key, expires_in) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Our new definitions of #setex and #expire above assume that the
|
||||
# #namespace method exists. Because we cannot be sure of that, we
|
||||
# re-implement the #namespace method from Redis::Store::Namespace so
|
||||
# that it is available for all Redis::Store instances, whether they use
|
||||
# namespacing or not.
|
||||
#
|
||||
# Based on lib/redis/store/namespace.rb L49-51 (redis-store 1.1.4)
|
||||
def namespace(key)
|
||||
if @namespace
|
||||
yield interpolate(key)
|
||||
else
|
||||
# This Redis::Store instance does not use a namespace so we should
|
||||
# just pass through the key.
|
||||
yield key
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Redis::Store.class_eval do
|
||||
include Gitlab::Redis::Store::Namespace
|
||||
end
|
|
@ -72,8 +72,26 @@ module Grack
|
|||
end
|
||||
|
||||
def authenticate_user(login, password)
|
||||
auth = Gitlab::Auth.new
|
||||
auth.find(login, password)
|
||||
user = Gitlab::Auth.new.find(login, password)
|
||||
return user if user.present?
|
||||
|
||||
# At this point, we know the credentials were wrong. 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
|
||||
Rack::Attack::Allow2Ban.filter(@request.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?(@request.ip)
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
nil # No user was found
|
||||
end
|
||||
|
||||
def authorized_request?
|
||||
|
|
Loading…
Reference in a new issue