diff options
author | Pawel Chojnacki <pawel@chojnacki.ws> | 2017-02-06 13:48:46 +0100 |
---|---|---|
committer | Pawel Chojnacki <pawel@chojnacki.ws> | 2017-03-06 15:41:24 +0100 |
commit | e5cf3f51fb568361a247d715facb6cd9bb15bb16 (patch) | |
tree | d12f9644c8b0dd0765fd0de90d69027848341083 /lib/gitlab/auth | |
parent | 27729aa3a4666c6b06006c76023f4bff60f8ba25 (diff) | |
download | gitlab-ce-e5cf3f51fb568361a247d715facb6cd9bb15bb16.tar.gz |
Allow limiting logging in users from too many different IPs.
Diffstat (limited to 'lib/gitlab/auth')
-rw-r--r-- | lib/gitlab/auth/unique_ips_limiter.rb | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/lib/gitlab/auth/unique_ips_limiter.rb b/lib/gitlab/auth/unique_ips_limiter.rb new file mode 100644 index 00000000000..21307eb35e4 --- /dev/null +++ b/lib/gitlab/auth/unique_ips_limiter.rb @@ -0,0 +1,70 @@ +module Gitlab + module Auth + class TooManyIps < StandardError + attr_reader :user_id, :ip, :unique_ips_count + + def initialize(user_id, ip, unique_ips_count) + @user_id = user_id + @ip = ip + @unique_ips_count = unique_ips_count + end + + def message + "User #{user_id} from IP: #{ip} tried logging from too many ips: #{unique_ips_count}" + end + end + + class UniqueIpsLimiter + USER_UNIQUE_IPS_PREFIX = 'user_unique_ips' + + class << self + def limit_user_id!(user_id) + if config.unique_ips_limit_enabled + ip = RequestContext.client_ip + unique_ips = count_unique_ips(user_id, ip) + raise TooManyIps.new(user_id, ip, unique_ips) if unique_ips > config.unique_ips_limit_per_user + end + end + + def limit_user!(user = nil) + user = yield if user.nil? + limit_user_id!(user.id) unless user.nil? + user + end + + def config + Gitlab::CurrentSettings.current_application_settings + end + + def count_unique_ips(user_id, ip) + time = Time.now.to_i + key = "#{USER_UNIQUE_IPS_PREFIX}:#{user_id}" + + Gitlab::Redis.with do |redis| + unique_ips_count = nil + redis.multi do |r| + r.zadd(key, time, ip) + r.zremrangebyscore(key, 0, time - config.unique_ips_limit_time_window) + unique_ips_count = r.zcard(key) + end + unique_ips_count.value + end + end + end + + def initialize(app) + @app = app + end + + def call(env) + begin + @app.call(env) + rescue TooManyIps => ex + + Rails.logger.info ex.message + [429, {'Content-Type' => 'text/plain', 'Retry-After' => UniqueIpsLimiter.config.unique_ips_limit_time_window }, ["Retry later\n"]] + end + end + end + end +end |