Merge lp:~james-w/canonical-identity-provider/email-timeout into lp:canonical-identity-provider/release

Proposed by James Westby
Status: Merged
Approved by: Matias Bordese
Approved revision: no longer in the source branch.
Merged at revision: 1031
Proposed branch: lp:~james-w/canonical-identity-provider/email-timeout
Merge into: lp:canonical-identity-provider/release
Diff against target: 70 lines (+26/-1)
4 files modified
src/identityprovider/forms.py (+4/-0)
src/identityprovider/tests/test_forms.py (+10/-0)
src/webui/tests/test_views_account.py (+11/-0)
src/webui/views/account.py (+1/-1)
To merge this branch: bzr merge lp:~james-w/canonical-identity-provider/email-timeout
Reviewer Review Type Date Requested Status
Matias Bordese (community) Approve
Review via email: mp+182124@code.launchpad.net

Commit message

Don't allow adding an email that is already registered with a different case.

When registering you can't use a different-case version of someone else's
email. However, you could add one after you registered if the other person
hadn't validated yet.

Description of the change

Hi,

I was looking at:
https://oops.canonical.com/oops/?oopsid=OOPS-c756fbc2750a2f29751f2a2626caeeef

There's a slow query because it's doing a case-sensitive search when looking
for addresses to invalidate. I fixed it to do case-insensitive search to use
the index.

I was worried that this would mean you could invlidate someone else's email
address, but the check for > 1 email should avoid that, because it would
find both case versions if you were able to add one. However, I still did
some tests to try and add an email that is a different-case version of
someone else's. You can't do it at registration, but you could do it
by adding a new email to an existing account if the other person hadn't
validated the email yet. I fixed that at the same time for extra security.

Thanks,

James

To post a comment you must log in.
Revision history for this message
Matias Bordese (matiasb) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/identityprovider/forms.py'
2--- src/identityprovider/forms.py 2013-08-22 16:21:57 +0000
3+++ src/identityprovider/forms.py 2013-08-26 15:13:38 +0000
4@@ -289,6 +289,10 @@
5 raise forms.ValidationError(_(
6 "Please verify your email."
7 ))
8+ else:
9+ raise forms.ValidationError(_(
10+ "Email already registered."
11+ ))
12 except EmailAddress.DoesNotExist:
13 return data
14 return data
15
16=== modified file 'src/identityprovider/tests/test_forms.py'
17--- src/identityprovider/tests/test_forms.py 2013-07-31 13:50:43 +0000
18+++ src/identityprovider/tests/test_forms.py 2013-08-26 15:13:38 +0000
19@@ -533,6 +533,16 @@
20 def get_form(self, **kwargs):
21 return NewEmailForm(**kwargs)
22
23+ def test_existing_email_different_case(self):
24+ account = self.factory.make_account()
25+ email = 'test@example.com'
26+ self.factory.make_email_for_account(account, email,
27+ status=EmailStatus.NEW)
28+ form = NewEmailForm(dict(newemail=email.upper()))
29+ self.assertFalse(form.is_valid())
30+ self.assertEqual(['Email already registered.'],
31+ form.errors['newemail'])
32+
33
34 class UserAttribsRequestFormTest(SSOBaseTestCase):
35
36
37=== modified file 'src/webui/tests/test_views_account.py'
38--- src/webui/tests/test_views_account.py 2013-08-22 16:21:57 +0000
39+++ src/webui/tests/test_views_account.py 2013-08-26 15:13:38 +0000
40@@ -864,6 +864,17 @@
41 expected_logging = [mock.call.info(log_msg, self.email)]
42 self.assert_happy_path(response, expected_logging)
43
44+ def test_nonexisting_email_different_case(self):
45+ EmailAddress.objects.all().delete()
46+ assert EmailAddress.objects.count() == 0
47+ self.factory.make_email_for_account(self.account,
48+ email=self.email.upper())
49+
50+ response = self.client.post(self.url)
51+ log_msg = 'Setting email %r status to invalidated.'
52+ expected_logging = [mock.call.info(log_msg, self.email)]
53+ self.assert_happy_path(response, expected_logging)
54+
55 def test_shows_confirmation(self):
56 response = self.client.get(self.url)
57 # response is a confirmation page
58
59=== modified file 'src/webui/views/account.py'
60--- src/webui/views/account.py 2013-08-22 16:21:57 +0000
61+++ src/webui/views/account.py 2013-08-26 15:13:38 +0000
62@@ -315,7 +315,7 @@
63
64 # email may not exist since the user may have tried an operation with
65 # an email unknown to our system
66- emails = EmailAddress.objects.filter(email=email_address)
67+ emails = EmailAddress.objects.filter(email__iexact=email_address)
68 if emails.count() == 0:
69 # This case matches, for example, registration web where the Account
70 # is not created until the user validates the email address.