Merge lp:~jml/launchpad/extract-ssh-server-auth into lp:launchpad

Proposed by Jonathan Lange
Status: Merged
Approved by: Eleanor Berger
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~jml/launchpad/extract-ssh-server-auth
Merge into: lp:launchpad
Prerequisite: lp:~jml/launchpad/extract-ssh-server-logging
Diff against target: 620 lines (+252/-125) (has conflicts)
9 files modified
daemons/sftp.tac (+3/-2)
lib/lp/codehosting/sshserver/auth.py (+17/-49)
lib/lp/codehosting/sshserver/daemon.py (+105/-0)
lib/lp/codehosting/sshserver/service.py (+19/-57)
lib/lp/codehosting/sshserver/tests/test_auth.py (+7/-7)
lib/lp/codehosting/sshserver/tests/test_daemon.py (+93/-0)
lib/lp/codehosting/sshserver/tests/test_session.py (+4/-4)
lib/lp/codehosting/tests/helpers.py (+0/-2)
lib/lp/codehosting/tests/test_sftp.py (+4/-4)
Text conflict in daemons/sftp.tac
Text conflict in lib/lp/codehosting/sshserver/accesslog.py
Text conflict in lib/lp/codehosting/sshserver/service.py
Text conflict in lib/lp/codehosting/sshserver/tests/test_auth.py
To merge this branch: bzr merge lp:~jml/launchpad/extract-ssh-server-auth
Reviewer Review Type Date Requested Status
Eleanor Berger (community) code Approve
Review via email: mp+23482@code.launchpad.net

Commit message

Move codehosting-specific stuff into new codehosting-specific module

Description of the change

This is yet another part of the massive branch that splits out the ssh server from codehosting.

This branch takes the codehosting-specific auth stuff and puts it into a new module: lp.codehosting.sshserver.daemon. It also takes the codehosting-specific stuff from the "service" module and puts it in there.

Most of the changes are fairly simple. The only subtlety is that the LaunchpadAvatar class now has a new child class called CodehostingAvatar.

To post a comment you must log in.
Revision history for this message
Eleanor Berger (intellectronica) wrote :

There were a few places where moved legacy code didn't conform to our stringent coding conventions, and you kindly offered to fix them before landing this branch.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'daemons/sftp.tac'
2--- daemons/sftp.tac 2010-04-16 19:00:51 +0000
3+++ daemons/sftp.tac 2010-04-16 19:00:53 +0000
4@@ -18,9 +18,10 @@
5 # Construct an Application that has the codehosting SSH server.
6 =======
7
8-from lp.codehosting.sshserver.service import (
9+from lp.codehosting.sshserver.daemon import (
10 ACCESS_LOG_NAME, get_key_path, LOG_NAME, make_portal, OOPS_CONFIG_SECTION,
11- PRIVATE_KEY_FILE, PUBLIC_KEY_FILE, SSHService)
12+ PRIVATE_KEY_FILE, PUBLIC_KEY_FILE)
13+from lp.codehosting.sshserver.service import SSHService
14
15
16 # Construct an Application that has the codehosting SSH server.
17
18=== modified file 'lib/lp/codehosting/sshserver/auth.py'
19--- lib/lp/codehosting/sshserver/auth.py 2010-04-16 19:00:51 +0000
20+++ lib/lp/codehosting/sshserver/auth.py 2010-04-16 19:00:53 +0000
21@@ -13,7 +13,8 @@
22
23 __metaclass__ = type
24 __all__ = [
25- 'get_portal',
26+ 'LaunchpadAvatar',
27+ 'PublicKeyFromLaunchpadChecker',
28 'SSHUserAuthServer',
29 ]
30
31@@ -21,48 +22,47 @@
32
33 from twisted.conch import avatar
34 from twisted.conch.error import ConchError
35-from twisted.conch.interfaces import IConchUser, ISession
36-from twisted.conch.ssh import filetransfer, keys, userauth
37+from twisted.conch.interfaces import IConchUser
38+from twisted.conch.ssh import keys, userauth
39 from twisted.conch.ssh.common import getNS, NS
40 from twisted.conch.checkers import SSHPublicKeyDatabase
41
42 from twisted.cred.error import UnauthorizedLogin
43 from twisted.cred.checkers import ICredentialsChecker
44 from twisted.cred import credentials
45-from twisted.cred.portal import IRealm, Portal
46
47 from twisted.internet import defer
48
49-from twisted.python import components, failure
50+from twisted.python import failure
51
52 from zope.event import notify
53 from zope.interface import implements
54
55 from lp.codehosting import sftp
56 from lp.codehosting.sshserver import events
57-from lp.codehosting.sshserver.session import (
58- launch_smart_server, PatchedSSHSession)
59+from lp.codehosting.sshserver.session import PatchedSSHSession
60 from lp.services.twistedsupport.xmlrpc import trap_fault
61-from canonical.config import config
62 from canonical.launchpad.xmlrpc import faults
63
64
65 class LaunchpadAvatar(avatar.ConchUser):
66 """An account on the SSH server, corresponding to a Launchpad person.
67
68- :ivar branchfs_proxy: A Twisted XML-RPC client for the authserver. The
69- server must implement `IBranchFileSystem`.
70 :ivar channelLookup: See `avatar.ConchUser`.
71 :ivar subsystemLookup: See `avatar.ConchUser`.
72 :ivar user_id: The Launchpad database ID of the Person for this account.
73 :ivar username: The Launchpad username for this account.
74 """
75
76- def __init__(self, userDict, branchfs_proxy):
77+ def __init__(self, user_dict):
78+ """Construct a `LaunchpadAvatar`.
79+
80+ :param user_dict: The result of a call to
81+ `IAuthServer.getUserAndSSHKeys`.
82+ """
83 avatar.ConchUser.__init__(self)
84- self.branchfs_proxy = branchfs_proxy
85- self.user_id = userDict['id']
86- self.username = userDict['name']
87+ self.user_id = user_dict['id']
88+ self.username = user_dict['name']
89
90 # Set the only channel as a standard SSH session (with a couple of bug
91 # fixes).
92@@ -74,34 +74,10 @@
93 notify(events.UserLoggedOut(self))
94
95
96-components.registerAdapter(launch_smart_server, LaunchpadAvatar, ISession)
97-
98-components.registerAdapter(
99- sftp.avatar_to_sftp_server, LaunchpadAvatar, filetransfer.ISFTPServer)
100-
101-
102 class UserDisplayedUnauthorizedLogin(UnauthorizedLogin):
103 """UnauthorizedLogin which should be reported to the user."""
104
105
106-class Realm:
107- implements(IRealm)
108-
109- def __init__(self, authentication_proxy, branchfs_proxy):
110- self.authentication_proxy = authentication_proxy
111- self.branchfs_proxy = branchfs_proxy
112-
113- def requestAvatar(self, avatarId, mind, *interfaces):
114- # Fetch the user's details from the authserver
115- deferred = mind.lookupUserDetails(self.authentication_proxy, avatarId)
116-
117- # Once all those details are retrieved, we can construct the avatar.
118- def gotUserDict(userDict):
119- avatar = LaunchpadAvatar(userDict, self.branchfs_proxy)
120- return interfaces[0], avatar, avatar.logout
121- return deferred.addCallback(gotUserDict)
122-
123-
124 class ISSHPrivateKeyWithMind(credentials.ISSHPrivateKey):
125 """Marker interface for SSH credentials that reference a Mind."""
126
127@@ -303,7 +279,7 @@
128 raise UserDisplayedUnauthorizedLogin(
129 "No such Launchpad account: %s" % credentials.username)
130
131- def _checkForAuthorizedKey(self, userDict, credentials):
132+ def _checkForAuthorizedKey(self, user_dict, credentials):
133 """Check the key data in credentials against the keys found in LP."""
134 if credentials.algName == 'ssh-dss':
135 wantKeyType = 'DSA'
136@@ -313,12 +289,12 @@
137 # unknown key type
138 return False
139
140- if len(userDict['keys']) == 0:
141+ if len(user_dict['keys']) == 0:
142 raise UserDisplayedUnauthorizedLogin(
143 "Launchpad user %r doesn't have a registered SSH key"
144 % credentials.username)
145
146- for keytype, keytext in userDict['keys']:
147+ for keytype, keytext in user_dict['keys']:
148 if keytype != wantKeyType:
149 continue
150 try:
151@@ -330,11 +306,3 @@
152 raise UnauthorizedLogin(
153 "Your SSH key does not match any key registered for Launchpad "
154 "user %s" % credentials.username)
155-
156-
157-def get_portal(authentication_proxy, branchfs_proxy):
158- """Get a portal for connecting to Launchpad codehosting."""
159- portal = Portal(Realm(authentication_proxy, branchfs_proxy))
160- portal.registerChecker(
161- PublicKeyFromLaunchpadChecker(authentication_proxy))
162- return portal
163
164=== added file 'lib/lp/codehosting/sshserver/daemon.py'
165--- lib/lp/codehosting/sshserver/daemon.py 1970-01-01 00:00:00 +0000
166+++ lib/lp/codehosting/sshserver/daemon.py 2010-04-16 19:00:53 +0000
167@@ -0,0 +1,105 @@
168+# Copyright 2010 Canonical Ltd. This software is licensed under the
169+# GNU Affero General Public License version 3 (see the file LICENSE).
170+
171+"""Glues the codehosting SSH daemon together."""
172+
173+__metaclass__ = type
174+__all__ = [
175+ 'ACCESS_LOG_NAME',
176+ 'CodehostingAvatar',
177+ 'get_key_path',
178+ 'get_portal',
179+ 'LOG_NAME',
180+ 'make_portal',
181+ 'PRIVATE_KEY_FILE',
182+ 'PUBLIC_KEY_FILE',
183+ ]
184+
185+import os
186+
187+from twisted.conch.interfaces import ISession
188+from twisted.conch.ssh import filetransfer
189+from twisted.cred.portal import IRealm, Portal
190+from twisted.python import components
191+from twisted.web.xmlrpc import Proxy
192+
193+from zope.interface import implements
194+
195+from canonical.config import config
196+from lp.codehosting import sftp
197+from lp.codehosting.sshserver.auth import (
198+ LaunchpadAvatar, PublicKeyFromLaunchpadChecker)
199+from lp.codehosting.sshserver.session import launch_smart_server
200+
201+
202+# The names of the key files of the server itself. The directory itself is
203+# given in config.codehosting.host_key_pair_path.
204+PRIVATE_KEY_FILE = 'ssh_host_key_rsa'
205+PUBLIC_KEY_FILE = 'ssh_host_key_rsa.pub'
206+
207+OOPS_CONFIG_SECTION = 'codehosting'
208+LOG_NAME = 'codehosting'
209+ACCESS_LOG_NAME = 'codehosting.access'
210+
211+
212+class CodehostingAvatar(LaunchpadAvatar):
213+ """An SSH avatar specific to codehosting.
214+
215+ :ivar branchfs_proxy: A Twisted XML-RPC client for the authserver. The
216+ server must implement `IBranchFileSystem`.
217+ """
218+
219+ def __init__(self, user_dict, branchfs_proxy):
220+ LaunchpadAvatar.__init__(self, user_dict)
221+ self.branchfs_proxy = branchfs_proxy
222+
223+
224+components.registerAdapter(launch_smart_server, CodehostingAvatar, ISession)
225+
226+components.registerAdapter(
227+ sftp.avatar_to_sftp_server, CodehostingAvatar, filetransfer.ISFTPServer)
228+
229+
230+class Realm:
231+ implements(IRealm)
232+
233+ def __init__(self, authentication_proxy, branchfs_proxy):
234+ self.authentication_proxy = authentication_proxy
235+ self.branchfs_proxy = branchfs_proxy
236+
237+ def requestAvatar(self, avatar_id, mind, *interfaces):
238+ # Fetch the user's details from the authserver
239+ deferred = mind.lookupUserDetails(
240+ self.authentication_proxy, avatar_id)
241+
242+ # Once all those details are retrieved, we can construct the avatar.
243+ def got_user_dict(user_dict):
244+ avatar = CodehostingAvatar(user_dict, self.branchfs_proxy)
245+ return interfaces[0], avatar, avatar.logout
246+
247+ return deferred.addCallback(got_user_dict)
248+
249+
250+def get_portal(authentication_proxy, branchfs_proxy):
251+ """Get a portal for connecting to Launchpad codehosting."""
252+ portal = Portal(Realm(authentication_proxy, branchfs_proxy))
253+ portal.registerChecker(
254+ PublicKeyFromLaunchpadChecker(authentication_proxy))
255+ return portal
256+
257+
258+def get_key_path(key_filename):
259+ key_directory = config.codehosting.host_key_pair_path
260+ return os.path.join(config.root, key_directory, key_filename)
261+
262+
263+def make_portal():
264+ """Create and return a `Portal` for the SSH service.
265+
266+ This portal accepts SSH credentials and returns our customized SSH
267+ avatars (see `lp.codehosting.sshserver.auth.CodehostingAvatar`).
268+ """
269+ authentication_proxy = Proxy(
270+ config.codehosting.authentication_endpoint)
271+ branchfs_proxy = Proxy(config.codehosting.branchfs_endpoint)
272+ return get_portal(authentication_proxy, branchfs_proxy)
273
274=== modified file 'lib/lp/codehosting/sshserver/service.py'
275--- lib/lp/codehosting/sshserver/service.py 2010-04-16 19:00:51 +0000
276+++ lib/lp/codehosting/sshserver/service.py 2010-04-16 19:00:53 +0000
277@@ -8,12 +8,6 @@
278
279 __metaclass__ = type
280 __all__ = [
281- 'ACCESS_LOG_NAME',
282- 'get_key_path',
283- 'LOG_NAME',
284- 'make_portal',
285- 'PRIVATE_KEY_FILE',
286- 'PUBLIC_KEY_FILE',
287 'SSHService',
288 ]
289
290@@ -27,13 +21,11 @@
291 from twisted.conch.ssh.transport import SSHServerTransport
292 from twisted.internet import defer
293 from twisted.protocols.policies import TimeoutFactory
294-from twisted.web.xmlrpc import Proxy
295
296 from zope.event import notify
297
298-from canonical.config import config
299 from lp.codehosting.sshserver import accesslog, events
300-from lp.codehosting.sshserver.auth import get_portal, SSHUserAuthServer
301+from lp.codehosting.sshserver.auth import SSHUserAuthServer
302 from lp.services.twistedsupport import gatherResults
303 from lp.services.twistedsupport.loggingsupport import set_up_oops_reporting
304
305@@ -43,16 +35,6 @@
306 PRIVATE_KEY_FILE = 'ssh_host_key_rsa'
307 PUBLIC_KEY_FILE = 'ssh_host_key_rsa.pub'
308
309-OOPS_CONFIG_SECTION = 'codehosting'
310-LOG_NAME = 'codehosting'
311-ACCESS_LOG_NAME = 'codehosting.access'
312-
313-
314-# The names of the key files of the server itself. The directory itself is
315-# given in config.codehosting.host_key_pair_path.
316-PRIVATE_KEY_FILE = 'ssh_host_key_rsa'
317-PUBLIC_KEY_FILE = 'ssh_host_key_rsa.pub'
318-
319
320 class KeepAliveSettingSSHServerTransport(SSHServerTransport):
321
322@@ -61,44 +43,24 @@
323 self.transport.setTcpKeepAlive(True)
324
325
326-<<<<<<< TREE
327-def get_key_path(key_filename):
328- key_directory = config.codehosting.host_key_pair_path
329- return os.path.join(config.root, key_directory, key_filename)
330-
331-
332-def make_portal():
333- """Create and return a `Portal` for the SSH service.
334-
335- This portal accepts SSH credentials and returns our customized SSH
336- avatars (see `lp.codehosting.sshserver.auth.LaunchpadAvatar`).
337- """
338- authentication_proxy = Proxy(
339- config.codehosting.authentication_endpoint)
340- branchfs_proxy = Proxy(config.codehosting.branchfs_endpoint)
341- return get_portal(authentication_proxy, branchfs_proxy)
342-
343-
344-
345-=======
346-def get_key_path(key_filename):
347- key_directory = config.codehosting.host_key_pair_path
348- return os.path.join(config.root, key_directory, key_filename)
349-
350-
351-def make_portal():
352- """Create and return a `Portal` for the SSH service.
353-
354- This portal accepts SSH credentials and returns our customized SSH
355- avatars (see `lp.codehosting.sshserver.auth.LaunchpadAvatar`).
356- """
357- authentication_proxy = Proxy(
358- config.codehosting.authentication_endpoint)
359- branchfs_proxy = Proxy(config.codehosting.branchfs_endpoint)
360- return get_portal(authentication_proxy, branchfs_proxy)
361-
362-
363->>>>>>> MERGE-SOURCE
364+def get_key_path(key_filename):
365+ key_directory = config.codehosting.host_key_pair_path
366+ return os.path.join(config.root, key_directory, key_filename)
367+
368+
369+def make_portal():
370+ """Create and return a `Portal` for the SSH service.
371+
372+ This portal accepts SSH credentials and returns our customized SSH
373+ avatars (see `lp.codehosting.sshserver.auth.LaunchpadAvatar`).
374+ """
375+ authentication_proxy = Proxy(
376+ config.codehosting.authentication_endpoint)
377+ branchfs_proxy = Proxy(config.codehosting.branchfs_endpoint)
378+ return get_portal(authentication_proxy, branchfs_proxy)
379+
380+
381+
382 class Factory(SSHFactory):
383 """SSH factory that uses Launchpad's custom authentication.
384
385
386=== modified file 'lib/lp/codehosting/sshserver/tests/test_auth.py'
387--- lib/lp/codehosting/sshserver/tests/test_auth.py 2010-04-13 18:32:15 +0000
388+++ lib/lp/codehosting/sshserver/tests/test_auth.py 2010-04-16 19:00:53 +0000
389@@ -18,14 +18,13 @@
390 from twisted.internet import defer
391 from twisted.python import failure
392 from twisted.python.util import sibpath
393-from twisted.test.proto_helpers import StringTransport
394
395 from twisted.trial.unittest import TestCase as TrialTestCase
396
397 from canonical.config import config
398 from canonical.launchpad.xmlrpc import faults
399 from canonical.testing.layers import TwistedLayer
400-from lp.codehosting.sshserver import auth, service
401+from lp.codehosting.sshserver import auth
402 from lp.services.twistedsupport import suppress_stderr
403
404
405@@ -38,14 +37,12 @@
406
407 implements(IRealm)
408
409- def requestAvatar(self, avatarId, mind, *interfaces):
410+ def requestAvatar(self, avatar_id, mind, *interfaces):
411 user_dict = {
412- 'id': avatarId, 'name': avatarId, 'teams': [],
413+ 'id': avatar_id, 'name': avatar_id, 'teams': [],
414 'initialBranches': []}
415 return (
416- interfaces[0],
417- auth.LaunchpadAvatar(user_dict, None),
418- lambda: None)
419+ interfaces[0], auth.LaunchpadAvatar(user_dict), lambda: None)
420
421
422 class MockSSHTransport(SSHServerTransport):
423@@ -501,6 +498,7 @@
424 return d
425
426
427+<<<<<<< TREE
428 class StringTransportWith_setTcpKeepAlive(StringTransport):
429 def __init__(self, hostAddress=None, peerAddress=None):
430 StringTransport.__init__(self, hostAddress, peerAddress)
431@@ -569,5 +567,7 @@
432
433 self.assertNotIdentical(mind1.cache, mind2.cache)
434
435+=======
436+>>>>>>> MERGE-SOURCE
437 def test_suite():
438 return unittest.TestLoader().loadTestsFromName(__name__)
439
440=== added file 'lib/lp/codehosting/sshserver/tests/test_daemon.py'
441--- lib/lp/codehosting/sshserver/tests/test_daemon.py 1970-01-01 00:00:00 +0000
442+++ lib/lp/codehosting/sshserver/tests/test_daemon.py 2010-04-16 19:00:53 +0000
443@@ -0,0 +1,93 @@
444+# Copyright 2010 Canonical Ltd. This software is licensed under the
445+# GNU Affero General Public License version 3 (see the file LICENSE).
446+
447+"""Tests for the codehosting SSH server glue."""
448+
449+__metaclass__ = type
450+
451+import unittest
452+
453+from twisted.conch.ssh.common import NS
454+from twisted.conch.ssh.keys import Key
455+from twisted.test.proto_helpers import StringTransport
456+from twisted.trial.unittest import TestCase as TrialTestCase
457+
458+from canonical.testing.layers import TwistedLayer
459+
460+from lp.codehosting.sshserver.auth import SSHUserAuthServer
461+from lp.codehosting.sshserver.daemon import (
462+ get_key_path, get_portal, PRIVATE_KEY_FILE, PUBLIC_KEY_FILE)
463+from lp.codehosting.sshserver.service import Factory
464+
465+
466+class StringTransportWith_setTcpKeepAlive(StringTransport):
467+ def __init__(self, hostAddress=None, peerAddress=None):
468+ StringTransport.__init__(self, hostAddress, peerAddress)
469+ self._keepAlive = False
470+
471+ def setTcpKeepAlive(self, flag):
472+ self._keepAlive = flag
473+
474+
475+class TestFactory(TrialTestCase):
476+ """Tests for our SSH factory."""
477+
478+ layer = TwistedLayer
479+
480+ def makeFactory(self):
481+ """Create and start the factory that our SSH server uses."""
482+ factory = Factory(
483+ get_portal(None, None),
484+ private_key=Key.fromFile(
485+ get_key_path(PRIVATE_KEY_FILE)),
486+ public_key=Key.fromFile(
487+ get_key_path(PUBLIC_KEY_FILE)))
488+ factory.startFactory()
489+ return factory
490+
491+ def startConnecting(self, factory):
492+ """Connect to the `factory`."""
493+ server_transport = factory.buildProtocol(None)
494+ server_transport.makeConnection(StringTransportWith_setTcpKeepAlive())
495+ return server_transport
496+
497+ def test_set_keepalive_on_connection(self):
498+ # The server transport sets TCP keep alives on the underlying
499+ # transport.
500+ factory = self.makeFactory()
501+ server_transport = self.startConnecting(factory)
502+ self.assertTrue(server_transport.transport._keepAlive)
503+
504+ def beginAuthentication(self, factory):
505+ """Connect to `factory` and begin authentication on this connection.
506+
507+ :return: The `SSHServerTransport` after the process of authentication
508+ has begun.
509+ """
510+ server_transport = self.startConnecting(factory)
511+ server_transport.ssh_SERVICE_REQUEST(NS('ssh-userauth'))
512+ self.addCleanup(server_transport.service.serviceStopped)
513+ return server_transport
514+
515+ def test_authentication_uses_our_userauth_service(self):
516+ # The service of a SSHServerTransport after authentication has started
517+ # is an instance of our SSHUserAuthServer class.
518+ factory = self.makeFactory()
519+ transport = self.beginAuthentication(factory)
520+ self.assertIsInstance(transport.service, SSHUserAuthServer)
521+
522+ def test_two_connections_two_minds(self):
523+ # Two attempts to authenticate do not share the user-details cache.
524+ factory = self.makeFactory()
525+
526+ server_transport1 = self.beginAuthentication(factory)
527+ server_transport2 = self.beginAuthentication(factory)
528+
529+ mind1 = server_transport1.service.getMind()
530+ mind2 = server_transport2.service.getMind()
531+
532+ self.assertNotIdentical(mind1.cache, mind2.cache)
533+
534+
535+def test_suite():
536+ return unittest.TestLoader().loadTestsFromName(__name__)
537
538=== modified file 'lib/lp/codehosting/sshserver/tests/test_session.py'
539--- lib/lp/codehosting/sshserver/tests/test_session.py 2010-03-15 06:42:34 +0000
540+++ lib/lp/codehosting/sshserver/tests/test_session.py 2010-04-16 19:00:53 +0000
541@@ -14,7 +14,7 @@
542
543 from canonical.config import config
544 from lp.codehosting import get_bzr_path, get_BZR_PLUGIN_PATH_for_subprocess
545-from lp.codehosting.sshserver.auth import LaunchpadAvatar
546+from lp.codehosting.sshserver.daemon import CodehostingAvatar
547 from lp.codehosting.sshserver.session import (
548 ExecOnlySession, ForbiddenCommand, RestrictedExecOnlySession)
549 from lp.codehosting.tests.helpers import AvatarTestCase
550@@ -83,7 +83,7 @@
551
552 def setUp(self):
553 AvatarTestCase.setUp(self)
554- self.avatar = LaunchpadAvatar(self.aliceUserDict, None)
555+ self.avatar = CodehostingAvatar(self.aliceUserDict, None)
556 # The logging system will try to get the id of avatar.transport, so
557 # let's give it something to take the id of.
558 self.avatar.transport = object()
559@@ -239,7 +239,7 @@
560
561 def setUp(self):
562 AvatarTestCase.setUp(self)
563- self.avatar = LaunchpadAvatar(self.aliceUserDict, None)
564+ self.avatar = CodehostingAvatar(self.aliceUserDict, None)
565 self.reactor = MockReactor()
566 self.session = RestrictedExecOnlySession(
567 self.avatar, self.reactor, 'foo', 'bar baz %(user_id)s')
568@@ -305,7 +305,7 @@
569
570 def setUp(self):
571 AvatarTestCase.setUp(self)
572- self.avatar = LaunchpadAvatar(self.aliceUserDict, None)
573+ self.avatar = CodehostingAvatar(self.aliceUserDict, None)
574
575 def test_avatarAdaptsToRestrictedExecOnlySession(self):
576 # When Conch tries to adapt the SSH server avatar to ISession, it
577
578=== modified file 'lib/lp/codehosting/tests/helpers.py'
579--- lib/lp/codehosting/tests/helpers.py 2009-06-25 04:06:00 +0000
580+++ lib/lp/codehosting/tests/helpers.py 2010-04-16 19:00:53 +0000
581@@ -7,9 +7,7 @@
582 __all__ = [
583 'AvatarTestCase',
584 'adapt_suite',
585- 'BranchTestCase',
586 'CodeHostingTestProviderAdapter',
587- 'CodeHostingRepositoryTestProviderAdapter',
588 'create_branch_with_one_revision',
589 'deferToThread',
590 'LoomTestMixin',
591
592=== modified file 'lib/lp/codehosting/tests/test_sftp.py'
593--- lib/lp/codehosting/tests/test_sftp.py 2010-02-01 04:33:22 +0000
594+++ lib/lp/codehosting/tests/test_sftp.py 2010-04-16 19:00:53 +0000
595@@ -25,7 +25,7 @@
596 from lp.codehosting.inmemory import InMemoryFrontend, XMLRPCWrapper
597 from lp.codehosting.sftp import (
598 FatLocalTransport, TransportSFTPServer, FileIsADirectory)
599-from lp.codehosting.sshserver.auth import LaunchpadAvatar
600+from lp.codehosting.sshserver.daemon import CodehostingAvatar
601 from lp.testing.factory import LaunchpadObjectFactory
602 from canonical.testing.layers import TwistedLayer
603
604@@ -110,13 +110,13 @@
605 self.branchfs_endpoint = XMLRPCWrapper(
606 frontend.getFilesystemEndpoint())
607
608- def makeLaunchpadAvatar(self):
609+ def makeCodehostingAvatar(self):
610 user = self.factory.makePerson()
611 user_dict = dict(id=user.id, name=user.name)
612- return LaunchpadAvatar(user_dict, self.branchfs_endpoint)
613+ return CodehostingAvatar(user_dict, self.branchfs_endpoint)
614
615 def test_canAdaptToSFTPServer(self):
616- avatar = self.makeLaunchpadAvatar()
617+ avatar = self.makeCodehostingAvatar()
618 # The adapter logs the SFTPStarted event, which gets the id of the
619 # transport attribute of 'avatar'. Here we set transport to an
620 # arbitrary object that can have its id taken.