OpenSecurity/install/web.py-0.37/web/wsgiserver/ssl_builtin.py
author om
Mon, 02 Dec 2013 14:02:05 +0100
changeset 3 65432e6c6042
permissions -rwxr-xr-x
initial deployment and project layout commit
om@3
     1
"""A library for integrating Python's builtin ``ssl`` library with CherryPy.
om@3
     2
om@3
     3
The ssl module must be importable for SSL functionality.
om@3
     4
om@3
     5
To use this module, set ``CherryPyWSGIServer.ssl_adapter`` to an instance of
om@3
     6
``BuiltinSSLAdapter``.
om@3
     7
"""
om@3
     8
om@3
     9
try:
om@3
    10
    import ssl
om@3
    11
except ImportError:
om@3
    12
    ssl = None
om@3
    13
om@3
    14
from cherrypy import wsgiserver
om@3
    15
om@3
    16
om@3
    17
class BuiltinSSLAdapter(wsgiserver.SSLAdapter):
om@3
    18
    """A wrapper for integrating Python's builtin ssl module with CherryPy."""
om@3
    19
    
om@3
    20
    certificate = None
om@3
    21
    """The filename of the server SSL certificate."""
om@3
    22
    
om@3
    23
    private_key = None
om@3
    24
    """The filename of the server's private key file."""
om@3
    25
    
om@3
    26
    def __init__(self, certificate, private_key, certificate_chain=None):
om@3
    27
        if ssl is None:
om@3
    28
            raise ImportError("You must install the ssl module to use HTTPS.")
om@3
    29
        self.certificate = certificate
om@3
    30
        self.private_key = private_key
om@3
    31
        self.certificate_chain = certificate_chain
om@3
    32
    
om@3
    33
    def bind(self, sock):
om@3
    34
        """Wrap and return the given socket."""
om@3
    35
        return sock
om@3
    36
    
om@3
    37
    def wrap(self, sock):
om@3
    38
        """Wrap and return the given socket, plus WSGI environ entries."""
om@3
    39
        try:
om@3
    40
            s = ssl.wrap_socket(sock, do_handshake_on_connect=True,
om@3
    41
                    server_side=True, certfile=self.certificate,
om@3
    42
                    keyfile=self.private_key, ssl_version=ssl.PROTOCOL_SSLv23)
om@3
    43
        except ssl.SSLError, e:
om@3
    44
            if e.errno == ssl.SSL_ERROR_EOF:
om@3
    45
                # This is almost certainly due to the cherrypy engine
om@3
    46
                # 'pinging' the socket to assert it's connectable;
om@3
    47
                # the 'ping' isn't SSL.
om@3
    48
                return None, {}
om@3
    49
            elif e.errno == ssl.SSL_ERROR_SSL:
om@3
    50
                if e.args[1].endswith('http request'):
om@3
    51
                    # The client is speaking HTTP to an HTTPS server.
om@3
    52
                    raise wsgiserver.NoSSLError
om@3
    53
            raise
om@3
    54
        return s, self.get_environ(s)
om@3
    55
    
om@3
    56
    # TODO: fill this out more with mod ssl env
om@3
    57
    def get_environ(self, sock):
om@3
    58
        """Create WSGI environ entries to be merged into each request."""
om@3
    59
        cipher = sock.cipher()
om@3
    60
        ssl_environ = {
om@3
    61
            "wsgi.url_scheme": "https",
om@3
    62
            "HTTPS": "on",
om@3
    63
            'SSL_PROTOCOL': cipher[1],
om@3
    64
            'SSL_CIPHER': cipher[0]
om@3
    65
##            SSL_VERSION_INTERFACE 	string 	The mod_ssl program version
om@3
    66
##            SSL_VERSION_LIBRARY 	string 	The OpenSSL program version
om@3
    67
            }
om@3
    68
        return ssl_environ
om@3
    69
    
om@3
    70
    def makefile(self, sock, mode='r', bufsize=-1):
om@3
    71
        return wsgiserver.CP_fileobject(sock, mode, bufsize)
om@3
    72