Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 2098

Show
Ignore:
Timestamp:
01/09/09 16:19:08
Author:
fumanchu
Message:

New ssl_context attribute on wsgiserver. See http://groups.google.com/group/cherrypy-users/browse_thread/thread/201e85a9028a3f80.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/_cpserver.py

    r2035 r2098  
    5454    max_request_body_size = 100 * 1024 * 1024 
    5555    instance = None 
     56    ssl_context = None 
    5657    ssl_certificate = None 
    5758    ssl_private_key = None 
  • trunk/cherrypy/_cpwsgi_server.py

    r2035 r2098  
    5151        self.protocol = server.protocol_version 
    5252        self.nodelay = server.nodelay 
     53        self.ssl_context = server.ssl_context 
    5354        self.ssl_certificate = server.ssl_certificate 
    5455        self.ssl_private_key = server.ssl_private_key 
  • trunk/cherrypy/wsgiserver/__init__.py

    r2079 r2098  
    14481448    You can obtain it from http://pyopenssl.sourceforge.net/ 
    14491449     
    1450     ssl_certificate: the filename of the server SSL certificate. 
    1451     ssl_privatekey: the filename of the server's private key file. 
    1452      
    1453     If either of these is None (both are None by default), this server 
    1454     will not use SSL. If both are given and are valid, they will be read 
    1455     on server start and used in the SSL context for the listening socket. 
     1450    There are two ways to use SSL: 
     1451     
     1452    Method One: 
     1453        ssl_context: an instance of SSL.Context. 
     1454         
     1455        If this is not None, it is assumed to be an SSL.Context instance, 
     1456        and will be passed to SSL.Connection on bind(). The developer is 
     1457        responsible for forming a valid Context object. This approach is 
     1458        to be preferred for more flexibility, e.g. if the cert and key are 
     1459        streams instead of files, or need decryption, or SSL.SSLv3_METHOD 
     1460        is desired instead of the default SSL.SSLv23_METHOD, etc. Consult 
     1461        the pyOpenSSL documentation for complete options. 
     1462     
     1463    Method Two (shortcut): 
     1464        ssl_certificate: the filename of the server SSL certificate. 
     1465        ssl_privatekey: the filename of the server's private key file. 
     1466         
     1467        Both are None by default. If ssl_context is None, but ssl_privatekey 
     1468        and ssl_certificate are both given and valid, they will be read on 
     1469        server start, and self.ssl_context will be automatically created 
     1470        from them. 
    14561471    """ 
    14571472     
     
    14671482    environ = {} 
    14681483     
    1469     # Paths to certificate and private key files 
     1484    # An SSL.Context instance... 
     1485    ssl_context = None 
     1486     
     1487    # ...or paths to certificate and private key files 
    14701488    ssl_certificate = None 
    14711489    ssl_private_key = None 
     
    16091627        if self.nodelay: 
    16101628            self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 
    1611         if self.ssl_certificate and self.ssl_private_key: 
     1629         
     1630        if (self.ssl_context is None and 
     1631            self.ssl_certificate and self.ssl_private_key): 
    16121632            if SSL is None: 
    16131633                raise ImportError("You must install pyOpenSSL to use HTTPS.") 
    16141634             
    16151635            # See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473 
    1616             ctx = SSL.Context(SSL.SSLv23_METHOD) 
    1617             ctx.use_privatekey_file(self.ssl_private_key) 
    1618             ctx.use_certificate_file(self.ssl_certificate) 
    1619             self.socket = SSLConnection(ctx, self.socket) 
     1636            self.ssl_context = SSL.Context(SSL.SSLv23_METHOD) 
     1637            self.ssl_context.use_privatekey_file(self.ssl_private_key) 
     1638            self.ssl_context.use_certificate_file(self.ssl_certificate) 
     1639         
     1640        if self.ssl_context is not None: 
     1641            self.socket = SSLConnection(self.ssl_context, self.socket) 
    16201642            self.populate_ssl_environ() 
    1621              
    1622             # If listening on the IPV6 any address ('::' = IN6ADDR_ANY), 
    1623             # activate dual-stack. See http://www.cherrypy.org/ticket/871. 
    1624             if (not isinstance(self.bind_addr, basestring) 
    1625                 and self.bind_addr[0] == '::' and family == socket.AF_INET6): 
    1626                 try: 
    1627                     self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) 
    1628                 except (AttributeError, socket.error): 
    1629                     # Apparently, the socket option is not available in 
    1630                     # this machine's TCP stack 
    1631                     pass 
     1643         
     1644        # If listening on the IPV6 any address ('::' = IN6ADDR_ANY), 
     1645        # activate dual-stack. See http://www.cherrypy.org/ticket/871. 
     1646        if (not isinstance(self.bind_addr, basestring) 
     1647            and self.bind_addr[0] == '::' and family == socket.AF_INET6): 
     1648            try: 
     1649                self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) 
     1650            except (AttributeError, socket.error): 
     1651                # Apparently, the socket option is not available in 
     1652                # this machine's TCP stack 
     1653                pass 
    16321654         
    16331655        self.socket.bind(self.bind_addr) 
     
    17391761    def populate_ssl_environ(self): 
    17401762        """Create WSGI environ entries to be merged into each request.""" 
    1741         cert = open(self.ssl_certificate, 'rb').read() 
    1742         cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert) 
    17431763        ssl_environ = { 
    17441764            "wsgi.url_scheme": "https", 
     
    17511771            } 
    17521772         
    1753         # Server certificate attributes 
    1754         ssl_environ.update({ 
    1755             'SSL_SERVER_M_VERSION': cert.get_version(), 
    1756             'SSL_SERVER_M_SERIAL': cert.get_serial_number(), 
    1757 ##            'SSL_SERVER_V_START': Validity of server's certificate (start time), 
    1758 ##            'SSL_SERVER_V_END': Validity of server's certificate (end time), 
    1759             }) 
    1760          
    1761         for prefix, dn in [("I", cert.get_issuer()), 
    1762                            ("S", cert.get_subject())]: 
    1763             # X509Name objects don't seem to have a way to get the 
    1764             # complete DN string. Use str() and slice it instead, 
    1765             # because str(dn) == "<X509Name object '/C=US/ST=...'>" 
    1766             dnstr = str(dn)[18:-2] 
     1773        if self.ssl_certificate: 
     1774            # Server certificate attributes 
     1775            cert = open(self.ssl_certificate, 'rb').read() 
     1776            cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert) 
     1777            ssl_environ.update({ 
     1778                'SSL_SERVER_M_VERSION': cert.get_version(), 
     1779                'SSL_SERVER_M_SERIAL': cert.get_serial_number(), 
     1780##                'SSL_SERVER_V_START': Validity of server's certificate (start time), 
     1781##                'SSL_SERVER_V_END': Validity of server's certificate (end time), 
     1782                }) 
    17671783             
    1768             wsgikey = 'SSL_SERVER_%s_DN' % prefix 
    1769             ssl_environ[wsgikey] = dnstr 
    1770              
    1771             # The DN should be of the form: /k1=v1/k2=v2, but we must allow 
    1772             # for any value to contain slashes itself (in a URL). 
    1773             while dnstr: 
    1774                 pos = dnstr.rfind("=") 
    1775                 dnstr, value = dnstr[:pos], dnstr[pos + 1:] 
    1776                 pos = dnstr.rfind("/") 
    1777                 dnstr, key = dnstr[:pos], dnstr[pos + 1:] 
    1778                 if key and value: 
    1779                     wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key) 
    1780                     ssl_environ[wsgikey] = value 
     1784            for prefix, dn in [("I", cert.get_issuer()), 
     1785                               ("S", cert.get_subject())]: 
     1786                # X509Name objects don't seem to have a way to get the 
     1787                # complete DN string. Use str() and slice it instead, 
     1788                # because str(dn) == "<X509Name object '/C=US/ST=...'>" 
     1789                dnstr = str(dn)[18:-2] 
     1790                 
     1791                wsgikey = 'SSL_SERVER_%s_DN' % prefix 
     1792                ssl_environ[wsgikey] = dnstr 
     1793                 
     1794                # The DN should be of the form: /k1=v1/k2=v2, but we must allow 
     1795                # for any value to contain slashes itself (in a URL). 
     1796                while dnstr: 
     1797                    pos = dnstr.rfind("=") 
     1798                    dnstr, value = dnstr[:pos], dnstr[pos + 1:] 
     1799                    pos = dnstr.rfind("/") 
     1800                    dnstr, key = dnstr[:pos], dnstr[pos + 1:] 
     1801                    if key and value: 
     1802                        wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key) 
     1803                        ssl_environ[wsgikey] = value 
    17811804         
    17821805        self.environ.update(ssl_environ) 

Hosted by WebFaction

Log in as guest/cpguest to create tickets