Support CIDR notation in IP rate limiter

This will make it possible to whitelist multiple IP addresses
(e.g. 192.168.0.1/24).
This commit is contained in:
Stan Hu 2019-06-27 15:44:46 -07:00
parent ae68c7ea14
commit 82c31a9add
5 changed files with 94 additions and 3 deletions

View File

@ -0,0 +1,5 @@
---
title: Support CIDR notation in IP rate limiter
merge_request: 30146
author:
type: changed

View File

@ -53,8 +53,9 @@ For more information on how to use these options check out
The following settings can be configured:
- `enabled`: By default this is set to `false`. Set this to `true` to enable Rack Attack.
- `ip_whitelist`: Whitelist any IPs from being blocked. They must be formatted as strings within a ruby array.
For example, `["127.0.0.1", "127.0.0.2", "127.0.0.3"]`.
- `ip_whitelist`: Whitelist any IPs from being blocked. They must be formatted as strings within a Ruby array.
CIDR notation is supported in GitLab v12.1 and up.
For example, `["127.0.0.1", "127.0.0.2", "127.0.0.3", "192.168.0.1/24"]`.
- `maxretry`: The maximum amount of times a request can be made in the
specified time.
- `findtime`: The maximum amount of time that failed requests can count against an IP

View File

@ -3,6 +3,8 @@
module Gitlab
module Auth
class IpRateLimiter
include ::Gitlab::Utils::StrongMemoize
attr_reader :ip
def initialize(ip)
@ -37,7 +39,20 @@ module Gitlab
end
def ip_can_be_banned?
config.ip_whitelist.exclude?(ip)
!trusted_ip?
end
def trusted_ip?
trusted_ips.any? { |netmask| netmask.include?(ip) }
end
def trusted_ips
strong_memoize(:trusted_ips) do
config.ip_whitelist.map do |proxy|
IPAddr.new(proxy)
rescue IPAddr::InvalidAddressError
end.compact
end
end
end
end

View File

@ -0,0 +1,65 @@
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Auth::IpRateLimiter, :use_clean_rails_memory_store_caching do
let(:ip) { '10.2.2.3' }
let(:whitelist) { ['127.0.0.1'] }
let(:options) do
{
enabled: true,
ip_whitelist: whitelist,
bantime: 1.minute,
findtime: 1.minute,
maxretry: 2
}
end
subject { described_class.new(ip) }
before do
stub_rack_attack_setting(options)
end
after do
subject.reset!
end
describe '#register_fail!' do
it 'bans after 3 consecutive failures' do
expect(subject.banned?).to be_falsey
3.times { subject.register_fail! }
expect(subject.banned?).to be_truthy
end
shared_examples 'whitelisted IPs' do
it 'does not ban after max retry limit' do
expect(subject.banned?).to be_falsey
3.times { subject.register_fail! }
expect(subject.banned?).to be_falsey
end
end
context 'with a whitelisted netmask' do
before do
options[:ip_whitelist] = ['127.0.0.1', '10.2.2.0/24', 'bad']
stub_rack_attack_setting(options)
end
it_behaves_like 'whitelisted IPs'
end
context 'with a whitelisted IP' do
before do
options[:ip_whitelist] = ['10.2.2.3']
stub_rack_attack_setting(options)
end
it_behaves_like 'whitelisted IPs'
end
end
end

View File

@ -95,6 +95,11 @@ module StubConfiguration
allow(Gitlab.config.gitlab_shell).to receive_messages(to_settings(messages))
end
def stub_rack_attack_setting(messages)
allow(Gitlab.config.rack_attack).to receive(:git_basic_auth).and_return(messages)
allow(Gitlab.config.rack_attack.git_basic_auth).to receive_messages(to_settings(messages))
end
private
# Modifies stubbed messages to also stub possible predicate versions