From d41d1609ae13010d2f524e31a802dd8c35bdaa73 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 15 Feb 2015 12:12:25 -0500 Subject: [PATCH] Update ssl_options docs to use SSLContext. Now that Python 2 has a modern SSL package, SSLContext can be presented as the default instead of the dictionary of options. Fixes #1322. --- tornado/httpserver.py | 18 +++++++++--------- tornado/httputil.py | 17 ++++++++--------- tornado/iostream.py | 17 +++++++++-------- tornado/netutil.py | 12 ++++++------ tornado/tcpserver.py | 17 +++++++++-------- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/tornado/httpserver.py b/tornado/httpserver.py index e470e0e7d..13a6e92fa 100644 --- a/tornado/httpserver.py +++ b/tornado/httpserver.py @@ -60,15 +60,15 @@ class HTTPServer(TCPServer, httputil.HTTPServerConnectionDelegate): if Tornado is run behind an SSL-decoding proxy that does not set one of the supported ``xheaders``. - To make this server serve SSL traffic, send the ``ssl_options`` dictionary - argument with the arguments required for the `ssl.wrap_socket` method, - including ``certfile`` and ``keyfile``. (In Python 3.2+ you can pass - an `ssl.SSLContext` object instead of a dict):: - - HTTPServer(applicaton, ssl_options={ - "certfile": os.path.join(data_dir, "mydomain.crt"), - "keyfile": os.path.join(data_dir, "mydomain.key"), - }) + To make this server serve SSL traffic, send the ``ssl_options`` keyword + argument with an `ssl.SSLContext` object. For compatibility with older + versions of Python ``ssl_options`` may also be a dictionary of keyword + arguments for the `ssl.wrap_socket` method.:: + + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"), + os.path.join(data_dir, "mydomain.key")) + HTTPServer(applicaton, ssl_options=ssl_ctx) `HTTPServer` initialization follows one of three patterns (the initialization methods are defined on `tornado.tcpserver.TCPServer`): diff --git a/tornado/httputil.py b/tornado/httputil.py index 21b170919..871ffaa7f 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -411,15 +411,14 @@ class HTTPServerRequest(object): def get_ssl_certificate(self, binary_form=False): """Returns the client's SSL certificate, if any. - To use client certificates, the HTTPServer must have been constructed - with cert_reqs set in ssl_options, e.g.:: - - server = HTTPServer(app, - ssl_options=dict( - certfile="foo.crt", - keyfile="foo.key", - cert_reqs=ssl.CERT_REQUIRED, - ca_certs="cacert.crt")) + To use client certificates, the HTTPServer's + `ssl.SSLContext.verify_mode` field must be set, e.g.:: + + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain("foo.crt", "foo.key") + ssl_ctx.load_verify_locations("cacerts.pem") + ssl_ctx.verify_mode = ssl.CERT_REQUIRED + server = HTTPServer(app, ssl_options=ssl_ctx) By default, the return value is a dictionary (or None, if no client certificate is present). If ``binary_form`` is true, a diff --git a/tornado/iostream.py b/tornado/iostream.py index 08701a0c5..2f0753fa8 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -1025,7 +1025,7 @@ class IOStream(BaseIOStream): If specified, the ``server_hostname`` parameter will be used in SSL connections for certificate validation (if requested in the ``ssl_options``) and SNI (if supported; requires - Python 3.2+). + Python 2.7.9+). Note that it is safe to call `IOStream.write ` while the connection is pending, in @@ -1078,10 +1078,11 @@ class IOStream(BaseIOStream): data. It can also be used immediately after connecting, before any reads or writes. - The ``ssl_options`` argument may be either a dictionary - of options or an `ssl.SSLContext`. If a ``server_hostname`` - is given, it will be used for certificate verification - (as configured in the ``ssl_options``). + The ``ssl_options`` argument may be either an `ssl.SSLContext` + object or a dictionary of keyword arguments for the + `ssl.wrap_socket` function. If a ``server_hostname`` is + given, it will be used for certificate verification (as + configured in the ``ssl_options``). This method returns a `.Future` whose result is the new `SSLIOStream`. After this method has been called, @@ -1179,9 +1180,9 @@ class SSLIOStream(IOStream): wrapped when `IOStream.connect` is finished. """ def __init__(self, *args, **kwargs): - """The ``ssl_options`` keyword argument may either be a dictionary - of keywords arguments for `ssl.wrap_socket`, or an `ssl.SSLContext` - object. + """The ``ssl_options`` keyword argument may either be an + `ssl.SSLContext` object or a dictionary of keywords arguments + for `ssl.wrap_socket` """ self._ssl_options = kwargs.pop('ssl_options', {}) super(SSLIOStream, self).__init__(*args, **kwargs) diff --git a/tornado/netutil.py b/tornado/netutil.py index 06923b2af..426b85950 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -420,7 +420,7 @@ def ssl_options_to_context(ssl_options): `~ssl.SSLContext` object. The ``ssl_options`` dictionary contains keywords to be passed to - `ssl.wrap_socket`. In Python 3.2+, `ssl.SSLContext` objects can + `ssl.wrap_socket`. In Python 2.7.9+, `ssl.SSLContext` objects can be used instead. This function converts the dict form to its `~ssl.SSLContext` equivalent, and may be used when a component which accepts both forms needs to upgrade to the `~ssl.SSLContext` version @@ -451,11 +451,11 @@ def ssl_options_to_context(ssl_options): def ssl_wrap_socket(socket, ssl_options, server_hostname=None, **kwargs): """Returns an ``ssl.SSLSocket`` wrapping the given socket. - ``ssl_options`` may be either a dictionary (as accepted by - `ssl_options_to_context`) or an `ssl.SSLContext` object. - Additional keyword arguments are passed to ``wrap_socket`` - (either the `~ssl.SSLContext` method or the `ssl` module function - as appropriate). + ``ssl_options`` may be either an `ssl.SSLContext` object or a + dictionary (as accepted by `ssl_options_to_context`). Additional + keyword arguments are passed to ``wrap_socket`` (either the + `~ssl.SSLContext` method or the `ssl` module function as + appropriate). """ context = ssl_options_to_context(ssl_options) if hasattr(ssl, 'SSLContext') and isinstance(context, ssl.SSLContext): diff --git a/tornado/tcpserver.py b/tornado/tcpserver.py index a02b36fff..3b59a4ed0 100644 --- a/tornado/tcpserver.py +++ b/tornado/tcpserver.py @@ -41,14 +41,15 @@ class TCPServer(object): To use `TCPServer`, define a subclass which overrides the `handle_stream` method. - To make this server serve SSL traffic, send the ssl_options dictionary - argument with the arguments required for the `ssl.wrap_socket` method, - including "certfile" and "keyfile":: - - TCPServer(ssl_options={ - "certfile": os.path.join(data_dir, "mydomain.crt"), - "keyfile": os.path.join(data_dir, "mydomain.key"), - }) + To make this server serve SSL traffic, send the ``ssl_options`` keyword + argument with an `ssl.SSLContext` object. For compatibility with older + versions of Python ``ssl_options`` may also be a dictionary of keyword + arguments for the `ssl.wrap_socket` method.:: + + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"), + os.path.join(data_dir, "mydomain.key")) + TCPServer(ssl_options=ssl_ctx) `TCPServer` initialization follows one of three patterns: -- 2.47.2