Merge lp:~wgrant/launchpad/no-passwords into lp:launchpad

Proposed by William Grant on 2012-01-18
Status: Merged
Merged at revision: 14694
Proposed branch: lp:~wgrant/launchpad/no-passwords
Merge into: lp:launchpad
Prerequisite: lp:~wgrant/launchpad/hardcoded-password
Diff against target: 694 lines (+33/-309)
14 files modified
lib/lp/registry/doc/person-account.txt (+3/-5)
lib/lp/registry/doc/person.txt (+1/-1)
lib/lp/registry/interfaces/person.py (+3/-9)
lib/lp/registry/model/person.py (+5/-10)
lib/lp/services/database/doc/storm.txt (+0/-4)
lib/lp/services/identity/configure.zcml (+1/-1)
lib/lp/services/identity/doc/account.txt (+5/-45)
lib/lp/services/identity/interfaces/account.py (+4/-17)
lib/lp/services/identity/model/account.py (+3/-64)
lib/lp/services/webapp/authentication.py (+0/-47)
lib/lp/services/webapp/configure.zcml (+0/-6)
lib/lp/services/webapp/interfaces.py (+0/-14)
lib/lp/services/webapp/tests/test_encryptor.py (+0/-63)
lib/lp/testing/factory.py (+8/-23)
To merge this branch: bzr merge lp:~wgrant/launchpad/no-passwords
Reviewer Review Type Date Requested Status
Steve Kowalik (community) code 2012-01-18 Approve on 2012-01-18
Review via email: mp+88971@code.launchpad.net

Commit Message

[r=stevenk][no-qa] Rip out the password infrastructure.

Description of the Change

The password infrastructure (AccountPassword and friends) is no longer used. Good riddance.

To post a comment you must log in.
Steve Kowalik (stevenk) wrote :

As you say, good riddance.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/doc/person-account.txt'
2--- lib/lp/registry/doc/person-account.txt 2012-01-15 11:50:42 +0000
3+++ lib/lp/registry/doc/person-account.txt 2012-01-18 07:40:38 +0000
4@@ -31,17 +31,16 @@
5 the profile. Sample Person cannot claim it.
6
7 >>> login('test@canonical.com')
8- >>> matsubara.account.reactivate(comment="test", password='ok')
9+ >>> matsubara.account.reactivate(comment="test")
10 Traceback (most recent call last):
11 ...
12 Unauthorized: ...'launchpad.Special')
13
14-Matsubara can. A password and a preferred email address must be passed
15-as arguments.
16+Matsubara can.
17
18 >>> from zope.security.proxy import removeSecurityProxy
19 >>> login('matsubara@async.com.br')
20- >>> matsubara.account.reactivate(comment="test", password='ok')
21+ >>> matsubara.account.reactivate(comment="test")
22 >>> matsubara.setPreferredEmail(emailaddress)
23 >>> import transaction
24 >>> transaction.commit()
25@@ -215,7 +214,6 @@
26
27 >>> foobar.reactivate(
28 ... 'User reactivated the account using reset password.',
29- ... password="ok",
30 ... preferred_email=foobar_preferredemail)
31 >>> transaction.commit() # To see the changes on other stores.
32 >>> foobar.account.status
33
34=== modified file 'lib/lp/registry/doc/person.txt'
35--- lib/lp/registry/doc/person.txt 2012-01-17 00:39:56 +0000
36+++ lib/lp/registry/doc/person.txt 2012-01-18 07:40:38 +0000
37@@ -142,7 +142,7 @@
38 >>> from lp.services.identity.model.account import Account
39 >>> from lp.services.database.lpstorm import IMasterStore
40 >>> account = IMasterStore(Account).get(Account, p.accountID)
41- >>> account.reactivate("Activated by doc test.", account.password)
42+ >>> account.reactivate("Activated by doc test.")
43 >>> p.account_status
44 <DBItem AccountStatus.ACTIVE...
45
46
47=== modified file 'lib/lp/registry/interfaces/person.py'
48--- lib/lp/registry/interfaces/person.py 2012-01-15 11:50:42 +0000
49+++ lib/lp/registry/interfaces/person.py 2012-01-18 07:40:38 +0000
50@@ -1817,7 +1817,6 @@
51 """Deactivate this person's Launchpad account.
52
53 Deactivating an account means:
54- - Setting its password to NULL;
55 - Removing the user from all teams he's a member of;
56 - Changing all his email addresses' status to NEW;
57 - Revoking Code of Conduct signatures of that user;
58@@ -1827,17 +1826,16 @@
59 :param comment: An explanation of why the account status changed.
60 """
61
62- def reactivate(comment, password, preferred_email):
63+ def reactivate(comment, preferred_email):
64 """Reactivate this person and its account.
65
66- Set the account status to ACTIVE, the account's password to the given
67- one and its preferred email address.
68+ Set the account status to ACTIVE, and update the preferred email
69+ address.
70
71 If the person's name contains a -deactivatedaccount suffix (usually
72 added by `IPerson`.deactivateAccount(), it is removed.
73
74 :param comment: An explanation of why the account status changed.
75- :param password: The user's password.
76 :param preferred_email: The `EmailAddress` to set as the account's
77 preferred email address. It cannot be None.
78 """
79@@ -2070,7 +2068,6 @@
80
81 def createPersonAndEmail(
82 email, rationale, comment=None, name=None, displayname=None,
83- password=None, passwordEncrypted=False,
84 hide_email_addresses=False, registrant=None):
85 """Create and return an `IPerson` and `IEmailAddress`.
86
87@@ -2091,9 +2088,6 @@
88 (e.g. "when the foo package was imported into Ubuntu Breezy").
89 :param name: The person's name.
90 :param displayname: The person's displayname.
91- :param password: The person's password.
92- :param passwordEncrypted: Whether or not the given password is
93- encrypted.
94 :param registrant: The user who created this person, if any.
95 :param hide_email_addresses: Whether or not Launchpad should hide the
96 person's email addresses from other users.
97
98=== modified file 'lib/lp/registry/model/person.py'
99--- lib/lp/registry/model/person.py 2012-01-16 13:11:00 +0000
100+++ lib/lp/registry/model/person.py 2012-01-18 07:40:38 +0000
101@@ -2516,10 +2516,10 @@
102 else:
103 return None
104
105- def reactivate(self, comment, password, preferred_email):
106+ def reactivate(self, comment, preferred_email):
107 """See `IPersonSpecialRestricted`."""
108 account = IMasterObject(self.account)
109- account.reactivate(comment, password)
110+ account.reactivate(comment)
111 self.setPreferredEmail(preferred_email)
112 if '-deactivatedaccount' in self.name:
113 # The name was changed by deactivateAccount(). Restore the
114@@ -3153,9 +3153,7 @@
115
116 elif person.account.status in [AccountStatus.DEACTIVATED,
117 AccountStatus.NOACCOUNT]:
118- password = ''
119- removeSecurityProxy(person.account).reactivate(
120- comment, password)
121+ removeSecurityProxy(person.account).reactivate(comment)
122 removeSecurityProxy(person).setPreferredEmail(email)
123 db_updated = True
124 else:
125@@ -3186,8 +3184,7 @@
126 return team
127
128 def createPersonAndEmail(
129- self, email, rationale, comment=None, name=None,
130- displayname=None, password=None, passwordEncrypted=False,
131+ self, email, rationale, comment=None, name=None, displayname=None,
132 hide_email_addresses=False, registrant=None):
133 """See `IPersonSet`."""
134
135@@ -3208,9 +3205,7 @@
136 # Convert the PersonCreationRationale to an AccountCreationRationale
137 account_rationale = getattr(AccountCreationRationale, rationale.name)
138
139- account = getUtility(IAccountSet).new(
140- account_rationale, displayname, password=password,
141- password_is_encrypted=passwordEncrypted)
142+ account = getUtility(IAccountSet).new(account_rationale, displayname)
143
144 person = self._newPerson(
145 name, displayname, hide_email_addresses, rationale=rationale,
146
147=== modified file 'lib/lp/services/database/doc/storm.txt'
148--- lib/lp/services/database/doc/storm.txt 2012-01-06 11:08:30 +0000
149+++ lib/lp/services/database/doc/storm.txt 2012-01-18 07:40:38 +0000
150@@ -16,10 +16,6 @@
151 ... ISlaveStore,
152 ... IStore,
153 ... )
154- >>> from lp.services.identity.model.account import (
155- ... Account,
156- ... AccountPassword,
157- ... )
158 >>> from lp.services.identity.model.emailaddress import EmailAddress
159 >>> from zope.security.proxy import ProxyFactory
160 >>> from lp.registry.interfaces.person import IPersonSet
161
162=== modified file 'lib/lp/services/identity/configure.zcml'
163--- lib/lp/services/identity/configure.zcml 2011-12-24 17:49:30 +0000
164+++ lib/lp/services/identity/configure.zcml 2012-01-18 07:40:38 +0000
165@@ -59,7 +59,7 @@
166 set_attributes="status date_status_set status_comment"/>
167 <require
168 permission="launchpad.Edit"
169- set_attributes="displayname password"/>
170+ set_attributes="displayname"/>
171 </class>
172
173 <securedutility
174
175=== modified file 'lib/lp/services/identity/doc/account.txt'
176--- lib/lp/services/identity/doc/account.txt 2012-01-03 11:08:31 +0000
177+++ lib/lp/services/identity/doc/account.txt 2012-01-18 07:40:38 +0000
178@@ -83,22 +83,6 @@
179 >>> account
180 <Account 'No Privileges Person' (Active account)>
181
182-It also has an encrypted password.
183-
184- >>> print account.password
185- K7Qmeansl6RbuPfulfcmyDQOzp70OxVh5Fcf
186-
187-Ensure the password changes are sticky, as this is a property hiding the
188-AccountPassword table.
189-
190- >>> account.password = None
191- >>> print account.password
192- None
193-
194- >>> account.password = u'K7Qmeansl6RbuPfulfcmyDQOzp70OxVh5Fcf'
195- >>> print account.password
196- K7Qmeansl6RbuPfulfcmyDQOzp70OxVh5Fcf
197-
198 The account has other metadata.
199
200 >>> account.date_created
201@@ -152,36 +136,12 @@
202
203 >>> from lp.services.identity.interfaces.account import (
204 ... AccountCreationRationale)
205- >>> from storm.store import Store
206
207 >>> login('admin@canonical.com')
208- >>> passwordless_account = account_set.new(
209- ... AccountCreationRationale.USER_CREATED, 'Passwordless')
210+ >>> new_account = account_set.new(
211+ ... AccountCreationRationale.USER_CREATED, 'New Account')
212 >>> transaction.commit()
213- >>> print passwordless_account.creation_rationale.name
214+ >>> print new_account.creation_rationale.name
215 USER_CREATED
216- >>> print passwordless_account.displayname
217- Passwordless
218- >>> print passwordless_account.password
219- None
220-
221-The new() method accepts the optional parameters of password and
222-password_is_encrypted. If password_is_encrypted is False, the default,
223-then the method encrypts it for us.
224-
225- >>> passworded_account = account_set.new(
226- ... AccountCreationRationale.OWNER_CREATED_LAUNCHPAD , 'Passworded',
227- ... password=u'clear_password')
228- >>> Store.of(passworded_account).flush()
229- >>> passworded_account.password == u'clear_password'
230- False
231-
232-The method does not encrypt the password if told that it is already
233-encrypted, by setting password_is_encrypted to True.
234-
235- >>> clear_account = account_set.new(
236- ... AccountCreationRationale.OWNER_CREATED_LAUNCHPAD , 'Clear',
237- ... password=u'clear_password', password_is_encrypted=True)
238- >>> Store.of(clear_account).flush()
239- >>> print clear_account.password
240- clear_password
241+ >>> print new_account.displayname
242+ New Account
243
244=== modified file 'lib/lp/services/identity/interfaces/account.py'
245--- lib/lp/services/identity/interfaces/account.py 2012-01-03 11:42:33 +0000
246+++ lib/lp/services/identity/interfaces/account.py 2012-01-18 07:40:38 +0000
247@@ -35,10 +35,7 @@
248 )
249
250 from lp import _
251-from lp.services.fields import (
252- PasswordField,
253- StrippedTextLine,
254- )
255+from lp.services.fields import StrippedTextLine
256
257
258 class AccountSuspendedError(Exception):
259@@ -229,9 +226,6 @@
260
261 openid_identifiers = Attribute(_("Linked OpenId Identifiers"))
262
263- password = PasswordField(
264- title=_("Password."), readonly=False, required=True)
265-
266
267 class IAccountSpecialRestricted(Interface):
268 """Attributes of `IAccount` protected with launchpad.Special."""
269@@ -244,14 +238,12 @@
270 title=_("Why are you deactivating your account?"),
271 required=False, readonly=False)
272
273- def reactivate(comment, password):
274+ def reactivate(comment):
275 """Activate this account.
276
277- Set the account status to ACTIVE, the account's password to the given
278- one and its preferred email address.
279+ Set the account status to ACTIVE.
280
281 :param comment: An explanation of why the account status changed.
282- :param password: The user's password.
283 """
284
285
286@@ -262,16 +254,11 @@
287 class IAccountSet(Interface):
288 """Creation of and access to `IAccount` providers."""
289
290- def new(rationale, displayname, password=None,
291- password_is_encrypted=False):
292+ def new(rationale, displayname):
293 """Create a new `IAccount`.
294
295 :param rationale: An `AccountCreationRationale` value.
296 :param displayname: The user's display name.
297- :param password: A password.
298- :param password_is_encrypted: If True, the password parameter has
299- already been encrypted using the `IPasswordEncryptor` utility.
300- If False, the password will be encrypted automatically.
301
302 :return: The newly created `IAccount` provider.
303 """
304
305=== modified file 'lib/lp/services/identity/model/account.py'
306--- lib/lp/services/identity/model/account.py 2012-01-03 11:08:31 +0000
307+++ lib/lp/services/identity/model/account.py 2012-01-18 07:40:38 +0000
308@@ -6,16 +6,11 @@
309 __metaclass__ = type
310 __all__ = [
311 'Account',
312- 'AccountPassword',
313 'AccountSet',
314 ]
315
316-from sqlobject import (
317- ForeignKey,
318- StringCol,
319- )
320+from sqlobject import StringCol
321 from storm.locals import ReferenceSet
322-from zope.component import getUtility
323 from zope.interface import implements
324
325 from lp.services.database.constants import UTC_NOW
326@@ -33,7 +28,6 @@
327 IAccountSet,
328 )
329 from lp.services.openid.model.openididentifier import OpenIdIdentifier
330-from lp.services.webapp.interfaces import IPasswordEncryptor
331
332
333 class Account(SQLBase):
334@@ -61,55 +55,17 @@
335 return "<%s '%s' (%s)>" % (
336 self.__class__.__name__, displayname, self.status)
337
338- def reactivate(self, comment, password):
339+ def reactivate(self, comment):
340 """See `IAccountSpecialRestricted`."""
341 self.status = AccountStatus.ACTIVE
342 self.status_comment = comment
343- self.password = password
344-
345- # The password is actually stored in a separate table for security
346- # reasons, so use a property to hide this implementation detail.
347- def _get_password(self):
348- # We have to force the switch to the auth store, because the
349- # AccountPassword table is not visible via the main store
350- # for security reasons.
351- password = IStore(AccountPassword).find(
352- AccountPassword, accountID=self.id).one()
353- if password is None:
354- return None
355- else:
356- return password.password
357-
358- def _set_password(self, value):
359- # Making a modification, so we explicitly use the auth store master.
360- store = IMasterStore(AccountPassword)
361- password = store.find(
362- AccountPassword, accountID=self.id).one()
363-
364- if value is not None and password is None:
365- # There is currently no AccountPassword record and we need one.
366- AccountPassword(accountID=self.id, password=value)
367- elif value is None and password is not None:
368- # There is an AccountPassword record that needs removing.
369- store.remove(password)
370- elif value is not None:
371- # There is an AccountPassword record that needs updating.
372- password.password = value
373- elif value is None and password is None:
374- # Nothing to do
375- pass
376- else:
377- assert False, "This should not be reachable."
378-
379- password = property(_get_password, _set_password)
380
381
382 class AccountSet:
383 """See `IAccountSet`."""
384 implements(IAccountSet)
385
386- def new(self, rationale, displayname, password=None,
387- password_is_encrypted=False, openid_identifier=None):
388+ def new(self, rationale, displayname, openid_identifier=None):
389 """See `IAccountSet`."""
390
391 account = Account(
392@@ -123,12 +79,6 @@
393 identifier.identifier = openid_identifier
394 IMasterStore(OpenIdIdentifier).add(identifier)
395
396- # Create the password record.
397- if password is not None:
398- if not password_is_encrypted:
399- password = getUtility(IPasswordEncryptor).encrypt(password)
400- AccountPassword(account=account, password=password)
401-
402 return account
403
404 def get(self, id):
405@@ -148,14 +98,3 @@
406 if account is None:
407 raise LookupError(openid_identifier)
408 return account
409-
410-
411-class AccountPassword(SQLBase):
412- """SQLObject wrapper to the AccountPassword table.
413-
414- Note that this class is not exported, as the existence of the
415- AccountPassword table only needs to be known by this module.
416- """
417- account = ForeignKey(
418- dbName='account', foreignKey='Account', alternateID=True)
419- password = StringCol(dbName='password', notNull=True)
420
421=== modified file 'lib/lp/services/webapp/authentication.py'
422--- lib/lp/services/webapp/authentication.py 2012-01-18 07:40:38 +0000
423+++ lib/lp/services/webapp/authentication.py 2012-01-18 07:40:38 +0000
424@@ -9,13 +9,10 @@
425 'LaunchpadLoginSource',
426 'LaunchpadPrincipal',
427 'PlacelessAuthUtility',
428- 'SSHADigestEncryptor',
429 ]
430
431
432 import binascii
433-import hashlib
434-import random
435 from UserDict import UserDict
436
437 from contrib.oauth import OAuthRequest
438@@ -46,7 +43,6 @@
439 BasicAuthLoggedInEvent,
440 CookieAuthPrincipalIdentifiedEvent,
441 ILaunchpadPrincipal,
442- IPasswordEncryptor,
443 IPlacelessAuthUtility,
444 IPlacelessLoginSource,
445 )
446@@ -180,49 +176,6 @@
447 return getUtility(IPlacelessLoginSource).getPrincipalByLogin(login)
448
449
450-class SSHADigestEncryptor:
451- """SSHA is a modification of the SHA digest scheme with a salt
452- starting at byte 20 of the base64-encoded string.
453- """
454- implements(IPasswordEncryptor)
455-
456- # Source: http://developer.netscape.com/docs/technote/ldap/pass_sha.html
457-
458- saltLength = 20
459-
460- def generate_salt(self):
461- # Salt can be any length, but not more than about 37 characters
462- # because of limitations of the binascii module.
463- # All 256 characters are available.
464- salt = ''
465- for n in range(self.saltLength):
466- salt += chr(random.randrange(256))
467- return salt
468-
469- def encrypt(self, plaintext, salt=None):
470- plaintext = str(plaintext)
471- if salt is None:
472- salt = self.generate_salt()
473- v = binascii.b2a_base64(
474- hashlib.sha1(plaintext + salt).digest() + salt)
475- return v[:-1]
476-
477- def validate(self, plaintext, encrypted):
478- encrypted = str(encrypted)
479- plaintext = str(plaintext)
480- try:
481- ref = binascii.a2b_base64(encrypted)
482- except binascii.Error:
483- # Not valid base64.
484- return False
485- salt = ref[20:]
486- v = binascii.b2a_base64(
487- hashlib.sha1(plaintext + salt).digest() + salt)[:-1]
488- pw1 = (v or '').strip()
489- pw2 = (encrypted or '').strip()
490- return pw1 == pw2
491-
492-
493 class LaunchpadLoginSource:
494 """A login source that uses the launchpad SQL database to look up
495 principal information.
496
497=== modified file 'lib/lp/services/webapp/configure.zcml'
498--- lib/lp/services/webapp/configure.zcml 2011-12-30 07:32:58 +0000
499+++ lib/lp/services/webapp/configure.zcml 2012-01-18 07:40:38 +0000
500@@ -169,12 +169,6 @@
501 />
502
503 <utility
504- factory="lp.services.webapp.authentication.SSHADigestEncryptor"
505- provides="lp.services.webapp.interfaces.IPasswordEncryptor"
506- permission="zope.Public"
507- />
508-
509- <utility
510 component="lp.services.webapp.authentication.loginSource"
511 provides="lp.services.webapp.interfaces.IPlacelessLoginSource"
512 permission="zope.Public"
513
514=== modified file 'lib/lp/services/webapp/interfaces.py'
515--- lib/lp/services/webapp/interfaces.py 2012-01-18 07:40:38 +0000
516+++ lib/lp/services/webapp/interfaces.py 2012-01-18 07:40:38 +0000
517@@ -412,20 +412,6 @@
518 schema=IBrowserFormNG)
519
520
521-class IPasswordEncryptor(Interface):
522- """An interface representing a password encryption scheme."""
523-
524- def encrypt(plaintext):
525- """Return the encrypted value of plaintext."""
526-
527- def validate(plaintext, encrypted):
528- """Return a true value if the encrypted value of 'plaintext' is
529- equivalent to the value of 'encrypted'. In general, if this
530- method returns true, it can also be assumed that the value of
531- self.encrypt(plaintext) will compare equal to 'encrypted'.
532- """
533-
534-
535 class IPrincipalIdentifiedEvent(Interface):
536 """An event that is sent after a principal has been recovered from the
537 request's credentials.
538
539=== removed file 'lib/lp/services/webapp/tests/test_encryptor.py'
540--- lib/lp/services/webapp/tests/test_encryptor.py 2012-01-01 02:58:52 +0000
541+++ lib/lp/services/webapp/tests/test_encryptor.py 1970-01-01 00:00:00 +0000
542@@ -1,63 +0,0 @@
543-# Copyright 2009 Canonical Ltd. This software is licensed under the
544-# GNU Affero General Public License version 3 (see the file LICENSE).
545-
546-__metaclass__ = type
547-
548-
549-import binascii
550-import hashlib
551-import unittest
552-
553-from zope.app.testing import ztapi
554-from zope.app.testing.placelesssetup import PlacelessSetup
555-from zope.component import getUtility
556-
557-from lp.services.webapp.authentication import SSHADigestEncryptor
558-from lp.services.webapp.interfaces import IPasswordEncryptor
559-
560-
561-class TestSSHADigestEncryptor(PlacelessSetup, unittest.TestCase):
562-
563- def setUp(self):
564- PlacelessSetup.setUp(self)
565- encryptor = SSHADigestEncryptor()
566- ztapi.provideUtility(IPasswordEncryptor, encryptor)
567-
568- def test_encrypt(self):
569- encryptor = getUtility(IPasswordEncryptor)
570- encrypted1 = encryptor.encrypt('motorhead')
571- encrypted2 = encryptor.encrypt('motorhead')
572- self.failIfEqual(encrypted1, encrypted2)
573- salt = encrypted1[20:]
574- v = binascii.b2a_base64(
575- hashlib.sha1('motorhead' + salt).digest() + salt)[:-1]
576- return (v == encrypted1)
577-
578- def test_validate(self):
579- encryptor = getUtility(IPasswordEncryptor)
580- self.assertEqual(encryptor.validate(
581- 'motorhead', '+uSsxIfQDRUxG1oDTu1SsQN0P0RTl4SL9XRd'), True)
582-
583- def test_unicode_encrypt(self):
584- encryptor = getUtility(IPasswordEncryptor)
585- encrypted1 = encryptor.encrypt(u'motorhead')
586- encrypted2 = encryptor.encrypt(u'motorhead')
587- self.failIfEqual(encrypted1, encrypted2)
588- salt = encrypted1[20:]
589- v = binascii.b2a_base64(
590- hashlib.sha1('motorhead' + salt).digest() + salt)[:-1]
591- return v == encrypted1
592-
593- def test_unicode_validate(self):
594- encryptor = getUtility(IPasswordEncryptor)
595- self.assertEqual(encryptor.validate(
596- u'motorhead', u'+uSsxIfQDRUxG1oDTu1SsQN0P0RTl4SL9XRd'), True)
597-
598- def test_nonunicode_password(self):
599- encryptor = getUtility(IPasswordEncryptor)
600- try:
601- encryptor.encrypt(u'motorhead\xc3\xb3')
602- except UnicodeEncodeError:
603- pass
604- else:
605- self.fail("uncaught non-ascii text")
606
607=== modified file 'lib/lp/testing/factory.py'
608--- lib/lp/testing/factory.py 2012-01-17 14:14:49 +0000
609+++ lib/lp/testing/factory.py 2012-01-18 07:40:38 +0000
610@@ -529,20 +529,16 @@
611
612 @with_celebrity_logged_in('admin')
613 def makeAdministrator(self, name=None, email=None, password=None):
614- user = self.makePerson(name=name,
615- email=email,
616- password=password)
617+ user = self.makePerson(name=name, email=email)
618 administrators = getUtility(ILaunchpadCelebrities).admin
619 administrators.addMember(user, administrators.teamowner)
620 return user
621
622 def makeRegistryExpert(self, name=None, email='expert@example.com',
623- password='test'):
624+ password=None):
625 from lp.testing.sampledata import ADMIN_EMAIL
626 login(ADMIN_EMAIL)
627- user = self.makePerson(name=name,
628- email=email,
629- password=password)
630+ user = self.makePerson(name=name, email=email)
631 registry_team = getUtility(ILaunchpadCelebrities).registry_experts
632 registry_team.addMember(user, registry_team.teamowner)
633 return user
634@@ -561,14 +557,12 @@
635 pocket)
636 return ProxyFactory(location)
637
638- def makeAccount(self, displayname=None, password=None,
639- status=AccountStatus.ACTIVE,
640+ def makeAccount(self, displayname=None, status=AccountStatus.ACTIVE,
641 rationale=AccountCreationRationale.UNKNOWN):
642 """Create and return a new Account."""
643 if displayname is None:
644 displayname = self.getUniqueString('displayname')
645- account = getUtility(IAccountSet).new(
646- rationale, displayname, password=password)
647+ account = getUtility(IAccountSet).new(rationale, displayname)
648 removeSecurityProxy(account).status = status
649 self.makeOpenIdIdentifier(account)
650 return account
651@@ -612,10 +606,7 @@
652
653 :param email: The email address for the new person.
654 :param name: The name for the new person.
655- :param password: The password for the person.
656- This password can be used in setupBrowser in combination
657- with the email address to create a browser for this new
658- person.
659+ :param password: Ignored.
660 :param email_address_status: If specified, the status of the email
661 address is set to the email_address_status.
662 :param displayname: The display name to use for the person.
663@@ -630,20 +621,15 @@
664 email = self.getUniqueEmailAddress()
665 if name is None:
666 name = self.getUniqueString('person-name')
667- if password is None:
668- password = self.getUniqueString('password')
669 # By default, make the email address preferred.
670 if (email_address_status is None
671 or email_address_status == EmailAddressStatus.VALIDATED):
672 email_address_status = EmailAddressStatus.PREFERRED
673- # Set the password to test in order to allow people that have
674- # been created this way can be logged in.
675 person, email = getUtility(IPersonSet).createPersonAndEmail(
676 email, rationale=PersonCreationRationale.UNKNOWN, name=name,
677- password=password, displayname=displayname,
678+ displayname=displayname,
679 hide_email_addresses=hide_email_addresses)
680 naked_person = removeSecurityProxy(person)
681- naked_person._password_cleartext_cached = password
682 if homepage_content is not None:
683 naked_person.homepage_content = homepage_content
684
685@@ -721,8 +707,7 @@
686 # setPreferredEmail no longer activates the account
687 # automatically.
688 account = IMasterStore(Account).get(Account, person.accountID)
689- account.reactivate(
690- "Activated by factory.makePersonByName", password='foo')
691+ account.reactivate("Activated by factory.makePersonByName")
692 person.setPreferredEmail(email)
693
694 if not use_default_autosubscribe_policy: