diff --git a/eventlet/__init__.py b/eventlet/__init__.py index dda5923..62dc790 100644 --- a/eventlet/__init__.py +++ b/eventlet/__init__.py @@ -31,6 +31,7 @@ try: listen = convenience.listen serve = convenience.serve StopServe = convenience.StopServe + wrap_ssl = convenience.wrap_ssl getcurrent = greenlet.greenlet.getcurrent diff --git a/eventlet/api.py b/eventlet/api.py index 3ee73cb..5b78e83 100644 --- a/eventlet/api.py +++ b/eventlet/api.py @@ -68,6 +68,8 @@ def ssl_listener(address, certificate, private_key): Returns a socket object on which one should call ``accept()`` to accept a connection on the newly bound socket. """ + warnings.warn("""eventlet.api.ssl_listener is deprecated. Please use eventlet.wrap_ssl(eventlet.listen()) instead.""", + DeprecationWarning, stacklevel=2) from eventlet import util import socket diff --git a/eventlet/convenience.py b/eventlet/convenience.py index b737242..887ca3b 100644 --- a/eventlet/convenience.py +++ b/eventlet/convenience.py @@ -97,11 +97,14 @@ def serve(sock, handle, concurrency=1000): def wrap_ssl(sock, keyfile=None, certfile=None, server_side=False, - cert_reqs=None, ssl_version=None, ca_certs=None, + cert_reqs=0, ssl_version=2, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True): - """Convenience function for converting a regular socket into an SSL - socket. Has the same interface as :func:`ssl.wrap_socket`, but - works on 2.5 or earlier, using PyOpenSSL. + """Convenience function for converting a regular socket into an + SSL socket. Has the same interface as :func:`ssl.wrap_socket`, + but works on 2.5 or earlier, using PyOpenSSL (though note that it + ignores the *cert_reqs*, *ssl_version*, *ca_certs*, + *do_handshake_on_connect*, and *suppress_ragged_eofs* arguments + when using PyOpenSSL). The preferred idiom is to call wrap_ssl directly on the creation method, e.g., ``wrap_ssl(connect(addr))`` or @@ -111,4 +114,41 @@ def wrap_ssl(sock, keyfile=None, certfile=None, server_side=False, :return Green SSL object. """ - pass + return wrap_ssl_impl(sock, keyfile=keyfile, certfile=certfile, + server_side=server_side, + cert_reqs=cert_reqs, + ssl_version=ssl_version, + ca_certs=ca_certs, + do_handshake_on_connect=do_handshake_on_connect, + suppress_ragged_eofs=suppress_ragged_eofs) + +try: + from eventlet.green import ssl + wrap_ssl_impl = ssl.wrap_socket +except ImportError: + # < 2.6, trying PyOpenSSL + from eventlet.green.OpenSSL import SSL + try: + def wrap_ssl_impl(sock, keyfile=None, certfile=None, server_side=False, + cert_reqs=None, ssl_version=None, ca_certs=None, + do_handshake_on_connect=True, suppress_ragged_eofs=True): + # theoretically the ssl_version could be respected in this + # next line + context = SSL.Context(SSL.SSLv23_METHOD) + if certfile is not None: + context.use_certificate_file(certfile) + if keyfile is not None: + context.use_privatekey_file(keyfile) + context.set_verify(SSL.VERIFY_NONE, lambda *x: True) + + connection = SSL.Connection(context, sock) + if server_side: + connection.set_accept_state() + else: + connection.set_connect_state() + return connection + except ImportError: + def wrap_ssl_impl(*a, **kw): + raise ImportError("To use SSL with Eventlet, " + "you must install PyOpenSSL or use Python 2.6 or later.") + diff --git a/tests/convenience_test.py b/tests/convenience_test.py index 64aba0a..7b86861 100644 --- a/tests/convenience_test.py +++ b/tests/convenience_test.py @@ -1,7 +1,12 @@ +import os + import eventlet from eventlet import event from tests import LimitedTestCase, s2b +certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') +private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') + class TestServe(LimitedTestCase): def setUp(self): super(TestServe, self).setUp() @@ -101,3 +106,17 @@ class TestServe(LimitedTestCase): timeout_value="timed out") self.assertEquals(x, "timed out") + def test_wrap_ssl(self): + server = eventlet.wrap_ssl(eventlet.listen(('localhost', 0)), + certfile=certificate_file, + keyfile=private_key_file, server_side=True) + port = server.getsockname()[1] + def handle(sock,addr): + sock.sendall(sock.recv(1024)) + raise eventlet.StopServe() + eventlet.spawn(eventlet.serve, server, handle) + client = eventlet.wrap_ssl(eventlet.connect(('localhost', port))) + client.sendall("echo") + self.assertEquals("echo", client.recv(1024)) + + diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py index e4de67e..2f5c05c 100644 --- a/tests/wsgi_test.py +++ b/tests/wsgi_test.py @@ -8,8 +8,6 @@ import sys from tests import skipped, LimitedTestCase from unittest import main -from eventlet import api -from eventlet import util from eventlet import greenio from eventlet import event from eventlet.green import socket as greensocket @@ -382,11 +380,14 @@ class TestHttpd(_TestBase): certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') - server_sock = api.ssl_listener(('localhost', 0), certificate_file, private_key_file) + server_sock = eventlet.wrap_ssl(eventlet.listen(('localhost', 0)), + certfile=certificate_file, + keyfile=private_key_file, + server_side=True) self.spawn_server(sock=server_sock, site=wsgi_app) sock = eventlet.connect(('localhost', self.port)) - sock = util.wrap_ssl(sock) + sock = eventlet.wrap_ssl(sock) sock.write('POST /foo HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\nContent-length:3\r\n\r\nabc') result = sock.read(8192) self.assertEquals(result[-3:], 'abc') @@ -398,11 +399,14 @@ class TestHttpd(_TestBase): certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') - server_sock = api.ssl_listener(('localhost', 0), certificate_file, private_key_file) + server_sock = eventlet.wrap_ssl(eventlet.listen(('localhost', 0)), + certfile=certificate_file, + keyfile=private_key_file, + server_side=True) self.spawn_server(sock=server_sock, site=wsgi_app) sock = eventlet.connect(('localhost', server_sock.getsockname()[1])) - sock = util.wrap_ssl(sock) + sock = eventlet.wrap_ssl(sock) sock.write('GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') result = sock.read(8192) self.assertEquals(result[-4:], '\r\n\r\n') @@ -505,12 +509,14 @@ class TestHttpd(_TestBase): certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') - sock = api.ssl_listener(('localhost', 0), certificate_file, private_key_file) - + sock = eventlet.wrap_ssl(eventlet.listen(('localhost', 0)), + certfile=certificate_file, + keyfile=private_key_file, + server_side=True) server_coro = eventlet.spawn(server, sock, wsgi_app, self.logfile) client = eventlet.connect(('localhost', sock.getsockname()[1])) - client = util.wrap_ssl(client) + client = eventlet.wrap_ssl(client) client.write('X') # non-empty payload so that SSL handshake occurs greenio.shutdown_safe(client) client.close() @@ -788,7 +794,10 @@ class TestHttpd(_TestBase): except Exception, e: errored[0] = 'SSL handshake error raised exception %s.' % e for data in ('', 'GET /non-ssl-request HTTP/1.0\r\n\r\n'): - srv_sock = api.ssl_listener(('localhost', 0), certificate_file, private_key_file) + srv_sock = eventlet.wrap_ssl(eventlet.listen(('localhost', 0)), + certfile=certificate_file, + keyfile=private_key_file, + server_side=True) port = srv_sock.getsockname()[1] g = eventlet.spawn_n(server, srv_sock) client = eventlet.connect(('localhost', port))