Added SSL wrapper support

This commit is contained in:
Jiri Lunacek 2016-06-29 14:39:15 +02:00
parent 9d7d97aaba
commit 921d4cb64b
3 changed files with 62 additions and 4 deletions

6
README
View File

@ -12,6 +12,12 @@ called rfoo.marsh which extends the Python built in marshal module by
eliminating serialization of code objects and protecting against bad input. eliminating serialization of code objects and protecting against bad input.
The result is a safe to use ultra fast serializer. The result is a safe to use ultra fast serializer.
SSL wrapper support added by
Jiri Lunacek of Hosting90 Systems s.r.o.
Email: jiri.lunacek@hosting90.cz
Website: http://www.hosting90.cz
SSL patch version: 0
Example server code: Example server code:
> class MyHandler(rfoo.BaseHandler): > class MyHandler(rfoo.BaseHandler):
> def echo(self, str): > def echo(self, str):

View File

@ -176,6 +176,14 @@ class BaseHandler(object):
members = inspect.getmembers(self, inspect.ismethod) members = inspect.getmembers(self, inspect.ismethod)
return [m[0] for m in members if not m[0].startswith('_')] return [m[0] for m in members if not m[0].startswith('_')]
class SSLHandler(BaseHandler):
"""
Handler for SSL server. This handler has access to SSL Socket object of the connection
"""
def __init__(self,conn,addr,context=None):
"""docstring for __init__"""
super(SSLHandler,self).__init__(addr,context)
self._conn = conn
def restrict_local(foo): def restrict_local(foo):
"""Decorator to restrict handler method to local proxies only.""" """Decorator to restrict handler method to local proxies only."""
@ -264,7 +272,21 @@ class InetConnection(Connection):
self._conn.connect((host, port)) self._conn.connect((host, port))
return self return self
class SSLConnection(Connection):
"""Connection type for SSL wrapped INET sockets."""
def __init__(self,ssl_context=None):
import ssl
if ssl_context == None:
ssl_context = ssl.create_default_context()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_conn = ssl_context.wrap_socket(s)
#s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
Connection.__init__(self, ssl_conn)
def connect(self, host=LOOPBACK, port=DEFAULT_PORT):
self._conn.connect((host, port))
return self
class UnixConnection(Connection): class UnixConnection(Connection):
"""Connection type for Unix sockets.""" """Connection type for Unix sockets."""
@ -417,10 +439,11 @@ def run_in_thread(foo):
class Server(object): class Server(object):
"""Serve calls over connection.""" """Serve calls over connection."""
def __init__(self, handler_type, handler_context=None, conn=None): def __init__(self, handler_type, handler_context=None, conn=None, ssl_context=None):
self._handler_context = handler_context self._handler_context = handler_context
self._handler_type = handler_type self._handler_type = handler_type
self._conn = conn self._conn = conn
self._ssl_context = ssl_context
def close(self): def close(self):
if self._conn is not None: if self._conn is not None:
@ -443,6 +466,13 @@ class Server(object):
while True: while True:
conn, addr = self._conn.accept() conn, addr = self._conn.accept()
conn.settimeout(None) conn.settimeout(None)
if self._ssl_context != None:
try:
conn = self._ssl_context.wrap_socket(conn, server_side=True)
except Exception as e:
logging.warning(str(e))
conn.close()
continue
self._on_accept(conn, addr) self._on_accept(conn, addr)
finally: finally:
@ -463,7 +493,12 @@ class Server(object):
# Instantiate handler for the lifetime of the connection, # Instantiate handler for the lifetime of the connection,
# making it possible to manage a state between calls. # making it possible to manage a state between calls.
# #
handler = self._handler_type(addr, self._handler_context) if SSLHandler in self._handler_type.__bases__:
# if SSL connection is used, pass both SSL socket and addr to handler
# this is needed so that the handler can use SSL extension functions
handler = self._handler_type(conn,addr, self._handler_context)
else:
handler = self._handler_type(addr, self._handler_context)
try: try:
while True: while True:
@ -520,7 +555,24 @@ class InetServer(Server):
_on_accept = run_in_thread(Server._on_accept) _on_accept = run_in_thread(Server._on_accept)
class SSLServer(Server):
"""Serve calls over SSL wrapped INET sockets."""
def __init__(self, handler_type, handler_context=None, ssl_context=None,certfile=None,keyfile=None):
import ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.settimeout(None)
if ssl_context == None and certfile != None and keyfile != None:
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
Server.__init__(self, handler_type, handler_context, s, ssl_context)
def start(self, host=LOOPBACK, port=DEFAULT_PORT):
self._conn.bind((host, port))
Server.start(self)
_on_accept = run_in_thread(Server._on_accept)
class UnixServer(Server): class UnixServer(Server):
"""Serve calls over Unix sockets.""" """Serve calls over Unix sockets."""

View File

@ -74,7 +74,7 @@ ext_modules = [Extension("rfoo.marsh", ["rfoo/marsh.pyx"])]
setup( setup(
name = 'rfoo', name = 'rfoo',
version = '1.3.0', version = '1.3.0-ssl-0',
description = 'Fast RPC client/server module.', description = 'Fast RPC client/server module.',
author = 'Nir Aides', author = 'Nir Aides',
author_email = 'nir@winpdb.org', author_email = 'nir@winpdb.org',