[Twisted-Python] database access via cred and ssl encryption

Clark C. Evans cce at clarkevans.com
Fri May 16 22:27:08 EDT 2003


Joe,

My requirement was to have a server authenticate via a client
via a server certificate known by the client.   To implement
this, I had to patch the internet/ssl.py file; and to make 
the 'fetch' aspect easy, I had a small change to web/client.py
As far as I know, these patches have not been applied; however,
you may find them useful...

Clark
-------------- next part --------------
39c39
< from OpenSSL import SSL
---
> from OpenSSL import SSL, crypto
57a58,60
> def dumpCertificate(cert, filetype = crypto.FILETYPE_PEM ):
>     ''' a helper to dump an incoming cert as a PEM '''
>     return crypto.dump_certificate(filetype, cert)
62,63c65,67
<                  sslmethod=SSL.SSLv23_METHOD):
<         self.privateKeyFileName = privateKeyFileName
---
>                  sslmethod=SSL.SSLv23_METHOD, verifyCallback = None):
>         self.verifyCallback      = (verifyCallback, )      
>         self.privateKeyFileName  = privateKeyFileName
67a72,77
>                         
>     def verifyCertificate(self, conn, cert, errno, depth, retcode):
>         cb = self.verifyCallback[0]
>         if cb: return cb(cert)
>         return 1
> 
71a82,83
>         if self.verifyCallback[0]:
>             ctx.set_verify(SSL.VERIFY_PEER, self.verifyCertificate) 
-------------- next part --------------
--- client.py.orig	Tue Mar 25 18:10:28 2003
+++ client.py	Tue Mar 25 18:55:08 2003
@@ -63,7 +63,8 @@
         l = self.headers.get('location')
         if not l:
             self.handleStatusDefault()
-        host, port, url = _parse(l[0])
+        https, host, port, url = _parse(l[0])
+        assert not https, "https redirects not implemented yet"
         self.factory.host, self.factory.url = host, url
         reactor.connectTCP(host, port, self.factory)
         self.quietLoss = 1
@@ -105,7 +106,9 @@
 
     protocol = HTTPPageGetter
 
-    def __init__(self, host, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter"):
+    def __init__(self, host, url, method='GET', postdata=None, 
+                 headers=None, agent=None):
+        if agent is None: agent = "Twisted PageGetter"
         if headers is not None:
             self.headers = headers
         if postdata is not None:
@@ -141,8 +144,10 @@
     protocol = HTTPPageDownloader
     value = None
 
-    def __init__(self, host, url, fileName, method='GET', postdata=None, headers=None, agent="Twisted client"):
-        HTTPClientFactory.__init__(self, host, url, method=method, postdata=postdata, headers=headers, agent=agent)
+    def __init__(self, host, url, fileName, method='GET', postdata=None, 
+                 headers=None, agent = None):
+        HTTPClientFactory.__init__(self, host, url, method, 
+                                   postdata, headers, agent)
         self.fileName = fileName
         self.deferred = defer.Deferred()
         self.waiting = 1
@@ -166,26 +171,59 @@
 def _parse(url):
     parsed = urlparse.urlparse(url)
     url = urlparse.urlunparse(('','')+parsed[2:])
-    host, port = parsed[1], 80
+    host = parsed[1]
+    if 'https' == parsed[0]:
+        https, port = 1, 443
+    else:
+        https, port = 0, 80
     if ':' in host:
         host, port = host.split(':')
         port = int(port)
-    return host, port, url
+    return https, host, port, url
 
-def getPage(url, *args, **kwargs):
+def getPage(url, method='GET', postdata=None, headers=None, agent = None):
     '''download a web page
 
     Download a page. Return a deferred, which will
     callback with a page or errback with a description
     of the error.
     '''
-    host, port, url = _parse(url)
-    factory = HTTPClientFactory(host, url, *args, **kwargs)
+    https, host, port, path = _parse(url)
+    if https: return getSecurePage(url, method, postdata, headers, agent)
+    factory = HTTPClientFactory(host, path, method, postdata, headers, agent)
     reactor.connectTCP(host, port, factory)
     return factory.deferred
 
+try:
+    from twisted.internet import ssl
+    def getSecurePage(url, method='GET', postdata=None, headers=None, 
+                      agent = None,
+                      privateKeyFileName = None, certificateFileName = None,
+                      sslmethod=ssl.SSL.SSLv23_METHOD, verifyCallback = None, 
+                      serverCertificateFileName = None):
+        """ download a secure page """
+        https, host, port, path = _parse(url)
+        if serverCertificateFileName:
+            cert = file(serverCertificateFileName).read()
+            verifyCallback = lambda rhs: ssl.dumpCertificate(cert) == rhs
+        if verifyCallback or certificateFileName or privateKeyFileName:
+            context = ssl.DefaultOpenSSLContextFactory(
+                          privateKeyFileName, certificateFileName,
+                          sslmethod, verifyCallback)
+            context.isClient = 1
+        else:
+            context = ssl.ClientContextFactory()
+        factory = HTTPClientFactory(host, path, method, postdata, headers)
+        reactor.connectSSL(host, port, factory, context)
+        return factory.deferred
+except:
+    def getSecurePage(*args,**kwargs):
+        raise Exception("ssl not available")
+
 def downloadPage(url, file, *args, **kwargs):
-    host, port, url = _parse(url)
-    factory = HTTPDownloader(host, url, file, *args, **kwargs)
+    https, host, port, path = _parse(url)
+    assert not https, "https is not yet implemented here"
+    factory = HTTPDownloader(host, path, file, *args, **kwargs)
     reactor.connectTCP(host, port, factory)
     return factory.deferred
+


More information about the Twisted-Python mailing list