From 30f52ad3293445e82fb1d30d970d2caf3dc201fd Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Thu, 21 Feb 2019 07:38:03 +0000 Subject: [PATCH] Support SSL URL parameters correctly for rediss protocol (#1002) * fixed rediss url parsing * added ssl parameter test * added ssl parameter test * added ssl parameter test * added ssl parameter test * added ssl parameter test * added no ssl module parse_url test * added no ssl module parse_url test * added no ssl module parse_url test * convert to list comprehension * simulate no ssl in test * add missing logger --- kombu/utils/url.py | 23 +++++++++++++++++++++++ t/unit/utils/test_url.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/kombu/utils/url.py b/kombu/utils/url.py index c5ad8aef..0cae13c9 100644 --- a/kombu/utils/url.py +++ b/kombu/utils/url.py @@ -15,12 +15,19 @@ try: except ImportError: from urllib import quote, unquote # noqa from urlparse import urlparse, parse_qsl # noqa +try: + import ssl + ssl_available = True +except ImportError: # pragma: no cover + ssl_available = False from kombu.five import bytes_if_py2, string_t from .compat import NamedTuple +from ..log import get_logger safequote = partial(quote, safe=bytes_if_py2('')) +logger = get_logger(__name__) urlparts = NamedTuple('urlparts', [ @@ -38,6 +45,22 @@ def parse_url(url): # type: (str) -> Dict """Parse URL into mapping of components.""" scheme, host, port, user, password, path, query = _parse_url(url) + if query: + keys = [key for key in query.keys() if key.startswith('ssl_')] + for key in keys: + if key == 'ssl_cert_reqs': + if ssl_available: + query[key] = getattr(ssl, query[key]) + else: + query[key] = None + logger.warn('Defaulting to insecure SSL behaviour.') + + if 'ssl' not in query: + query['ssl'] = {} + + query['ssl'][key] = query[key] + del query[key] + return dict(transport=scheme, hostname=host, port=port, userid=user, password=password, virtual_host=path, **query) diff --git a/t/unit/utils/test_url.py b/t/unit/utils/test_url.py index 3d2b0ede..942426b4 100644 --- a/t/unit/utils/test_url.py +++ b/t/unit/utils/test_url.py @@ -1,7 +1,16 @@ from __future__ import absolute_import, unicode_literals +try: + from urllib.parse import urlencode + +except ImportError: + from urllib import urlencode + +import ssl + import pytest +import kombu.utils.url from kombu.utils.url import as_url, parse_url, maybe_sanitize_url @@ -37,3 +46,26 @@ def test_maybe_sanitize_url(url, expected): assert maybe_sanitize_url(url) == expected assert (maybe_sanitize_url('http://u:p@e.com//foo') == 'http://u:**@e.com//foo') + + +def test_ssl_parameters(): + url = 'rediss://user:password@host:6379/0?' + querystring = urlencode({ + 'ssl_cert_reqs': 'CERT_REQUIRED', + 'ssl_ca_certs': '/var/ssl/myca.pem', + 'ssl_certfile': '/var/ssl/server-cert.pem', + 'ssl_keyfile': '/var/ssl/priv/worker-key.pem', + }) + kwargs = parse_url(url + querystring) + assert kwargs['transport'] == 'rediss' + assert kwargs['ssl']['ssl_cert_reqs'] == ssl.CERT_REQUIRED + assert kwargs['ssl']['ssl_ca_certs'] == '/var/ssl/myca.pem' + assert kwargs['ssl']['ssl_certfile'] == '/var/ssl/server-cert.pem' + assert kwargs['ssl']['ssl_keyfile'] == '/var/ssl/priv/worker-key.pem' + + kombu.utils.url.ssl_available = False + + kwargs = parse_url(url + querystring) + assert kwargs['ssl']['ssl_cert_reqs'] is None + + kombu.utils.url.ssl_available = True