diff options
author | rpereira2 <rpereira@gitlab.com> | 2019-07-09 16:42:24 +0530 |
---|---|---|
committer | rpereira2 <rpereira@gitlab.com> | 2019-07-24 12:43:07 +0530 |
commit | cc0ea991edfcf1ba0a159230bbc102e1d6bb718f (patch) | |
tree | 4f2bfedfa920f2c3dfe6c5496eb711ce9c719569 | |
parent | cfcde04d9eb43eea2bbf7cef09cd3caff2df7c05 (diff) | |
download | gitlab-ce-cc0ea991edfcf1ba0a159230bbc102e1d6bb718f.tar.gz |
Allow ip ranges in local requests whitelist
- Use IPAddr to test if ips belong to a whitelisted ip or range.
-rw-r--r-- | app/helpers/application_settings_helper.rb | 1 | ||||
-rw-r--r-- | app/models/application_setting.rb | 6 | ||||
-rw-r--r-- | app/models/application_setting_implementation.rb | 66 | ||||
-rw-r--r-- | app/views/admin/application_settings/_outbound.html.haml | 9 | ||||
-rw-r--r-- | changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml | 3 | ||||
-rw-r--r-- | config/initializers/1_settings.rb | 1 | ||||
-rw-r--r-- | db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb | 6 | ||||
-rw-r--r-- | doc/api/settings.md | 6 | ||||
-rw-r--r-- | lib/gitlab/url_blocker.rb | 21 | ||||
-rw-r--r-- | lib/gitlab/utils.rb | 7 | ||||
-rw-r--r-- | locale/gitlab.pot | 3 | ||||
-rw-r--r-- | spec/lib/gitlab/url_blocker_spec.rb | 145 | ||||
-rw-r--r-- | spec/lib/gitlab/utils_spec.rb | 19 | ||||
-rw-r--r-- | spec/support/shared_examples/application_setting_examples.rb | 111 |
14 files changed, 264 insertions, 140 deletions
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 4bf9b708401..3847a35fbab 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -177,6 +177,7 @@ module ApplicationSettingsHelper :domain_blacklist_enabled, :domain_blacklist_raw, :domain_whitelist_raw, + :outbound_local_requests_whitelist_raw, :dsa_key_restriction, :ecdsa_key_restriction, :ed25519_key_restriction, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 9347d82e9e5..af55f86aa0b 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -19,7 +19,7 @@ class ApplicationSetting < ApplicationRecord serialize :restricted_visibility_levels # rubocop:disable Cop/ActiveRecordSerialize serialize :import_sources # rubocop:disable Cop/ActiveRecordSerialize serialize :disabled_oauth_sign_in_sources, Array # rubocop:disable Cop/ActiveRecordSerialize - serialize :outbound_requests_whitelist, Array # rubocop:disable Cop/ActiveRecordSerialize + serialize :outbound_local_requests_whitelist, Array # rubocop:disable Cop/ActiveRecordSerialize serialize :domain_whitelist, Array # rubocop:disable Cop/ActiveRecordSerialize serialize :domain_blacklist, Array # rubocop:disable Cop/ActiveRecordSerialize serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize @@ -118,10 +118,6 @@ class ApplicationSetting < ApplicationRecord validates :enabled_git_access_protocol, inclusion: { in: %w(ssh http), allow_blank: true, allow_nil: true } - validates :outbound_requests_whitelist, - presence: { message: 'Outbound requests whitelist cannot be activated if local requests from hooks and services is enabled.' }, - if: :allow_local_requests_from_hooks_and_services? - validates :domain_blacklist, presence: { message: 'Domain blacklist cannot be empty if Blacklist is enabled.' }, if: :domain_blacklist_enabled? diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index d80777fba0f..1fec62c5cd2 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -2,6 +2,7 @@ module ApplicationSettingImplementation extend ActiveSupport::Concern + include Gitlab::Utils::StrongMemoize DOMAIN_LIST_SEPARATOR = %r{\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace | # or @@ -97,7 +98,7 @@ module ApplicationSettingImplementation commit_email_hostname: default_commit_email_hostname, protected_ci_variables: false, local_markdown_version: 0, - outbound_requests_whitelist: Settings.gitlab['outbound_requests_whitelist'] + outbound_local_requests_whitelist: [] } end @@ -131,52 +132,51 @@ module ApplicationSettingImplementation super(sources) end - def outbound_requests_whitelist_raw - self.outbound_requests_whitelist&.join("\n") - end - - def outbound_requests_whitelist_raw=(values) - self.outbound_requests_whitelist = [] - self.outbound_requests_whitelist = values.split(DOMAIN_LIST_SEPARATOR) - self.outbound_requests_whitelist.reject! { |d| d.empty? } - self.outbound_requests_whitelist - end - def domain_whitelist_raw - self.domain_whitelist&.join("\n") + array_to_string(self.domain_whitelist) end def domain_blacklist_raw - self.domain_blacklist&.join("\n") + array_to_string(self.domain_blacklist) end def domain_whitelist_raw=(values) - self.domain_whitelist = [] - self.domain_whitelist = values.split(DOMAIN_LIST_SEPARATOR) - self.domain_whitelist.reject! { |d| d.empty? } - self.domain_whitelist + self.domain_whitelist = domain_strings_to_array(values) end def domain_blacklist_raw=(values) - self.domain_blacklist = [] - self.domain_blacklist = values.split(DOMAIN_LIST_SEPARATOR) - self.domain_blacklist.reject! { |d| d.empty? } - self.domain_blacklist + self.domain_blacklist = domain_strings_to_array(values) end def domain_blacklist_file=(file) self.domain_blacklist_raw = file.read end - def outbound_requests_whitelist_raw - self.outbound_requests_whitelist = string_to_array(values) + def outbound_local_requests_whitelist_raw + array_to_string(self.outbound_local_requests_whitelist) end - def outbound_requests_whitelist_raw=(values) - self.outbound_requests_whitelist = [] - self.outbound_requests_whitelist = values.split(DOMAIN_LIST_SEPARATOR) - self.outbound_requests_whitelist.reject! { |d| d.empty? } - self.outbound_requests_whitelist + def outbound_local_requests_whitelist_raw=(values) + self.outbound_local_requests_whitelist = domain_strings_to_array(values) + end + + def outbound_local_requests_whitelist_arrays + strong_memoize(:outbound_local_requests_whitelist_arrays) do + ip_whitelist = [] + domain_whitelist = [] + + self.outbound_local_requests_whitelist.each do |str| + ip_obj = Gitlab::Utils.string_to_ip_object(str) + + if ip_obj + ip_whitelist << ip_obj + else + domain_whitelist << str + end + end + + [ip_whitelist, domain_whitelist] + end end def repository_storages @@ -278,6 +278,14 @@ module ApplicationSettingImplementation private + def array_to_string(arr) + arr&.join("\n") + end + + def domain_strings_to_array(values) + values.split(DOMAIN_LIST_SEPARATOR).reject(&:empty?) + end + def ensure_uuid! return if uuid? diff --git a/app/views/admin/application_settings/_outbound.html.haml b/app/views/admin/application_settings/_outbound.html.haml index c302b042a95..255c2803cad 100644 --- a/app/views/admin/application_settings/_outbound.html.haml +++ b/app/views/admin/application_settings/_outbound.html.haml @@ -8,9 +8,12 @@ = f.label :allow_local_requests_from_hooks_and_services, class: 'form-check-label' do Allow requests to the local network from hooks and services - = f.label :web_hook_uri_whitelist, class: 'label-bold' do - URI of trusted services for web hook integrations - = f.text_field :web_hook_uri_whitelist, placeholder: "example.com,192.168.1.1", class: 'form-control' + .form-group + = f.label :outbound_local_requests_whitelist_raw, class: 'label-bold' do + Whitelist to allow requests to the local network from hooks and services + = f.text_area :outbound_local_requests_whitelist_raw, placeholder: "example.com, 192.168.1.1", class: 'form-control', rows: 8 + %span.form-text.text-muted + = _('Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are disabled. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. Ex: domain.com, 192.168.1.1, 127.0.0.0/28') .form-group .form-check diff --git a/changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml b/changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml index 41305aa160e..9b50175f536 100644 --- a/changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml +++ b/changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml @@ -1,6 +1,5 @@ --- title: Add Outbound requests whitelist for local networks -merge_request: 21377 +merge_request: 30350 author: Istvan Szalai type: added - diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 64a004ac620..494c4dd1f93 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -197,7 +197,6 @@ Settings.gitlab.default_projects_features['snippets'] = true if Settin Settings.gitlab.default_projects_features['builds'] = true if Settings.gitlab.default_projects_features['builds'].nil? Settings.gitlab.default_projects_features['container_registry'] = true if Settings.gitlab.default_projects_features['container_registry'].nil? Settings.gitlab.default_projects_features['visibility_level'] = Settings.__send__(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE) -Settings.gitlab['outbound_requests_whitelist'] ||= [] Settings.gitlab['domain_whitelist'] ||= [] Settings.gitlab['import_sources'] ||= Gitlab::ImportSources.values Settings.gitlab['trusted_proxies'] ||= [] diff --git a/db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb b/db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb index f43a9c19048..c0c1bde0a1e 100644 --- a/db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb +++ b/db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb @@ -1,9 +1,9 @@ -class AddOutboundRequestsWhitelistToApplicationSettings < ActiveRecord::Migration +# frozen_string_literal: true - # Set this constant to true if this migration requires downtime. +class AddOutboundRequestsWhitelistToApplicationSettings < ActiveRecord::Migration[5.1] DOWNTIME = false def change - add_column :application_settings, :outbound_requests_whitelist, :text + add_column :application_settings, :outbound_local_requests_whitelist, :text end end diff --git a/doc/api/settings.md b/doc/api/settings.md index 695eff1dad0..68da88af698 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -39,7 +39,7 @@ Example response: "session_expire_delay" : 10080, "home_page_url" : null, "default_snippet_visibility" : "private", - "outbound_requests_whitelist": [], + "outbound_local_requests_whitelist": [], "domain_whitelist" : [], "domain_blacklist_enabled" : false, "domain_blacklist" : [], @@ -114,7 +114,7 @@ Example response: "default_project_visibility": "internal", "default_snippet_visibility": "private", "default_group_visibility": "private", - "outbound_requests_whitelist": [], + "outbound_local_requests_whitelist": [], "domain_whitelist": [], "domain_blacklist_enabled" : false, "domain_blacklist" : [], @@ -195,7 +195,7 @@ are listed in the descriptions of the relevant settings. | `domain_blacklist` | array of strings | required by: `domain_blacklist_enabled` | Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: `domain.com`, `*.domain.com`. | | `domain_blacklist_enabled` | boolean | no | (**If enabled, requires:** `domain_blacklist`) Allows blocking sign-ups from emails from specific domains. | | `domain_whitelist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is `null`, meaning there is no restriction. | -| `outbound_requests_whitelist` | array of strings | no | Define a list of trusted domains or ip addresses for outbound requests. +| `outbound_local_requests_whitelist` | array of strings | no | Define a list of trusted domains or ip addresses to which local requests are allowed when local requests for hooks and services are disabled. | `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. | | `ecdsa_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA key. Default is `0` (no restriction). `-1` disables ECDSA keys. | | `ed25519_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ED25519 key. Default is `0` (no restriction). `-1` disables ED25519 keys. | diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb index 8732e5dec09..174abfb9415 100644 --- a/lib/gitlab/url_blocker.rb +++ b/lib/gitlab/url_blocker.rb @@ -57,6 +57,8 @@ module Gitlab return protected_uri_with_hostname if internal?(uri) validate_local_request( + uri: protected_uri_with_hostname[0], + hostname: protected_uri_with_hostname[1], address_info: address_info, allow_localhost: allow_localhost, allow_local_network: allow_local_network @@ -113,9 +115,12 @@ module Gitlab rescue SocketError end - def validate_local_request(address_info:, allow_localhost:, allow_local_network:) + def validate_local_request(uri:, hostname:, address_info:, allow_localhost:, allow_local_network:) return if allow_local_network && allow_localhost + return if local_request_whitelisted?(uri.host) || + local_request_whitelisted?(hostname) + unless allow_localhost validate_localhost(address_info) validate_loopback(address_info) @@ -231,8 +236,18 @@ module Gitlab (uri.port.blank? || uri.port == config.gitlab_shell.ssh_port) end - def whitelisted?(uri) - config.gitlab.outbound_requests_whitelist.include?(uri) + def local_request_whitelisted?(str) + ip_obj = Gitlab::Utils.string_to_ip_object(str) + + ip_whitelist, domain_whitelist = Gitlab::CurrentSettings.outbound_local_requests_whitelist_arrays + + if ip_obj + return true if ip_whitelist.any? { |ip| ip.include?(ip_obj) } + else + return true if domain_whitelist.include?(str) + end + + false end def config diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb index 16ec8a8bb28..31c9e18c996 100644 --- a/lib/gitlab/utils.rb +++ b/lib/gitlab/utils.rb @@ -131,5 +131,12 @@ module Gitlab data end end + + def string_to_ip_object(str) + return unless str + + IPAddr.new(str) + rescue IPAddr::InvalidAddressError + end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 833c8c9fe11..60d7e3865f9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8994,6 +8994,9 @@ msgstr "" msgid "Requests Profiles" msgstr "" +msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are disabled. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. Ex: domain.com, 192.168.1.1, 127.0.0.0/28" +msgstr "" + msgid "Require all users in this group to setup Two-factor authentication" msgstr "" diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb index f8b0cbfb6f6..fb83b9510f5 100644 --- a/spec/lib/gitlab/url_blocker_spec.rb +++ b/spec/lib/gitlab/url_blocker_spec.rb @@ -220,53 +220,53 @@ describe Gitlab::UrlBlocker do end let(:fake_domain) { 'www.fakedomain.fake' } - context 'true (default)' do + shared_examples 'allows local requests' do |url_blocker_attributes| it 'does not block urls from private networks' do local_ips.each do |ip| - stub_domain_resolv(fake_domain, ip) - - expect(described_class).not_to be_blocked_url("http://#{fake_domain}") - - unstub_domain_resolv + stub_domain_resolv(fake_domain, ip) do + expect(described_class).not_to be_blocked_url("http://#{fake_domain}", url_blocker_attributes) + end - expect(described_class).not_to be_blocked_url("http://#{ip}") + expect(described_class).not_to be_blocked_url("http://#{ip}", url_blocker_attributes) end end it 'allows localhost endpoints' do - expect(described_class).not_to be_blocked_url('http://0.0.0.0', allow_localhost: true) - expect(described_class).not_to be_blocked_url('http://localhost', allow_localhost: true) - expect(described_class).not_to be_blocked_url('http://127.0.0.1', allow_localhost: true) + expect(described_class).not_to be_blocked_url('http://0.0.0.0', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://localhost', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://127.0.0.1', url_blocker_attributes) end it 'allows loopback endpoints' do - expect(described_class).not_to be_blocked_url('http://127.0.0.2', allow_localhost: true) + expect(described_class).not_to be_blocked_url('http://127.0.0.2', url_blocker_attributes) end it 'allows IPv4 link-local endpoints' do - expect(described_class).not_to be_blocked_url('http://169.254.169.254') - expect(described_class).not_to be_blocked_url('http://169.254.168.100') + expect(described_class).not_to be_blocked_url('http://169.254.169.254', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://169.254.168.100', url_blocker_attributes) end it 'allows IPv6 link-local endpoints' do - expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.169.254]') - expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.169.254]') - expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a9fe]') - expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.168.100]') - expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.168.100]') - expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a864]') - expect(described_class).not_to be_blocked_url('http://[fe80::c800:eff:fe74:8]') + expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.169.254]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.169.254]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a9fe]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.168.100]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.168.100]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a864]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[fe80::c800:eff:fe74:8]', url_blocker_attributes) end end + context 'true (default)' do + it_behaves_like 'allows local requests', { allow_localhost: true, allow_local_network: true } + end + context 'false' do it 'blocks urls from private networks' do local_ips.each do |ip| - stub_domain_resolv(fake_domain, ip) - - expect(described_class).to be_blocked_url("http://#{fake_domain}", allow_local_network: false) - - unstub_domain_resolv + stub_domain_resolv(fake_domain, ip) do + expect(described_class).to be_blocked_url("http://#{fake_domain}", allow_local_network: false) + end expect(described_class).to be_blocked_url("http://#{ip}", allow_local_network: false) end @@ -286,15 +286,104 @@ describe Gitlab::UrlBlocker do expect(described_class).to be_blocked_url('http://[::ffff:a9fe:a864]', allow_local_network: false) expect(described_class).to be_blocked_url('http://[fe80::c800:eff:fe74:8]', allow_local_network: false) end + + context 'when local url/ip is whitelisted' do + before do + Gitlab::CurrentSettings.outbound_local_requests_whitelist = whitelist + end + + context 'with IPs in whitelist' do + let(:whitelist) do + [ + '0.0.0.0', + '127.0.0.1', + '127.0.0.2', + '192.168.1.2', + '0:0:0:0:0:ffff:192.168.1.2', + '::ffff:c0a8:102', + '10.0.0.2', + '0:0:0:0:0:ffff:10.0.0.2', + '::ffff:a00:2', + '172.16.0.2', + '0:0:0:0:0:ffff:172.16.0.2', + '::ffff:ac10:20', + 'feef::1', + 'fee2::', + 'fc00:bf8b:e62c:abcd:abcd:aaaa:aaaa:aaaa', + '0:0:0:0:0:ffff:169.254.169.254', + '::ffff:a9fe:a9fe', + '::ffff:169.254.168.100', + '::ffff:a9fe:a864', + 'fe80::c800:eff:fe74:8' + ] + end + + it_behaves_like 'allows local requests', { allow_localhost: false, allow_local_network: false } + end + + context 'with domains in whitelist' do + let(:whitelist) do + [ + 'www.example.com', + 'example.com' + ] + end + + it 'allows domains present in whitelist' do + domain = 'example.com' + subdomain1 = 'www.example.com' + subdomain2 = 'subdomain.example.com' + + stub_domain_resolv(domain, '192.168.1.1') do + expect(described_class).not_to be_blocked_url("http://#{domain}", + { allow_localhost: false, allow_local_network: false }) + end + + stub_domain_resolv(subdomain1, '192.168.1.1') do + expect(described_class).not_to be_blocked_url("http://#{subdomain1}", + { allow_localhost: false, allow_local_network: false }) + end + + # subdomain2 is not part of the whitelist so it should be blocked + stub_domain_resolv(subdomain2, '192.168.1.1') do + expect(described_class).to be_blocked_url("http://#{subdomain2}", + { allow_localhost: false, allow_local_network: false }) + end + end + end + + context 'with ip ranges in whitelist' do + let(:whitelist) do + [ + '127.0.0.0/28', + '1:0:0:0:0:0:0:0/124' + ] + end + + it 'allows all ipv4s in the range' do + IPAddr.new("127.0.0.0/28").to_range.to_a.each do |ip| + expect(described_class).not_to be_blocked_url("http://#{ip}", + { allow_localhost: false, allow_local_network: false }) + end + end + + it 'allows all ipv6s in the range' do + IPAddr.new("1:0:0:0:0:0:0:0/124").to_range.to_a.each do |ip| + expect(described_class).not_to be_blocked_url("http://[#{ip}]", + { allow_localhost: false, allow_local_network: false }) + end + end + end + end end - def stub_domain_resolv(domain, ip) + def stub_domain_resolv(domain, ip, &block) address = double(ip_address: ip, ipv4_private?: true, ipv6_link_local?: false, ipv4_loopback?: false, ipv6_loopback?: false, ipv4?: false) allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([address]) allow(address).to receive(:ipv6_v4mapped?).and_return(false) - end - def unstub_domain_resolv + yield + allow(Addrinfo).to receive(:getaddrinfo).and_call_original end end diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb index 4645339f439..0c20b3aa4c8 100644 --- a/spec/lib/gitlab/utils_spec.rb +++ b/spec/lib/gitlab/utils_spec.rb @@ -231,4 +231,23 @@ describe Gitlab::Utils do end end end + + describe '.string_to_ip_object' do + it 'returns nil when string is nil' do + expect(described_class.string_to_ip_object(nil)).to eq(nil) + end + + it 'returns nil when string is invalid IP' do + expect(described_class.string_to_ip_object('invalid ip')).to eq(nil) + expect(described_class.string_to_ip_object('')).to eq(nil) + end + + it 'returns IP object when string is valid IP' do + expect(described_class.string_to_ip_object('192.168.1.1')).to eq(IPAddr.new('192.168.1.1')) + expect(described_class.string_to_ip_object('::ffff:a9fe:a864')).to eq(IPAddr.new('::ffff:a9fe:a864')) + expect(described_class.string_to_ip_object('[::ffff:a9fe:a864]')).to eq(IPAddr.new('::ffff:a9fe:a864')) + expect(described_class.string_to_ip_object('127.0.0.0/28')).to eq(IPAddr.new('127.0.0.0/28')) + expect(described_class.string_to_ip_object('1:0:0:0:0:0:0:0/124')).to eq(IPAddr.new('1:0:0:0:0:0:0:0/124')) + end + end end diff --git a/spec/support/shared_examples/application_setting_examples.rb b/spec/support/shared_examples/application_setting_examples.rb index 1fcc304e941..cdc4774645a 100644 --- a/spec/support/shared_examples/application_setting_examples.rb +++ b/spec/support/shared_examples/application_setting_examples.rb @@ -1,84 +1,69 @@ # frozen_string_literal: true -RSpec.shared_examples 'application settings examples' do - context 'restricted signup domains' do - it 'sets single domain' do - setting.domain_whitelist_raw = 'example.com' - expect(setting.domain_whitelist).to eq(['example.com']) - end - - it 'sets multiple domains with spaces' do - setting.domain_whitelist_raw = 'example.com *.example.com' - expect(setting.domain_whitelist).to eq(['example.com', '*.example.com']) - end +RSpec.shared_examples 'string of domains' do |attribute| + it 'sets single domain' do + setting.method("#{attribute}_raw=").call('example.com') + expect(setting.method(attribute).call).to eq(['example.com']) + end - it 'sets multiple domains with newlines and a space' do - setting.domain_whitelist_raw = "example.com\n *.example.com" - expect(setting.domain_whitelist).to eq(['example.com', '*.example.com']) - end + it 'sets multiple domains with spaces' do + setting.method("#{attribute}_raw=").call('example.com *.example.com') + expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) + end - it 'sets multiple domains with commas' do - setting.domain_whitelist_raw = "example.com, *.example.com" - expect(setting.domain_whitelist).to eq(['example.com', '*.example.com']) - end + it 'sets multiple domains with newlines and a space' do + setting.method("#{attribute}_raw=").call("example.com\n *.example.com") + expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) end - context 'restricted outbound requests domain' do - it 'sets outbound requests domain' do - setting.outbound_requests_whitelist_raw = 'example.com' - expect(setting.outbound_requests_whitelist).to eq(['example.com']) - end + it 'sets multiple domains with commas' do + setting.method("#{attribute}_raw=").call("example.com, *.example.com") + expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) + end - it 'sets multiple outbound requests domain with spaces' do - setting.outbound_requests_whitelist_raw = 'example.com *.example.com' - expect(setting.outbound_requests_whitelist).to eq(['example.com', '*.example.com']) - end + it 'sets multiple domains with semicolon' do + setting.method("#{attribute}_raw=").call("example.com; *.example.com") + expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com') + end - it 'sets multiple outbound requests domains with newlines and a space' do - setting.outbound_requests_whitelist_raw = "example.com\n *.example.com" - expect(setting.outbound_requests_whitelist).to eq(['example.com', '*.example.com']) - end + it 'sets multiple domains with mixture of everything' do + setting.method("#{attribute}_raw=").call("example.com; *.example.com\n test.com\sblock.com yes.com") + expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com') + end +end - it 'sets multiple outbound requests domains with commas' do - setting.outbound_requests_whitelist_raw = "example.com, *.example.com" - expect(setting.outbound_requests_whitelist).to eq(['example.com', '*.example.com']) - end +RSpec.shared_examples 'application settings examples' do + context 'restricted signup domains' do + it_behaves_like 'string of domains', :domain_whitelist end context 'blacklisted signup domains' do - it 'sets single domain' do - setting.domain_blacklist_raw = 'example.com' - expect(setting.domain_blacklist).to contain_exactly('example.com') - end - - it 'sets multiple domains with spaces' do - setting.domain_blacklist_raw = 'example.com *.example.com' - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') - end + it_behaves_like 'string of domains', :domain_blacklist - it 'sets multiple domains with newlines and a space' do - setting.domain_blacklist_raw = "example.com\n *.example.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') + it 'sets multiple domain with file' do + setting.domain_blacklist_file = File.open(Rails.root.join('spec/fixtures/', 'domain_blacklist.txt')) + expect(setting.domain_blacklist).to contain_exactly('example.com', 'test.com', 'foo.bar') end + end - it 'sets multiple domains with commas' do - setting.domain_blacklist_raw = "example.com, *.example.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') - end + context 'outbound_local_requests_whitelist' do + it_behaves_like 'string of domains', :outbound_local_requests_whitelist + end - it 'sets multiple domains with semicolon' do - setting.domain_blacklist_raw = "example.com; *.example.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') - end + context 'outbound_local_requests_whitelist_arrays' do + it 'separates the IPs and domains' do + setting.outbound_local_requests_whitelist = [ + '192.168.1.1', '127.0.0.0/28', 'www.example.com', 'example.com', + '::ffff:a00:2', '1:0:0:0:0:0:0:0/124', 'subdomain.example.com' + ] - it 'sets multiple domains with mixture of everything' do - setting.domain_blacklist_raw = "example.com; *.example.com\n test.com\sblock.com yes.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com') - end + ip_whitelist = [ + IPAddr.new('192.168.1.1'), IPAddr.new('127.0.0.0/8'), + IPAddr.new('::ffff:a00:2'), IPAddr.new('1:0:0:0:0:0:0:0/124') + ] + domain_whitelist = ['www.example.com', 'example.com', 'subdomain.example.com'] - it 'sets multiple domain with file' do - setting.domain_blacklist_file = File.open(Rails.root.join('spec/fixtures/', 'domain_blacklist.txt')) - expect(setting.domain_blacklist).to contain_exactly('example.com', 'test.com', 'foo.bar') + expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(ip_whitelist, domain_whitelist) end end |