From 3f35728a4366abb9eed4a6a2d8e29e2f57ad7912 Mon Sep 17 00:00:00 2001 From: Forest Bond Date: Wed, 23 Oct 2013 09:33:46 -0400 Subject: [PATCH] Support HTTPS connection to the CouchDB server. --- paisley/client.py | 15 ++++++++--- paisley/test/server.crt | 20 +++++++++++++++ paisley/test/server.key | 27 ++++++++++++++++++++ paisley/test/test_client.py | 51 +++++++++++++++++++++++++++++++------ setup.py | 2 +- 5 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 paisley/test/server.crt create mode 100644 paisley/test/server.key diff --git a/paisley/client.py b/paisley/client.py index bbae57f..f892a41 100644 --- a/paisley/client.py +++ b/paisley/client.py @@ -119,7 +119,7 @@ class CouchDB(object): def __init__(self, host, port=5984, dbName=None, username=None, password=None, disable_log=False, - version=(1, 0, 1)): + version=(1, 0, 1), protocol='http', contextFactory=None): """ Initialize the client for given host. @@ -136,12 +136,19 @@ def __init__(self, host, port=5984, dbName=None, from twisted.internet import reactor # t.w.c imports reactor from twisted.web.client import Agent - self.client = Agent(reactor) + + agent_args = (reactor,) + if contextFactory is not None: + agent_args += (contextFactory,) + + self.client = Agent(*agent_args) self.host = host self.port = int(port) + self.protocol = protocol self.username = username - self.password =password - self.url_template = "http://%s:%s%%s" % (self.host, self.port) + self.password = password + self.url_template = "%s://%s:%s%%s" % (self.protocol, self.host, + self.port) if dbName is not None: self.bindToDB(dbName) diff --git a/paisley/test/server.crt b/paisley/test/server.crt new file mode 100644 index 0000000..b19e6ce --- /dev/null +++ b/paisley/test/server.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgIJANcpKw7AFifbMA0GCSqGSIb3DQEBBQUAMDYxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIDAdWZXJtb250MRUwEwYDVQQKDAxSYXBpZFJvbGxvdXQw +IBcNMTMxMDI0MTkyMDU2WhgPMjExMzA5MzAxOTIwNTZaMDYxCzAJBgNVBAYTAlVT +MRAwDgYDVQQIDAdWZXJtb250MRUwEwYDVQQKDAxSYXBpZFJvbGxvdXQwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzvTZEXk6QpAAKqBNEjS+y+JsOm84d +OnZsgWS6Zxf+pyUGlBgEMhBCO/4fteIV+9ni08uB+IiYio2YOOF7dtTsdovrYyed +ZCq6a018AJShODWh1SxX8mpIW6oIaorvfPU3PGYIEHO+JnW9eemTjqUsoGm7Rw8F +eJHkFPqq0vC8rXDkQ46cMLhCe5wmGva/R9fnFlG2UVwO2lQ2GQRS1py9KEeSUYwV +aIQQz6m6C2e8dqC9+Vhd8aOcR36SLpS56dFoO4hltneAF5WEeyEX5sHs64bGI11I +bRmg2XeeFuqpjLQpEoV8DieegOFDQuiH3W7OuG0edEHrRA1CoLpG2ubHAgMBAAGj +UDBOMB0GA1UdDgQWBBQ0FJvAMSoW6++sY/ntwTs9n9Ly5zAfBgNVHSMEGDAWgBQ0 +FJvAMSoW6++sY/ntwTs9n9Ly5zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA +A4IBAQBimUEdCobom4/oA0ZL3srvM+x2nOYDEi2nMwVGhhurNkhV4/EllpqDIaVH +WBy3Irt7HOI6NeTmoREHFSdcx0aKX+foh5PlE9deWOW3sZtaD99DgrQQzHdmcWk+ +hwp5aCBwPBguvT1fACtvKIVHJgzCmNZPR78qrALdeYloYCIJlFILxeSVmVJSUA5M +zP8Lqg7kzdp/F/V8l5Ay1LNfzM5X5ezHAb7at8lS3hnnVop+sVf/rVDvxe3dTLod +ERV5AuU7ny/c0bvZFHUn7/Srw+Q8wgFM5xTbq3neqWoDM89wf8BBDZmw03U7iFPu +Jb/o9AM2Bj3AaW5gzQE0N5p2NyBF +-----END CERTIFICATE----- diff --git a/paisley/test/server.key b/paisley/test/server.key new file mode 100644 index 0000000..4f38ac8 --- /dev/null +++ b/paisley/test/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAs702RF5OkKQACqgTRI0vsvibDpvOHTp2bIFkumcX/qclBpQY +BDIQQjv+H7XiFfvZ4tPLgfiImIqNmDjhe3bU7HaL62MnnWQqumtNfACUoTg1odUs +V/JqSFuqCGqK73z1NzxmCBBzviZ1vXnpk46lLKBpu0cPBXiR5BT6qtLwvK1w5EOO +nDC4QnucJhr2v0fX5xZRtlFcDtpUNhkEUtacvShHklGMFWiEEM+pugtnvHagvflY +XfGjnEd+ki6UuenRaDuIZbZ3gBeVhHshF+bB7OuGxiNdSG0ZoNl3nhbqqYy0KRKF +fA4nnoDhQ0Loh91uzrhtHnRB60QNQqC6RtrmxwIDAQABAoIBAEVl0QYkw4DlUX7L +1mSpfrlDc9r4HWT7pa3PZ+zw0Trpnkoj9AHqsoxgTYZA28JRM5d43yKXq2X6WSFl +FOpuv1dtjiicaDdE7Zp8w7YVI038Pfj2LeDnIFI/0i7dtDczsBpbn6mNcKMChoNa +Bu2KLgxFA43jqdEa9Hl0ADTkrT6rsyHB1Q185OVFwWtd86hGnn4GEdJNBj6NHgZa +b8L0aHsfBjvDnkbn6fZ4m+rsZswSh+XSkadkvnWSlQKoG5UxyuYVMwyEeALXKc6g +uNO3TJq1SpRuFSS6Xu3UaeeKWpg1dx0JvVYCKGVhQ8JRay4RQ/BRfrfTrqQELKz/ +4DSbH8ECgYEA3mwl/v8wlxnDy7YjgR036+ay4E065SsgcOraqTd1n7cHut6F/L0Z +FWyKKF6C68uRaScXejaGo9yKM0WYS8qQMgisZ9geIYu8NlKea+mj7xVnQtz9GCj6 +k4/3fYeQrMqGy2KVyxl4xJQX3KHXbNWEUQvKO7IcdfI6UPXVBoUgLAUCgYEAzt+A +UJI3YnPMtXlxRxzmVVU+dPfKDjQPtufuP517Qfxre4QGN78ysPHIMUa6ulZ01osz +3G85aDa0XXTsGD0n7VDT6UGuoNO/hfxBzVXrFf+PivR5S1OTL0z79cIla7xhxz4a +CxSlwIa1+f3giqzMrByNZ1AnK3rpWq30Hg+jDVsCgYEAvggWeoQbRq3brBukv/Zv +xdwoLh2t2Qh8whzVz0ez9k5Ri2X9gg8p9DT04ULGhqE5Tmb41xDo/e06Ik4urWqW +wjjI3Dw4mh6iIqN5+Ob4ihd2TxkyIEc6t4KESDrf79FlUzWal5jeps2EiZu4y6Kt +VvVExrYJPPhEvNEcPWLWNuUCgYEAiP+4USNTrE51zeR74RVBcFeAgiOq2tcdZQqZ +W+Wlv+AzKdwX5gknv8iOxBtMA6THwWD0WlIKGXrI3W9V/wNZEq9Jdxq5U+aG2mth +BGOWyL2yyNn4DatuOI/p+Cm3cG6T7kexJY9p6WMM1l6LuiqPbJeICVgqaIAAU74J +gXLnjysCgYEAjV6A3IvtsTEy5F9aOCd5zdWjMtx8BXlidIuBQClsDQnRmbaRB6B+ +aTk6gdfl2eJTl4JQYXtpNjkLC7yCrDC4WvBQHt5lFRRAw41OKKTnhJ7uVZO/rbqN +3u54X4ke28rLnuJJGptNtQf2899zbf25ONYc8PHAUGE6aJ8vt8OO7mk= +-----END RSA PRIVATE KEY----- diff --git a/paisley/test/test_client.py b/paisley/test/test_client.py index 3b346ac..0ff150d 100644 --- a/paisley/test/test_client.py +++ b/paisley/test/test_client.py @@ -10,14 +10,16 @@ from paisley import pjson as json +import os import cgi from twisted.internet import defer from twisted.trial.unittest import TestCase from twisted.internet.defer import Deferred -from twisted.internet import reactor +from twisted.internet import reactor, ssl from twisted.web import resource, server +from twisted.web.client import WebClientContextFactory from twisted.web._newclient import ResponseDone from twisted.python.failure import Failure @@ -418,20 +420,32 @@ class ConnectedCouchDBTestCase(TestCase): Test C{CouchDB} with a real web server. """ - def setUp(self): + def _connectToServer(self, protocol, clientContextFactory=None): """ Create a web server and a client bound to it. """ + self.resource = FakeCouchDBResource() site = server.Site(self.resource) - port = reactor.listenTCP(0, site, interface="127.0.0.1") + + if protocol == 'https': + ssl_key = os.path.join(os.path.dirname(__file__), 'server.key') + ssl_cert = os.path.join(os.path.dirname(__file__), 'server.crt') + serverContextFactory = ssl.DefaultOpenSSLContextFactory(ssl_key, + ssl_cert) + port = reactor.listenSSL(0, site, interface="127.0.0.1", + contextFactory=serverContextFactory) + else: + port = reactor.listenTCP(0, site, interface="127.0.0.1") self.addCleanup(port.stopListening) - self.client = client.CouchDB("127.0.0.1", port.getHost().port) - def test_createDB(self): - """ - Test listDB. - """ + kwargs = {} + if clientContextFactory is not None: + kwargs['contextFactory'] = clientContextFactory + self.client = client.CouchDB("127.0.0.1", port.getHost().port, + protocol=protocol, **kwargs) + + def _test_listDB(self): data = [u"mydb"] self.resource.result = json.dumps(data) d = self.client.listDB() @@ -441,6 +455,27 @@ def cb(result): d.addCallback(cb) return d + def test_listDB(self): + """ + Test listDB. + """ + self._connectToServer('http') + return self._test_listDB() + + def test_listDB_over_SSL(self): + """ + Test listDB over SSL. + """ + self._connectToServer('https') + return self._test_listDB() + + def test_listDB_over_SSL_with_clientContextFactory(self): + """ + Test listDB over SSL with clientContextFactory. + """ + self._connectToServer('https', WebClientContextFactory()) + return self._test_listDB() + class RealCouchDBTestCase(util.CouchDBTestCase): diff --git a/setup.py b/setup.py index c64e523..0ff1c21 100755 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ def main(): download_url="http://github.com/smcq/paisley/zipball/v0.3.1", packages = setuptools.find_packages (), package_data = { - '': ['*.template'], + 'paisley.test': ['*.template', 'server.crt', 'server.key'], }) if __name__ == "__main__":