Merge lp:~denys.duchier/bzr/bzr.ssl into lp:~bzr/bzr/trunk-old

Proposed by Denys Duchier
Status: Superseded
Proposed branch: lp:~denys.duchier/bzr/bzr.ssl
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 460 lines
To merge this branch: bzr merge lp:~denys.duchier/bzr/bzr.ssl
Reviewer Review Type Date Requested Status
Andrew Bennetts Pending
Review via email: mp+10175@code.launchpad.net

This proposal supersedes a proposal from 2009-08-14.

This proposal has been superseded by a proposal from 2009-08-14.

To post a comment you must log in.
Revision history for this message
Denys Duchier (denys.duchier) wrote : Posted in a previous version of this proposal

This branch introduces support for the bzr protocol over SSL.

Server Side
---------------

The smart server can be started with options --keyfile and --certfile to
request that client connections be SSL encrypted:

    bzr serve --keyfile FILE --certfile FILE ...

Client Side
--------------

a bzrs:// url causes the client to open an SSL connection to a bzr smart server.

Revision history for this message
Martin Pool (mbp) wrote : Posted in a previous version of this proposal

Thanks, that's an interesting feature to add!

Does this do authentication at all, or do you plan to add it?

--
Martin <http://launchpad.net/~mbp/>

Revision history for this message
Denys Duchier (denys.duchier) wrote : Posted in a previous version of this proposal

Martin Pool <email address hidden> writes:

> Does this do authentication at all, or do you plan to add it?

I wanted to use python's built-in SSL support. Verification of
certificates is only supported starting with python 2.6. Thus
certificate-based authentication is very easy to add, but can only be
activated for recent python distros. If there is interest, I can add
support for, it of course.

I am also interested in supporting client authentication and
authorization, but that's a more complex proposition and should be
attempted in a separate branch.

Cheers,

--Denys

Revision history for this message
Vincent Ladeuil (vila) wrote : Posted in a previous version of this proposal

>>>>> "Denys" == Denys Duchier <email address hidden> writes:

    Denys> Martin Pool <email address hidden> writes:
    >> Does this do authentication at all, or do you plan to add it?

    Denys> I wanted to use python's built-in SSL support.
    Denys> Verification of certificates is only supported
    Denys> starting with python 2.6.

That's the plan for the http client anyway.

    Denys> Thus certificate-based authentication is very easy to
    Denys> add, but can only be activated for recent python
    Denys> distros. If there is interest, I can add support for,
    Denys> it of course.

Preliminary work on the test infrastructure is in
bzrlib/tests/ssl_certs, bzrlib/tests/https_server.py and all.

It would be nice to reuse/stay compatible with that.

It's already possible to create the key and cert files and
version the results instead of embedding opaque versions like you
did in creds.py.

    Denys> I am also interested in supporting client
    Denys> authentication and authorization, but that's a more
    Denys> complex proposition and should be attempted in a
    Denys> separate branch.

Indeed.

Revision history for this message
Denys Duchier (denys.duchier) wrote : Posted in a previous version of this proposal

Vincent Ladeuil <email address hidden> writes:

> Preliminary work on the test infrastructure is in
> bzrlib/tests/ssl_certs, bzrlib/tests/https_server.py and all.
>
> It would be nice to reuse/stay compatible with that.
>
> It's already possible to create the key and cert files and
> version the results instead of embedding opaque versions like you
> did in creds.py.

Ah yes! I had not noticed ssl_certs. This is perfect; I'll use it
instead of my hack. Did you have more than this reuse in mind?

Cheers,

--Denys

Revision history for this message
Vincent Ladeuil (vila) wrote : Posted in a previous version of this proposal

>>>>> "Denys" == Denys Duchier <email address hidden> writes:

    Denys> Ah yes! I had not noticed ssl_certs. This is
    Denys> perfect; I'll use it instead of my hack. Did you have
    Denys> more than this reuse in mind?

_ssl_wrap_socket in bzrlib/transport/http/_urllib2_wrappers.py
looks very much like your wrap_socket :-)

I'm pretty sure the expand* should go somewhere else, closer to
the CLI UI... i.e. higher in the stack.

Then, since this is now needed in two different places, that may
need to be moved to osutils.py instead.

Other than that, the way you reuse the tests in
blackbox/test_server.py is not exactly what we prefer :)

You want to move these tests in their own class and make them
parameterized instead.

So I'm voting resubmit (the points above are worth doing a new
submission with them fixed but the overall patch sounds good) and
with that sorted out, I'd leave it to Andrew to review the smart
server part of it.

 review: resubmit

 reviewer: spiv

review: Needs Resubmitting
lp:~denys.duchier/bzr/bzr.ssl updated
4610. By Denys Duchier

load_tests to multiply bzr tests bare and over SSL

4611. By Denys Duchier

reinstate useful comments on ssl_wrap_socket.

4612. By Denys Duchier

improved refactoring. added doc comments.

4613. By Denys Duchier

renamed: bare->tcp ssl->ssl/tcp.

4614. By Denys Duchier

prune doc string for RemoteSSLTransport.

4615. By Denys Duchier

document bzr server over SSL.

4616. By Denys Duchier

sanity check for --keyfile and --certfile options

4617. By Denys Duchier

tests for options --keyfile and --certfile

Unmerged revisions

4617. By Denys Duchier

tests for options --keyfile and --certfile

4616. By Denys Duchier

sanity check for --keyfile and --certfile options

4615. By Denys Duchier

document bzr server over SSL.

4614. By Denys Duchier

prune doc string for RemoteSSLTransport.

4613. By Denys Duchier

renamed: bare->tcp ssl->ssl/tcp.

4612. By Denys Duchier

improved refactoring. added doc comments.

4611. By Denys Duchier

reinstate useful comments on ssl_wrap_socket.

4610. By Denys Duchier

load_tests to multiply bzr tests bare and over SSL

4609. By Denys Duchier

cleaned up ssl tests

4608. By Denys Duchier

moved ssl_wrap_socket to osutils as suggested by Vincent Ladeuil

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2009-08-10 08:25:53 +0000
+++ bzrlib/builtins.py 2009-08-14 20:35:20 +0000
@@ -4701,6 +4701,12 @@
4701 '--allow-writes enables write access to the contents of '4701 '--allow-writes enables write access to the contents of '
4702 'the served directory and below.'4702 'the served directory and below.'
4703 ),4703 ),
4704 Option('keyfile',
4705 help="Path to server's private key (for SSL).",
4706 type=str),
4707 Option('certfile',
4708 help="Path to server's certificate (for SSL).",
4709 type=str),
4704 ]4710 ]
47054711
4706 def get_host_and_port(self, port):4712 def get_host_and_port(self, port):
@@ -4723,10 +4729,14 @@
4723 return host, port4729 return host, port
47244730
4725 def run(self, port=None, inet=False, directory=None, allow_writes=False,4731 def run(self, port=None, inet=False, directory=None, allow_writes=False,
4726 protocol=None):4732 protocol=None, keyfile=None, certfile=None):
4727 from bzrlib.transport import get_transport, transport_server_registry4733 from bzrlib.transport import get_transport, transport_server_registry
4728 if directory is None:4734 if directory is None:
4729 directory = os.getcwd()4735 directory = os.getcwd()
4736 if keyfile:
4737 keyfile = os.path.expanduser(keyfile)
4738 if certfile:
4739 certfile = os.path.expanduser(certfile)
4730 if protocol is None:4740 if protocol is None:
4731 protocol = transport_server_registry.get()4741 protocol = transport_server_registry.get()
4732 host, port = self.get_host_and_port(port)4742 host, port = self.get_host_and_port(port)
@@ -4734,7 +4744,7 @@
4734 if not allow_writes:4744 if not allow_writes:
4735 url = 'readonly+' + url4745 url = 'readonly+' + url
4736 transport = get_transport(url)4746 transport = get_transport(url)
4737 protocol(transport, host, port, inet)4747 protocol(transport, host, port, inet, keyfile=keyfile, certfile=certfile)
47384748
47394749
4740class cmd_join(Command):4750class cmd_join(Command):
47414751
=== modified file 'bzrlib/osutils.py'
--- bzrlib/osutils.py 2009-07-23 16:01:17 +0000
+++ bzrlib/osutils.py 2009-08-14 20:35:20 +0000
@@ -1900,3 +1900,26 @@
1900 if use_cache:1900 if use_cache:
1901 _cached_concurrency = concurrency1901 _cached_concurrency = concurrency
1902 return concurrency1902 return concurrency
1903
1904_ssl_wrap_socket = None
1905
1906def ssl_wrap_socket(sock, keyfile=None, certfile=None, server_side=False):
1907 """Wrap SSL around a socket and return a SSLSocket object.
1908
1909 :param sock: the original socket object.
1910 :param keyfile: path to the server's private key (only for a server).
1911 :param certfile: path to the server's certificate (only for a server).
1912 :param server_side: boolean (default False. Pass True for a server).
1913 """
1914 global _ssl_wrap_socket
1915 if _ssl_wrap_socket is None:
1916 try:
1917 import ssl
1918 _ssl_wrap_socket = ssl.wrap_socket
1919 except ImportError:
1920 from httplib import FakeSocket
1921 def _ssl_wrap_socket(sock, keyfile=None, certfile=None,
1922 server_side=False):
1923 return FakeSocket(sock, socket.ssl(sock, keyfile, certfile))
1924 return _ssl_wrap_socket(sock, keyfile=keyfile, certfile=certfile,
1925 server_side=server_side)
19031926
=== modified file 'bzrlib/smart/medium.py'
--- bzrlib/smart/medium.py 2009-08-07 05:56:29 +0000
+++ bzrlib/smart/medium.py 2009-08-14 20:35:21 +0000
@@ -211,6 +211,7 @@
211 # None during interpreter shutdown.211 # None during interpreter shutdown.
212 from sys import stderr212 from sys import stderr
213 try:213 try:
214 self._before_serve()
214 while not self.finished:215 while not self.finished:
215 server_protocol = self._build_protocol()216 server_protocol = self._build_protocol()
216 self._serve_one_request(server_protocol)217 self._serve_one_request(server_protocol)
@@ -218,6 +219,11 @@
218 stderr.write("%s terminating on exception %s\n" % (self, e))219 stderr.write("%s terminating on exception %s\n" % (self, e))
219 raise220 raise
220221
222 def _before_serve(self):
223 """Executed before the serve loop. Maybe used to setup e.g. ssl.
224 """
225 pass
226
221 def _build_protocol(self):227 def _build_protocol(self):
222 """Identifies the version of the incoming request, and returns an228 """Identifies the version of the incoming request, and returns an
223 a protocol object that can interpret it.229 a protocol object that can interpret it.
@@ -260,7 +266,8 @@
260266
261class SmartServerSocketStreamMedium(SmartServerStreamMedium):267class SmartServerSocketStreamMedium(SmartServerStreamMedium):
262268
263 def __init__(self, sock, backing_transport, root_client_path='/'):269 def __init__(self, sock, backing_transport, root_client_path='/',
270 keyfile=None, certfile=None):
264 """Constructor.271 """Constructor.
265272
266 :param sock: the socket the server will read from. It will be put273 :param sock: the socket the server will read from. It will be put
@@ -269,8 +276,17 @@
269 SmartServerStreamMedium.__init__(276 SmartServerStreamMedium.__init__(
270 self, backing_transport, root_client_path=root_client_path)277 self, backing_transport, root_client_path=root_client_path)
271 sock.setblocking(True)278 sock.setblocking(True)
279 self._keyfile = keyfile
280 self._certfile = certfile
272 self.socket = sock281 self.socket = sock
273282
283 def _before_serve(self):
284 """Setup ssl if a certificate was provided."""
285 if self._certfile:
286 self.socket = osutils.ssl_wrap_socket(
287 self.socket, keyfile=self._keyfile, certfile=self._certfile,
288 server_side=True)
289
274 def _serve_one_request_unguarded(self, protocol):290 def _serve_one_request_unguarded(self, protocol):
275 while protocol.next_read_size():291 while protocol.next_read_size():
276 # We can safely try to read large chunks. If there is less data292 # We can safely try to read large chunks. If there is less data
@@ -815,13 +831,14 @@
815class SmartTCPClientMedium(SmartClientStreamMedium):831class SmartTCPClientMedium(SmartClientStreamMedium):
816 """A client medium using TCP."""832 """A client medium using TCP."""
817833
818 def __init__(self, host, port, base):834 def __init__(self, host, port, base, use_ssl=False):
819 """Creates a client that will connect on the first use."""835 """Creates a client that will connect on the first use."""
820 SmartClientStreamMedium.__init__(self, base)836 SmartClientStreamMedium.__init__(self, base)
821 self._connected = False837 self._connected = False
822 self._host = host838 self._host = host
823 self._port = port839 self._port = port
824 self._socket = None840 self._socket = None
841 self._use_ssl = use_ssl
825842
826 def _accept_bytes(self, bytes):843 def _accept_bytes(self, bytes):
827 """See SmartClientMedium.accept_bytes."""844 """See SmartClientMedium.accept_bytes."""
@@ -873,6 +890,9 @@
873 err_msg = err.args[1]890 err_msg = err.args[1]
874 raise errors.ConnectionError("failed to connect to %s:%d: %s" %891 raise errors.ConnectionError("failed to connect to %s:%d: %s" %
875 (self._host, port, err_msg))892 (self._host, port, err_msg))
893 if self._use_ssl:
894 self._socket = osutils.ssl_wrap_socket(self._socket,
895 server_side=False)
876 self._connected = True896 self._connected = True
877897
878 def _flush(self):898 def _flush(self):
879899
=== modified file 'bzrlib/smart/server.py'
--- bzrlib/smart/server.py 2009-07-20 11:27:05 +0000
+++ bzrlib/smart/server.py 2009-08-14 20:35:21 +0000
@@ -43,7 +43,7 @@
43 """43 """
4444
45 def __init__(self, backing_transport, host='127.0.0.1', port=0,45 def __init__(self, backing_transport, host='127.0.0.1', port=0,
46 root_client_path='/'):46 root_client_path='/', keyfile=None, certfile=None):
47 """Construct a new server.47 """Construct a new server.
4848
49 To actually start it running, call either start_background_thread or49 To actually start it running, call either start_background_thread or
@@ -54,6 +54,8 @@
54 :param port: TCP port to listen on, or 0 to allocate a transient port.54 :param port: TCP port to listen on, or 0 to allocate a transient port.
55 :param root_client_path: The client path that will correspond to root55 :param root_client_path: The client path that will correspond to root
56 of backing_transport.56 of backing_transport.
57 :param keyfile: Path to server's private key (for SSL).
58 :param certfile: Path to server's certificate (for SSL).
57 """59 """
58 # let connections timeout so that we get a chance to terminate60 # let connections timeout so that we get a chance to terminate
59 # Keep a reference to the exceptions we want to catch because the socket61 # Keep a reference to the exceptions we want to catch because the socket
@@ -84,6 +86,8 @@
84 self._started = threading.Event()86 self._started = threading.Event()
85 self._stopped = threading.Event()87 self._stopped = threading.Event()
86 self.root_client_path = root_client_path88 self.root_client_path = root_client_path
89 self._keyfile = keyfile
90 self._certfile = certfile
8791
88 def serve(self, thread_name_suffix=''):92 def serve(self, thread_name_suffix=''):
89 self._should_terminate = False93 self._should_terminate = False
@@ -150,7 +154,10 @@
150154
151 def get_url(self):155 def get_url(self):
152 """Return the url of the server"""156 """Return the url of the server"""
153 return "bzr://%s:%d/" % self._sockname157 if self._certfile:
158 return "bzrs://%s:%d/" % self._sockname
159 else:
160 return "bzr://%s:%d/" % self._sockname
154161
155 def serve_conn(self, conn, thread_name_suffix):162 def serve_conn(self, conn, thread_name_suffix):
156 # For WIN32, where the timeout value from the listening socket163 # For WIN32, where the timeout value from the listening socket
@@ -158,7 +165,8 @@
158 conn.setblocking(True)165 conn.setblocking(True)
159 conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)166 conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
160 handler = medium.SmartServerSocketStreamMedium(167 handler = medium.SmartServerSocketStreamMedium(
161 conn, self.backing_transport, self.root_client_path)168 conn, self.backing_transport, self.root_client_path,
169 keyfile=self._keyfile, certfile=self._certfile)
162 thread_name = 'smart-server-child' + thread_name_suffix170 thread_name = 'smart-server-child' + thread_name_suffix
163 connection_thread = threading.Thread(171 connection_thread = threading.Thread(
164 None, handler.serve, name=thread_name)172 None, handler.serve, name=thread_name)
@@ -313,7 +321,8 @@
313 return transport.get_transport(url)321 return transport.get_transport(url)
314322
315323
316def serve_bzr(transport, host=None, port=None, inet=False):324def serve_bzr(transport, host=None, port=None, inet=False,
325 keyfile=None, certfile=None):
317 from bzrlib import lockdir, ui326 from bzrlib import lockdir, ui
318 from bzrlib.transport import get_transport327 from bzrlib.transport import get_transport
319 from bzrlib.transport.chroot import ChrootServer328 from bzrlib.transport.chroot import ChrootServer
@@ -328,7 +337,8 @@
328 host = medium.BZR_DEFAULT_INTERFACE337 host = medium.BZR_DEFAULT_INTERFACE
329 if port is None:338 if port is None:
330 port = medium.BZR_DEFAULT_PORT339 port = medium.BZR_DEFAULT_PORT
331 smart_server = SmartTCPServer(transport, host=host, port=port)340 smart_server = SmartTCPServer(transport, host=host, port=port,
341 keyfile=keyfile, certfile=certfile)
332 trace.note('listening on port: %s' % smart_server.port)342 trace.note('listening on port: %s' % smart_server.port)
333 # For the duration of this server, no UI output is permitted. note343 # For the duration of this server, no UI output is permitted. note
334 # that this may cause problems with blackbox tests. This should be344 # that this may cause problems with blackbox tests. This should be
335345
=== modified file 'bzrlib/tests/blackbox/test_serve.py'
--- bzrlib/tests/blackbox/test_serve.py 2009-07-20 11:27:05 +0000
+++ bzrlib/tests/blackbox/test_serve.py 2009-08-14 20:35:21 +0000
@@ -40,7 +40,7 @@
40from bzrlib.transport import get_transport, remote40from bzrlib.transport import get_transport, remote
4141
4242
43class TestBzrServe(TestCaseWithTransport):43class TestBzrServeCommon(TestCaseWithTransport):
4444
45 def assertInetServerShutsdownCleanly(self, process):45 def assertInetServerShutsdownCleanly(self, process):
46 """Shutdown the server process looking for errors."""46 """Shutdown the server process looking for errors."""
@@ -71,6 +71,8 @@
71 finally:71 finally:
72 branch.unlock()72 branch.unlock()
7373
74class TestBzrServeInet(TestBzrServeCommon):
75
74 def start_server_inet(self, extra_options=()):76 def start_server_inet(self, extra_options=()):
75 """Start a bzr server subprocess using the --inet option.77 """Start a bzr server subprocess using the --inet option.
7678
@@ -90,23 +92,6 @@
90 transport = remote.RemoteTransport(url, medium=client_medium)92 transport = remote.RemoteTransport(url, medium=client_medium)
91 return process, transport93 return process, transport
9294
93 def start_server_port(self, extra_options=()):
94 """Start a bzr server subprocess.
95
96 :param extra_options: extra options to give the server.
97 :return: a tuple with the bzr process handle for passing to
98 finish_bzr_subprocess, and the base url for the server.
99 """
100 # Serve from the current directory
101 args = ['serve', '--port', 'localhost:0']
102 args.extend(extra_options)
103 process = self.start_bzr_subprocess(args, skip_if_plan_to_signal=True)
104 port_line = process.stderr.readline()
105 prefix = 'listening on port: '
106 self.assertStartsWith(port_line, prefix)
107 port = int(port_line[len(prefix):])
108 return process,'bzr://localhost:%d/' % port
109
110 def test_bzr_serve_inet_readonly(self):95 def test_bzr_serve_inet_readonly(self):
111 """bzr server should provide a read only filesystem by default."""96 """bzr server should provide a read only filesystem by default."""
112 process, transport = self.start_server_inet()97 process, transport = self.start_server_inet()
@@ -124,35 +109,7 @@
124 self.make_read_requests(branch)109 self.make_read_requests(branch)
125 self.assertInetServerShutsdownCleanly(process)110 self.assertInetServerShutsdownCleanly(process)
126111
127 def test_bzr_serve_port_readonly(self):112class TestBzrServeSSH(TestBzrServeCommon):
128 """bzr server should provide a read only filesystem by default."""
129 process, url = self.start_server_port()
130 transport = get_transport(url)
131 self.assertRaises(errors.TransportNotPossible, transport.mkdir, 'adir')
132 self.assertServerFinishesCleanly(process)
133
134 def test_bzr_serve_port_readwrite(self):
135 # Make a branch
136 self.make_branch('.')
137
138 process, url = self.start_server_port(['--allow-writes'])
139
140 # Connect to the server
141 branch = Branch.open(url)
142 self.make_read_requests(branch)
143 self.assertServerFinishesCleanly(process)
144
145 def test_bzr_serve_supports_protocol(self):
146 # Make a branch
147 self.make_branch('.')
148
149 process, url = self.start_server_port(['--allow-writes',
150 '--protocol=bzr'])
151
152 # Connect to the server
153 branch = Branch.open(url)
154 self.make_read_requests(branch)
155 self.assertServerFinishesCleanly(process)
156113
157 def test_bzr_connect_to_bzr_ssh(self):114 def test_bzr_connect_to_bzr_ssh(self):
158 """User acceptance that get_transport of a bzr+ssh:// behaves correctly.115 """User acceptance that get_transport of a bzr+ssh:// behaves correctly.
@@ -244,6 +201,76 @@
244 self.command_executed)201 self.command_executed)
245202
246203
204class TestBzrServePort(TestBzrServeCommon):
205
206 def start_server_port(self, extra_options=()):
207 """Start a bzr server subprocess.
208
209 :param extra_options: extra options to give the server.
210 :return: a tuple with the bzr process handle for passing to
211 finish_bzr_subprocess, and the base url for the server.
212 """
213 # Serve from the current directory
214 args = ['serve', '--port', 'localhost:0']
215 args.extend(extra_options)
216 urlfmt = 'bzr://localhost:%d/'
217 if self.use_ssl:
218 from bzrlib.tests.ssl_certs import build_path
219 keyfile = build_path('server_without_pass.key')
220 certfile = build_path('server.crt')
221 args.extend(("--keyfile", keyfile,
222 "--certfile", certfile))
223 urlfmt = 'bzrs://localhost:%d/'
224 process = self.start_bzr_subprocess(args, skip_if_plan_to_signal=True)
225 port_line = process.stderr.readline()
226 prefix = 'listening on port: '
227 self.assertStartsWith(port_line, prefix)
228 port = int(port_line[len(prefix):])
229 return process, urlfmt % port
230
231 def test_bzr_serve_port_readonly(self):
232 """bzr server should provide a read only filesystem by default."""
233 process, url = self.start_server_port()
234 transport = get_transport(url)
235 self.assertRaises(errors.TransportNotPossible, transport.mkdir, 'adir')
236 self.assertServerFinishesCleanly(process)
237
238 def test_bzr_serve_port_readwrite(self):
239 # Make a branch
240 self.make_branch('.')
241
242 process, url = self.start_server_port(['--allow-writes'])
243
244 # Connect to the server
245 branch = Branch.open(url)
246 self.make_read_requests(branch)
247 self.assertServerFinishesCleanly(process)
248
249 def test_bzr_serve_supports_protocol(self):
250 # Make a branch
251 self.make_branch('.')
252
253 process, url = self.start_server_port(['--allow-writes',
254 '--protocol=bzr'])
255
256 # Connect to the server
257 branch = Branch.open(url)
258 self.make_read_requests(branch)
259 self.assertServerFinishesCleanly(process)
260
261def serve_port_scenarios():
262 return (('bare', dict(use_ssl=False)),
263 ('ssl' , dict(use_ssl=True)))
264
265def load_tests(basic_tests, module, loader):
266 from bzrlib import tests
267 suite = loader.suiteClass()
268 serve_port_tests, remaining_tests = tests.split_suite_by_condition(
269 basic_tests, tests.condition_isinstance(TestBzrServePort))
270 tests.multiply_tests(serve_port_tests, serve_port_scenarios(), suite)
271 suite.addTest(remaining_tests)
272 return suite
273
247class TestCmdServeChrooting(TestCaseWithTransport):274class TestCmdServeChrooting(TestCaseWithTransport):
248275
249 def test_serve_tcp(self):276 def test_serve_tcp(self):
250277
=== modified file 'bzrlib/transport/__init__.py'
--- bzrlib/transport/__init__.py 2009-08-04 11:40:59 +0000
+++ bzrlib/transport/__init__.py 2009-08-14 20:35:21 +0000
@@ -1826,9 +1826,14 @@
1826register_transport_proto('bzr://',1826register_transport_proto('bzr://',
1827 help="Fast access using the Bazaar smart server.",1827 help="Fast access using the Bazaar smart server.",
1828 register_netloc=True)1828 register_netloc=True)
1829register_transport_proto('bzrs://',
1830 help="Fast access using the Bazaar smart server over SSL.",
1831 register_netloc=True)
18291832
1830register_lazy_transport('bzr://', 'bzrlib.transport.remote',1833register_lazy_transport('bzr://', 'bzrlib.transport.remote',
1831 'RemoteTCPTransport')1834 'RemoteTCPTransport')
1835register_lazy_transport('bzrs://', 'bzrlib.transport.remote',
1836 'RemoteSSLTransport')
1832register_transport_proto('bzr-v2://', register_netloc=True)1837register_transport_proto('bzr-v2://', register_netloc=True)
18331838
1834register_lazy_transport('bzr-v2://', 'bzrlib.transport.remote',1839register_lazy_transport('bzr-v2://', 'bzrlib.transport.remote',
18351840
=== modified file 'bzrlib/transport/http/_urllib2_wrappers.py'
--- bzrlib/transport/http/_urllib2_wrappers.py 2009-05-04 15:21:26 +0000
+++ bzrlib/transport/http/_urllib2_wrappers.py 2009-08-14 20:35:21 +0000
@@ -280,19 +280,6 @@
280 self._wrap_socket_for_reporting(self.sock)280 self._wrap_socket_for_reporting(self.sock)
281281
282282
283# Build the appropriate socket wrapper for ssl
284try:
285 # python 2.6 introduced a better ssl package
286 import ssl
287 _ssl_wrap_socket = ssl.wrap_socket
288except ImportError:
289 # python versions prior to 2.6 don't have ssl and ssl.wrap_socket instead
290 # they use httplib.FakeSocket
291 def _ssl_wrap_socket(sock, key_file, cert_file):
292 ssl_sock = socket.ssl(sock, key_file, cert_file)
293 return httplib.FakeSocket(sock, ssl_sock)
294
295
296class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):283class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):
297284
298 def __init__(self, host, port=None, key_file=None, cert_file=None,285 def __init__(self, host, port=None, key_file=None, cert_file=None,
@@ -313,7 +300,8 @@
313 self.connect_to_origin()300 self.connect_to_origin()
314301
315 def connect_to_origin(self):302 def connect_to_origin(self):
316 ssl_sock = _ssl_wrap_socket(self.sock, self.key_file, self.cert_file)303 ssl_sock = osutils.ssl_wrap_socket(
304 self.sock, self.key_file, self.cert_file)
317 # Wrap the ssl socket before anybody use it305 # Wrap the ssl socket before anybody use it
318 self._wrap_socket_for_reporting(ssl_sock)306 self._wrap_socket_for_reporting(ssl_sock)
319307
320308
=== modified file 'bzrlib/transport/remote.py'
--- bzrlib/transport/remote.py 2009-03-24 01:53:42 +0000
+++ bzrlib/transport/remote.py 2009-08-14 20:35:21 +0000
@@ -485,6 +485,19 @@
485 return client_medium, None485 return client_medium, None
486486
487487
488class RemoteSSLTransport(RemoteTransport):
489 """Connection to smart server over ssl.
490
491 This is essentially just a factory to get 'RemoteTransport(url,
492 SmartTCPClientMedium).
493 """
494
495 def _build_medium(self):
496 client_medium = medium.SmartTCPClientMedium(
497 self._host, self._port, self.base, use_ssl=True)
498 return client_medium, None
499
500
488class RemoteTCPTransportV2Only(RemoteTransport):501class RemoteTCPTransportV2Only(RemoteTransport):
489 """Connection to smart server over plain tcp with the client hard-coded to502 """Connection to smart server over plain tcp with the client hard-coded to
490 assume protocol v2 and remote server version <= 1.6.503 assume protocol v2 and remote server version <= 1.6.