Merge lp:~salgado/launchpad/remove-login-and-password-reset into lp:launchpad
- remove-login-and-password-reset
- Merge into devel
Proposed by
Guilherme Salgado
Status: | Merged |
---|---|
Approved by: | Francis J. Lacoste |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp:~salgado/launchpad/remove-login-and-password-reset |
Merge into: | lp:launchpad |
Prerequisite: | lp:~salgado/launchpad/openid-consumer |
Diff against target: |
2456 lines (+1/-2307) 20 files modified
lib/canonical/launchpad/browser/tests/test_registration.py (+0/-61) lib/canonical/launchpad/doc/login-pages.txt (+0/-139) lib/canonical/launchpad/pagetests/standalone/xx-invalid-people-cant-login.txt (+0/-56) lib/canonical/launchpad/pagetests/standalone/xx-login-and-join-links.txt (+0/-65) lib/canonical/launchpad/pagetests/standalone/xx-login-without-preferredemail.txt (+0/-76) lib/canonical/launchpad/pagetests/standalone/xx-new-account-redirection-url.txt (+0/-64) lib/canonical/launchpad/templates/launchpad-forgottenpassword.pt (+0/-91) lib/canonical/launchpad/templates/launchpad-login.pt (+0/-237) lib/canonical/launchpad/templates/launchpad-restrictedinfo.pt (+0/-45) lib/canonical/launchpad/templates/launchpad-restrictedlogin.pt (+0/-119) lib/canonical/launchpad/webapp/login.py (+1/-364) lib/canonical/launchpad/webapp/tests/test_login.py (+0/-34) lib/canonical/launchpad/zcml/launchpad.zcml (+0/-33) lib/lp/registry/stories/person/xx-changepassword.txt (+0/-62) lib/lp/registry/stories/person/xx-createaccount.txt (+0/-179) lib/lp/registry/stories/person/xx-login.txt (+0/-85) lib/lp/registry/stories/person/xx-reg-with-existing-email.txt (+0/-191) lib/lp/registry/stories/person/xx-resetpassword.txt (+0/-186) lib/lp/registry/stories/team/xx-team-restricted.txt (+0/-137) lib/lp/services/openid/stories/xx-resetpassword-of-sso-account.txt (+0/-83) |
To merge this branch: | bzr merge lp:~salgado/launchpad/remove-login-and-password-reset |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Francis J. Lacoste (community) | Approve | ||
Review via email:
|
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Guilherme Salgado (salgado) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Francis J. Lacoste (flacoste) wrote : | # |
Removing >2k lines... that must have felt good!
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed file 'lib/canonical/launchpad/browser/tests/test_registration.py' |
2 | --- lib/canonical/launchpad/browser/tests/test_registration.py 2009-06-25 05:30:52 +0000 |
3 | +++ lib/canonical/launchpad/browser/tests/test_registration.py 1970-01-01 00:00:00 +0000 |
4 | @@ -1,61 +0,0 @@ |
5 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
6 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
7 | - |
8 | -import unittest |
9 | - |
10 | -from zope.component import getUtility |
11 | - |
12 | -from canonical.launchpad.browser.tests.registration import ( |
13 | - finish_registration_through_the_web, start_registration_through_the_web) |
14 | -from canonical.launchpad.interfaces.authtoken import LoginTokenType |
15 | -from canonical.launchpad.interfaces.logintoken import ILoginTokenSet |
16 | -from lp.registry.interfaces.person import IPerson |
17 | -from lp.testing import TestCaseWithFactory |
18 | -from canonical.launchpad.testing.pages import get_feedback_messages |
19 | -from canonical.testing import DatabaseFunctionalLayer |
20 | - |
21 | - |
22 | -class TestEmailsOfPersonlessAccountsCantBeUsedToRegister(TestCaseWithFactory): |
23 | - # If a user tries to create a LP account using an email address that |
24 | - # is already associated with a personless account, we'll just tell them |
25 | - # they should use their SSO credentials to login. |
26 | - layer = DatabaseFunctionalLayer |
27 | - |
28 | - def setUp(self): |
29 | - TestCaseWithFactory.setUp(self) |
30 | - self.email = u'testX@example.com' |
31 | - self.expected_error = ( |
32 | - 'The email address %s is already registered in the ' |
33 | - 'Launchpad Login Service (used by the Ubuntu shop and ' |
34 | - 'other OpenID sites). Please use the same email and ' |
35 | - 'password to log into Launchpad.' % self.email) |
36 | - self.personless_account = self.factory.makeAccount( |
37 | - 'Test account', email=self.email) |
38 | - |
39 | - def test_first_step(self): |
40 | - # The +login page will prevent users from attempting to register a new |
41 | - # account using an email address associated with an existing |
42 | - # SSO (personless) account and instead tell them to use the SSO |
43 | - # account's credentials to login. |
44 | - browser = start_registration_through_the_web(self.email) |
45 | - errors = get_feedback_messages(browser.contents) |
46 | - self.assertIn(self.expected_error, errors) |
47 | - |
48 | - def test_last_step(self): |
49 | - # Just like the +login page, the +newaccount page of a LoginToken will |
50 | - # render an error if the email address stored on the token is |
51 | - # associated with an existing SSO account. |
52 | - self.assertIs(IPerson(self.personless_account, None), None) |
53 | - # Need to manually create the token here because the check on the |
54 | - # +login page (shown by the test above) prevents us from creating it |
55 | - # using the web UI. |
56 | - self.token = getUtility(ILoginTokenSet).new( |
57 | - requester=None, requesteremail=None, email=self.email, |
58 | - tokentype=LoginTokenType.NEWACCOUNT, redirection_url=None) |
59 | - browser = finish_registration_through_the_web(self.token) |
60 | - errors = get_feedback_messages(browser.contents) |
61 | - self.assertIn(self.expected_error, errors) |
62 | - |
63 | - |
64 | -def test_suite(): |
65 | - return unittest.TestLoader().loadTestsFromName(__name__) |
66 | |
67 | === removed file 'lib/canonical/launchpad/doc/login-pages.txt' |
68 | --- lib/canonical/launchpad/doc/login-pages.txt 2009-04-17 10:32:16 +0000 |
69 | +++ lib/canonical/launchpad/doc/login-pages.txt 1970-01-01 00:00:00 +0000 |
70 | @@ -1,139 +0,0 @@ |
71 | -= Login pages = |
72 | - |
73 | -The LoginOrRegister view is responsible for the login form and how it |
74 | -operates within the Launchpad workflows. |
75 | - |
76 | - # Import some stuff we'll use througout the test. |
77 | - >>> from zope.component import getMultiAdapter, getUtility |
78 | - >>> from zope.security.proxy import removeSecurityProxy |
79 | - >>> from lp.registry.interfaces.person import IPersonSet |
80 | - >>> from canonical.launchpad.webapp.publisher import rootObject |
81 | - >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
82 | - >>> person_set = getUtility(IPersonSet) |
83 | - |
84 | - >>> def create_request(form): |
85 | - ... return LaunchpadTestRequest( |
86 | - ... SERVER_URL='http://launchpad.dev', |
87 | - ... PATH_INFO='/+login', method='POST', form=form) |
88 | - |
89 | - |
90 | -== Unregistered email addresses can't be used to login == |
91 | - |
92 | -Trying to login with an email address that is not registered in Launchpad will |
93 | -cause an error message to be displayed. |
94 | - |
95 | - >>> request = create_request( |
96 | - ... form={'loginpage_email': 'non-registered@canonical.com', |
97 | - ... 'loginpage_password': u'test', |
98 | - ... 'loginpage_submit_login': 'Log In'}) |
99 | - >>> login_view = getMultiAdapter( |
100 | - ... (rootObject, request), name="+login") |
101 | - >>> login_view.process_login_form() |
102 | - >>> login_view.login_success() |
103 | - False |
104 | - >>> print login_view.login_error |
105 | - The email address and password do not match. |
106 | - |
107 | - |
108 | -== Can't login if using the wrong password == |
109 | - |
110 | -If a user tries to login using a password that is not the correct one for the |
111 | -account with the given email address, an error message is displayed. |
112 | - |
113 | -This is what happens if you have a full-fledged account: |
114 | - |
115 | - >>> person = factory.makePerson() |
116 | - >>> request = create_request( |
117 | - ... form={'loginpage_email': person.preferredemail.email, |
118 | - ... 'loginpage_password': person.password + 'foo', |
119 | - ... 'loginpage_submit_login': 'Log In'}) |
120 | - >>> login_view = getMultiAdapter( |
121 | - ... (rootObject, request), name="+login") |
122 | - >>> login_view.process_login_form() |
123 | - >>> login_view.login_success() |
124 | - False |
125 | - >>> print login_view.login_error |
126 | - The email address and password do not match. |
127 | - |
128 | -Or a personless one: |
129 | - |
130 | - >>> account = factory.makeAccount( |
131 | - ... 'Personless account', email='foo@example.com', password='foo') |
132 | - >>> request = create_request( |
133 | - ... form={'loginpage_email': 'foo@example.com', |
134 | - ... 'loginpage_password': u'wrong password', |
135 | - ... 'loginpage_submit_login': 'Log In'}) |
136 | - >>> login_view = getMultiAdapter( |
137 | - ... (rootObject, request), name="+login") |
138 | - >>> login_view.process_login_form() |
139 | - >>> login_view.login_success() |
140 | - False |
141 | - >>> print login_view.login_error |
142 | - The email address and password do not match. |
143 | - |
144 | - |
145 | -== Deactivated accounts cannot login == |
146 | - |
147 | -A deactivated account cannot use the LoginOrRegister view to login. |
148 | -The login_error message explains the situation to the user. Former User |
149 | -is an example of a user with a DEACTIVATED account. |
150 | - |
151 | - >>> former_user = person_set.getByEmail('former-user@canonical.com') |
152 | - >>> former_user_account = removeSecurityProxy(former_user.account) |
153 | - >>> former_user_account.status |
154 | - <DBItem AccountStatus.DEACTIVATED, ...> |
155 | - |
156 | - # Set the person's password so that we can try logging in. |
157 | - >>> from canonical.launchpad.interfaces.launchpad import IPasswordEncryptor |
158 | - >>> former_user_account.password = getUtility( |
159 | - ... IPasswordEncryptor).encrypt('foo') |
160 | - |
161 | - >>> request = create_request( |
162 | - ... form={'loginpage_email': 'former-user@canonical.com', |
163 | - ... 'loginpage_password': u'foo', |
164 | - ... 'loginpage_submit_login': 'Log In'}) |
165 | - >>> login_view = getMultiAdapter( |
166 | - ... (rootObject, request), name="+login") |
167 | - >>> login_view.process_login_form() |
168 | - >>> login_view.login_success() |
169 | - False |
170 | - >>> print login_view.login_error |
171 | - The email address belongs to a deactivated account. |
172 | - Use the "Forgotten your password" link to reactivate it. |
173 | - |
174 | -The user can use +resetpassword to reactivate his account. |
175 | -See "Reactivating an account using reset password" in `logintoken-pages`. |
176 | - |
177 | - |
178 | -== Suspended account cannot login == |
179 | - |
180 | -A user with a suspended account cannot login. The view's login_error |
181 | -explains the problem. |
182 | - |
183 | - >>> from canonical.launchpad.interfaces.account import AccountStatus |
184 | - |
185 | - # Only admins can suspend an account. |
186 | - >>> login('foo.bar@canonical.com') |
187 | - >>> bad_user = factory.makePerson( |
188 | - ... email='bad-user@canonical.com', |
189 | - ... name='bad-user', |
190 | - ... password='password') |
191 | - >>> from canonical.launchpad.interfaces import IMasterObject |
192 | - >>> IMasterObject(bad_user.account).status = AccountStatus.SUSPENDED |
193 | - >>> import transaction |
194 | - >>> transaction.commit() |
195 | - |
196 | - >>> login(ANONYMOUS, request) |
197 | - >>> request = create_request( |
198 | - ... form={'loginpage_email': 'bad-user@canonical.com', |
199 | - ... 'loginpage_password': u'password', |
200 | - ... 'loginpage_submit_login': 'Log In'}) |
201 | - >>> login_view = getMultiAdapter( |
202 | - ... (rootObject, request), name="+login") |
203 | - >>> login_view.process_login_form() |
204 | - >>> login_view.login_success() |
205 | - False |
206 | - >>> print login_view.login_error |
207 | - The email address belongs to a suspended account. |
208 | - Contact a <a href="mailto:feedback@launchpad.net?subject=SU...">Launchpad |
209 | - admin</a> about this issue. |
210 | |
211 | === removed file 'lib/canonical/launchpad/pagetests/standalone/xx-invalid-people-cant-login.txt' |
212 | --- lib/canonical/launchpad/pagetests/standalone/xx-invalid-people-cant-login.txt 2009-07-23 17:49:31 +0000 |
213 | +++ lib/canonical/launchpad/pagetests/standalone/xx-invalid-people-cant-login.txt 1970-01-01 00:00:00 +0000 |
214 | @@ -1,56 +0,0 @@ |
215 | -We need to ensure that an invalid account, such as the result of an |
216 | -account merge, can no longer authenticate using their existing |
217 | -credentials. See Bug #33427 |
218 | - |
219 | -First we log in via cookie |
220 | - |
221 | - >>> browser.open('http://launchpad.dev/+login') |
222 | - >>> browser.url |
223 | - 'http://launchpad.dev/+login' |
224 | - >>> browser.getControl('E-mail', index=0).value = 'foo.bar@canonical.com' |
225 | - >>> browser.getControl('Password').value = 'test' |
226 | - >>> browser.getControl('Log In').click() |
227 | - >>> browser.url |
228 | - 'http://launchpad.dev' |
229 | - >>> print extract_text(find_tag_by_id(browser.contents, 'logincontrol')) |
230 | - Foo Bar... |
231 | - |
232 | -Now invalidate that person |
233 | - |
234 | - >>> from canonical.launchpad.interfaces import AccountStatus |
235 | - >>> from lp.registry.model.person import Person |
236 | - >>> foobar = Person.byName('name16') |
237 | - >>> from canonical.launchpad.interfaces import IMasterObject |
238 | - >>> IMasterObject(foobar.account).status = AccountStatus.DEACTIVATED |
239 | - >>> import transaction |
240 | - >>> transaction.commit() |
241 | - |
242 | -Now if we reload the front page, we should be logged out. |
243 | - |
244 | - >>> browser.open('http://launchpad.dev') |
245 | - >>> browser.url |
246 | - 'http://launchpad.dev' |
247 | - >>> print extract_text(find_tag_by_id(browser.contents, 'logincontrol')) |
248 | - Log in / Register |
249 | - |
250 | -We also can only connect via Basic auth when then user is valid |
251 | - |
252 | - >>> IMasterObject(foobar.account).status = AccountStatus.ACTIVE |
253 | - >>> transaction.commit() |
254 | - |
255 | - >>> browser = setupBrowser(auth='Basic foo.bar@canonical.com:test') |
256 | - >>> browser.open('http://launchpad.dev') |
257 | - >>> browser.url |
258 | - 'http://launchpad.dev' |
259 | - >>> print extract_text(find_tag_by_id(browser.contents, 'logincontrol')) |
260 | - Foo Bar... |
261 | - |
262 | - >>> IMasterObject(foobar.account).status = AccountStatus.SUSPENDED |
263 | - >>> transaction.commit() |
264 | - |
265 | - >>> browser = setupBrowser(auth='Basic foo.bar@canonical.com:test') |
266 | - >>> browser.open('http://launchpad.dev') |
267 | - >>> browser.url |
268 | - 'http://launchpad.dev' |
269 | - >>> print extract_text(find_tag_by_id(browser.contents, 'logincontrol')) |
270 | - Log in / Register |
271 | |
272 | === removed file 'lib/canonical/launchpad/pagetests/standalone/xx-login-and-join-links.txt' |
273 | --- lib/canonical/launchpad/pagetests/standalone/xx-login-and-join-links.txt 2008-10-12 00:44:28 +0000 |
274 | +++ lib/canonical/launchpad/pagetests/standalone/xx-login-and-join-links.txt 1970-01-01 00:00:00 +0000 |
275 | @@ -1,65 +0,0 @@ |
276 | -Check that a page in launchpad has a login link. |
277 | - |
278 | - >>> print http(r""" |
279 | - ... GET /bugs HTTP/1.1 |
280 | - ... """) |
281 | - HTTP/1.1 200 Ok |
282 | - ... |
283 | - ...<a href=".../bugs/+login">... |
284 | - ... |
285 | - |
286 | -Check that a page in launchpad that is given query parameters has a login link |
287 | -that preserves those parameters. |
288 | - |
289 | - >>> print http(r""" |
290 | - ... GET /bugs?foo=14&bar=23 HTTP/1.1 |
291 | - ... """) |
292 | - HTTP/1.1 200 Ok |
293 | - ... |
294 | - ...<a href=".../bugs/+login?bar=23&foo=14">... |
295 | - ... |
296 | - |
297 | -The login page preserves all the query parameters it is given |
298 | - |
299 | - >>> result = http(r""" |
300 | - ... GET /bugs/+login?foo=mandrill&foo=bonobo&bar=tsimpson HTTP/1.1 |
301 | - ... """).getBody() |
302 | - >>> '<input type="hidden" name="foo" value="mandrill" />' in result |
303 | - True |
304 | - >>> '<input type="hidden" name="foo" value="bonobo" />' in result |
305 | - True |
306 | - >>> '<input type="hidden" name="bar" value="tsimpson" />' in result |
307 | - True |
308 | - |
309 | -Check that basic auth works. |
310 | - |
311 | - >>> print http(r""" |
312 | - ... GET /bugs HTTP/1.1 |
313 | - ... Authorization: Basic Zm9vLmJhckBjYW5vbmljYWwuY29tOnRlc3Q= |
314 | - ... """) |
315 | - HTTP/1.1 200 Ok |
316 | - ... |
317 | - ...<input type="submit" name="logout" value="Log Out" />... |
318 | - ... |
319 | - |
320 | -Check that the logout page redirects appropriately. |
321 | - |
322 | - >>> print http(r""" |
323 | - ... GET /+logout HTTP/1.1 |
324 | - ... Authorization: Basic Zm9vLmJhckBjYW5vbmljYWwuY29tOnRlc3Q= |
325 | - ... """) |
326 | - HTTP/1.1 303 See Other |
327 | - ... |
328 | - Location: http://localhost/?loggingout=1 |
329 | - ... |
330 | - |
331 | -Check that the logout page redirects appropriately from a more interesting url. |
332 | - |
333 | - >>> print http(r""" |
334 | - ... GET /firefox/+logout HTTP/1.1 |
335 | - ... Authorization: Basic Zm9vLmJhckBjYW5vbmljYWwuY29tOnRlc3Q= |
336 | - ... """) |
337 | - HTTP/1.1 303 See Other |
338 | - ... |
339 | - Location: http://localhost/firefox/?loggingout=1 |
340 | - ... |
341 | |
342 | === removed file 'lib/canonical/launchpad/pagetests/standalone/xx-login-without-preferredemail.txt' |
343 | --- lib/canonical/launchpad/pagetests/standalone/xx-login-without-preferredemail.txt 2009-09-09 23:16:08 +0000 |
344 | +++ lib/canonical/launchpad/pagetests/standalone/xx-login-without-preferredemail.txt 1970-01-01 00:00:00 +0000 |
345 | @@ -1,76 +0,0 @@ |
346 | -This test ensures that a user cannot login without a preferred email |
347 | -address. |
348 | - |
349 | -First, we need to set the password to something I know |
350 | - |
351 | - >>> import transaction |
352 | - >>> from canonical.launchpad.interfaces import IMasterStore |
353 | - >>> from canonical.launchpad.database.account import AccountPassword |
354 | - >>> IMasterStore(AccountPassword).execute(""" |
355 | - ... UPDATE AccountPassword |
356 | - ... SET password='K7Qmeansl6RbuPfulfcmyDQOzp70OxVh5Fcf' |
357 | - ... FROM Person, Account |
358 | - ... WHERE name='martin-pitt' AND Person.account = Account.id |
359 | - ... AND Account.id = AccountPassword.account |
360 | - ... """, noresult=True) |
361 | - >>> transaction.commit() |
362 | - |
363 | -'martin-pitt' doesn't have a preferred email address. |
364 | -He can't login without first validating his email address. |
365 | - |
366 | - >>> browser.open('http://launchpad.dev/+login') |
367 | - >>> browser.getControl('E-mail', index=0).value = 'martin.pitt@canonical.com' |
368 | - >>> browser.getControl('Password').value = 'test' |
369 | - >>> browser.getControl('Log In').click() |
370 | - >>> print '\n' + browser.contents |
371 | - <BLANKLINE> |
372 | - ... |
373 | - ...The email address 'martin.pitt@canonical.com', which you're... |
374 | - ...trying to use to login has not yet been validated to use in Launchpad... |
375 | - ...We sent an email to that address with instructions on how to confirm... |
376 | - ...that it belongs to you... |
377 | - ... |
378 | - |
379 | - |
380 | - When this happens, we automatically send an email to that address so the |
381 | - user can validate it and login. |
382 | - |
383 | - >>> import email, re |
384 | - >>> from lp.services.mail import stub |
385 | - >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop() |
386 | - |
387 | - Check if the email was sent to the right address. |
388 | - |
389 | - >>> to_addrs |
390 | - ['martin.pitt@canonical.com'] |
391 | - |
392 | - Get the token from the email address, in order to confirm the email address |
393 | - and then be able to login. |
394 | - |
395 | - >>> msg = email.message_from_string(raw_msg) |
396 | - >>> body = msg.get_payload() |
397 | - >>> link = re.findall(r'http.*/token/.*', body)[0] |
398 | - >>> token = re.sub(r'.*token/', '', link) |
399 | - >>> base_path = 'http://launchpad.dev/token/%s' % token |
400 | - |
401 | - >>> path = "%s/+validateemail" % base_path |
402 | - >>> browser.open(path) |
403 | - >>> print browser.title |
404 | - Confirm e-mail address |
405 | - |
406 | - >>> browser.getControl('Continue').click() |
407 | - >>> browser.url |
408 | - 'http://launchpad.dev/~martin-pitt' |
409 | - >>> print '\n' + browser.contents |
410 | - <BLANKLINE> |
411 | - ...informational message">Email address successfully confirmed... |
412 | - ... |
413 | - |
414 | - This is the first email 'martin-pitt' is validating, it must be set as the |
415 | - preferred one. |
416 | - |
417 | - >>> from canonical.launchpad.database import EmailAddressSet |
418 | - >>> [to_addr] = to_addrs |
419 | - >>> e = EmailAddressSet().getByEmail(to_addr) |
420 | - >>> e.status.title |
421 | - 'Preferred Email Address' |
422 | |
423 | === removed file 'lib/canonical/launchpad/pagetests/standalone/xx-new-account-redirection-url.txt' |
424 | --- lib/canonical/launchpad/pagetests/standalone/xx-new-account-redirection-url.txt 2009-10-16 16:13:00 +0000 |
425 | +++ lib/canonical/launchpad/pagetests/standalone/xx-new-account-redirection-url.txt 1970-01-01 00:00:00 +0000 |
426 | @@ -1,64 +0,0 @@ |
427 | -= Redirecting users after the registration process = |
428 | - |
429 | -We want to be nice with your users (the new ones, at least ;) and redirect |
430 | -them to any page they were trying to access before they were asked to create |
431 | -the new account. |
432 | - |
433 | -The most important case for us is when people get a file-bug URL from apport |
434 | -on an Ubuntu system. When this happens we need to make sure they're |
435 | -redirected to exactly the same URL they got from apport. |
436 | - |
437 | -Let's say Granny was playing around with Evolution (everybody's #1 MUA) and |
438 | -it crashed. Apport then gave her the following URL (which she promptly |
439 | -clicked): http://launchpad.dev/firefox/+filebug/121212 |
440 | - |
441 | - >>> anon_browser.handleErrors = True |
442 | - >>> anon_browser.open('http://launchpad.dev/firefox/+filebug/121212') |
443 | - >>> anon_browser.url |
444 | - 'http://launchpad.dev/firefox/+filebug/121212/+login' |
445 | - |
446 | - >>> anon_browser.getControl(name='redirection_url').value |
447 | - 'http://launchpad.dev/firefox/+filebug/121212' |
448 | - |
449 | - |
450 | -Similarly, if she wants to join a launchpad team, we'll try hard to redirect |
451 | -them back to that same team, after the registration is complete. |
452 | - |
453 | - >>> anon_browser.open('http://launchpad.dev/~ubuntu-team/+join') |
454 | - >>> anon_browser.url |
455 | - 'http://launchpad.dev/%7Eubuntu-team/+join/+login' |
456 | - |
457 | - >>> anon_browser.getControl(name='redirection_url').value |
458 | - 'http://launchpad.dev/%7Eubuntu-team/+join' |
459 | - |
460 | - # Clean up stub.test_emails to make sure other tests don't fuck us over. |
461 | - >>> from lp.services.mail import stub |
462 | - >>> stub.test_emails = [] |
463 | - |
464 | - |
465 | -If she now creates a new account, we'll certainly redirect her back to |
466 | -whatever we had stored on the redirection_url hidden field. |
467 | - |
468 | - >>> from lp.testing.registration import set_captcha_answer |
469 | - >>> anon_browser.getControl('E-mail address:', index=1).value = ( |
470 | - ... 'granny@canonical.com') |
471 | - >>> set_captcha_answer(anon_browser, prefix='loginpage_') |
472 | - >>> anon_browser.getControl('Register').click() |
473 | - >>> print anon_browser.contents |
474 | - <... |
475 | - <h1>Registration mail sent</h1> |
476 | - ... |
477 | - |
478 | - >>> from canonical.launchpad.ftests.logintoken import ( |
479 | - ... get_token_url_from_email) |
480 | - >>> from_addr, to_addr, msg = stub.test_emails.pop() |
481 | - >>> url = get_token_url_from_email(msg) |
482 | - >>> anon_browser.open(url) |
483 | - |
484 | - >>> anon_browser.getControl('Display Name').value = 'Granny' |
485 | - >>> anon_browser.getControl(name='field.password').value = 'foo' |
486 | - >>> anon_browser.getControl(name='field.password_dupe').value = 'foo' |
487 | - >>> anon_browser.getControl('Continue').click() |
488 | - |
489 | - >>> anon_browser.url |
490 | - 'http://launchpad.dev/%7Eubuntu-team/+join' |
491 | |
492 | === removed file 'lib/canonical/launchpad/templates/launchpad-forgottenpassword.pt' |
493 | --- lib/canonical/launchpad/templates/launchpad-forgottenpassword.pt 2009-11-23 03:10:04 +0000 |
494 | +++ lib/canonical/launchpad/templates/launchpad-forgottenpassword.pt 1970-01-01 00:00:00 +0000 |
495 | @@ -1,91 +0,0 @@ |
496 | -<tal:root |
497 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
498 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
499 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
500 | - omit-tag=""> |
501 | -<tal:do-this-first tal:content="view/process_form" /> |
502 | -<html |
503 | - metal:use-macro="view/macro:page/main_only"> |
504 | - <head metal:fill-slot="head_epilogue"> |
505 | - <meta name="robots" content="noindex" /> |
506 | - </head> |
507 | - |
508 | -<body> |
509 | - |
510 | - <div class="top-portlet" metal:fill-slot="main"> |
511 | - |
512 | - <div> |
513 | - |
514 | - <h1>Need a new Launchpad password?</h1> |
515 | - |
516 | - <div tal:condition="not: view/success"> |
517 | - |
518 | - <tal:block condition="view/errortext"> |
519 | - <h1>Your password reset request was unsuccessful</h1> |
520 | - <p class="error message" |
521 | - style="margin-top: 2em;" |
522 | - tal:content="structure view/errortext" /> |
523 | - </tal:block> |
524 | - |
525 | - <p> |
526 | - Enter your e-mail address, and we will send you instructions |
527 | - on how to reset your password. You'll also need to answer a simple |
528 | - question so we know that you're human. |
529 | - </p> |
530 | - |
531 | - <form name="forgottenpassword" method="POST"> |
532 | - <input type="hidden" |
533 | - tal:attributes="name view/captcha_hash; |
534 | - value view/get_captcha_hash" /> |
535 | - <div class="field"> |
536 | - <table> |
537 | - <tr> |
538 | - <th> |
539 | - <label for="email">Email address:</label> |
540 | - </th> |
541 | - <td> |
542 | - <input type="text" size="50" name="email" /> |
543 | - </td> |
544 | - </tr> |
545 | - <tr> |
546 | - <th> |
547 | - <label>Random question:</label> |
548 | - </th> |
549 | - <td> |
550 | - <span id="problem" tal:content="view/captcha_problem" /> |
551 | - <input type="text" size="5" |
552 | - id="captcha_submission" value="" |
553 | - tal:attributes="name view/captcha_submission" |
554 | - /> |
555 | - </td> |
556 | - </tr> |
557 | - </table> |
558 | - <div class="formHelp"> |
559 | - <p> |
560 | - Enter the email address registered for your Launchpad account. |
561 | - </p> |
562 | - <p> |
563 | - If you are claiming an existing account but don't know the email |
564 | - address that was used, <a href="/feedback">contact a |
565 | - Launchpad administrator</a>. |
566 | - </p> |
567 | - </div> |
568 | - <div class="formControls"> |
569 | - <input type="submit" value="Request Reset" /> |
570 | - </div> |
571 | - </div> |
572 | - </form> |
573 | - </div> |
574 | - </div> |
575 | - |
576 | - <div tal:condition="view/success"> |
577 | - <br /> |
578 | - <p>We have sent you an email with instructions to reset your |
579 | - password.</p> |
580 | - </div> |
581 | - |
582 | - </div> |
583 | - |
584 | -</body> |
585 | -</html> |
586 | -</tal:root> |
587 | |
588 | === removed file 'lib/canonical/launchpad/templates/launchpad-login.pt' |
589 | --- lib/canonical/launchpad/templates/launchpad-login.pt 2009-11-18 08:09:58 +0000 |
590 | +++ lib/canonical/launchpad/templates/launchpad-login.pt 1970-01-01 00:00:00 +0000 |
591 | @@ -1,237 +0,0 @@ |
592 | -<tal:root |
593 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
594 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
595 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
596 | - omit-tag=""> |
597 | -<tal:do-this-first tal:content="view/process_form" /> |
598 | -<html |
599 | - metal:use-macro="view/macro:page/locationless" |
600 | -> |
601 | - <head metal:fill-slot="head_epilogue"> |
602 | - <meta name="robots" content="noindex" /> |
603 | - </head> |
604 | - <body> |
605 | - <tal:comment condition="nothing"> |
606 | - This page handles cases in this order: |
607 | - 1. already logged in and shouldn't be here |
608 | - 2. just logged in successfully |
609 | - 3. just applied for registration successfully |
610 | - 4. might want to log in |
611 | - 4a. didn't try to log in last time |
612 | - 4b. just tried to log in and failed |
613 | - 5. might want to register |
614 | - 5a. didn't try to register last time |
615 | - 5b. just tried to register and failed. |
616 | - The usual case is 4 + 5. |
617 | - |
618 | - See also launchpad-restictedlogin.pt, which also uses |
619 | - these numbers in comments. |
620 | - </tal:comment> |
621 | - <div class="top-portlet" metal:fill-slot="main"> |
622 | - |
623 | - <!-- 1. already logged in and shouldn't be here: --> |
624 | - <tal:block condition="request/lp:person"> |
625 | - |
626 | - <!-- 2. just logged in successfully: --> |
627 | - <p tal:condition="view/login_success"> |
628 | - You are now logged in as <strong |
629 | - tal:content="request/lp:person/displayname">Person Name</strong>. |
630 | - </p> |
631 | - |
632 | - <tal:block condition="not: view/login_success"> |
633 | - <h1>You’re already logged in</h1> |
634 | - <p> |
635 | - You are already logged in as |
636 | - <strong tal:content="request/lp:person/displayname">person |
637 | - name</strong>. If this is not you, please |
638 | - <a href="/+logout">log out now</a>. |
639 | - </p> |
640 | - </tal:block> |
641 | - </tal:block> |
642 | - |
643 | - <tal:block condition="not: request/lp:person"> |
644 | - |
645 | - <tal:block condition="not: view/login_success"> |
646 | - |
647 | - <!-- 3. just registered successfully: --> |
648 | - <tal:registered condition="view/registration_success"> |
649 | - <h1>Registration mail sent</h1> |
650 | - <p id="address"> |
651 | - Instructions on completing your registration have been sent to |
652 | - <strong><code tal:content="view/email" |
653 | - >email@domain.com</code></strong>. |
654 | - </p> |
655 | - <p> |
656 | - If you don’t receive the instructions within a few |
657 | - minutes, it might be because: |
658 | - </p> |
659 | - <ul> |
660 | - <li> |
661 | - <p> |
662 | - Your mail provider uses “greylisting” to reduce |
663 | - spam. If so, you’ll need to wait an hour or two |
664 | - for the message to arrive. |
665 | - </p> |
666 | - </li> |
667 | - <li> |
668 | - <p> |
669 | - Your mail provider mistakenly blocks messages from Launchpad. |
670 | - Try signing up using a service like |
671 | - <a href="http://gmail.com/">Gmail</a> or |
672 | - <a href="http://mail.yahoo.com/">Yahoo Mail</a>. |
673 | - If that works, complain to your usual mail provider. |
674 | - </p> |
675 | - </li> |
676 | - <li> |
677 | - <p> |
678 | - If neither of those work, Launchpad might be broken somehow. |
679 | - Let us know by sending a message to |
680 | - <a href="mailto:feedback@launchpad.net" |
681 | - >feedback@launchpad.net</a>. |
682 | - </p> |
683 | - </li> |
684 | - </ul> |
685 | - </tal:registered> |
686 | - |
687 | - <tal:block condition="not: view/registration_success"> |
688 | - <!-- 4a. didn't try to log in last time: --> |
689 | - <h1 tal:condition="not: view/login_error"> |
690 | - Already registered? |
691 | - </h1> |
692 | - <!-- 4b. just tried to log in and failed: --> |
693 | - <div tal:condition="view/login_error"> |
694 | - <h1>Your login was unsuccessful</h1> |
695 | - <p class="error message" tal:content="structure view/login_error" /> |
696 | - </div> |
697 | - <!-- 4. might want to log in: --> |
698 | - <p> |
699 | - To log in, enter your e-mail address |
700 | - and Launchpad password. |
701 | - </p> |
702 | - <form name="login" method="POST"> |
703 | - <table> |
704 | - <tr> |
705 | - <th> |
706 | - <label for="email">E-mail address:</label> |
707 | - </th> |
708 | - <td> |
709 | - <input type="text" |
710 | - name="loginpage_email" |
711 | - id="email" |
712 | - size="30" |
713 | - tal:attributes="value request/email | nothing" |
714 | - /> |
715 | - <script> |
716 | - <!-- |
717 | - document.forms['login'].loginpage_email.focus(); |
718 | - //--> |
719 | - </script> |
720 | - </td> |
721 | - </tr> |
722 | - <tr> |
723 | - <th><label for="password">Password:</label></th> |
724 | - <td> |
725 | - <input |
726 | - type="password" |
727 | - id="password" |
728 | - name="loginpage_password" |
729 | - /> |
730 | - </td> |
731 | - </tr> |
732 | - <tr> |
733 | - <th></th> |
734 | - <td> |
735 | - <div> |
736 | - <input |
737 | - type="submit" |
738 | - name="loginpage_submit_login" |
739 | - value="Log In" /> |
740 | - [<a href="/+forgottenpassword">Forgotten your password?</a>] |
741 | - </div> |
742 | - </td> |
743 | - </tr> |
744 | - </table> |
745 | - <!-- Preserve extra query parameters as hidden fields. --> |
746 | - <tal:replacement tal:replace="structure view/preserve_query" /> |
747 | - </form> |
748 | - <p><strong>Note:</strong> You must enable cookies in your browser |
749 | - to log into or register for Launchpad.</p> |
750 | - <!-- 5a. didn't try to register last time: --> |
751 | - <h1 tal:condition="not: view/registration_error"> |
752 | - Not registered yet? |
753 | - </h1> |
754 | - <!-- 5b. just tried to register and failed: --> |
755 | - <tal:block condition="view/registration_error"> |
756 | - <h1>Your registration was unsuccessful</h1> |
757 | - <p class="error message" |
758 | - style="margin-top: 2em;" |
759 | - tal:content="structure view/registration_error" /> |
760 | - </tal:block> |
761 | - <!-- 5. might want to register: --> |
762 | - <p> |
763 | - Creating your Launchpad account is easy. Here's what to do:</p> |
764 | - |
765 | - <ol class="subordinate"> |
766 | - <li>Make sure cookies are enabled in your browser.</li> |
767 | - <li>Enter your e-mail address and answer our random question |
768 | - so we know that you're human. |
769 | - </li> |
770 | - <li>Follow the URL in the confirmation e-mail that Launchpad sends and you're done!</li> |
771 | - </ol> |
772 | - |
773 | - |
774 | - |
775 | - <form name="join" method="POST"> |
776 | - <input type="hidden" name="redirection_url" |
777 | - tal:condition="not: request/form/redirection_url|nothing" |
778 | - tal:attributes="value view/getRedirectionURL" /> |
779 | - <input type="hidden" |
780 | - tal:attributes="name view/captcha_hash; |
781 | - value view/get_captcha_hash" /> |
782 | - <table> |
783 | - <tr> |
784 | - <th> |
785 | - <label for="registeremail">E-mail address:</label> |
786 | - </th> |
787 | - <td> |
788 | - <input type="text" size="30" name="loginpage_email" |
789 | - id="registeremail" |
790 | - tal:attributes="value view/email|nothing" |
791 | - /> |
792 | - </td> |
793 | - </tr> |
794 | - <tr> |
795 | - <th> |
796 | - <label>Random question:</label> |
797 | - </th> |
798 | - <td> |
799 | - <span id="problem" tal:content="view/captcha_problem" /> |
800 | - <input type="text" size="5" |
801 | - id="captcha_submission" value="" |
802 | - tal:attributes="name view/captcha_submission" |
803 | - /> |
804 | - </td> |
805 | - </tr> |
806 | - <tr> |
807 | - <th></th> |
808 | - <td> |
809 | - <input |
810 | - type="submit" |
811 | - name="loginpage_submit_registration" |
812 | - value="Register" /> |
813 | - </td> |
814 | - </tr> |
815 | - </table> |
816 | - <p><strong>Note:</strong> We will never disclose, share or sell your |
817 | - personal information, nor send you e-mail not |
818 | - directly related to Launchpad.</p> |
819 | - <!-- Preserve extra query parameters as hidden fields. --> |
820 | - <tal:replacement tal:replace="structure view/preserve_query" /> |
821 | - </form> |
822 | - </tal:block> |
823 | - </tal:block> |
824 | - </tal:block> |
825 | - </div> |
826 | - </body> |
827 | -</html> |
828 | -</tal:root> |
829 | |
830 | === removed file 'lib/canonical/launchpad/templates/launchpad-restrictedinfo.pt' |
831 | --- lib/canonical/launchpad/templates/launchpad-restrictedinfo.pt 2009-10-13 20:59:13 +0000 |
832 | +++ lib/canonical/launchpad/templates/launchpad-restrictedinfo.pt 1970-01-01 00:00:00 +0000 |
833 | @@ -1,45 +0,0 @@ |
834 | -<html |
835 | - xmlns="http://www.w3.org/1999/xhtml" |
836 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
837 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
838 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
839 | - xml:lang="en" |
840 | - lang="en" |
841 | - dir="ltr" |
842 | - i18n:domain="launchpad" |
843 | -> |
844 | - <head> |
845 | - <title>Launchpad</title> |
846 | - <style type="text/css"> |
847 | - html { |
848 | - font-family: bitstream vera sans, dejavu sans, verdana, sans-serif; |
849 | - font-size: 8pt; |
850 | - } |
851 | - h1 {background: none; color: #83ad23; font-size: 3em; font-weight: normal;} |
852 | - </style> |
853 | - </head> |
854 | - <body> |
855 | - <tal:block condition="view/isTeamRestrictedServer" |
856 | - define="non_restricted_url request/form/production|nothing"> |
857 | - <h1>Restricted Launchpad test site</h1> |
858 | - |
859 | - <p>This site is accessible by launchpad admins and members of the |
860 | - <a tal:attributes="href view/getAllowedTeamURL" |
861 | - tal:content="view/getAllowedTeamDescription" /> |
862 | - team only. |
863 | - </p> |
864 | - <p tal:condition="non_restricted_url">You may be able to |
865 | - access this page |
866 | - <a tal:attributes="href non_restricted_url">on the main |
867 | - Launchpad site</a> instead.</p> |
868 | - |
869 | - <p tal:condition="not:non_restricted_url">You may use |
870 | - <a href="https://launchpad.net/">the main Launchpad site</a> instead.</p> |
871 | - |
872 | - <p>You can <a href="/+logout">log out</a>.</p> |
873 | - </tal:block> |
874 | - <tal:block condition="not: view/isTeamRestrictedServer"> |
875 | - <p>This server is open to anonymous access and registered users.</p> |
876 | - </tal:block> |
877 | - </body> |
878 | -</html> |
879 | |
880 | === removed file 'lib/canonical/launchpad/templates/launchpad-restrictedlogin.pt' |
881 | --- lib/canonical/launchpad/templates/launchpad-restrictedlogin.pt 2009-10-13 20:59:13 +0000 |
882 | +++ lib/canonical/launchpad/templates/launchpad-restrictedlogin.pt 1970-01-01 00:00:00 +0000 |
883 | @@ -1,119 +0,0 @@ |
884 | -<html |
885 | - xmlns="http://www.w3.org/1999/xhtml" |
886 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
887 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
888 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
889 | - xml:lang="en" |
890 | - lang="en" |
891 | - dir="ltr" |
892 | - i18n:domain="launchpad" |
893 | -> |
894 | -<tal:do-this-first tal:content="view/process_restricted_form" /> |
895 | - <head> |
896 | - <title>Log in to Launchpad</title> |
897 | - <style type="text/css"> |
898 | - html { |
899 | - font-family: bitstream vera sans, dejavu sans, verdana, sans-serif; |
900 | - font-size: 8pt; |
901 | - } |
902 | - h1 {background: none; color: #83ad23; font-size: 3em; font-weight: normal;} |
903 | - th {font-weight: normal; text-align: right;} |
904 | - .oopsid {color: #cc0000; font-weight: bold;} |
905 | - </style> |
906 | - </head> |
907 | - <body> |
908 | - <h1>Log in to a Launchpad test site</h1> |
909 | - |
910 | - <tal:comment condition="nothing"> |
911 | - See launchpad-login.pt for an explanation of the numbered comments. |
912 | - </tal:comment> |
913 | - |
914 | - <!-- 1. already logged in and shouldn't be here: --> |
915 | - <tal:block condition="request/lp:person"> |
916 | - |
917 | - <!-- 2. just logged in successfully: --> |
918 | - <p tal:condition="view/login_success"> |
919 | - You are now logged in as <strong |
920 | - tal:content="request/lp:person/displayname">Person Name</strong>. |
921 | - </p> |
922 | - |
923 | - <tal:block condition="not: view/login_success"> |
924 | - <h1>You’re already logged in</h1> |
925 | - <p> |
926 | - You are already logged in as |
927 | - <strong tal:content="request/lp:person/displayname">person |
928 | - name</strong>. If this is not you, please |
929 | - <a href="/+logout">log out now</a>. |
930 | - </p> |
931 | - </tal:block> |
932 | - </tal:block> |
933 | - |
934 | - <tal:block condition="not: request/lp:person"> |
935 | - |
936 | - <h1 tal:condition="not: view/login_error"> |
937 | - Already registered? |
938 | - </h1> |
939 | - <!-- 4b. just tried to log in and failed: --> |
940 | - <div tal:condition="view/login_error"> |
941 | - <h1>Your login was unsuccessful</h1> |
942 | - <p class="error message" tal:content="view/login_error" /> |
943 | - </div> |
944 | - <!-- 4. might want to log in: --> |
945 | - <p> |
946 | - To log in, enter your e-mail address |
947 | - and Launchpad password. |
948 | - </p> |
949 | - <form name="login" method="POST"> |
950 | - <table> |
951 | - <tr> |
952 | - <th> |
953 | - <label for="email">E-mail address:</label> |
954 | - </th> |
955 | - <td> |
956 | - <input type="text" |
957 | - name="loginpage_email" |
958 | - id="email" |
959 | - size="30" |
960 | - tal:attributes="value request/email | nothing" |
961 | - /> |
962 | - <script> |
963 | - <!-- |
964 | - document.forms['login'].loginpage_email.focus(); |
965 | - //--> |
966 | - </script> |
967 | - </td> |
968 | - </tr> |
969 | - <tr> |
970 | - <th><label for="password">Password:</label></th> |
971 | - <td> |
972 | - <input |
973 | - type="password" |
974 | - id="password" |
975 | - name="loginpage_password" |
976 | - /> |
977 | - </td> |
978 | - </tr> |
979 | - <tr> |
980 | - <th></th> |
981 | - <td> |
982 | - <div> |
983 | - <input |
984 | - type="submit" |
985 | - name="loginpage_submit_login" |
986 | - value="Log In" /> |
987 | - </div> |
988 | - </td> |
989 | - </tr> |
990 | - </table> |
991 | - </form> |
992 | - |
993 | - <p tal:define="non_restricted_url request/form/production|nothing" |
994 | - tal:condition="non_restricted_url"> |
995 | - You may be able to access this page |
996 | - <a tal:attributes="href non_restricted_url">on the main |
997 | - Launchpad site</a> instead. |
998 | - </p> |
999 | - </tal:block> |
1000 | - </body> |
1001 | -</html> |
1002 | - |
1003 | |
1004 | === modified file 'lib/canonical/launchpad/webapp/login.py' |
1005 | --- lib/canonical/launchpad/webapp/login.py 2010-02-18 11:01:16 +0000 |
1006 | +++ lib/canonical/launchpad/webapp/login.py 2010-02-18 11:01:19 +0000 |
1007 | @@ -5,9 +5,6 @@ |
1008 | |
1009 | __metaclass__ = type |
1010 | |
1011 | -import cgi |
1012 | -import hashlib |
1013 | -import random |
1014 | import urllib |
1015 | |
1016 | from datetime import datetime, timedelta |
1017 | @@ -34,16 +31,9 @@ |
1018 | from canonical.config import config |
1019 | from canonical.launchpad import _ |
1020 | from canonical.launchpad.interfaces.account import AccountStatus, IAccountSet |
1021 | -from canonical.launchpad.interfaces.authtoken import ( |
1022 | - IAuthTokenSet, LoginTokenType) |
1023 | -from canonical.launchpad.interfaces.emailaddress import IEmailAddressSet |
1024 | -from canonical.launchpad.interfaces.logintoken import ILoginTokenSet |
1025 | from canonical.launchpad.interfaces.openidconsumer import IOpenIDConsumerStore |
1026 | -from lp.registry.interfaces.person import ( |
1027 | - IPerson, IPersonSet, PersonCreationRationale) |
1028 | -from canonical.launchpad.interfaces.validation import valid_password |
1029 | +from lp.registry.interfaces.person import IPerson, PersonCreationRationale |
1030 | from canonical.launchpad.readonly import is_read_only |
1031 | -from canonical.launchpad.validators.email import valid_email |
1032 | from canonical.launchpad.webapp.error import SystemErrorView |
1033 | from canonical.launchpad.webapp.interfaces import ( |
1034 | CookieAuthLoggedInEvent, ILaunchpadApplication, ILaunchpadPrincipal, |
1035 | @@ -164,60 +154,6 @@ |
1036 | name='+basiclogin') |
1037 | |
1038 | |
1039 | -class RestrictedLoginInfo: |
1040 | - """On a team-restricted launchpad server, show who may access the server. |
1041 | - |
1042 | - Otherwise, show that this is an unrestricted server. |
1043 | - """ |
1044 | - |
1045 | - def isTeamRestrictedServer(self): |
1046 | - return bool(config.launchpad.restrict_to_team) |
1047 | - |
1048 | - def getAllowedTeamURL(self): |
1049 | - return 'https://launchpad.net/people/%s' % ( |
1050 | - config.launchpad.restrict_to_team) |
1051 | - |
1052 | - def getAllowedTeamDescription(self): |
1053 | - return getUtility(IPersonSet).getByName( |
1054 | - config.launchpad.restrict_to_team).title |
1055 | - |
1056 | -class CaptchaMixin: |
1057 | - """Mixin class to provide simple captcha capabilities.""" |
1058 | - def validateCaptcha(self): |
1059 | - """Validate the submitted captcha value matches what we expect.""" |
1060 | - expected = self.request.form.get(self.captcha_hash) |
1061 | - submitted = self.request.form.get(self.captcha_submission) |
1062 | - if expected is not None and submitted is not None: |
1063 | - return hashlib.md5(submitted).hexdigest() == expected |
1064 | - return False |
1065 | - |
1066 | - @cachedproperty |
1067 | - def captcha_answer(self): |
1068 | - """Get the answer for the current captcha challenge. |
1069 | - |
1070 | - With each failed attempt a new challenge will be given. Our answer |
1071 | - space is acknowledged to be ridiculously small but is chosen in the |
1072 | - interest of ease-of-use. We're not trying to create an iron-clad |
1073 | - challenge but only a minimal obstacle to dumb bots. |
1074 | - """ |
1075 | - return random.randint(10, 20) |
1076 | - |
1077 | - @property |
1078 | - def get_captcha_hash(self): |
1079 | - """Get the captcha hash. |
1080 | - |
1081 | - The hash is the value we put in the form for later comparison. |
1082 | - """ |
1083 | - return hashlib.md5(str(self.captcha_answer)).hexdigest() |
1084 | - |
1085 | - @property |
1086 | - def captcha_problem(self): |
1087 | - """Create the captcha challenge.""" |
1088 | - op1 = random.randint(1, self.captcha_answer - 1) |
1089 | - op2 = self.captcha_answer - op1 |
1090 | - return '%d + %d =' % (op1, op2) |
1091 | - |
1092 | - |
1093 | # The Python OpenID package uses pycurl by default, but pycurl chokes on |
1094 | # self-signed certificates (like the ones we use when developing), so we |
1095 | # change the default to urllib2 here. That's also a good thing because it |
1096 | @@ -372,252 +308,6 @@ |
1097 | template = ViewPageTemplateFile("../templates/login-already.pt") |
1098 | |
1099 | |
1100 | -class LoginOrRegister(CaptchaMixin): |
1101 | - """Merges the former CookieLoginPage and JoinLaunchpadView classes |
1102 | - to allow the two forms to appear on a single page. |
1103 | - |
1104 | - This page is a self-posting form. Actually, there are two forms |
1105 | - on the page. The first time this page is loaded, when there's been |
1106 | - no POST of its form, we want to preserve any query parameters, and put |
1107 | - them into hidden inputs. |
1108 | - """ |
1109 | - |
1110 | - # Names used in the template's HTML form. |
1111 | - form_prefix = 'loginpage_' |
1112 | - submit_login = form_prefix + 'submit_login' |
1113 | - submit_registration = form_prefix + 'submit_registration' |
1114 | - input_email = form_prefix + 'email' |
1115 | - input_password = form_prefix + 'password' |
1116 | - captcha_submission = form_prefix + 'captcha_submission' |
1117 | - captcha_hash = form_prefix + 'captcha_hash' |
1118 | - |
1119 | - # Instance variables that represent the state of the form. |
1120 | - login_error = None |
1121 | - registration_error = None |
1122 | - submitted = False |
1123 | - email = None |
1124 | - |
1125 | - def process_restricted_form(self): |
1126 | - """Entry-point for the team-restricted login page. |
1127 | - |
1128 | - If we're not running in team-restricted mode, then redirect to a |
1129 | - regular login page. Otherwise, process_form as usual. |
1130 | - """ |
1131 | - if config.launchpad.restrict_to_team: |
1132 | - self.process_form() |
1133 | - else: |
1134 | - self.request.response.redirect('/+login', |
1135 | - temporary_if_possible=True) |
1136 | - |
1137 | - def process_form(self): |
1138 | - """Determines whether this is the login form or the register |
1139 | - form, and delegates to the appropriate function. |
1140 | - """ |
1141 | - if self.request.method != "POST": |
1142 | - return |
1143 | - |
1144 | - self.submitted = True |
1145 | - if self.request.form.get(self.submit_login): |
1146 | - self.process_login_form() |
1147 | - elif self.request.form.get(self.submit_registration): |
1148 | - self.process_registration_form() |
1149 | - |
1150 | - def getRedirectionURL(self): |
1151 | - """Return the URL we should redirect the user to, after finishing a |
1152 | - registration or password reset process. |
1153 | - |
1154 | - IOW, the current URL without the "/+login" bit. |
1155 | - """ |
1156 | - return self.request.getURL(1) |
1157 | - |
1158 | - def process_login_form(self): |
1159 | - """Process the form data. |
1160 | - |
1161 | - If there is an error, assign a string containing a description |
1162 | - of the error to self.login_error for presentation to the user. |
1163 | - """ |
1164 | - email = self.request.form.get(self.input_email) |
1165 | - password = self.request.form.get(self.input_password) |
1166 | - if not email or not password: |
1167 | - self.login_error = _("Enter your email address and password.") |
1168 | - return |
1169 | - |
1170 | - # XXX matsubara 2006-05-08 bug=43675: This class should inherit from |
1171 | - # LaunchpadFormView, that way we could take advantage of Zope's widget |
1172 | - # validation, instead of checking manually for password validity. |
1173 | - if not valid_password(password): |
1174 | - self.login_error = _( |
1175 | - "The password provided contains non-ASCII characters.") |
1176 | - return |
1177 | - |
1178 | - loginsource = getUtility(IPlacelessLoginSource) |
1179 | - principal = loginsource.getPrincipalByLogin(email) |
1180 | - if principal is None or not principal.validate(password): |
1181 | - self.login_error = "The email address and password do not match." |
1182 | - elif principal.person is None: |
1183 | - logInPrincipalAndMaybeCreatePerson(self.request, principal, email) |
1184 | - self.redirectMinusLogin() |
1185 | - elif principal.person.account_status == AccountStatus.DEACTIVATED: |
1186 | - self.login_error = _( |
1187 | - 'The email address belongs to a deactivated account. ' |
1188 | - 'Use the "Forgotten your password" link to reactivate it.') |
1189 | - elif principal.person.account_status == AccountStatus.SUSPENDED: |
1190 | - email_link = ( |
1191 | - 'mailto:feedback@launchpad.net?subject=SUSPENDED%20account') |
1192 | - self.login_error = _( |
1193 | - 'The email address belongs to a suspended account. ' |
1194 | - 'Contact a <a href="%s">Launchpad admin</a> ' |
1195 | - 'about this issue.' % email_link) |
1196 | - else: |
1197 | - person = getUtility(IPersonSet).getByEmail(email) |
1198 | - if person.preferredemail is None: |
1199 | - self.login_error = _( |
1200 | - "The email address '%s', which you're trying to use to " |
1201 | - "login has not yet been validated to use in Launchpad. " |
1202 | - "We sent an email to that address with instructions on " |
1203 | - "how to confirm that it belongs to you. As soon as we " |
1204 | - "have that confirmation you'll be able to log into " |
1205 | - "Launchpad." |
1206 | |
1207 | - token = getUtility(ILoginTokenSet).new( |
1208 | - person, email, email, LoginTokenType.VALIDATEEMAIL) |
1209 | - token.sendEmailValidationRequest() |
1210 | - return |
1211 | - if person.is_valid_person: |
1212 | - logInPrincipal(self.request, principal, email) |
1213 | - self.redirectMinusLogin() |
1214 | - else: |
1215 | - # Normally invalid accounts will have a NULL password |
1216 | - # so this will be rarely seen, if ever. An account with no |
1217 | - # valid email addresses might end up in this situation, |
1218 | - # such as having them flagged as OLD by a email bounce |
1219 | - # processor or manual changes by the DBA. |
1220 | - self.login_error = "This account cannot be used." |
1221 | - |
1222 | - def process_registration_form(self): |
1223 | - """A user has asked to join launchpad. |
1224 | - |
1225 | - Check if everything is ok with the email address and send an email |
1226 | - with a link to the user complete the registration process. |
1227 | - """ |
1228 | - request = self.request |
1229 | - # For some reason, redirection_url can sometimes be a list, and |
1230 | - # sometimes a string. See OOPS-68D508, where redirection_url has |
1231 | - # the following value: |
1232 | - # [u'https://launchpad.net/.../it/+translate/+login', u''] |
1233 | - redirection_url = request.form.get('redirection_url') |
1234 | - if isinstance(redirection_url, list): |
1235 | - # Remove blank entries. |
1236 | - redirection_url_list = [url for url in redirection_url if url] |
1237 | - # XXX Guilherme Salgado 2006-09-27: |
1238 | - # Shouldn't this be an UnexpectedFormData? |
1239 | - assert len(redirection_url_list) == 1, redirection_url_list |
1240 | - redirection_url = redirection_url_list[0] |
1241 | - |
1242 | - self.email = request.form.get(self.input_email).strip() |
1243 | - |
1244 | - if not valid_email(self.email): |
1245 | - self.registration_error = ( |
1246 | - "The email address you provided isn't valid. " |
1247 | - "Please verify it and try again.") |
1248 | - return |
1249 | - |
1250 | - # Validate the user is human, more or less. |
1251 | - if not self.validateCaptcha(): |
1252 | - self.registration_error = ( |
1253 | - "The answer to the simple math question was incorrect " |
1254 | - "or missing. Please try again.") |
1255 | - return |
1256 | - |
1257 | - registered_email = getUtility(IEmailAddressSet).getByEmail(self.email) |
1258 | - if registered_email is not None: |
1259 | - person = registered_email.person |
1260 | - if person is not None: |
1261 | - if person.is_valid_person: |
1262 | - self.registration_error = ( |
1263 | - "Sorry, someone with the address %s already has a " |
1264 | - "Launchpad account. If this is you and you've " |
1265 | - "forgotten your password, Launchpad can " |
1266 | - '<a href="/+forgottenpassword">reset it for you.</a>' |
1267 | - % cgi.escape(self.email)) |
1268 | - return |
1269 | - else: |
1270 | - # This is an unvalidated profile; let's move on with the |
1271 | - # registration process as if we had never seen it. |
1272 | - pass |
1273 | - else: |
1274 | - account = registered_email.account |
1275 | - assert IPerson(account, None) is None, ( |
1276 | - "This email address should be linked to the person who " |
1277 | - "owns it.") |
1278 | - self.registration_error = ( |
1279 | - 'The email address %s is already registered in the ' |
1280 | - 'Launchpad Login Service (used by the Ubuntu shop and ' |
1281 | - 'other OpenID sites). Please use the same email and ' |
1282 | - 'password to log into Launchpad.' |
1283 | - % cgi.escape(self.email)) |
1284 | - return |
1285 | - |
1286 | - logintokenset = getUtility(ILoginTokenSet) |
1287 | - token = logintokenset.new( |
1288 | - requester=None, requesteremail=None, email=self.email, |
1289 | - tokentype=LoginTokenType.NEWACCOUNT, |
1290 | - redirection_url=redirection_url) |
1291 | - token.sendNewUserEmail() |
1292 | - |
1293 | - def login_success(self): |
1294 | - return (self.submitted and |
1295 | - self.request.form.get(self.submit_login) and |
1296 | - not self.login_error) |
1297 | - |
1298 | - def registration_success(self): |
1299 | - return (self.submitted and |
1300 | - self.request.form.get(self.submit_registration) and |
1301 | - not self.registration_error) |
1302 | - |
1303 | - def redirectMinusLogin(self): |
1304 | - """Redirect to the URL with the '/+login' removed from the end. |
1305 | - |
1306 | - Also, take into account the preserved query from the URL. |
1307 | - """ |
1308 | - target = self.request.URL[-1] |
1309 | - query_string = urllib.urlencode( |
1310 | - list(self.iter_form_items()), doseq=True) |
1311 | - if query_string: |
1312 | - target = '%s?%s' % (target, query_string) |
1313 | - self.request.response.redirect(target, temporary_if_possible=True) |
1314 | - |
1315 | - def iter_form_items(self): |
1316 | - """Iterate over keys and single values, excluding stuff we don't |
1317 | - want such as '-C' and things starting with self.form_prefix. |
1318 | - """ |
1319 | - for name, value in self.request.form.items(): |
1320 | - # XXX SteveAlexander 2005-04-11: Exclude '-C' because this is |
1321 | - # left in from sys.argv in Zope3 using python's |
1322 | - # cgi.FieldStorage to process requests. |
1323 | - if name == '-C' or name == 'loggingout': |
1324 | - continue |
1325 | - if name.startswith(self.form_prefix): |
1326 | - continue |
1327 | - if isinstance(value, list): |
1328 | - value_list = value |
1329 | - else: |
1330 | - value_list = [value] |
1331 | - for value_list_item in value_list: |
1332 | - yield (name, value_list_item) |
1333 | - |
1334 | - def preserve_query(self): |
1335 | - """Return zero or more hidden inputs that preserve the URL's query.""" |
1336 | - L = [] |
1337 | - html = u'<input type="hidden" name="%s" value="%s" />' |
1338 | - for name, value in self.iter_form_items(): |
1339 | - # Thanks to apport (https://launchpad.net/bugs/61171), we need to |
1340 | - # do this here. |
1341 | - value = UnicodeDammit(value).markup |
1342 | - L.append(html % (name, cgi.escape(value, quote=True))) |
1343 | - return '\n'.join(L) |
1344 | - |
1345 | - |
1346 | def logInPrincipal(request, principal, email): |
1347 | """Log the principal in. Password validation must be done in callsites.""" |
1348 | session = ISession(request) |
1349 | @@ -726,59 +416,6 @@ |
1350 | return '' |
1351 | |
1352 | |
1353 | -class ForgottenPasswordPage(CaptchaMixin): |
1354 | - |
1355 | - errortext = None |
1356 | - submitted = False |
1357 | - captcha_submission = 'captcha_submission' |
1358 | - captcha_hash = 'captcha_hash' |
1359 | - page_title = 'Need a new Launchpad password?' |
1360 | - |
1361 | - def process_form(self): |
1362 | - request = self.request |
1363 | - if request.method != "POST": |
1364 | - return |
1365 | - |
1366 | - # Validate the user is human, more or less. |
1367 | - if not self.validateCaptcha(): |
1368 | - self.errortext = ( |
1369 | - "The answer to the simple math question was incorrect " |
1370 | - "or missing. Please try again.") |
1371 | - return |
1372 | - |
1373 | - email = request.form.get("email").strip() |
1374 | - email_address = getUtility(IEmailAddressSet).getByEmail(email) |
1375 | - if email_address is None: |
1376 | - self.errortext = ("Your account details have not been found. " |
1377 | - "Please check your subscription email " |
1378 | - "address and try again.") |
1379 | - return |
1380 | - |
1381 | - person = email_address.person |
1382 | - if person is not None and person.isTeam(): |
1383 | - self.errortext = ("The email address <strong>%s</strong> " |
1384 | - "belongs to a team, and teams cannot log in to " |
1385 | - "Launchpad." % email) |
1386 | - return |
1387 | - |
1388 | - if person is None: |
1389 | - account = email_address.account |
1390 | - redirection_url = urlappend( |
1391 | - self.request.getApplicationURL(), '+login') |
1392 | - token = getUtility(IAuthTokenSet).new( |
1393 | - account, email, email, LoginTokenType.PASSWORDRECOVERY, |
1394 | - redirection_url=redirection_url) |
1395 | - else: |
1396 | - token = getUtility(ILoginTokenSet).new( |
1397 | - person, email, email, LoginTokenType.PASSWORDRECOVERY) |
1398 | - token.sendPasswordResetEmail() |
1399 | - self.submitted = True |
1400 | - return |
1401 | - |
1402 | - def success(self): |
1403 | - return self.submitted and not self.errortext |
1404 | - |
1405 | - |
1406 | class FeedsUnauthorizedView(UnauthorizedView): |
1407 | """All users of feeds are anonymous, so don't redirect to login.""" |
1408 | |
1409 | |
1410 | === removed file 'lib/canonical/launchpad/webapp/tests/test_login.py' |
1411 | --- lib/canonical/launchpad/webapp/tests/test_login.py 2009-07-31 19:56:48 +0000 |
1412 | +++ lib/canonical/launchpad/webapp/tests/test_login.py 1970-01-01 00:00:00 +0000 |
1413 | @@ -1,34 +0,0 @@ |
1414 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
1415 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
1416 | - |
1417 | -__metaclass__ = type |
1418 | - |
1419 | -import unittest |
1420 | - |
1421 | -from canonical.launchpad.ftests import logout |
1422 | -from canonical.launchpad.testing.pages import setupBrowser |
1423 | -from canonical.testing import DatabaseFunctionalLayer |
1424 | - |
1425 | -from lp.testing import TestCase |
1426 | - |
1427 | - |
1428 | -class TestLoginOrRegister_preserve_query(TestCase): |
1429 | - layer = DatabaseFunctionalLayer |
1430 | - |
1431 | - def test_non_ascii_characters_in_query_string_ascii_encoded(self): |
1432 | - # Apport can construct ASCII-encoded URLs containing non-ASCII |
1433 | - # characters (in the query string), where they send users to so that |
1434 | - # they can finish reporting bugs. Apport shouldn't do that but we |
1435 | - # can't OOPS when it does, so we use UnicodeDammit to figure out its |
1436 | - # original encoding and decode it back. If UnicodeDammit can't figure |
1437 | - # out the correct encoding, we replace those non-ASCII characters. For |
1438 | - # more details, see https://launchpad.net/bugs/61171. |
1439 | - logout() |
1440 | - browser = setupBrowser() |
1441 | - browser.open('http://launchpad.dev/+login?foo=subproc%E9s') |
1442 | - self.assertEquals( |
1443 | - 'subproc\xc3\xa9s', browser.getControl(name='foo', index=0).value) |
1444 | - |
1445 | - |
1446 | -def test_suite(): |
1447 | - return unittest.TestLoader().loadTestsFromName(__name__) |
1448 | |
1449 | === modified file 'lib/canonical/launchpad/zcml/launchpad.zcml' |
1450 | --- lib/canonical/launchpad/zcml/launchpad.zcml 2010-02-18 11:01:16 +0000 |
1451 | +++ lib/canonical/launchpad/zcml/launchpad.zcml 2010-02-18 11:01:19 +0000 |
1452 | @@ -212,22 +212,6 @@ |
1453 | /> |
1454 | |
1455 | <browser:page |
1456 | - for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication" |
1457 | - template="../templates/launchpad-login.pt" |
1458 | - class="canonical.launchpad.webapp.login.LoginOrRegister" |
1459 | - permission="zope.Public" |
1460 | - name="+login-old" |
1461 | - /> |
1462 | - |
1463 | - <browser:page |
1464 | - for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication" |
1465 | - template="../templates/launchpad-forgottenpassword.pt" |
1466 | - class="canonical.launchpad.webapp.login.ForgottenPasswordPage" |
1467 | - permission="zope.Public" |
1468 | - name="+forgottenpassword" |
1469 | - /> |
1470 | - |
1471 | - <browser:page |
1472 | for="*" |
1473 | attribute="logout" |
1474 | class="canonical.launchpad.webapp.login.CookieLogoutPage" |
1475 | @@ -243,23 +227,6 @@ |
1476 | permission="zope.Public" |
1477 | /> |
1478 | |
1479 | - <!-- Special login and information pages for a site restricted so that just |
1480 | - one team given in launchpad.conf may access it. --> |
1481 | - <browser:page |
1482 | - for="canonical.launchpad.interfaces.ILaunchpadRoot" |
1483 | - name="+restricted-login" |
1484 | - template="../templates/launchpad-restrictedlogin.pt" |
1485 | - permission="zope.Public" |
1486 | - class="canonical.launchpad.webapp.login.LoginOrRegister" |
1487 | - /> |
1488 | - <browser:page |
1489 | - for="canonical.launchpad.interfaces.ILaunchpadRoot" |
1490 | - name="+restricted-info" |
1491 | - template="../templates/launchpad-restrictedinfo.pt" |
1492 | - permission="zope.Public" |
1493 | - class="canonical.launchpad.webapp.login.RestrictedLoginInfo" |
1494 | - /> |
1495 | - |
1496 | <!-- Other non-application-specific pages. --> |
1497 | |
1498 | <browser:page |
1499 | |
1500 | === removed file 'lib/lp/registry/stories/person/xx-changepassword.txt' |
1501 | --- lib/lp/registry/stories/person/xx-changepassword.txt 2009-09-22 20:56:12 +0000 |
1502 | +++ lib/lp/registry/stories/person/xx-changepassword.txt 1970-01-01 00:00:00 +0000 |
1503 | @@ -1,62 +0,0 @@ |
1504 | -================== |
1505 | -Changing passwords |
1506 | -================== |
1507 | - |
1508 | -No Privileges Person wants to change his password. |
1509 | - |
1510 | - >>> user_browser.open('http://launchpad.dev/~no-priv/+changepassword') |
1511 | - |
1512 | -He accidentally uses an illegal character in the new password. |
1513 | - |
1514 | - >>> user_browser.getControl('Current password').value = 'test' |
1515 | - >>> user_browser.getControl('New password').value = 'tésté' |
1516 | - >>> user_browser.getControl(name='field.password_dupe').value = 'tésté' |
1517 | - >>> user_browser.getControl('Change Password').click() |
1518 | - >>> print_feedback_messages(user_browser.contents) |
1519 | - There is 1 error. |
1520 | - The password provided contains non-ASCII characters. |
1521 | - |
1522 | -No Priv tries again, but this time he enters the wrong password! |
1523 | - |
1524 | - >>> user_browser.getControl('Current password').value = 'wrong' |
1525 | - >>> user_browser.getControl('New password').value = 'test' |
1526 | - >>> user_browser.getControl(name='field.password_dupe').value = 'test' |
1527 | - >>> user_browser.getControl('Change Password').click() |
1528 | - >>> print_feedback_messages(user_browser.contents) |
1529 | - There is 1 error. |
1530 | - The provided password doesn't match your current password. |
1531 | - |
1532 | -He uses an illegal character in his current password, which is also the wrong |
1533 | -password. |
1534 | - |
1535 | - >>> user_browser.getControl('Current password').value = 'ééé' |
1536 | - >>> user_browser.getControl('New password').value = 'test' |
1537 | - >>> user_browser.getControl(name='field.password_dupe').value = 'test' |
1538 | - >>> user_browser.getControl('Change Password').click() |
1539 | - >>> print_feedback_messages(user_browser.contents) |
1540 | - There is 1 error. |
1541 | - The provided password doesn't match your current password. |
1542 | - |
1543 | -And finally he uses a legal password, containing only ascii characters. |
1544 | - |
1545 | - >>> user_browser.getControl('Current password').value = 'test' |
1546 | - >>> user_browser.getControl('New password').value = 'abc' |
1547 | - >>> user_browser.getControl(name='field.password_dupe').value = 'abc' |
1548 | - >>> user_browser.getControl('Change Password').click() |
1549 | - >>> print user_browser.url |
1550 | - http://launchpad.dev/~no-priv |
1551 | - >>> print_feedback_messages(user_browser.contents) |
1552 | - Password changed successfully |
1553 | - |
1554 | -Now, No Priv logs in with his new password. |
1555 | - |
1556 | - >>> anon_browser.open('http://launchpad.dev/+login') |
1557 | - >>> anon_browser.getControl('E-mail address:', index=0).value = ( |
1558 | - ... 'no-priv@canonical.com') |
1559 | - >>> anon_browser.getControl('Password:').value = 'abc' |
1560 | - >>> anon_browser.getControl('Log In').click() |
1561 | - >>> print anon_browser.url |
1562 | - http://launchpad.dev |
1563 | - >>> print extract_text(find_main_content(anon_browser.contents)) |
1564 | - Recent Launchpad blog posts |
1565 | - ... |
1566 | |
1567 | === removed file 'lib/lp/registry/stories/person/xx-createaccount.txt' |
1568 | --- lib/lp/registry/stories/person/xx-createaccount.txt 2009-10-16 16:13:00 +0000 |
1569 | +++ lib/lp/registry/stories/person/xx-createaccount.txt 1970-01-01 00:00:00 +0000 |
1570 | @@ -1,179 +0,0 @@ |
1571 | -================= |
1572 | -Create an account |
1573 | -================= |
1574 | - |
1575 | -Jane wants to register with Launchpad, so she goes to the registration/login |
1576 | -page. |
1577 | - |
1578 | - >>> browser = setupBrowser() |
1579 | - >>> browser.open('http://launchpad.dev/+login') |
1580 | - >>> print extract_text(find_main_content(browser.contents)) |
1581 | - Already registered? |
1582 | - ... |
1583 | - Not registered yet? |
1584 | - ... |
1585 | - |
1586 | -She enters an invalid email address, and gets a warning message. |
1587 | - |
1588 | - >>> browser.getControl(name='loginpage_email', index=1).value = 'ab' |
1589 | - >>> browser.getControl('Register').click() |
1590 | - >>> print_feedback_messages(browser.contents) |
1591 | - The email address you provided isn't valid. Please verify it and try |
1592 | - again. |
1593 | - |
1594 | -Next she enters a valid email address but enters a wrong answer for |
1595 | -the incredibly trivial math captcha. She gets an error message. |
1596 | - |
1597 | - >>> browser.getControl(name='loginpage_email', index=1).value = ( |
1598 | - ... 'jane@example.com') |
1599 | - >>> browser.getControl(name='loginpage_captcha_submission').value = '-1' |
1600 | - >>> browser.getControl('Register').click() |
1601 | - >>> print_feedback_messages(browser.contents) |
1602 | - The answer to the simple math question was incorrect or missing. |
1603 | - Please try again. |
1604 | - |
1605 | -Jane tries again, providing a the correct captcha answer. Her valid |
1606 | -email address from before has been retained in the form. |
1607 | - |
1608 | - >>> from lp.testing.registration import set_captcha_answer |
1609 | - >>> set_captcha_answer(browser, prefix='loginpage_') |
1610 | - >>> browser.getControl('Register').click() |
1611 | - >>> print_feedback_messages(browser.contents) |
1612 | - >>> print extract_text(find_main_content(browser.contents)) |
1613 | - Registration mail sent |
1614 | - Instructions on completing your registration have been sent to |
1615 | - jane@example.com. |
1616 | - ... |
1617 | - |
1618 | -Launchpad sends Jane an email message containing a token she must use to |
1619 | -complete the registration process. |
1620 | - |
1621 | - >>> import email |
1622 | - >>> from lp.services.mail import stub |
1623 | - >>> from canonical.launchpad.ftests.logintoken import ( |
1624 | - ... get_token_url_from_email) |
1625 | - |
1626 | - >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop() |
1627 | - >>> token_url = get_token_url_from_email(raw_msg) |
1628 | - |
1629 | -The email was sent to the address Jane registered. |
1630 | - |
1631 | - >>> to_addrs |
1632 | - ['jane@example.com'] |
1633 | - |
1634 | -Jane follows the link, but gets distracted before she can complete the |
1635 | -registration process. |
1636 | - |
1637 | - >>> browser.open(token_url) |
1638 | - >>> print extract_text(find_main_content(browser.contents)) |
1639 | - Display Name: |
1640 | - Your name as you would like it displayed throughout Launchpad. Most |
1641 | - people use their full name here. |
1642 | - Hide my email addresses from other Launchpad users |
1643 | - Create password: |
1644 | - Retype the password: |
1645 | - |
1646 | -While Jane was deciding whether to hide her email address, Sneaky Salgado |
1647 | -manages to register her email address out from under her. |
1648 | - |
1649 | - >>> from lp.registry.interfaces.person import IPersonSet |
1650 | - >>> from zope.component import getUtility |
1651 | - |
1652 | - >>> login('admin@canonical.com') |
1653 | - >>> salgado = getUtility(IPersonSet).getByName('salgado') |
1654 | - >>> email = factory.makeEmail('jane@example.com', salgado) |
1655 | - >>> transaction.commit() |
1656 | - |
1657 | - >>> [email.email for email in salgado.validatedemails] |
1658 | - [u'jane@example.com'] |
1659 | - >>> logout() |
1660 | - |
1661 | -Now Jane attempts completes the registration, but she gets an error. |
1662 | - |
1663 | - >>> browser.getControl('Display Name').value = 'Janerie' |
1664 | - >>> browser.getControl('Create password').value = 'foo' |
1665 | - >>> browser.getControl('Retype the password').value = 'foo' |
1666 | - >>> browser.getControl('Continue').click() |
1667 | - >>> print_feedback_messages(browser.contents) |
1668 | - There is 1 error. |
1669 | - The email address jane@example.com is already registered. |
1670 | - |
1671 | -Jane tries again with a different email address. |
1672 | - |
1673 | - >>> browser.open('http://launchpad.dev/+login') |
1674 | - >>> browser.getControl(name='loginpage_email', index=1).value = ( |
1675 | - ... 'jperson@example.com') |
1676 | - >>> set_captcha_answer(browser, prefix='loginpage_') |
1677 | - >>> browser.getControl('Register').click() |
1678 | - |
1679 | - >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop() |
1680 | - >>> token_url = get_token_url_from_email(raw_msg) |
1681 | - |
1682 | - >>> to_addrs |
1683 | - ['jperson@example.com'] |
1684 | - |
1685 | -Unfortunately, Jane forgets to enter her display name. |
1686 | - |
1687 | - >>> browser.open(token_url) |
1688 | - >>> browser.getControl('Create password').value = 'foo' |
1689 | - >>> browser.getControl('Retype the password').value = 'foo' |
1690 | - >>> browser.getControl('Continue').click() |
1691 | - >>> print_feedback_messages(browser.contents) |
1692 | - There is 1 error. |
1693 | - Required input is missing. |
1694 | - |
1695 | -She tries again, but forgets to enter a password. |
1696 | - |
1697 | - >>> browser.getControl('Display Name').value = 'Janerie' |
1698 | - >>> browser.getControl('Continue').click() |
1699 | - >>> print_feedback_messages(browser.contents) |
1700 | - There is 1 error. |
1701 | - You must enter a password. |
1702 | - |
1703 | -Third time's a charm? No; she forgets to confirm her password. |
1704 | - |
1705 | - >>> browser.getControl('Display Name').value = 'Janerie' |
1706 | - >>> browser.getControl('Create password').value = 'foo' |
1707 | - >>> browser.getControl('Continue').click() |
1708 | - >>> print_feedback_messages(browser.contents) |
1709 | - There is 1 error. |
1710 | - Passwords do not match. |
1711 | - |
1712 | -The fourth time she tries a non-ascii password, which isn't allowed. |
1713 | - |
1714 | - >>> browser.getControl('Display Name').value = 'Janerie' |
1715 | - >>> browser.getControl('Create password').value = 'tésté' |
1716 | - >>> browser.getControl('Retype the password').value = 'tésté' |
1717 | - >>> browser.getControl('Continue').click() |
1718 | - >>> print_feedback_messages(browser.contents) |
1719 | - There is 1 error. |
1720 | - The password provided contains non-ASCII characters. |
1721 | - |
1722 | -Now Jane enters all the necessary information to create the new account. She |
1723 | -decides to hide her email address. |
1724 | - |
1725 | - >>> browser.getControl('Display Name').value = 'Janerie' |
1726 | - >>> browser.getControl('Create password').value = 'foo' |
1727 | - >>> browser.getControl('Retype the password').value = 'foo' |
1728 | - >>> browser.getControl( |
1729 | - ... 'Hide my email addresses from other Launchpad users').click() |
1730 | - >>> browser.getControl('Continue').click() |
1731 | - >>> print_feedback_messages(browser.contents) |
1732 | - Registration completed successfully |
1733 | - |
1734 | -And now the account is created. |
1735 | - |
1736 | - >>> login('admin@canonical.com') |
1737 | - >>> jane = getUtility(IPersonSet).getByEmail('jperson@example.com') |
1738 | - >>> print jane.creation_rationale.name |
1739 | - OWNER_CREATED_LAUNCHPAD |
1740 | - >>> jane.hide_email_addresses |
1741 | - True |
1742 | - >>> logout() |
1743 | - |
1744 | -If we try to go to that token's page again, we'll see a message explaining |
1745 | -that the confirmation that token was created for is already concluded, so we |
1746 | -don't need to do anything else. |
1747 | - |
1748 | - >>> browser.open(token_url) |
1749 | - >>> print_feedback_messages(browser.contents) |
1750 | |
1751 | === removed file 'lib/lp/registry/stories/person/xx-login.txt' |
1752 | --- lib/lp/registry/stories/person/xx-login.txt 2009-12-23 20:29:05 +0000 |
1753 | +++ lib/lp/registry/stories/person/xx-login.txt 1970-01-01 00:00:00 +0000 |
1754 | @@ -1,85 +0,0 @@ |
1755 | -====== |
1756 | -Log in |
1757 | -====== |
1758 | - |
1759 | -New user Foo chooses to log into Launchpad. |
1760 | - |
1761 | - >>> browser = setupBrowser() |
1762 | - >>> browser.open('http://launchpad.dev/') |
1763 | - >>> browser.getLink('Log in / Register').click() |
1764 | - >>> print browser.title |
1765 | - Log in or register with Launchpad |
1766 | - |
1767 | -If Foo inadvertently use a non-ascii character in his password, an error |
1768 | -message is displayed. |
1769 | - |
1770 | - >>> browser.getControl( |
1771 | - ... 'E-mail address:', index=0).value = 'foo@baz.com' |
1772 | - >>> browser.getControl('Password').value = 't\xC3\xA9st' |
1773 | - >>> browser.getControl('Log In').click() |
1774 | - >>> print browser.title |
1775 | - Log in or register with Launchpad |
1776 | - |
1777 | - >>> print_feedback_messages(browser.contents) |
1778 | - The password provided contains non-ASCII characters. |
1779 | - |
1780 | -When the user logs in, his browser is redirected to the page he was on |
1781 | -before the login page. |
1782 | - |
1783 | - >>> browser.getControl('E-mail address:', index=0).value = 'foo@baz.com' |
1784 | - >>> browser.getControl('Password').value = 'f' |
1785 | - >>> browser.getControl('Log In').click() |
1786 | - >>> print browser.title |
1787 | - Log in or register with Launchpad |
1788 | - |
1789 | - |
1790 | -Users with suspended account cannot log in |
1791 | -========================================== |
1792 | - |
1793 | -Users with suspended accounts cannot log into Launchpad. |
1794 | - |
1795 | - # Open up the black box and shine a light on the test's inner workings. |
1796 | - # Create a user with a SUSPENDED account. |
1797 | - >>> from canonical.launchpad.interfaces.account import AccountStatus |
1798 | - |
1799 | - # Only admins can suspend an account. |
1800 | - >>> login('admin@canonical.com') |
1801 | - >>> bad_user = factory.makePerson( |
1802 | - ... email='bad-user@canonical.com', |
1803 | - ... name='bad-user', |
1804 | - ... password='test') |
1805 | - >>> from canonical.launchpad.interfaces import IMasterObject |
1806 | - >>> IMasterObject(bad_user.account).status = AccountStatus.SUSPENDED |
1807 | - >>> logout() |
1808 | - >>> transaction.commit() |
1809 | - |
1810 | -Bad User has a suspended account. He discovers that his account is disabled |
1811 | -when he visits his profile page. |
1812 | - |
1813 | - >>> browser = setupBrowser() |
1814 | - >>> browser.handleErrors = True |
1815 | - >>> browser.raiseHttpErrors = False |
1816 | - >>> browser.open('http://launchpad.dev/~bad-user') |
1817 | - >>> print browser.title |
1818 | - Error: Page gone |
1819 | - |
1820 | -He believes he can still use his Launchpad profile because he knows his |
1821 | -password. |
1822 | - |
1823 | - >>> browser.getLink('Log in / Register').click() |
1824 | - >>> print browser.title |
1825 | - Log in or register with Launchpad |
1826 | - |
1827 | - >>> browser.getControl('E-mail address:', index=0).value = ( |
1828 | - ... 'bad-user@canonical.com') |
1829 | - >>> browser.getControl('Password').value = 'test' |
1830 | - >>> browser.getControl('Log In').click() |
1831 | - >>> print browser.title |
1832 | - Log in or register with Launchpad |
1833 | - |
1834 | -But he cannot log in. He sees a error message that states he needs to contact |
1835 | -a Launchpad admin. |
1836 | - |
1837 | - >>> print_errors(browser.contents) |
1838 | - The email address belongs to a suspended account. Contact a Launchpad |
1839 | - admin about this issue. |
1840 | |
1841 | === removed file 'lib/lp/registry/stories/person/xx-reg-with-existing-email.txt' |
1842 | --- lib/lp/registry/stories/person/xx-reg-with-existing-email.txt 2009-12-23 16:17:12 +0000 |
1843 | +++ lib/lp/registry/stories/person/xx-reg-with-existing-email.txt 1970-01-01 00:00:00 +0000 |
1844 | @@ -1,191 +0,0 @@ |
1845 | -= Registering new accounts = |
1846 | - |
1847 | -When registering new accounts, we always check if the email address used |
1848 | -is not already registered in Launchpad. |
1849 | - |
1850 | - |
1851 | -== Email addresses cannot be registered twice == |
1852 | - |
1853 | -If the email address is registered and assigned to an account that has |
1854 | -been validated, we show a message and point the user to the forgotten |
1855 | -password page. |
1856 | - |
1857 | - >>> browser.open('http://launchpad.dev/') |
1858 | - >>> browser.getLink('Log in / Register').click() |
1859 | - |
1860 | - >>> browser.getControl('E-mail address:', index=1).value = ( |
1861 | - ... 'test@canonical.com') |
1862 | - >>> from lp.testing.registration import set_captcha_answer |
1863 | - >>> set_captcha_answer(browser, prefix='loginpage_') |
1864 | - >>> browser.getControl('Register').click() |
1865 | - |
1866 | - >>> for message in get_feedback_messages(browser.contents): |
1867 | - ... print message |
1868 | - Sorry, someone with the address test@canonical.com already has a |
1869 | - Launchpad account. If this is you and you've forgotten your password, |
1870 | - Launchpad can reset it for you. |
1871 | - |
1872 | - |
1873 | -== Claiming a profile via registration == |
1874 | - |
1875 | -On the other hand, if the email is assigned to a profile that has not |
1876 | -been validated, we pretend that we have never seen this email and move |
1877 | -on with the registration process. |
1878 | - |
1879 | - >>> browser.getControl('E-mail address:', index=1).value = 'mpo@iki.fi' |
1880 | - >>> set_captcha_answer(browser, prefix='loginpage_') |
1881 | - >>> browser.getControl('Register').click() |
1882 | - |
1883 | - >>> print extract_text(find_tag_by_id(browser.contents, 'address')) |
1884 | - Instructions on completing your registration have been sent to... |
1885 | - |
1886 | - >>> from lp.services.mail import stub |
1887 | - >>> from canonical.launchpad.ftests.logintoken import ( |
1888 | - ... get_token_url_from_email) |
1889 | - >>> from_addr, to_addr, msg = stub.test_emails.pop() |
1890 | - >>> token_url = get_token_url_from_email(msg) |
1891 | - >>> token_url |
1892 | - 'http://launchpad.dev/token/...' |
1893 | - |
1894 | - >>> browser.open(token_url) |
1895 | - >>> browser.url == '%s/+newaccount' % token_url |
1896 | - True |
1897 | - |
1898 | - >>> browser.getControl('Name').value = 'My name' |
1899 | - >>> label = 'Hide my email addresses from other Launchpad users' |
1900 | - >>> browser.getControl(label).selected = True |
1901 | - >>> browser.getControl(name='field.password').value = 'foo' |
1902 | - >>> browser.getControl(name='field.password_dupe').value = 'foo' |
1903 | - |
1904 | - >>> browser.getControl('Continue').click() |
1905 | - >>> browser.url |
1906 | - 'http://launchpad.dev' |
1907 | - |
1908 | - >>> for message in get_feedback_messages(browser.contents): |
1909 | - ... print message |
1910 | - Registration completed successfully |
1911 | - |
1912 | -It's also possible that a person tries to register a new account using an |
1913 | -email address that is already set as the preferred email of an existing |
1914 | -unvalidated profile, like some accounts imported from Ubuntu's bugzilla. |
1915 | -Although these accounts are not considered valid (that's why we allow the |
1916 | -users to proceed with the registration as if we haven't heard of the given |
1917 | -email address before), they /do/ have a preferred email and we need to handle |
1918 | -this. |
1919 | - |
1920 | - (To see kiko's email we must be logged in, so we'll use user_browser) |
1921 | - >>> user_browser.open('http://launchpad.dev/~kiko') |
1922 | - >>> unregistered_user_info = find_tag_by_id( |
1923 | - ... user_browser.contents, 'not-lp-user-or-team') |
1924 | - >>> unregistered_user_info.li.renderContents() |
1925 | - '...christian.reis@ubuntulinux.com...' |
1926 | - |
1927 | - >>> anon_browser.open('http://launchpad.dev/') |
1928 | - >>> anon_browser.getLink('Log in / Register').click() |
1929 | - |
1930 | - >>> anon_browser.getControl('E-mail address:', index=1).value = ( |
1931 | - ... 'christian.reis@ubuntulinux.com') |
1932 | - >>> set_captcha_answer(anon_browser, prefix='loginpage_') |
1933 | - >>> anon_browser.getControl('Register').click() |
1934 | - |
1935 | - >>> from_addr, to_addr, msg = stub.test_emails.pop() |
1936 | - >>> to_addr |
1937 | - ['christian.reis@ubuntulinux.com'] |
1938 | - >>> token_url = get_token_url_from_email(msg) |
1939 | - >>> token_url |
1940 | - 'http://launchpad.dev/token/...' |
1941 | - |
1942 | - >>> anon_browser.open(token_url) |
1943 | - >>> anon_browser.url == "%s/+newaccount" % token_url |
1944 | - True |
1945 | - |
1946 | - >>> anon_browser.getControl('Name').value = 'My name' |
1947 | - >>> anon_browser.getControl(name='field.password').value = 'foo' |
1948 | - >>> anon_browser.getControl(name='field.password_dupe').value = 'foo' |
1949 | - >>> anon_browser.getControl('Continue').click() |
1950 | - |
1951 | - >>> anon_browser.url |
1952 | - 'http://launchpad.dev' |
1953 | - >>> for message in get_feedback_messages(anon_browser.contents): |
1954 | - ... print message |
1955 | - Registration completed successfully |
1956 | - |
1957 | - |
1958 | -== Suspended email addresses cannot use registration == |
1959 | - |
1960 | -Users with suspended accounts cannot reactivate their account using |
1961 | -registration. |
1962 | - |
1963 | - # Open up the black box and shine a light on the test's inner workings. |
1964 | - # Create a user with a SUSPENDED account. |
1965 | - >>> from canonical.launchpad.interfaces.account import AccountStatus |
1966 | - |
1967 | - # Only admins can suspend an account. |
1968 | - >>> login('foo.bar@canonical.com') |
1969 | - >>> bad_user = factory.makePerson( |
1970 | - ... email='bad-user@canonical.com', |
1971 | - ... name='bad-user', |
1972 | - ... password='invalid') |
1973 | - >>> from canonical.launchpad.interfaces import IMasterObject |
1974 | - >>> IMasterObject(bad_user.account).status = AccountStatus.SUSPENDED |
1975 | - >>> logout() |
1976 | - |
1977 | -Bad User has a suspended account. He discovers that his account is disabled |
1978 | -when he visits his profile page. |
1979 | - |
1980 | - >>> browser = setupBrowser() |
1981 | - >>> browser.handleErrors = True |
1982 | - >>> browser.raiseHttpErrors = False |
1983 | - >>> browser.open('http://launchpad.dev/~bad-user') |
1984 | - >>> browser.title |
1985 | - 'Error: Page gone' |
1986 | - |
1987 | -He believes he can reactivate his account by re-registering with his |
1988 | -email address. |
1989 | - |
1990 | - >>> browser.getLink('Log in / Register').click() |
1991 | - >>> browser.title |
1992 | - 'Log in or register with Launchpad' |
1993 | - |
1994 | - >>> browser.getControl('E-mail address:', index=1).value = ( |
1995 | - ... 'bad-user@canonical.com') |
1996 | - >>> set_captcha_answer(browser, prefix='loginpage_') |
1997 | - >>> browser.getControl('Register').click() |
1998 | - |
1999 | - >>> print extract_text(find_main_content(browser.contents).p) |
2000 | - Instructions on completing your registration have been sent to |
2001 | - bad-user@canonical.com. |
2002 | - |
2003 | -Bad User retrieves the URL from the email and opens it in his browser. |
2004 | - |
2005 | - >>> len(stub.test_emails) |
2006 | - 1 |
2007 | - >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop() |
2008 | - >>> link = get_token_url_from_email(raw_msg) |
2009 | - >>> to_addrs |
2010 | - ['bad-user@canonical.com'] |
2011 | - >>> link |
2012 | - 'http://launchpad.dev/token/...' |
2013 | - |
2014 | - >>> browser.open(link) |
2015 | - >>> browser.url |
2016 | - 'http://launchpad.dev/token/.../+newaccount' |
2017 | - |
2018 | -Bad User types his name and password twice to verify it and submits it with |
2019 | -the Continue button. He is disappointed to see that his account is still |
2020 | -suspended, and that he is instructed to contact an admin. |
2021 | - |
2022 | - >>> browser.getControl('Name').value = 'Bad User' |
2023 | - >>> browser.getControl(name='field.password').value = 'test' |
2024 | - >>> browser.getControl(name='field.password_dupe').value = 'test' |
2025 | - >>> browser.getControl('Continue').click() |
2026 | - Traceback (most recent call last): |
2027 | - ... |
2028 | - HTTPError: HTTP Error 410: Gone |
2029 | - |
2030 | - >>> for tag in find_tags_by_class( |
2031 | - ... browser.contents, 'warning'): |
2032 | - ... print tag |
2033 | - <div ...>This profile cannot be claimed because the account is suspended. |
2034 | - Contact a <a href="mailto:feedback@launchpad.net?subject=SU...">Launchpad |
2035 | - admin</a> about this issue.</div> |
2036 | |
2037 | === removed file 'lib/lp/registry/stories/person/xx-resetpassword.txt' |
2038 | --- lib/lp/registry/stories/person/xx-resetpassword.txt 2009-10-29 15:09:28 +0000 |
2039 | +++ lib/lp/registry/stories/person/xx-resetpassword.txt 1970-01-01 00:00:00 +0000 |
2040 | @@ -1,186 +0,0 @@ |
2041 | -= Reset Password = |
2042 | - |
2043 | -David Allouche forgot his password and he's going to use the forgotten |
2044 | -password form to reset it. |
2045 | - |
2046 | -He locates the forgotten password link on the login page to visit |
2047 | -the page. |
2048 | - |
2049 | - >>> browser.open('http://launchpad.dev/+login') |
2050 | - >>> browser.getLink('Forgotten your password?').click() |
2051 | - |
2052 | - >>> browser.url |
2053 | - 'http://launchpad.dev/+forgottenpassword' |
2054 | - |
2055 | - >>> browser.title |
2056 | - 'Need a new Launchpad password?' |
2057 | - |
2058 | -He types the email address registered in Launchpad and submits the form. |
2059 | - |
2060 | - >>> from lp.testing.registration import set_captcha_answer |
2061 | - >>> browser.getControl(name='email').value = ( |
2062 | - ... 'david.allouche@canonical.com') |
2063 | - >>> set_captcha_answer(browser) |
2064 | - >>> browser.getControl('Request Reset').click() |
2065 | - >>> print extract_text(find_main_content(browser.contents)) |
2066 | - Need a new Launchpad password? |
2067 | - We have sent you an email with instructions to reset your password. |
2068 | - |
2069 | -David receives an email from Launchpad. |
2070 | - |
2071 | - # Get the to-addresses and link form the email. |
2072 | - >>> from lp.services.mail import stub |
2073 | - >>> from canonical.launchpad.ftests.logintoken import ( |
2074 | - ... get_token_url_from_email) |
2075 | - >>> len(stub.test_emails) |
2076 | - 1 |
2077 | - >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop() |
2078 | - >>> link = get_token_url_from_email(raw_msg) |
2079 | - |
2080 | -The email was sent to him. |
2081 | - |
2082 | - >>> to_addrs |
2083 | - ['david.allouche@canonical.com'] |
2084 | - |
2085 | -David uses the link in the email to visit the reset password page. |
2086 | - |
2087 | - >>> link |
2088 | - 'http://launchpad.dev/token/...' |
2089 | - >>> browser.open(link) |
2090 | - >>> browser.url |
2091 | - 'http://launchpad.dev/token/.../+resetpassword' |
2092 | - |
2093 | -The token can only be used to reset the password. Manually typing |
2094 | -another login token view name will redirect to the correct one: |
2095 | - |
2096 | - >>> wrong_link = link + "/+validateemail" |
2097 | - >>> browser.open(wrong_link) |
2098 | - >>> browser.url |
2099 | - 'http://launchpad.dev/token/.../+resetpassword' |
2100 | - |
2101 | -He may now enter his password. Unfortunately, he picks a password with |
2102 | -invalid characters: |
2103 | - |
2104 | - >>> browser.getControl( |
2105 | - ... name='field.email').value = 'david.allouche@canonical.com' |
2106 | - >>> browser.getControl(name='field.password').value = 'é' |
2107 | - >>> browser.getControl(name='field.password_dupe').value = 'é' |
2108 | - >>> browser.getControl('Continue').click() |
2109 | - |
2110 | - >>> browser.url |
2111 | - 'http://launchpad.dev/token/.../+resetpassword' |
2112 | - |
2113 | - >>> print_feedback_messages(browser.contents) |
2114 | - There is 1 error. |
2115 | - The password provided contains non-ASCII characters. |
2116 | - |
2117 | -This time, David corrects the password and continues: |
2118 | - |
2119 | - >>> browser.getControl(name='field.password').value = 'test2' |
2120 | - >>> browser.getControl(name='field.password_dupe').value = 'test2' |
2121 | - >>> browser.getControl('Continue').click() |
2122 | - |
2123 | - >>> browser.url |
2124 | - 'http://launchpad.dev' |
2125 | - |
2126 | - >>> print_feedback_messages(browser.contents) |
2127 | - Your password has been reset successfully. |
2128 | - |
2129 | - >>> print extract_text(find_tag_by_id(browser.contents, 'logincontrol')) |
2130 | - David Allouche... |
2131 | - |
2132 | -Now that the token is consumed, he's not able to use it again. |
2133 | - |
2134 | - >>> browser.open(link) |
2135 | - >>> print browser.title |
2136 | - You have already done this |
2137 | - >>> print extract_text(find_main_content(browser.contents)) |
2138 | - You reached this page probably because you followed a link received by |
2139 | - email. That link was sent to confirm you have access to the email |
2140 | - address it was sent to, but this confirmation was already concluded, so |
2141 | - you don't need to do anything else. |
2142 | - |
2143 | -It is now possible for David to log in with his new password. He |
2144 | -logs out and then logs in again: |
2145 | - |
2146 | - >>> browser.open('http://launchpad.dev/+logout') |
2147 | - >>> print_feedback_messages(browser.contents) |
2148 | - You have been logged out |
2149 | - |
2150 | - >>> browser.getLink('Log in / Register').click() |
2151 | - |
2152 | - >>> browser.getControl( |
2153 | - ... 'E-mail address:', index=0).value = 'david.allouche@canonical.com' |
2154 | - >>> browser.getControl('Password').value = 'test2' |
2155 | - >>> browser.getControl('Log In').click() |
2156 | - |
2157 | - >>> browser.url |
2158 | - 'http://launchpad.dev' |
2159 | - |
2160 | - >>> print extract_text(find_tag_by_id(browser.contents, 'logincontrol')) |
2161 | - David Allouche... |
2162 | - |
2163 | - |
2164 | -== Reset is protected by a math captcha == |
2165 | - |
2166 | -When requesting a password reset David is presented with a simple math |
2167 | -problem which must be solved correctly before proceeding. |
2168 | - |
2169 | - >>> browser.open('http://launchpad.dev/+forgottenpassword') |
2170 | - >>> browser.getControl(name='email').value = ( |
2171 | - ... 'david.allouche@canonical.com') |
2172 | - >>> browser.getControl(name='captcha_submission').value = '-1' |
2173 | - >>> browser.getControl('Request Reset').click() |
2174 | - >>> print_feedback_messages(browser.contents) |
2175 | - The answer to the simple math question was incorrect or missing. Please try again. |
2176 | - |
2177 | - |
2178 | -== Using email addresses other than the preferred one == |
2179 | - |
2180 | -Any of a person's validated email addresses can be used to reset his |
2181 | -password. |
2182 | - |
2183 | -David has a second email address (david@canonical.com), which he will |
2184 | -use to reset his password now. |
2185 | - |
2186 | - >>> browser = setupBrowser() |
2187 | - >>> browser.open('http://launchpad.dev/+login') |
2188 | - >>> browser.getLink('Forgotten your password?').click() |
2189 | - >>> browser.getControl(name='email').value = 'david@canonical.com' |
2190 | - >>> set_captcha_answer(browser) |
2191 | - >>> browser.getControl('Request Reset').click() |
2192 | - >>> print_feedback_messages(browser.contents) |
2193 | - |
2194 | -He follows the link sent to his email just like he did before. |
2195 | - |
2196 | - >>> len(stub.test_emails) |
2197 | - 1 |
2198 | - >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop() |
2199 | - >>> link = get_token_url_from_email(raw_msg) |
2200 | - >>> browser.open(link) |
2201 | - >>> browser.url |
2202 | - 'http://launchpad.dev/token/.../+resetpassword' |
2203 | - |
2204 | -And then resets his password. |
2205 | - |
2206 | - >>> browser.getControl(name='field.email').value = 'david@canonical.com' |
2207 | - >>> browser.getControl(name='field.password').value = 'test3' |
2208 | - >>> browser.getControl(name='field.password_dupe').value = 'test3' |
2209 | - >>> browser.getControl('Continue').click() |
2210 | - >>> browser.url |
2211 | - 'http://launchpad.dev' |
2212 | - >>> print_feedback_messages(browser.contents) |
2213 | - Your password has been reset successfully. |
2214 | - |
2215 | - |
2216 | -== Teams do not have passwords == |
2217 | - |
2218 | -Teams do not have passwords, they cannot be reset. |
2219 | - |
2220 | - >>> browser.open('http://launchpad.dev/+forgottenpassword') |
2221 | - >>> browser.getControl(name='email').value = 'support@ubuntu.com' |
2222 | - >>> set_captcha_answer(browser) |
2223 | - >>> browser.getControl('Request Reset').click() |
2224 | - >>> print_feedback_messages(browser.contents) |
2225 | - The email address support@ubuntu.com |
2226 | - belongs to a team, and teams cannot log in to Launchpad. |
2227 | |
2228 | === removed file 'lib/lp/registry/stories/team/xx-team-restricted.txt' |
2229 | --- lib/lp/registry/stories/team/xx-team-restricted.txt 2009-11-22 15:43:16 +0000 |
2230 | +++ lib/lp/registry/stories/team/xx-team-restricted.txt 1970-01-01 00:00:00 +0000 |
2231 | @@ -1,137 +0,0 @@ |
2232 | -= Team-restricted Launchpad = |
2233 | - |
2234 | -It is possible to run Launchpad in a special mode where access is restricted |
2235 | -to Launchpad admins and members of a particular team. |
2236 | - |
2237 | -You turn on this feature by setting the 'restrict_to_team' variable in the |
2238 | -launchpad.conf file. |
2239 | - |
2240 | - <launchpad> |
2241 | - restrict_to_team teamname |
2242 | - ... |
2243 | - </launchpad> |
2244 | - |
2245 | -We'll temporarily restrict Launchpad to be used only by Launchpad admins |
2246 | -and Landscape developers. |
2247 | - |
2248 | - >>> from canonical.config import config |
2249 | - >>> config.launchpad.restrict_to_team == '' |
2250 | - True |
2251 | - |
2252 | - >>> restrict_data = """ |
2253 | - ... [launchpad] |
2254 | - ... restrict_to_team: landscape-developers |
2255 | - ... """ |
2256 | - >>> config.push('restrict_data', restrict_data) |
2257 | - |
2258 | -When in this condition, anonymous users are shown a special trimmed-down |
2259 | -login page when they go to any page. |
2260 | - |
2261 | - >>> browser.open("http://launchpad.dev/people") |
2262 | - >>> print browser.url |
2263 | - http://launchpad.dev/+restricted-login?production=http%3A//launchpad.net/people |
2264 | - |
2265 | -A link is provided to the equivalent page on the non-restricted |
2266 | -Launchpad instance: |
2267 | - |
2268 | - >>> print browser.contents |
2269 | - <... |
2270 | - <p> |
2271 | - You may be able to access this page |
2272 | - <a href="http://launchpad.net/people">on the main |
2273 | - Launchpad site</a> instead. |
2274 | - </p> |
2275 | - ... |
2276 | - |
2277 | -This includes nonsense URLs and not-found URLs. |
2278 | - |
2279 | - >>> browser.open("http://bugs.launchpad.dev/p/p/p/p?key=value") |
2280 | - >>> print browser.url |
2281 | - http://bugs.launchpad.dev/+restricted-login?production=http%3A//bugs.launchpad.net/p/p/p/p%3Fkey%3Dvalue |
2282 | - >>> print browser.contents |
2283 | - <... |
2284 | - <p> |
2285 | - You may be able to access this page |
2286 | - <a href="http://bugs.launchpad.net/p/p/p/p?key=value">on the main |
2287 | - Launchpad site</a> instead. |
2288 | - </p> |
2289 | - ... |
2290 | - |
2291 | -That is, any page except an information page about the restriction. |
2292 | - |
2293 | - >>> browser.open("http://launchpad.dev/+restricted-info") |
2294 | - >>> print browser.url |
2295 | - http://launchpad.dev/+restricted-info |
2296 | - |
2297 | -Anyway, the anonymous user logs in as name16 (foo.bar@canonical.com), who |
2298 | -is in the admin team, and gets redirected to the front page. |
2299 | - |
2300 | - >>> def submit_login(browser_instance, email, password): |
2301 | - ... emailcontrol = browser_instance.getControl(name="loginpage_email") |
2302 | - ... passwordcontrol = browser_instance.getControl( |
2303 | - ... name="loginpage_password") |
2304 | - ... emailcontrol.value = email |
2305 | - ... passwordcontrol.value = password |
2306 | - ... submitbutton = browser_instance.getControl( |
2307 | - ... name="loginpage_submit_login") |
2308 | - ... submitbutton.click() |
2309 | - |
2310 | - >>> browser.open("http://launchpad.dev/p/p/p/p") |
2311 | - >>> print browser.url |
2312 | - http://launchpad.dev/+restricted-login?production=http%3A//launchpad.net/p/p/p/p |
2313 | - >>> submit_login(browser, 'foo.bar@canonical.com', 'test') |
2314 | - >>> print browser.url |
2315 | - http://launchpad.dev |
2316 | - |
2317 | -Let's log out name16 (foo.bar@canonical.com), and log in someone else. |
2318 | -name12 (test@canonical.com) is in the landscape-developers team, so will |
2319 | -be able to log in. |
2320 | - |
2321 | - >>> browser.getControl(name="logout").click() |
2322 | - >>> print browser.url |
2323 | - http://launchpad.dev/+restricted-login?production=http%3A//launchpad.net/%3Floggingout%3D1 |
2324 | - >>> submit_login(browser, 'test@canonical.com', 'test') |
2325 | - >>> print browser.url |
2326 | - http://launchpad.dev |
2327 | - |
2328 | -We'll now log out name12 (test@canonical.com), and try to log in cprov, who |
2329 | -isn't an admin, and isn't a landscape-developer. So, he gets sent to the info |
2330 | -page to explain why he can't use the server. |
2331 | - |
2332 | - >>> browser.getControl(name="logout").click() |
2333 | - >>> print browser.url |
2334 | - http://launchpad.dev/+restricted-login?production=http%3A//launchpad.net/%3Floggingout%3D1 |
2335 | - >>> submit_login(browser, 'celso.providelo@canonical.com', 'cprov') |
2336 | - >>> print browser.url |
2337 | - http://launchpad.dev/+restricted-info?production=http%3A//launchpad.net/ |
2338 | - |
2339 | -Now that the user is logged in, they will be directed to the |
2340 | -+restricted-info page if they try to browse other pages: |
2341 | - |
2342 | - >>> browser.open("http://bugs.launchpad.dev/evolution") |
2343 | - >>> print browser.url |
2344 | - http://bugs.launchpad.dev/+restricted-info?production=http%3A//bugs.launchpad.net/evolution |
2345 | - >>> print browser.contents |
2346 | - <... |
2347 | - <p>You may be able to |
2348 | - access this page |
2349 | - <a href="http://bugs.launchpad.net/evolution">on the main |
2350 | - Launchpad site</a> instead.</p> |
2351 | - ... |
2352 | - |
2353 | -Set restrict_to_team back to being a server that is open to anyone. |
2354 | - |
2355 | - >>> config_data = config.pop('restrict_data') |
2356 | - |
2357 | -Note that the info page still works even when the server is open. |
2358 | - |
2359 | - >>> browser.open("http://launchpad.dev/+restricted-info") |
2360 | - >>> print browser.contents |
2361 | - <...This server is open to anonymous access and registered users... |
2362 | - |
2363 | -The restricted login page redirects to the normal login page. |
2364 | - |
2365 | - >>> browser.open("http://launchpad.dev/+restricted-login") |
2366 | - >>> print browser.url |
2367 | - http://launchpad.dev/+login |
2368 | - |
2369 | |
2370 | === removed file 'lib/lp/services/openid/stories/xx-resetpassword-of-sso-account.txt' |
2371 | --- lib/lp/services/openid/stories/xx-resetpassword-of-sso-account.txt 2009-12-04 22:36:22 +0000 |
2372 | +++ lib/lp/services/openid/stories/xx-resetpassword-of-sso-account.txt 1970-01-01 00:00:00 +0000 |
2373 | @@ -1,83 +0,0 @@ |
2374 | -= Resetting the password of SSO-only accounts = |
2375 | - |
2376 | -Every once in a while people come to register Launchpad accounts using email |
2377 | -addresses that belong to SSO-only accounts. In these cases we explain to them |
2378 | -that they should use the SSO credentials to log into Launchpad, but it's |
2379 | -possible that they've forgotten their password so they'll try to use the |
2380 | -'Forgotten your password?' link to reset it. |
2381 | - |
2382 | -Since their account is SSO-only (i.e. it has no Person record associated |
2383 | -with), we can't use Launchpad's workflow for resetting the password -- it |
2384 | -expects a Person entry to be associated with the given email addres. Because |
2385 | -of that we'll allow the user to initiate the password-reset workflow on |
2386 | -Launchpad but we'll force the use of SSO's password-reset workflow to complete |
2387 | -it. |
2388 | - |
2389 | - # Create a personless account to demostrate what we want. |
2390 | - >>> login(ANONYMOUS) |
2391 | - >>> account = factory.makeAccount('Test', email='test@example.com') |
2392 | - >>> logout() |
2393 | - |
2394 | -Trying to register will give an error, telling the user to use the SSO |
2395 | -credentials to login. |
2396 | - |
2397 | - >>> from lp.testing.registration import set_captcha_answer |
2398 | - >>> browser.open('http://launchpad.dev/+login') |
2399 | - >>> browser.getControl(name='loginpage_email', index=1).value = ( |
2400 | - ... 'test@example.com') |
2401 | - >>> set_captcha_answer(browser, prefix='loginpage_') |
2402 | - >>> browser.getControl('Register').click() |
2403 | - >>> print_feedback_messages(browser.contents) |
2404 | - The email address test@example.com is already registered in the Launchpad |
2405 | - Login Service... Please use the same email and password to log into |
2406 | - Launchpad. |
2407 | - |
2408 | -But the user has forgotten their credentials, so they'll have to reset the |
2409 | -password. |
2410 | - |
2411 | - >>> browser.getLink('Forgotten your password?').click() |
2412 | - >>> browser.url |
2413 | - 'http://launchpad.dev/+forgottenpassword' |
2414 | - >>> browser.getControl(name='email').value = 'test@example.com' |
2415 | - >>> set_captcha_answer(browser) |
2416 | - >>> browser.getControl('Request Reset').click() |
2417 | - >>> print extract_text(find_main_content(browser.contents)) |
2418 | - Need a new Launchpad password? |
2419 | - We have sent you an email with instructions to reset your password. |
2420 | - |
2421 | - # Get the link from the email. |
2422 | - >>> from lp.services.mail import stub |
2423 | - >>> from canonical.launchpad.ftests.logintoken import ( |
2424 | - ... get_token_url_from_email) |
2425 | - >>> len(stub.test_emails) |
2426 | - 1 |
2427 | - >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop() |
2428 | - >>> link = get_token_url_from_email(raw_msg) |
2429 | - >>> to_addrs |
2430 | - ['test@example.com'] |
2431 | - |
2432 | -Following the link sent by email will take the user to the SSO site to |
2433 | -complete the password reset. |
2434 | - |
2435 | - >>> browser.open(link) |
2436 | - >>> browser.url |
2437 | - 'http://openid.launchpad.dev/token/.../+resetpassword' |
2438 | - >>> browser.getControl(name='field.email').value = 'test@example.com' |
2439 | - >>> browser.getControl(name='field.password').value = 'test' |
2440 | - >>> browser.getControl(name='field.password_dupe').value = 'test' |
2441 | - >>> browser.getControl('Continue').click() |
2442 | - >>> print_feedback_messages(browser.contents) |
2443 | - Your password has been reset successfully. |
2444 | - |
2445 | -Since the password reset was done on SSO, the user won't be logged into |
2446 | -Launchpad, so we redirect the user back to Launchpad's +login page for them to |
2447 | -login. |
2448 | - |
2449 | - >>> browser.url |
2450 | - 'http://launchpad.dev/+login' |
2451 | - >>> browser.getControl( |
2452 | - ... 'E-mail address:', index=0).value = 'test@example.com' |
2453 | - >>> browser.getControl('Password').value = 'test' |
2454 | - >>> browser.getControl('Log In').click() |
2455 | - >>> print extract_text(find_tag_by_id(browser.contents, 'logincontrol')) |
2456 | - Test... |
Remove the views for the old login and reset password forms, together with tests that were exercising them.