Skip to content

Commit 07a5fac

Browse files
committed
Rename existing runner parameter from "hosts_blacklist" to
"url_hosts_blacklist" and also add support for whitelist approach using "url_hosts_whitelist" runner parameter.
1 parent cd5fb03 commit 07a5fac

File tree

3 files changed

+118
-18
lines changed

3 files changed

+118
-18
lines changed

contrib/runners/http_runner/http_runner/http_runner.py

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
RUNNER_VERIFY_SSL_CERT = 'verify_ssl_cert'
5858
RUNNER_USERNAME = 'username'
5959
RUNNER_PASSWORD = 'password'
60-
RUNNER_HOSTS_BLACKLIST = 'hosts_blacklist'
60+
RUNNER_URL_HOSTS_BLACKLIST = 'url_hosts_blacklist'
61+
RUNNER_URL_HOSTS_WHITELIST = 'url_hosts_whitelist'
6162

6263
# Lookup constants for action params
6364
ACTION_AUTH = 'auth'
@@ -96,11 +97,17 @@ def pre_run(self):
9697
self._http_proxy = self.runner_parameters.get(RUNNER_HTTP_PROXY, None)
9798
self._https_proxy = self.runner_parameters.get(RUNNER_HTTPS_PROXY, None)
9899
self._verify_ssl_cert = self.runner_parameters.get(RUNNER_VERIFY_SSL_CERT, None)
99-
self._hosts_blacklist = self.runner_parameters.get(RUNNER_HOSTS_BLACKLIST, [])
100+
self._url_hosts_blacklist = self.runner_parameters.get(RUNNER_URL_HOSTS_BLACKLIST, [])
101+
self._url_hosts_whitelist = self.runner_parameters.get(RUNNER_URL_HOSTS_WHITELIST, [])
100102

101103
def run(self, action_parameters):
102104
client = self._get_http_client(action_parameters)
103105

106+
if self._url_hosts_blacklist and self._url_hosts_whitelist:
107+
msg = ('"url_hosts_blacklist" and "url_hosts_whitelist" parameters are mutually '
108+
'exclusive. Only one should be provided.')
109+
raise ValueError(msg)
110+
104111
try:
105112
result = client.run()
106113
except requests.exceptions.Timeout as e:
@@ -152,7 +159,8 @@ def _get_http_client(self, action_parameters):
152159
timeout=timeout, allow_redirects=self._allow_redirects,
153160
proxies=proxies, files=files, verify=self._verify_ssl_cert,
154161
username=self._username, password=self._password,
155-
hosts_blacklist=self._hosts_blacklist)
162+
url_hosts_blacklist=self._url_hosts_blacklist,
163+
url_hosts_whitelist=self._url_hosts_whitelist)
156164

157165
@staticmethod
158166
def _get_result_status(status_code):
@@ -164,7 +172,7 @@ class HTTPClient(object):
164172
def __init__(self, url=None, method=None, body='', params=None, headers=None, cookies=None,
165173
auth=None, timeout=60, allow_redirects=False, proxies=None,
166174
files=None, verify=False, username=None, password=None,
167-
hosts_blacklist=None):
175+
url_hosts_blacklist=None, url_hosts_whitelist=None):
168176
if url is None:
169177
raise Exception('URL must be specified.')
170178

@@ -194,7 +202,8 @@ def __init__(self, url=None, method=None, body='', params=None, headers=None, co
194202
self.verify = verify
195203
self.username = username
196204
self.password = password
197-
self.hosts_blacklist = hosts_blacklist or []
205+
self.url_hosts_blacklist = url_hosts_blacklist or []
206+
self.url_hosts_whitelist = url_hosts_whitelist or []
198207

199208
def run(self):
200209
results = {}
@@ -207,6 +216,11 @@ def run(self):
207216
if is_url_blacklisted:
208217
raise ValueError('URL "%s" is blacklisted' % (self.url))
209218

219+
is_url_whitelisted = self._is_url_whitelisted(url=self.url)
220+
221+
if not is_url_whitelisted:
222+
raise ValueError('URL "%s" is not whitelisted' % (self.url))
223+
210224
try:
211225
if json_content:
212226
# cast params (body) to dict
@@ -316,24 +330,46 @@ def _cast_object(self, value):
316330

317331
def _is_url_blacklisted(self, url):
318332
"""
319-
Verify if the provided URL is blacklisted via hosts_blacklist runner parameter.
333+
Verify if the provided URL is blacklisted via url_hosts_blacklist runner parameter.
320334
"""
321-
if not self.hosts_blacklist:
335+
if not self.url_hosts_blacklist:
322336
# Blacklist is empty
323337
return False
324338

339+
host = self._get_host_from_url(url=url)
340+
341+
if host in self.url_hosts_blacklist:
342+
return True
343+
344+
return False
345+
346+
def _is_url_whitelisted(self, url):
347+
"""
348+
Verify if the provided URL is whitelisted via url_hosts_whitelist runner parameter.
349+
"""
350+
if not self.url_hosts_whitelist:
351+
return True
352+
353+
host = self._get_host_from_url(url=url)
354+
355+
if host in self.url_hosts_whitelist:
356+
return True
357+
358+
return False
359+
360+
def _get_host_from_url(self, url):
361+
"""
362+
Return sanitized host (netloc) value from the provided url.
363+
"""
325364
parsed = urlparse.urlparse(url)
326365

327-
# Remove the port and []
366+
# Remove port and []
328367
host = parsed.netloc.replace('[', '').replace(']', '')
329368

330369
if parsed.port is not None:
331370
host = host.replace(':%s' % (parsed.port), '')
332371

333-
if host in self.hosts_blacklist:
334-
return True
335-
336-
return False
372+
return host
337373

338374

339375
def get_runner():

contrib/runners/http_runner/http_runner/runner.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,18 @@
3636
CA bundle which comes from Mozilla. Verification using a custom CA bundle
3737
is not yet supported. Set to False to skip verification.
3838
type: boolean
39-
hosts_blacklist:
39+
url_hosts_blacklist:
4040
description: Optional list of hosts (network locations) to blacklist (e.g. example.com,
41-
127.0.0.1, etc.)
41+
127.0.0.1, ::1, etc.). If action will try to access that endpoint, an exception will be
42+
thrown and action will be marked as failed.
43+
required: false
44+
type: array
45+
items:
46+
type: string
47+
url_hosts_whitelist:
48+
description: Optional list of hosts (network locations) to whitelist (e.g. example.com,
49+
127.0.0.1, ::1, etc.). If specified, actions will only be able to hit hosts on this
50+
whitelist.
4251
required: false
4352
type: array
4453
items:

contrib/runners/http_runner/tests/unit/test_http_runner.py

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def test_http_unicode_body_data(self, mock_requests):
216216
self.assertEqual(call_kwargs['data'], expected_data)
217217

218218
@mock.patch('http_runner.http_runner.requests')
219-
def test_blacklisted_url_netloc(self, mock_requests):
219+
def test_blacklisted_url_url_hosts_blacklist_runner_parameter(self, mock_requests):
220220
# Black list is empty
221221
self.assertEqual(mock_requests.request.call_count, 0)
222222

@@ -227,7 +227,7 @@ def test_blacklisted_url_netloc(self, mock_requests):
227227
self.assertEqual(mock_requests.request.call_count, 1)
228228

229229
# Blacklist is set
230-
hosts_blacklist = [
230+
url_hosts_blacklist = [
231231
'example.com',
232232
'127.0.0.1',
233233
'::1',
@@ -250,7 +250,7 @@ def test_blacklisted_url_netloc(self, mock_requests):
250250

251251
for url in urls:
252252
expected_msg = r'URL "%s" is blacklisted' % (re.escape(url))
253-
client = HTTPClient(url=url, method='GET', hosts_blacklist=hosts_blacklist)
253+
client = HTTPClient(url=url, method='GET', url_hosts_blacklist=url_hosts_blacklist)
254254
self.assertRaisesRegexp(ValueError, expected_msg, client.run)
255255

256256
# Non blacklisted URLs
@@ -265,7 +265,62 @@ def test_blacklisted_url_netloc(self, mock_requests):
265265

266266
self.assertEqual(mock_requests.request.call_count, 0)
267267

268-
client = HTTPClient(url=url, method='GET')
268+
client = HTTPClient(url=url, method='GET', url_hosts_blacklist=url_hosts_blacklist)
269+
client.run()
270+
271+
self.assertEqual(mock_requests.request.call_count, 1)
272+
273+
@mock.patch('http_runner.http_runner.requests')
274+
def test_whitelisted_url_url_hosts_whitelist_runner_parameter(self, mock_requests):
275+
# Whitelist is empty
276+
self.assertEqual(mock_requests.request.call_count, 0)
277+
278+
url = 'http://www.example.com'
279+
client = HTTPClient(url=url, method='GET')
280+
client.run()
281+
282+
self.assertEqual(mock_requests.request.call_count, 1)
283+
284+
# Whitelist is set
285+
url_hosts_whitelist = [
286+
'example.com',
287+
'127.0.0.1',
288+
'::1',
289+
'2001:0db8:85a3:0000:0000:8a2e:0370:7334'
290+
]
291+
292+
# Non whitelisted urls
293+
urls = [
294+
'https://www.google.com',
295+
'https://www.example2.com',
296+
'http://127.0.0.2'
297+
]
298+
299+
for url in urls:
300+
expected_msg = r'URL "%s" is not whitelisted' % (re.escape(url))
301+
client = HTTPClient(url=url, method='GET', url_hosts_whitelist=url_hosts_whitelist)
302+
self.assertRaisesRegexp(ValueError, expected_msg, client.run)
303+
304+
# Whitelisted URLS
305+
urls = [
306+
'https://example.com',
307+
'http://example.com',
308+
'http://example.com:81',
309+
'http://example.com:80',
310+
'http://example.com:9000',
311+
'http://[::1]:80/',
312+
'http://[::1]',
313+
'http://[::1]:9000',
314+
'http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]',
315+
'https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8000'
316+
]
317+
318+
for url in urls:
319+
mock_requests.request.reset_mock()
320+
321+
self.assertEqual(mock_requests.request.call_count, 0)
322+
323+
client = HTTPClient(url=url, method='GET', url_hosts_whitelist=url_hosts_whitelist)
269324
client.run()
270325

271326
self.assertEqual(mock_requests.request.call_count, 1)

0 commit comments

Comments
 (0)