Commit aa5253c7 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents b6269363 86a3d822
---
title: Allow not resolvable urls when dns rebind protection is disabled
merge_request: 32523
author:
type: fixed
...@@ -49,7 +49,7 @@ module Gitlab ...@@ -49,7 +49,7 @@ module Gitlab
hostname = uri.hostname hostname = uri.hostname
port = get_port(uri) port = get_port(uri)
address_info = get_address_info(hostname, port) address_info = get_address_info(hostname, port, dns_rebind_protection)
return [uri, nil] unless address_info return [uri, nil] unless address_info
ip_address = ip_address(address_info) ip_address = ip_address(address_info)
...@@ -110,11 +110,15 @@ module Gitlab ...@@ -110,11 +110,15 @@ module Gitlab
validate_unicode_restriction(uri) if ascii_only validate_unicode_restriction(uri) if ascii_only
end end
def get_address_info(hostname, port) def get_address_info(hostname, port, dns_rebind_protection)
Addrinfo.getaddrinfo(hostname, port, nil, :STREAM).map do |addr| Addrinfo.getaddrinfo(hostname, port, nil, :STREAM).map do |addr|
addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr
end end
rescue SocketError rescue SocketError
# If the dns rebinding protection is not enabled, we allow
# urls that can't be resolved at this point.
return unless dns_rebind_protection
# In the test suite we use a lot of mocked urls that are either invalid or # In the test suite we use a lot of mocked urls that are either invalid or
# don't exist. In order to avoid modifying a ton of tests and factories # don't exist. In order to avoid modifying a ton of tests and factories
# we allow invalid urls unless the environment variable RSPEC_ALLOW_INVALID_URLS # we allow invalid urls unless the environment variable RSPEC_ALLOW_INVALID_URLS
......
...@@ -4,80 +4,114 @@ ...@@ -4,80 +4,114 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::UrlBlocker do describe Gitlab::UrlBlocker do
include StubRequests
describe '#validate!' do describe '#validate!' do
subject { described_class.validate!(import_url) }
shared_examples 'validates URI and hostname' do
it 'runs the url validations' do
uri, hostname = subject
expect(uri).to eq(Addressable::URI.parse(expected_uri))
expect(hostname).to eq(expected_hostname)
end
end
context 'when URI is nil' do context 'when URI is nil' do
let(:import_url) { nil } let(:import_url) { nil }
it 'returns no URI and hostname' do it_behaves_like 'validates URI and hostname' do
uri, hostname = described_class.validate!(import_url) let(:expected_uri) { nil }
let(:expected_hostname) { nil }
expect(uri).to be(nil)
expect(hostname).to be(nil)
end end
end end
context 'when URI is internal' do context 'when URI is internal' do
let(:import_url) { 'http://localhost' } let(:import_url) { 'http://localhost' }
it 'returns URI and no hostname' do it_behaves_like 'validates URI and hostname' do
uri, hostname = described_class.validate!(import_url) let(:expected_uri) { 'http://[::1]' }
let(:expected_hostname) { 'localhost' }
expect(uri).to eq(Addressable::URI.parse('http://[::1]'))
expect(hostname).to eq('localhost')
end end
end end
context 'when the URL hostname is a domain' do context 'when the URL hostname is a domain' do
let(:import_url) { 'https://example.org' } context 'when domain can be resolved' do
let(:import_url) { 'https://example.org' }
it 'returns URI and hostname' do before do
uri, hostname = described_class.validate!(import_url) stub_dns(import_url, ip_address: '93.184.216.34')
end
expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34')) it_behaves_like 'validates URI and hostname' do
expect(hostname).to eq('example.org') let(:expected_uri) { 'https://93.184.216.34' }
let(:expected_hostname) { 'example.org' }
end
end
context 'when domain cannot be resolved' do
let(:import_url) { 'http://foobar.x' }
it 'raises an error' do
stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
expect { subject }.to raise_error(described_class::BlockedUrlError)
end
end end
end end
context 'when the URL hostname is an IP address' do context 'when the URL hostname is an IP address' do
let(:import_url) { 'https://93.184.216.34' } let(:import_url) { 'https://93.184.216.34' }
it 'returns URI and no hostname' do it_behaves_like 'validates URI and hostname' do
uri, hostname = described_class.validate!(import_url) let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
end
context 'when the address is invalid' do
let(:import_url) { 'http://1.1.1.1.1' }
expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34')) it 'raises an error' do
expect(hostname).to be(nil) stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
expect { subject }.to raise_error(described_class::BlockedUrlError)
end
end end
end end
context 'disabled DNS rebinding protection' do context 'disabled DNS rebinding protection' do
subject { described_class.validate!(import_url, dns_rebind_protection: false) }
context 'when URI is internal' do context 'when URI is internal' do
let(:import_url) { 'http://localhost' } let(:import_url) { 'http://localhost' }
it 'returns URI and no hostname' do it_behaves_like 'validates URI and hostname' do
uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false) let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
expect(uri).to eq(Addressable::URI.parse('http://localhost'))
expect(hostname).to be(nil)
end end
end end
context 'when the URL hostname is a domain' do context 'when the URL hostname is a domain' do
let(:import_url) { 'https://example.org' } let(:import_url) { 'https://example.org' }
it 'returns URI and no hostname' do before do
uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false) stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
end
expect(uri).to eq(Addressable::URI.parse('https://example.org')) context 'when domain can be resolved' do
expect(hostname).to eq(nil) it_behaves_like 'validates URI and hostname' do
let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
end
end end
context 'when it cannot be resolved' do context 'when domain cannot be resolved' do
let(:import_url) { 'http://foobar.x' } let(:import_url) { 'http://foobar.x' }
it 'raises error' do it_behaves_like 'validates URI and hostname' do
stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError)
end end
end end
end end
...@@ -85,20 +119,17 @@ describe Gitlab::UrlBlocker do ...@@ -85,20 +119,17 @@ describe Gitlab::UrlBlocker do
context 'when the URL hostname is an IP address' do context 'when the URL hostname is an IP address' do
let(:import_url) { 'https://93.184.216.34' } let(:import_url) { 'https://93.184.216.34' }
it 'returns URI and no hostname' do it_behaves_like 'validates URI and hostname' do
uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false) let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34'))
expect(hostname).to be(nil)
end end
context 'when it is invalid' do context 'when it is invalid' do
let(:import_url) { 'http://1.1.1.1.1' } let(:import_url) { 'http://1.1.1.1.1' }
it 'raises an error' do it_behaves_like 'validates URI and hostname' do
stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError)
end end
end end
end end
......
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