Package web :: Package web :: Package wsgiserver :: Module ssl_builtin
[hide private]
[frames] | no frames]

Source Code for Module web.web.wsgiserver.ssl_builtin

  1  """A library for integrating pyOpenSSL with CherryPy. 
  2   
  3  The ssl module must be importable for SSL functionality. 
  4   
  5  To use this module, set CherryPyWSGIServer.ssl_adapter to an instance of 
  6  BuiltinSSLAdapter. 
  7   
  8      ssl_adapter.certificate: the filename of the server SSL certificate. 
  9      ssl_adapter.private_key: the filename of the server's private key file. 
 10  """ 
 11   
 12  try: 
 13      import ssl 
 14  except ImportError: 
 15      ssl = None 
 16   
 17   
 18  from web import wsgiserver 
 19   
20 -def decode_cert( prefix, cert ):
21 22 if not cert: 23 return None 24 25 key_map = { 'countryName':'C', 26 'stateOrProvinceName':'ST', 27 'localityName':'L', 28 'organizationName':'O', 29 'organizationalUnitName':'OU', 30 'commonName':'CN', 31 # Don't know by what key names python's ssl 32 # implementation uses for these fields. 33 #'???':'T', 34 #'???':'I', 35 #'???':'G', 36 #'???':'S', 37 #'???':'D', 38 #'???':'UID', 39 'emailAddress':'Email', 40 } 41 42 DN_string = ["subject=",] 43 cert_dict = {} 44 45 for rdn in cert: 46 for key, item in rdn: 47 if key in key_map: 48 cert_dict["%s_%s" % ( prefix, key_map[key] ) ] = item 49 DN_string.append( "%s=%s" % ( key_map[key], item )) 50 51 cert_dict[prefix] = "/".join( DN_string ) 52 53 return cert_dict
54 55
56 -class BuiltinSSLAdapter(wsgiserver.SSLAdapter):
57 """A wrapper for integrating Python's builtin ssl module with CherryPy.""" 58
59 - def __init__(self, certificate, private_key, certificate_chain=None, client_CA=None):
60 if ssl is None: 61 raise ImportError("You must install the ssl module to use HTTPS.") 62 self.certificate = certificate 63 self.private_key = private_key 64 self.certificate_chain = certificate_chain 65 self.client_CA = client_CA
66
67 - def bind(self, sock):
68 """Wrap and return the given socket.""" 69 return sock
70
71 - def wrap(self, sock):
72 """Wrap and return the given socket, plus WSGI environ entries.""" 73 try: 74 if self.client_CA: 75 s = ssl.wrap_socket(sock, do_handshake_on_connect=True, 76 server_side=True, certfile=self.certificate, 77 keyfile=self.private_key, ssl_version=ssl.PROTOCOL_SSLv23, 78 ca_certs=self.client_CA, 79 cert_reqs=ssl.CERT_REQUIRED) 80 else: 81 s = ssl.wrap_socket(sock, do_handshake_on_connect=True, 82 server_side=True, certfile=self.certificate, 83 keyfile=self.private_key, ssl_version=ssl.PROTOCOL_SSLv23) 84 except ssl.SSLError, e: 85 if e.errno == ssl.SSL_ERROR_EOF: 86 # This is almost certainly due to the cherrypy engine 87 # 'pinging' the socket to assert it's connectable; 88 # the 'ping' isn't SSL. 89 return None, {} 90 elif e.errno == ssl.SSL_ERROR_SSL: 91 if e.args[1].endswith('http request'): 92 # The client is speaking HTTP to an HTTPS server. 93 raise wsgiserver.NoSSLError 94 raise 95 return s, self.get_environ(s)
96 97 # TODO: fill this out more with mod ssl env
98 - def get_environ(self, sock):
99 """Create WSGI environ entries to be merged into each request.""" 100 cipher = sock.cipher() 101 ssl_environ = { 102 "wsgi.url_scheme": "https", 103 "HTTPS": "on", 104 'SSL_PROTOCOL': cipher[1], 105 'SSL_CIPHER': cipher[0] 106 ## SSL_VERSION_INTERFACE string The mod_ssl program version 107 ## SSL_VERSION_LIBRARY string The OpenSSL program version 108 } 109 110 111 client_cert = sock.getpeercert() 112 113 client_cert_subject = decode_cert( "SSL_CLIENT_S_DN", client_cert["subject"] ) 114 115 116 # Update for client environment variables 117 ssl_environ.update( { 118 #"SSL_CLIENT_M_VERSION": "", 119 #"SSL_CLIENT_M_SERIAL": "", 120 #"SSL_CLIENT_V_START": "", 121 "SSL_CLIENT_V_END": client_cert["notAfter"], 122 #"SSL_CLIENT_A_SIG": "", 123 #"SSL_CLIENT_A_KEY": "", 124 #"SSL_CLIENT_CERT": "", 125 #"SSL_CLIENT_CERT_CHAIN": "", 126 #"SSL_CLIENT_VERIFY": "", 127 } ) 128 129 ssl_environ.update( client_cert_subject ) 130 131 # Update for server environment variables 132 ssl_environ.update( { 133 #"SSL_SERVER_M_VERSION": "", 134 #"SSL_SERVER_M_SERIAL": "", 135 #"SSL_SERVER_V_START": "", 136 #"SSL_SERVER_V_END": "", 137 #"SSL_SERVER_A_SIG": "", 138 #"SSL_SERVER_A_KEY": "", 139 #"SSL_SERVER_CERT": "", 140 } ) 141 142 143 return ssl_environ
144
145 - def makefile(self, sock, mode='r', bufsize=-1):
146 return wsgiserver.CP_fileobject(sock, mode, bufsize)
147