Merge lp:~maxiberta/canonical-identity-provider/canonical-email-urls into lp:canonical-identity-provider/release

Proposed by Maximiliano Bertacchini
Status: Merged
Approved by: Maximiliano Bertacchini
Approved revision: no longer in the source branch.
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: lp:~maxiberta/canonical-identity-provider/canonical-email-urls
Merge into: lp:canonical-identity-provider/release
Diff against target: 814 lines (+87/-112)
11 files modified
django_project/settings_test.py (+2/-0)
src/api/v10/handlers.py (+1/-2)
src/api/v10/tests/utils.py (+2/-1)
src/api/v20/handlers.py (+4/-7)
src/api/v20/registration.py (+3/-3)
src/api/v20/tests/test_handlers.py (+3/-5)
src/api/v20/tests/test_registration.py (+26/-31)
src/identityprovider/emailutils.py (+21/-22)
src/identityprovider/tests/test_emailutils.py (+23/-34)
src/webui/views/account.py (+1/-5)
src/webui/views/ui.py (+1/-2)
To merge this branch: bzr merge lp:~maxiberta/canonical-identity-provider/canonical-email-urls
Reviewer Review Type Date Requested Status
Celso Providelo (community) Approve
Review via email: mp+353119@code.launchpad.net

Commit message

Use settings.SSO_ROOT_URL as the base for all URLs in emails.

Description of the change

Use settings.SSO_ROOT_URL as the base for all URLs in emails, instead of calculating it from the current request which might come from the internal API client via HTTP. This prevents including http:// URLS in emails.

Implementation notes: basically
- Dropped the `root_url` parameter from all functions in emailutils.py and replaced by settings.SSO_ROOT_URL.
- Dropped `root_url` from all call sites to emailutils functions.
- Set settings.SSO_ROOT_URL="http://testserver" in testing mode to match Django testing internals.

To post a comment you must log in.
Revision history for this message
Celso Providelo (cprov) wrote :

Generally agree with the change to respect the settings parameter, instead of calculate it from the context request.

I wish the change was smaller by avoiding changing the implementation and methods signatures at the same time, but you already managed to do it all at once <bonus/>.

review: Approve
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'django_project/settings_test.py'
2--- django_project/settings_test.py 2018-02-15 13:17:06 +0000
3+++ django_project/settings_test.py 2018-08-15 14:28:34 +0000
4@@ -2,6 +2,8 @@
5
6 from settings_devel import * # noqa
7
8+SSO_ROOT_URL = 'http://testserver'
9+
10 # https://github.com/sunlightlabs/django-honeypot/issues/12
11 # until django-honeypot provides a way of using the middleware in tests,
12 # we'll remove the middleware
13
14=== modified file 'src/api/v10/handlers.py'
15--- src/api/v10/handlers.py 2018-02-21 11:59:00 +0000
16+++ src/api/v10/handlers.py 2018-08-15 14:28:34 +0000
17@@ -224,9 +224,8 @@
18
19 account = Account.objects.create_account(
20 displayname, email, password, email_validated=False)
21- root_url = request.build_absolute_uri('/')
22 emailutils.send_new_user_email(
23- root_url, account=account, email=email,
24+ account=account, email=email,
25 redirection_url=redirection_url, platform=platform)
26 account_created.send(
27 sender=self, openid_identifier=account.openid_identifier)
28
29=== modified file 'src/api/v10/tests/utils.py'
30--- src/api/v10/tests/utils.py 2018-02-09 20:56:16 +0000
31+++ src/api/v10/tests/utils.py 2018-08-15 14:28:34 +0000
32@@ -40,7 +40,8 @@
33 self.addCleanup(urllib_intercept.uninstall_opener)
34 httplib2_intercept.install()
35 self.addCleanup(httplib2_intercept.uninstall)
36- add_wsgi_intercept(parse.hostname, parse.port, WSGIHandler)
37+ # This should intercept requests to http://testserver on port 80.
38+ add_wsgi_intercept(parse.hostname, parse.port or 80, WSGIHandler)
39 self.addCleanup(remove_wsgi_intercept, parse.hostname, parse.port)
40 self.api = ServiceRoot(None, host_url + '/api/1.0')
41
42
43=== modified file 'src/api/v20/handlers.py'
44--- src/api/v20/handlers.py 2018-02-09 14:17:25 +0000
45+++ src/api/v20/handlers.py 2018-08-15 14:28:34 +0000
46@@ -215,8 +215,7 @@
47 if account is None:
48 # they've tried to reset with an invalid email, so send them
49 # an email on how to create an account
50- root_url = request.build_absolute_uri('/')
51- emailutils.send_invitation_after_password_reset(root_url, email)
52+ emailutils.send_invitation_after_password_reset(email)
53
54 if invalidated_email.exists():
55 # there is no account with this email
56@@ -264,9 +263,8 @@
57
58 # create new token and send email to user
59 redirection_url = redirection_url_for_token(token_string)
60- root_url = request.build_absolute_uri('/')
61 auth_token, inv_auth_token = emailutils.send_password_reset_email(
62- root_url, account, email, redirection_url)
63+ account, email, redirection_url)
64
65 # return response
66 data = dict(email=auth_token.email)
67@@ -335,7 +333,7 @@
68 root_url = request.build_absolute_uri('/')
69 try:
70 account = registration.register(
71- root_url, email, password, displayname, username=username,
72+ email, password, displayname, username=username,
73 creation_source=data.get('creation_source'),
74 oid_token=data.get('oid_token')
75 )
76@@ -378,10 +376,9 @@
77 missing = dict((k, [FIELD_REQUIRED]) for k in expected - set(data))
78 return errors.INVALID_DATA(**missing)
79
80- root_url = request.build_absolute_uri('/')
81 try:
82 account = registration.register(
83- root_url, email, password=None, displayname=displayname,
84+ email, password=None, displayname=displayname,
85 email_validated=True, send_email=False,
86 creation_source=data.get('creation_source'),
87 require_password=False,
88
89=== modified file 'src/api/v20/registration.py'
90--- src/api/v20/registration.py 2018-02-09 20:56:16 +0000
91+++ src/api/v20/registration.py 2018-08-15 14:28:34 +0000
92@@ -29,7 +29,7 @@
93
94
95 def register(
96- root_url, email, password, displayname, username=None,
97+ email, password, displayname, username=None,
98 email_validated=False, send_email=True, creation_source=None,
99 require_password=True, oid_token=None):
100 """Register a new account"""
101@@ -39,7 +39,7 @@
102 # Only send email if the account is active; otherwise, a disabled
103 # account can be spammed.
104 if other_email.account.is_active and send_email:
105- send_impersonation_email(root_url, other_email.email)
106+ send_impersonation_email(other_email.email)
107 raise EmailAlreadyRegistered(other_email.account)
108
109 data = {
110@@ -81,7 +81,7 @@
111 account_created.send('api', openid_identifier=account.openid_identifier)
112
113 if send_email:
114- send_new_user_email(root_url=root_url, account=account, email=email,
115+ send_new_user_email(account=account, email=email,
116 oid_token=oid_token)
117
118 return account
119
120=== modified file 'src/api/v20/tests/test_handlers.py'
121--- src/api/v20/tests/test_handlers.py 2018-05-28 17:22:45 +0000
122+++ src/api/v20/tests/test_handlers.py 2018-08-15 14:28:34 +0000
123@@ -1767,8 +1767,7 @@
124
125 extra = {'email': ['No account associated with invalid@foo.com']}
126 self.assert_bad_request(data={'email': 'invalid@foo.com'}, extra=extra)
127- mock_send_invitation.assert_called_once_with(
128- self.sso_root_url, 'invalid@foo.com')
129+ mock_send_invitation.assert_called_once_with('invalid@foo.com')
130
131 def test_suspended_account(self):
132 self.account.suspend()
133@@ -1910,8 +1909,7 @@
134 content = self.do_post(
135 {'email': invalidated_email.email}, status_code=403)
136
137- mock_send_invitation.assert_called_once_with(self.sso_root_url,
138- self.email.email)
139+ mock_send_invitation.assert_called_once_with(self.email.email)
140 expected = {
141 'message': ('This email address has been invalidated. '
142 'Please contact login support.'),
143@@ -1930,7 +1928,7 @@
144 {'email': self.email.email, 'token': token}, status_code=201)
145
146 mock_send_password_reset_email.assert_called_once_with(
147- self.sso_root_url, self.account, self.email.email, redirection_url)
148+ self.account, self.email.email, redirection_url)
149
150 def test_invalid_email_throttle_decorator(self):
151 self.assert_bad_request(
152
153=== modified file 'src/api/v20/tests/test_registration.py'
154--- src/api/v20/tests/test_registration.py 2018-05-25 22:02:57 +0000
155+++ src/api/v20/tests/test_registration.py 2018-08-15 14:28:34 +0000
156@@ -38,7 +38,7 @@
157 super(RegistrationTestCase, self).setUp()
158 self.email = self.factory.make_email_address()
159 self.data = [
160- self.sso_root_url, self.email, 'SecretPassword1', 'displayname']
161+ self.email, 'SecretPassword1', 'displayname']
162
163 self.mock_send_impersonation_email = self.patch(
164 'api.v20.registration.send_impersonation_email')
165@@ -60,8 +60,7 @@
166 if password is not None:
167 account.user.check_password(password)
168 self.mock_send_new_user_email.assert_called_once_with(
169- root_url=self.sso_root_url, account=account, email=self.email,
170- oid_token=None)
171+ account=account, email=self.email, oid_token=None)
172 self.assertFalse(self.mock_send_impersonation_email.called)
173
174 def test_register_already_registered_and_inactive(self):
175@@ -71,8 +70,7 @@
176
177 with self.assertRaises(registration.EmailAlreadyRegistered):
178 registration.register(
179- self.sso_root_url, email=self.email, password="",
180- displayname="")
181+ email=self.email, password="", displayname="")
182
183 self.assertFalse(self.mock_send_impersonation_email.called)
184 self.assertFalse(self.mock_send_new_user_email.called)
185@@ -83,11 +81,9 @@
186
187 with self.assertRaises(registration.EmailAlreadyRegistered):
188 registration.register(
189- self.sso_root_url, email=self.email, password="",
190- displayname="")
191+ email=self.email, password="", displayname="")
192
193- self.mock_send_impersonation_email.assert_called_once_with(
194- self.sso_root_url, self.email)
195+ self.mock_send_impersonation_email.assert_called_once_with(self.email)
196 self.assertFalse(self.mock_send_new_user_email.called)
197
198 def test_register_success(self):
199@@ -269,7 +265,7 @@
200 username = 'InvalidUsername'
201 with self.assertRaises(ValidationError) as ctx:
202 registration.register(
203- self.sso_root_url, email=self.email, password=None,
204+ email=self.email, password=None,
205 displayname='displayname', username=username)
206 e = ctx.exception
207 self.assertEqual(e.message_dict['username'], [INVALID_NAME])
208@@ -289,7 +285,7 @@
209 return_value=fake_lp_response)
210
211 account = registration.register(
212- self.sso_root_url, email=self.email, password=None,
213+ email=self.email, password=None,
214 displayname='displayname', username=username,
215 require_password=False)
216
217@@ -298,7 +294,7 @@
218 @switches(USERNAME_UI=False)
219 def test_can_create_account_without_pw_with_feature_flag_disabled(self):
220 account = registration.register(
221- self.sso_root_url, email=self.email, password=None,
222+ email=self.email, password=None,
223 displayname='displayname', username='validusername',
224 require_password=False)
225
226@@ -316,7 +312,7 @@
227 return_value=fake_lp_response)
228
229 account = registration.register(
230- self.sso_root_url, email=self.email, password='',
231+ email=self.email, password='',
232 displayname='displayname', username=username,
233 require_password=False)
234
235@@ -325,7 +321,7 @@
236 @switches(USERNAME_UI=False)
237 def test_can_create_account_with_empty_pw_with_feature_flag_disabled(self):
238 account = registration.register(
239- self.sso_root_url, email=self.email, password='',
240+ email=self.email, password='',
241 displayname='displayname', require_password=False)
242
243 self.assert_correct_account_content(account)
244@@ -333,7 +329,7 @@
245 def test_password_required_by_default(self):
246 with self.assertRaises(ValidationError) as ctx:
247 registration.register(
248- self.sso_root_url, email=self.email, password=None,
249+ email=self.email, password=None,
250 displayname='displayname', username='validusername')
251
252 e = ctx.exception
253@@ -343,7 +339,7 @@
254 def test_form_validation_with_valid_pw_with_feature_flag_enabled(self):
255 with self.assertRaises(ValidationError) as ctx:
256 registration.register(
257- self.sso_root_url, email='bad.email', password='TheSecret1',
258+ email='bad.email', password='TheSecret1',
259 displayname=None, username='InvalidUsername')
260 e = ctx.exception
261 self.assertEqual(e.message_dict['displayname'], [FIELD_REQUIRED])
262@@ -356,7 +352,7 @@
263 def test_form_validation_with_valid_pw_with_feature_flag_disabled(self):
264 with self.assertRaises(ValidationError) as ctx:
265 registration.register(
266- self.sso_root_url, email='bad.email', password='TheSecret1',
267+ email='bad.email', password='TheSecret1',
268 displayname=None, username='InvalidUsername')
269
270 e = ctx.exception
271@@ -372,7 +368,7 @@
272 def test_form_validation_with_no_pw_and_with_feature_flag_enabled(self):
273 with self.assertRaises(ValidationError) as ctx:
274 registration.register(
275- self.sso_root_url, email='bad.email', password=None,
276+ email='bad.email', password=None,
277 displayname=None, username='InvalidUsername')
278
279 e = ctx.exception
280@@ -387,7 +383,7 @@
281 def test_form_validation_with_no_pw_and_feature_flag_disabled(self):
282 with self.assertRaises(ValidationError) as ctx:
283 registration.register(
284- self.sso_root_url, email='bad.email', password=None,
285+ email='bad.email', password=None,
286 displayname=None, username='InvalidUsername',
287 require_password=False)
288
289@@ -419,7 +415,7 @@
290 def test_invalid_email_and_no_pw_with_default_require_password(self):
291 with self.assertRaises(ValidationError) as ctx:
292 registration.register(
293- self.sso_root_url, email="", password=None,
294+ email="", password=None,
295 displayname='displayname', require_password=True)
296
297 e = ctx.exception
298@@ -428,9 +424,8 @@
299
300 def test_invalid_email_and_password_with_no_require_password(self):
301 with self.assertRaises(ValidationError) as ctx:
302- registration.register(
303- self.sso_root_url, email="", password=123,
304- displayname='displayname')
305+ registration.register(email="", password=123,
306+ displayname='displayname')
307
308 e = ctx.exception
309 self.assertEqual(e.message_dict['email'], [FIELD_REQUIRED])
310@@ -442,7 +437,7 @@
311 assert Account.objects.all().count() == 0
312
313 registration.register(
314- self.sso_root_url, self.email, 'SecretPassword1', 'displayname',
315+ self.email, 'SecretPassword1', 'displayname',
316 oid_token="fake_oid_token")
317
318 self.assertEqual(Account.objects.all().count(), 1)
319@@ -455,13 +450,13 @@
320 self.client.login(username=self.email, password='SecretPassword1'),
321 'Password was not properly set on new account.')
322 self.mock_send_new_user_email.assert_called_once_with(
323- root_url=self.sso_root_url, oid_token="fake_oid_token",
324+ oid_token="fake_oid_token",
325 account=account, email=self.email)
326 self.assertFalse(self.mock_send_impersonation_email.called)
327
328 def test_invalid_email_and_pw(self):
329 with self.assertRaises(ValidationError) as ctx:
330- registration.register(self.sso_root_url, "", '', 'displayname')
331+ registration.register("", '', 'displayname')
332
333 e = ctx.exception
334 self.assertEqual(e.message_dict['email'], [FIELD_REQUIRED])
335@@ -471,7 +466,7 @@
336 self.factory.make_leaked_credential(email='foo@example.com',
337 password=DEFAULT_USER_PASSWORD)
338 with self.assertRaises(PasswordPolicyError) as ctx:
339- registration.register(self.sso_root_url, 'foo@example.com',
340+ registration.register('foo@example.com',
341 DEFAULT_USER_PASSWORD, 'displayname')
342
343 self.assertIn('there was a security breach', str(ctx.exception))
344@@ -479,26 +474,26 @@
345
346 def test_email_not_validated(self):
347 account = registration.register(
348- self.sso_root_url, self.email, 'SecretPassword1', 'displayname',
349+ self.email, 'SecretPassword1', 'displayname',
350 email_validated=False)
351 self.assertFalse(account.is_verified)
352
353 def test_email_validated(self):
354 account = registration.register(
355- self.sso_root_url, self.email, 'SecretPassword1', 'displayname',
356+ self.email, 'SecretPassword1', 'displayname',
357 email_validated=True)
358 self.assertTrue(account.is_verified)
359
360 def test_creation_rationale_unset_source(self):
361 account = registration.register(
362- self.sso_root_url, self.email, 'SecretPassword1', 'displayname')
363+ self.email, 'SecretPassword1', 'displayname')
364 self.assertEqual(
365 account.creation_rationale, AccountCreationRationale.API_CREATED)
366 self.assertIsNone(account.creation_source)
367
368 def test_creation_rationale_set_source(self):
369 account = registration.register(
370- self.sso_root_url, self.email, 'SecretPassword1', 'displayname',
371+ self.email, 'SecretPassword1', 'displayname',
372 creation_source='foo bar baz')
373 self.assertEqual(
374 account.creation_rationale, AccountCreationRationale.API_CREATED)
375
376=== modified file 'src/identityprovider/emailutils.py'
377--- src/identityprovider/emailutils.py 2018-05-28 19:44:56 +0000
378+++ src/identityprovider/emailutils.py 2018-08-15 14:28:34 +0000
379@@ -96,7 +96,7 @@
380 return result
381
382
383-def _context_for_email_request(root_url, account, email, token_type,
384+def _context_for_email_request(account, email, token_type,
385 redirection_url, requester_email=None,
386 oid_token=None,
387 **kwargs):
388@@ -117,7 +117,7 @@
389 token_path = token.get_absolute_url()
390 if oid_token:
391 token_path = oid_token + token_path
392- token_url = urljoin(root_url, token_path)
393+ token_url = urljoin(settings.SSO_ROOT_URL, token_path)
394 context = {
395 'requester': name,
396 'requester_email': token.requester_email,
397@@ -136,15 +136,15 @@
398 email=email, token_type=AuthTokenType.INVALIDATEEMAIL,
399 redirection_url=redirection_url)
400 token_url = urljoin(
401- root_url, invalidate_email_token.get_absolute_url())
402+ settings.SSO_ROOT_URL, invalidate_email_token.get_absolute_url())
403 context['invalidate_email_url'] = token_url
404
405 return context, token, invalidate_email_token
406
407
408-def send_impersonation_email(root_url, email):
409+def send_impersonation_email(email):
410 """Send an email to user warning of attempted registration"""
411- url = urljoin(root_url, reverse('forgot_password'))
412+ url = urljoin(settings.SSO_ROOT_URL, reverse('forgot_password'))
413 context = {
414 'forgotten_password_url': url, 'to_email': email,
415 }
416@@ -152,7 +152,7 @@
417 _("Warning"), 'email/impersonate-warning.txt', context, email)
418
419
420-def send_new_user_email(root_url, account, email, redirection_url=None,
421+def send_new_user_email(account, email, redirection_url=None,
422 platform='all', oid_token=None):
423 """
424 Send an email to a new user.
425@@ -165,7 +165,7 @@
426 """
427
428 context, token, invalidate_email_token = _context_for_email_request(
429- root_url, account, email, AuthTokenType.VALIDATEEMAIL, redirection_url,
430+ account, email, AuthTokenType.VALIDATEEMAIL, redirection_url,
431 oid_token=oid_token)
432
433 if platform != 'desktop':
434@@ -194,7 +194,7 @@
435 return {'subject': subject, 'template': template}
436
437
438-def send_password_reset_email(root_url, account, email, redirection_url=None,
439+def send_password_reset_email(account, email, redirection_url=None,
440 reason='forgot_password'):
441 """
442 Send an email with password reset instructions.
443@@ -213,7 +213,7 @@
444 template = data['template']
445
446 context, token, invalidate_email_token = _context_for_email_request(
447- root_url, account, email, AuthTokenType.PASSWORDRECOVERY,
448+ account, email, AuthTokenType.PASSWORDRECOVERY,
449 redirection_url, requester_email=email)
450 send_fancy_email(subject, template, context, email)
451 return token, invalidate_email_token
452@@ -235,7 +235,7 @@
453 context=context, email=email.email)
454
455
456-def send_printed_codes_renewal_email(root_url, account, devices):
457+def send_printed_codes_renewal_email(account, devices):
458 email = account.preferredemail
459 if email is None:
460 logger.warning(
461@@ -246,7 +246,7 @@
462 device_urls = []
463 for device in devices:
464 device_urls.append(
465- urljoin(root_url,
466+ urljoin(settings.SSO_ROOT_URL,
467 reverse('device-print', kwargs=dict(device_id=device.id))))
468 context = dict(display_name=account.displayname, device_urls=device_urls)
469 send_fancy_email(
470@@ -255,7 +255,7 @@
471 context=context, email=email)
472
473
474-def send_validation_email_request(root_url, account, email,
475+def send_validation_email_request(account, email,
476 redirection_url=None, oid_token=None):
477 """
478 Send an email asking to validate the email account.
479@@ -272,7 +272,7 @@
480 preferredemail_email = account.preferredemail.email
481
482 context, token, invalidate_email_token = _context_for_email_request(
483- root_url, account, email, AuthTokenType.VALIDATEEMAIL, redirection_url,
484+ account, email, AuthTokenType.VALIDATEEMAIL, redirection_url,
485 requester_email=preferredemail_email, oid_token=oid_token)
486 send_fancy_email(
487 _("Validate your email address"), 'email/validate-email.txt',
488@@ -280,7 +280,7 @@
489 return token, invalidate_email_token
490
491
492-def send_invalidation_email_notice(root_url, account, invalidated_email):
493+def send_invalidation_email_notice(account, invalidated_email):
494 preferredemail = account.preferredemail
495 assert preferredemail is not None
496 email = preferredemail.email
497@@ -289,7 +289,7 @@
498 to_email=email,
499 )
500 if account.unverified_emails().count() > 0:
501- url = urljoin(root_url, reverse('account-emails'))
502+ url = urljoin(settings.SSO_ROOT_URL, reverse('account-emails'))
503 context['verify_emails_link'] = url
504 send_fancy_email(
505 _("The email address {email} was removed from your account").format(
506@@ -297,8 +297,7 @@
507 'email/email-invalidated.txt', context=context, email=email)
508
509
510-def send_notification_to_invalidated_email_address(root_url, account,
511- invalidated_email):
512+def send_notification_to_invalidated_email_address(account, invalidated_email):
513 context = dict(
514 display_name=account.displayname, invalidated_email=invalidated_email,
515 to_email=invalidated_email,
516@@ -319,15 +318,15 @@
517 {'new_preferred': new_preferred}, email)
518
519
520-def send_invitation_after_password_reset(root_url, email):
521- url = urljoin(root_url, reverse('new_account'))
522+def send_invitation_after_password_reset(email):
523+ url = urljoin(settings.SSO_ROOT_URL, reverse('new_account'))
524 send_fancy_email(
525 _("Password reset request"), 'email/invitation.txt',
526 {'email': email, 'signup': url}, email,
527 )
528
529
530-def send_action_required_warning(root_url, account, days_of_warning, action):
531+def send_action_required_warning(account, days_of_warning, action):
532 """
533 Send an email to warn the user that an action is required.
534
535@@ -343,10 +342,10 @@
536 assert preferredemail is not None
537 email = preferredemail.email
538 context, token, invalidate_email_token = _context_for_email_request(
539- root_url, account, email, AuthTokenType.VALIDATEEMAIL,
540+ account, email, AuthTokenType.VALIDATEEMAIL,
541 redirection_url=None)
542 context.update(dict(
543- emails_url=urljoin(root_url, reverse('account-emails')),
544+ emails_url=urljoin(settings.SSO_ROOT_URL, reverse('account-emails')),
545 created=account.date_created, action=action,
546 days_of_warning=days_of_warning,
547 ))
548
549=== modified file 'src/identityprovider/tests/test_emailutils.py'
550--- src/identityprovider/tests/test_emailutils.py 2018-05-28 19:44:56 +0000
551+++ src/identityprovider/tests/test_emailutils.py 2018-08-15 14:28:34 +0000
552@@ -321,7 +321,7 @@
553 self.assertNotIn(invalidate_msg, email.body)
554
555 def test_send_impersonation_email(self):
556- send_impersonation_email(self.sso_root_url, self.email)
557+ send_impersonation_email(self.email)
558
559 url = self.request.build_absolute_uri(
560 reverse('forgot_password'))
561@@ -338,7 +338,7 @@
562
563 def test_send_new_user_email_no_platform(self):
564 token, invalidate_token = send_new_user_email(
565- self.sso_root_url, self.account, self.email, self.redirection_url)
566+ self.account, self.email, self.redirection_url)
567
568 self.assert_tokens()
569 self.assert_email_properly_formatted(
570@@ -349,8 +349,7 @@
571 @patch('identityprovider.emailutils.logger')
572 def test_send_new_user_email_invalid_platform(self, mock_logger):
573 token, invalidate_token = send_new_user_email(
574- self.sso_root_url, self.account, self.email,
575- self.redirection_url, platform='foo')
576+ self.account, self.email, self.redirection_url, platform='foo')
577
578 self.assert_tokens()
579 self.assert_email_properly_formatted(
580@@ -360,8 +359,7 @@
581
582 def test_send_new_user_email_platform_desktop(self):
583 token, invalidate_token = send_new_user_email(
584- self.sso_root_url, self.account, self.email, self.redirection_url,
585- platform='desktop')
586+ self.account, self.email, self.redirection_url, platform='desktop')
587
588 self.assert_tokens()
589 self.assert_email_properly_formatted(
590@@ -372,8 +370,7 @@
591 def test_send_new_user_email_platform_mobile(self):
592 self.account = None
593 token, invalidate_token = send_new_user_email(
594- self.sso_root_url, self.account, self.email, self.redirection_url,
595- platform='mobile')
596+ self.account, self.email, self.redirection_url, platform='mobile')
597
598 self.assert_tokens()
599 self.assert_email_properly_formatted(
600@@ -384,7 +381,7 @@
601 def test_send_new_user_email_with_oid_token(self):
602 oid_token = "iama_oid_token"
603 token, invalidate_token = send_new_user_email(
604- self.sso_root_url, self.account, self.email, self.redirection_url,
605+ self.account, self.email, self.redirection_url,
606 oid_token=oid_token)
607
608 self.assert_tokens()
609@@ -396,7 +393,7 @@
610
611 def test_send_password_reset_email_with_redirection_url(self):
612 token, invalidate_token = send_password_reset_email(
613- self.sso_root_url, self.account, self.email, self.redirection_url)
614+ self.account, self.email, self.redirection_url)
615
616 self.assert_tokens(requester_email=self.email)
617 self.assert_email_properly_formatted(
618@@ -406,7 +403,7 @@
619
620 def test_send_password_reset_email_no_redirection_url(self):
621 token, invalidate_token = send_password_reset_email(
622- self.sso_root_url, self.account, self.email)
623+ self.account, self.email)
624
625 self.assert_tokens(requester_email=self.email, redirection_url=None)
626 self.assert_email_properly_formatted(
627@@ -416,8 +413,7 @@
628
629 def test_send_password_reset_email_with_custom_reason(self):
630 token, invalidate_token = send_password_reset_email(
631- self.sso_root_url, self.account, self.email,
632- reason='password_leak|adobe')
633+ self.account, self.email, reason='password_leak|adobe')
634
635 self.assert_tokens(requester_email=self.email, redirection_url=None)
636 token_type = AuthTokenType.PASSWORDRECOVERY
637@@ -433,8 +429,7 @@
638
639 def test_send_password_reset_email_with_generic_leak_template(self):
640 token, invalidate_token = send_password_reset_email(
641- self.sso_root_url, self.account, self.email,
642- reason='password_leak|foo')
643+ self.account, self.email, reason='password_leak|foo')
644
645 self.assert_tokens(requester_email=self.email, redirection_url=None)
646 token_type = AuthTokenType.PASSWORDRECOVERY
647@@ -449,15 +444,14 @@
648 context=context, token_type=token_type)
649
650 def test_send_password_reset_email_with_invalid_reason(self):
651- send_password_reset_email(self.sso_root_url, self.account, self.email,
652- reason='invalid')
653+ send_password_reset_email(self.account, self.email, reason='invalid')
654
655 self.assert_tokens(requester_email=self.email, redirection_url=None,
656 tokens_count=0)
657 self.assertEqual(len(mail.outbox), 0)
658
659 def test_leaked_password_reset_email_without_invalidation_link(self):
660- send_password_reset_email(self.sso_root_url, self.account, self.email,
661+ send_password_reset_email(self.account, self.email,
662 reason='password_leak|adobe')
663
664 self.assertEqual(len(mail.outbox), 1)
665@@ -469,7 +463,7 @@
666 assert self.account.preferredemail is not None
667
668 token, invalidate_token = send_validation_email_request(
669- self.sso_root_url, self.account, self.email, self.redirection_url)
670+ self.account, self.email, self.redirection_url)
671
672 email = self.account.preferredemail.email
673 self.assert_tokens(requester_email=email)
674@@ -484,7 +478,7 @@
675 assert self.account.preferredemail is None
676
677 token, invalidate_token = send_validation_email_request(
678- self.sso_root_url, self.account, self.email, self.redirection_url)
679+ self.account, self.email, self.redirection_url)
680
681 # two tokens are created, one for validation, and one for invalidation,
682 # since the email being validated is not in the system, so the real
683@@ -497,7 +491,7 @@
684
685 def test_send_validation_email_request_no_redirection_url(self):
686 token, invalidate_token = send_validation_email_request(
687- self.sso_root_url, self.account, self.email)
688+ self.account, self.email)
689
690 email = self.account.preferredemail.email
691 self.assert_tokens(requester_email=email, redirection_url=None)
692@@ -509,7 +503,7 @@
693 def test_send_validation_email_request_with_oid_token(self):
694 oid_token = 'a' * 16
695 token, invalidate_token = send_validation_email_request(
696- self.sso_root_url, self.account, self.email, self.redirection_url,
697+ self.account, self.email, self.redirection_url,
698 oid_token=oid_token)
699
700 email = self.account.preferredemail.email
701@@ -522,8 +516,7 @@
702
703 def _assert_send_invalidation_email_notice(self):
704 invalidated_email = 'invalid@example.com'
705- send_invalidation_email_notice(self.sso_root_url, self.account,
706- invalidated_email)
707+ send_invalidation_email_notice(self.account, invalidated_email)
708
709 verify_emails_link = self.request.build_absolute_uri(
710 reverse('account-emails'))
711@@ -561,8 +554,7 @@
712
713 def test_send_notification_to_invalidated_email_address(self):
714 invalidated_email = 'invalid@example.com'
715- send_notification_to_invalidated_email_address(self.sso_root_url,
716- self.account,
717+ send_notification_to_invalidated_email_address(self.account,
718 invalidated_email)
719 context = dict(
720 display_name=self.account.displayname,
721@@ -588,7 +580,7 @@
722
723 def test_send_invitation_after_password_reset(self):
724 url = self.request.build_absolute_uri(reverse('new_account'))
725- send_invitation_after_password_reset(self.sso_root_url, self.email)
726+ send_invitation_after_password_reset(self.email)
727
728 context = {
729 'email': self.email, 'signup': url,
730@@ -607,7 +599,7 @@
731 url = self.request.build_absolute_uri(reverse('account-emails'))
732
733 token, invalidate_token = send_action_required_warning(
734- self.sso_root_url, self.account, days_of_warning=8, action=action)
735+ self.account, days_of_warning=8, action=action)
736
737 # tokens will always be 2, since we need the validate email token *and*
738 # the invalidate email
739@@ -655,8 +647,7 @@
740 settings.TWOFACTOR_PAPER_CODES_WARN_RENEWAL + 1)
741 device = self.factory.make_device(
742 account=self.account, device_type='paper', counter=counter)
743- send_printed_codes_renewal_email(
744- self.sso_root_url, self.account, [device])
745+ send_printed_codes_renewal_email(self.account, [device])
746 url = self.request.build_absolute_uri(
747 reverse('device-print', kwargs=dict(device_id=device.id)))
748 context = dict(display_name=self.account.displayname,
749@@ -680,8 +671,7 @@
750 account=self.account, device_type='paper', counter=counter)
751 device2 = self.factory.make_device(
752 account=self.account, device_type='paper', counter=counter)
753- send_printed_codes_renewal_email(
754- self.sso_root_url, self.account, [device1, device2])
755+ send_printed_codes_renewal_email(self.account, [device1, device2])
756 url1 = self.request.build_absolute_uri(
757 reverse('device-print', kwargs=dict(device_id=device1.id)))
758 url2 = self.request.build_absolute_uri(
759@@ -712,8 +702,7 @@
760 device = self.factory.make_device(
761 account=self.account, device_type='paper', counter=counter)
762 with patch('identityprovider.emailutils.logger') as mock_logger:
763- send_printed_codes_renewal_email(
764- self.sso_root_url, self.account, [device])
765+ send_printed_codes_renewal_email(self.account, [device])
766 self.assertEqual(len(mail.outbox), 0)
767 mock_logger.warning.assert_called_once_with(
768 'Unable to find a suitable email address to send OTP reminder '
769
770=== modified file 'src/webui/views/account.py'
771--- src/webui/views/account.py 2018-05-28 20:15:33 +0000
772+++ src/webui/views/account.py 2018-08-15 14:28:34 +0000
773@@ -305,8 +305,7 @@
774
775 redirection_url = redirection_url_for_token(token)
776
777- root_url = request.build_absolute_uri('/')
778- send_validation_email_request(root_url, request.user, email,
779+ send_validation_email_request(request.user, email,
780 redirection_url, oid_token=token)
781 set_session_email(request.session, email)
782
783@@ -416,16 +415,13 @@
784 return response
785
786 # notify the account of the email invalidation, prioritize validated emails
787- root_url = request.build_absolute_uri('/')
788 if account.preferredemail is not None:
789 send_invalidation_email_notice(
790- root_url,
791 account,
792 invalidated_email=email.email,
793 )
794 else:
795 send_notification_to_invalidated_email_address(
796- root_url,
797 account,
798 invalidated_email=email.email,
799 )
800
801=== modified file 'src/webui/views/ui.py'
802--- src/webui/views/ui.py 2018-05-28 20:15:33 +0000
803+++ src/webui/views/ui.py 2018-08-15 14:28:34 +0000
804@@ -360,9 +360,8 @@
805 url += "?next=" + urlquote(next_url)
806 return HttpResponseRedirect(url)
807 elif paper_devices_needing_renewal:
808- root_url = request.build_absolute_uri('/')
809 send_printed_codes_renewal_email(
810- root_url, request.user, paper_devices_needing_renewal)
811+ request.user, paper_devices_needing_renewal)
812 if next_url and is_safe_redirect_url(next_url):
813 return HttpResponseRedirect(next_url)
814 elif token: