From c66957bbe9ead62e625156e632595cd7886b341d Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Mon, 6 Feb 2017 09:40:10 +0300 Subject: [PATCH] Add support for named constants in the --ssl-version flag Fixes #1114 Co-Authored-By: Brett Randall Signed-off-by: Brett Randall --- THANKS | 1 + gunicorn/config.py | 43 +++++++++++++++++++++++++++++++++++++++++-- tests/test_config.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/THANKS b/THANKS index 5a19a83f..8f0c944a 100644 --- a/THANKS +++ b/THANKS @@ -31,6 +31,7 @@ Berker Peksag bninja Bob Hagemann Bobby Beckmann +Brett Randall Brian Rosner Bruno Bigras Caleb Brown diff --git a/gunicorn/config.py b/gunicorn/config.py index 59524316..e14161b6 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -344,6 +344,28 @@ def validate_pos_int(val): return val +def validate_ssl_version(val): + ssl_versions = {} + for protocol in [p for p in dir(ssl) if p.startswith("PROTOCOL_")]: + ssl_versions[protocol[9:]] = getattr(ssl, protocol) + if val in ssl_versions: + # string matching PROTOCOL_... + return ssl_versions[val] + + try: + intval = validate_pos_int(val) + if intval in ssl_versions.values(): + # positive int matching a protocol int constant + return intval + except (ValueError, TypeError): + # negative integer or not an integer + # drop this in favour of the more descriptive ValueError below + pass + + raise ValueError("Invalid ssl_version: %s. Valid options: %s" + % (val, ', '.join(ssl_versions))) + + def validate_string(val): if val is None: return None @@ -1861,14 +1883,31 @@ class SSLVersion(Setting): name = "ssl_version" section = "SSL" cli = ["--ssl-version"] - validator = validate_pos_int + validator = validate_ssl_version default = ssl.PROTOCOL_SSLv23 desc = """\ - SSL version to use (see stdlib ssl module's) + SSL version to use. + + ============= ============ + --ssl-version Description + ============= ============ + SSLv3 SSLv3 is not-secure and is strongly discouraged. + SSLv23 Alias for TLS. Deprecated in Python 3.6, use TLS. + TLS Negotiate highest possible version between client/server. + Can yield SSL. (Python 3.6+) + TLSv1 TLS 1.0 + TLSv1_1 TLS 1.1 (Python 3.4+) + TLSv2 TLS 1.2 (Python 3.4+) + TLS_SERVER Auto-negotiate the highest protocol version like TLS, + but only support server-side SSLSocket connections. + (Python 3.6+) .. versionchanged:: 19.7 The default value has been changed from ``ssl.PROTOCOL_TLSv1`` to ``ssl.PROTOCOL_SSLv23``. + .. versionchanged:: 20.0 + This setting now accepts string names based on ``ssl.PROTOCOL_`` + constants. """ class CertReqs(Setting): diff --git a/tests/test_config.py b/tests/test_config.py index 714d2926..2d009088 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -386,3 +386,46 @@ def test_umask_config(options, expected): with AltArgs(cmdline): app = NoConfigApp() assert app.cfg.umask == expected + + +@pytest.mark.parametrize("options, expected", [ + (["--ssl-version", "SSLv23"], 2), + (["--ssl-version", "TLSv1"], 3), + (["--ssl-version", "2"], 2), + (["--ssl-version", "3"], 3), +]) +def test_ssl_version_named_constants_python3(options, expected): + _test_ssl_version(options, expected) + + +@pytest.mark.skipif(sys.version_info < (3, 6), + reason="requires python3.6+") +@pytest.mark.parametrize("options, expected", [ + (["--ssl-version", "TLS"], 2), + (["--ssl-version", "TLSv1_1"], 4), + (["--ssl-version", "TLSv1_2"], 5), + (["--ssl-version", "TLS_SERVER"], 17), +]) +def test_ssl_version_named_constants_python36(options, expected): + _test_ssl_version(options, expected) + + +@pytest.mark.parametrize("ssl_version", [ + "FOO", + "-99", + "99991234" +]) +def test_ssl_version_bad(ssl_version): + c = config.Config() + with pytest.raises(ValueError) as exc: + c.set("ssl_version", ssl_version) + assert 'Valid options' in str(exc.value) + assert "TLSv" in str(exc.value) + + +def _test_ssl_version(options, expected): + cmdline = ["prog_name"] + cmdline.extend(options) + with AltArgs(cmdline): + app = NoConfigApp() + assert app.cfg.ssl_version == expected