Commit 90e4b400 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Merge branch 'git-http-blacklist' into 'master'

Git HTTP blacklist

See merge request !1328
parents 4659a281 dec16893
...@@ -13,6 +13,7 @@ v 7.7.0 ...@@ -13,6 +13,7 @@ v 7.7.0
- Show user SSH keys in admin area - Show user SSH keys in admin area
- Developer can push to protected branches option - Developer can push to protected branches option
- Set project path instead of project name in create form - 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) - Updates to the messages returned by API (sponsored by O'Reilly Media)
......
...@@ -366,7 +366,7 @@ GEM ...@@ -366,7 +366,7 @@ GEM
rack (1.5.2) rack (1.5.2)
rack-accept (0.4.5) rack-accept (0.4.5)
rack (>= 0.4) rack (>= 0.4)
rack-attack (2.3.0) rack-attack (4.2.0)
rack rack
rack-cors (0.2.9) rack-cors (0.2.9)
rack-mini-profiler (0.9.0) rack-mini-profiler (0.9.0)
......
...@@ -298,6 +298,20 @@ production: &base ...@@ -298,6 +298,20 @@ production: &base
# ![Company Logo](http://www.companydomain.com/logo.png) # ![Company Logo](http://www.companydomain.com/logo.png)
# [Learn more about CompanyName](http://www.companydomain.com/) # [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: development:
<<: *base <<: *base
......
...@@ -171,6 +171,16 @@ Settings.satellites['timeout'] ||= 30 ...@@ -171,6 +171,16 @@ Settings.satellites['timeout'] ||= 30
# #
Settings['extra'] ||= Settingslogic.new({}) 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 # Testing settings
# #
......
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
# 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 ...@@ -72,8 +72,26 @@ module Grack
end end
def authenticate_user(login, password) def authenticate_user(login, password)
auth = Gitlab::Auth.new user = Gitlab::Auth.new.find(login, password)
auth.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 end
def authorized_request? def authorized_request?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment