Merge lp:~maxiberta/canonical-identity-provider/revert-r1653 into lp:canonical-identity-provider/release
- revert-r1653
- Merge into trunk
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/revert-r1653 | ||||||||
Merge into: | lp:canonical-identity-provider/release | ||||||||
Diff against target: |
814 lines (+112/-87) 11 files modified
django_project/settings_test.py (+0/-2) src/api/v10/handlers.py (+2/-1) src/api/v10/tests/utils.py (+1/-2) src/api/v20/handlers.py (+7/-4) src/api/v20/registration.py (+3/-3) src/api/v20/tests/test_handlers.py (+5/-3) src/api/v20/tests/test_registration.py (+31/-26) src/identityprovider/emailutils.py (+22/-21) src/identityprovider/tests/test_emailutils.py (+34/-23) src/webui/views/account.py (+5/-1) src/webui/views/ui.py (+2/-1) |
||||||||
To merge this branch: | bzr merge lp:~maxiberta/canonical-identity-provider/revert-r1653 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Celso Providelo (community) | Approve | ||
Review via email: mp+353345@code.launchpad.net |
Commit message
Revert using settings.
Description of the change
r1653 broke emails from login.launchpad.net by using settings.
Revert procedure:
# Make sure we're on trunk r1653
$ bzr revno
1653
# Revert
$ bzr revert -r1652
M django_
M po/api/api.pot
M po/identityprov
M po/ubuntu_
M po/webui/webui.pot
M src/api/
M src/api/
M src/api/
M src/api/
M src/api/
M src/api/
M src/identitypro
M src/identitypro
M src/webui/
M src/webui/
# Ignore changes in po/
$ bzr revert po
M po/api/api.pot
M po/identityprov
M po/ubuntu_
M po/webui/webui.pot
$ bzr commit
Celso Providelo (cprov) : | # |
Preview Diff
1 | === modified file 'django_project/settings_test.py' |
2 | --- django_project/settings_test.py 2018-08-14 21:03:03 +0000 |
3 | +++ django_project/settings_test.py 2018-08-17 18:50:19 +0000 |
4 | @@ -2,8 +2,6 @@ |
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-08-14 20:27:59 +0000 |
16 | +++ src/api/v10/handlers.py 2018-08-17 18:50:19 +0000 |
17 | @@ -224,8 +224,9 @@ |
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 | - account=account, email=email, |
24 | + root_url, 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-08-14 20:27:59 +0000 |
31 | +++ src/api/v10/tests/utils.py 2018-08-17 18:50:19 +0000 |
32 | @@ -40,8 +40,7 @@ |
33 | self.addCleanup(urllib_intercept.uninstall_opener) |
34 | httplib2_intercept.install() |
35 | self.addCleanup(httplib2_intercept.uninstall) |
36 | - # This should intercept requests to http://testserver on port 80. |
37 | - add_wsgi_intercept(parse.hostname, parse.port or 80, WSGIHandler) |
38 | + add_wsgi_intercept(parse.hostname, parse.port, 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-08-14 20:27:59 +0000 |
45 | +++ src/api/v20/handlers.py 2018-08-17 18:50:19 +0000 |
46 | @@ -215,7 +215,8 @@ |
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 | - emailutils.send_invitation_after_password_reset(email) |
51 | + root_url = request.build_absolute_uri('/') |
52 | + emailutils.send_invitation_after_password_reset(root_url, email) |
53 | |
54 | if invalidated_email.exists(): |
55 | # there is no account with this email |
56 | @@ -263,8 +264,9 @@ |
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 | - account, email, redirection_url) |
63 | + root_url, account, email, redirection_url) |
64 | |
65 | # return response |
66 | data = dict(email=auth_token.email) |
67 | @@ -333,7 +335,7 @@ |
68 | root_url = request.build_absolute_uri('/') |
69 | try: |
70 | account = registration.register( |
71 | - email, password, displayname, username=username, |
72 | + root_url, email, password, displayname, username=username, |
73 | creation_source=data.get('creation_source'), |
74 | oid_token=data.get('oid_token') |
75 | ) |
76 | @@ -376,9 +378,10 @@ |
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 | - email, password=None, displayname=displayname, |
84 | + root_url, 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-08-14 20:27:59 +0000 |
91 | +++ src/api/v20/registration.py 2018-08-17 18:50:19 +0000 |
92 | @@ -29,7 +29,7 @@ |
93 | |
94 | |
95 | def register( |
96 | - email, password, displayname, username=None, |
97 | + root_url, 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(other_email.email) |
106 | + send_impersonation_email(root_url, 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(account=account, email=email, |
115 | + send_new_user_email(root_url=root_url, 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-08-14 20:27:59 +0000 |
122 | +++ src/api/v20/tests/test_handlers.py 2018-08-17 18:50:19 +0000 |
123 | @@ -1767,7 +1767,8 @@ |
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('invalid@foo.com') |
128 | + mock_send_invitation.assert_called_once_with( |
129 | + self.sso_root_url, 'invalid@foo.com') |
130 | |
131 | def test_suspended_account(self): |
132 | self.account.suspend() |
133 | @@ -1909,7 +1910,8 @@ |
134 | content = self.do_post( |
135 | {'email': invalidated_email.email}, status_code=403) |
136 | |
137 | - mock_send_invitation.assert_called_once_with(self.email.email) |
138 | + mock_send_invitation.assert_called_once_with(self.sso_root_url, |
139 | + self.email.email) |
140 | expected = { |
141 | 'message': ('This email address has been invalidated. ' |
142 | 'Please contact login support.'), |
143 | @@ -1928,7 +1930,7 @@ |
144 | {'email': self.email.email, 'token': token}, status_code=201) |
145 | |
146 | mock_send_password_reset_email.assert_called_once_with( |
147 | - self.account, self.email.email, redirection_url) |
148 | + self.sso_root_url, 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-08-14 20:27:59 +0000 |
155 | +++ src/api/v20/tests/test_registration.py 2018-08-17 18:50:19 +0000 |
156 | @@ -38,7 +38,7 @@ |
157 | super(RegistrationTestCase, self).setUp() |
158 | self.email = self.factory.make_email_address() |
159 | self.data = [ |
160 | - self.email, 'SecretPassword1', 'displayname'] |
161 | + self.sso_root_url, self.email, 'SecretPassword1', 'displayname'] |
162 | |
163 | self.mock_send_impersonation_email = self.patch( |
164 | 'api.v20.registration.send_impersonation_email') |
165 | @@ -60,7 +60,8 @@ |
166 | if password is not None: |
167 | account.user.check_password(password) |
168 | self.mock_send_new_user_email.assert_called_once_with( |
169 | - account=account, email=self.email, oid_token=None) |
170 | + root_url=self.sso_root_url, account=account, email=self.email, |
171 | + oid_token=None) |
172 | self.assertFalse(self.mock_send_impersonation_email.called) |
173 | |
174 | def test_register_already_registered_and_inactive(self): |
175 | @@ -70,7 +71,8 @@ |
176 | |
177 | with self.assertRaises(registration.EmailAlreadyRegistered): |
178 | registration.register( |
179 | - email=self.email, password="", displayname="") |
180 | + self.sso_root_url, email=self.email, password="", |
181 | + displayname="") |
182 | |
183 | self.assertFalse(self.mock_send_impersonation_email.called) |
184 | self.assertFalse(self.mock_send_new_user_email.called) |
185 | @@ -81,9 +83,11 @@ |
186 | |
187 | with self.assertRaises(registration.EmailAlreadyRegistered): |
188 | registration.register( |
189 | - email=self.email, password="", displayname="") |
190 | + self.sso_root_url, email=self.email, password="", |
191 | + displayname="") |
192 | |
193 | - self.mock_send_impersonation_email.assert_called_once_with(self.email) |
194 | + self.mock_send_impersonation_email.assert_called_once_with( |
195 | + self.sso_root_url, self.email) |
196 | self.assertFalse(self.mock_send_new_user_email.called) |
197 | |
198 | def test_register_success(self): |
199 | @@ -265,7 +269,7 @@ |
200 | username = 'InvalidUsername' |
201 | with self.assertRaises(ValidationError) as ctx: |
202 | registration.register( |
203 | - email=self.email, password=None, |
204 | + self.sso_root_url, email=self.email, password=None, |
205 | displayname='displayname', username=username) |
206 | e = ctx.exception |
207 | self.assertEqual(e.message_dict['username'], [INVALID_NAME]) |
208 | @@ -285,7 +289,7 @@ |
209 | return_value=fake_lp_response) |
210 | |
211 | account = registration.register( |
212 | - email=self.email, password=None, |
213 | + self.sso_root_url, email=self.email, password=None, |
214 | displayname='displayname', username=username, |
215 | require_password=False) |
216 | |
217 | @@ -294,7 +298,7 @@ |
218 | @switches(USERNAME_UI=False) |
219 | def test_can_create_account_without_pw_with_feature_flag_disabled(self): |
220 | account = registration.register( |
221 | - email=self.email, password=None, |
222 | + self.sso_root_url, email=self.email, password=None, |
223 | displayname='displayname', username='validusername', |
224 | require_password=False) |
225 | |
226 | @@ -312,7 +316,7 @@ |
227 | return_value=fake_lp_response) |
228 | |
229 | account = registration.register( |
230 | - email=self.email, password='', |
231 | + self.sso_root_url, email=self.email, password='', |
232 | displayname='displayname', username=username, |
233 | require_password=False) |
234 | |
235 | @@ -321,7 +325,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 | - email=self.email, password='', |
240 | + self.sso_root_url, email=self.email, password='', |
241 | displayname='displayname', require_password=False) |
242 | |
243 | self.assert_correct_account_content(account) |
244 | @@ -329,7 +333,7 @@ |
245 | def test_password_required_by_default(self): |
246 | with self.assertRaises(ValidationError) as ctx: |
247 | registration.register( |
248 | - email=self.email, password=None, |
249 | + self.sso_root_url, email=self.email, password=None, |
250 | displayname='displayname', username='validusername') |
251 | |
252 | e = ctx.exception |
253 | @@ -339,7 +343,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 | - email='bad.email', password='TheSecret1', |
258 | + self.sso_root_url, email='bad.email', password='TheSecret1', |
259 | displayname=None, username='InvalidUsername') |
260 | e = ctx.exception |
261 | self.assertEqual(e.message_dict['displayname'], [FIELD_REQUIRED]) |
262 | @@ -352,7 +356,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 | - email='bad.email', password='TheSecret1', |
267 | + self.sso_root_url, email='bad.email', password='TheSecret1', |
268 | displayname=None, username='InvalidUsername') |
269 | |
270 | e = ctx.exception |
271 | @@ -368,7 +372,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 | - email='bad.email', password=None, |
276 | + self.sso_root_url, email='bad.email', password=None, |
277 | displayname=None, username='InvalidUsername') |
278 | |
279 | e = ctx.exception |
280 | @@ -383,7 +387,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 | - email='bad.email', password=None, |
285 | + self.sso_root_url, email='bad.email', password=None, |
286 | displayname=None, username='InvalidUsername', |
287 | require_password=False) |
288 | |
289 | @@ -415,7 +419,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 | - email="", password=None, |
294 | + self.sso_root_url, email="", password=None, |
295 | displayname='displayname', require_password=True) |
296 | |
297 | e = ctx.exception |
298 | @@ -424,8 +428,9 @@ |
299 | |
300 | def test_invalid_email_and_password_with_no_require_password(self): |
301 | with self.assertRaises(ValidationError) as ctx: |
302 | - registration.register(email="", password=123, |
303 | - displayname='displayname') |
304 | + registration.register( |
305 | + self.sso_root_url, email="", password=123, |
306 | + displayname='displayname') |
307 | |
308 | e = ctx.exception |
309 | self.assertEqual(e.message_dict['email'], [FIELD_REQUIRED]) |
310 | @@ -437,7 +442,7 @@ |
311 | assert Account.objects.all().count() == 0 |
312 | |
313 | registration.register( |
314 | - self.email, 'SecretPassword1', 'displayname', |
315 | + self.sso_root_url, self.email, 'SecretPassword1', 'displayname', |
316 | oid_token="fake_oid_token") |
317 | |
318 | self.assertEqual(Account.objects.all().count(), 1) |
319 | @@ -450,13 +455,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 | - oid_token="fake_oid_token", |
324 | + root_url=self.sso_root_url, 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("", '', 'displayname') |
331 | + registration.register(self.sso_root_url, "", '', 'displayname') |
332 | |
333 | e = ctx.exception |
334 | self.assertEqual(e.message_dict['email'], [FIELD_REQUIRED]) |
335 | @@ -466,7 +471,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('foo@example.com', |
340 | + registration.register(self.sso_root_url, 'foo@example.com', |
341 | DEFAULT_USER_PASSWORD, 'displayname') |
342 | |
343 | self.assertIn('there was a security breach', str(ctx.exception)) |
344 | @@ -474,26 +479,26 @@ |
345 | |
346 | def test_email_not_validated(self): |
347 | account = registration.register( |
348 | - self.email, 'SecretPassword1', 'displayname', |
349 | + self.sso_root_url, 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.email, 'SecretPassword1', 'displayname', |
356 | + self.sso_root_url, 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.email, 'SecretPassword1', 'displayname') |
363 | + self.sso_root_url, 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.email, 'SecretPassword1', 'displayname', |
371 | + self.sso_root_url, 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-08-14 20:27:59 +0000 |
378 | +++ src/identityprovider/emailutils.py 2018-08-17 18:50:19 +0000 |
379 | @@ -96,7 +96,7 @@ |
380 | return result |
381 | |
382 | |
383 | -def _context_for_email_request(account, email, token_type, |
384 | +def _context_for_email_request(root_url, 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(settings.SSO_ROOT_URL, token_path) |
393 | + token_url = urljoin(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 | - settings.SSO_ROOT_URL, invalidate_email_token.get_absolute_url()) |
402 | + 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(email): |
409 | +def send_impersonation_email(root_url, email): |
410 | """Send an email to user warning of attempted registration""" |
411 | - url = urljoin(settings.SSO_ROOT_URL, reverse('forgot_password')) |
412 | + url = urljoin(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(account, email, redirection_url=None, |
421 | +def send_new_user_email(root_url, 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 | - account, email, AuthTokenType.VALIDATEEMAIL, redirection_url, |
430 | + root_url, 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(account, email, redirection_url=None, |
439 | +def send_password_reset_email(root_url, 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 | - account, email, AuthTokenType.PASSWORDRECOVERY, |
448 | + root_url, 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(account, devices): |
457 | +def send_printed_codes_renewal_email(root_url, 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(settings.SSO_ROOT_URL, |
466 | + urljoin(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(account, email, |
475 | +def send_validation_email_request(root_url, 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 | - account, email, AuthTokenType.VALIDATEEMAIL, redirection_url, |
484 | + root_url, 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(account, invalidated_email): |
493 | +def send_invalidation_email_notice(root_url, 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(settings.SSO_ROOT_URL, reverse('account-emails')) |
502 | + url = urljoin(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,7 +297,8 @@ |
507 | 'email/email-invalidated.txt', context=context, email=email) |
508 | |
509 | |
510 | -def send_notification_to_invalidated_email_address(account, invalidated_email): |
511 | +def send_notification_to_invalidated_email_address(root_url, account, |
512 | + invalidated_email): |
513 | context = dict( |
514 | display_name=account.displayname, invalidated_email=invalidated_email, |
515 | to_email=invalidated_email, |
516 | @@ -318,15 +319,15 @@ |
517 | {'new_preferred': new_preferred}, email) |
518 | |
519 | |
520 | -def send_invitation_after_password_reset(email): |
521 | - url = urljoin(settings.SSO_ROOT_URL, reverse('new_account')) |
522 | +def send_invitation_after_password_reset(root_url, email): |
523 | + url = urljoin(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(account, days_of_warning, action): |
531 | +def send_action_required_warning(root_url, account, days_of_warning, action): |
532 | """ |
533 | Send an email to warn the user that an action is required. |
534 | |
535 | @@ -342,10 +343,10 @@ |
536 | assert preferredemail is not None |
537 | email = preferredemail.email |
538 | context, token, invalidate_email_token = _context_for_email_request( |
539 | - account, email, AuthTokenType.VALIDATEEMAIL, |
540 | + root_url, account, email, AuthTokenType.VALIDATEEMAIL, |
541 | redirection_url=None) |
542 | context.update(dict( |
543 | - emails_url=urljoin(settings.SSO_ROOT_URL, reverse('account-emails')), |
544 | + emails_url=urljoin(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-08-14 20:27:59 +0000 |
551 | +++ src/identityprovider/tests/test_emailutils.py 2018-08-17 18:50:19 +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.email) |
557 | + send_impersonation_email(self.sso_root_url, 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.account, self.email, self.redirection_url) |
566 | + self.sso_root_url, self.account, self.email, self.redirection_url) |
567 | |
568 | self.assert_tokens() |
569 | self.assert_email_properly_formatted( |
570 | @@ -349,7 +349,8 @@ |
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.account, self.email, self.redirection_url, platform='foo') |
575 | + self.sso_root_url, self.account, self.email, |
576 | + self.redirection_url, platform='foo') |
577 | |
578 | self.assert_tokens() |
579 | self.assert_email_properly_formatted( |
580 | @@ -359,7 +360,8 @@ |
581 | |
582 | def test_send_new_user_email_platform_desktop(self): |
583 | token, invalidate_token = send_new_user_email( |
584 | - self.account, self.email, self.redirection_url, platform='desktop') |
585 | + self.sso_root_url, self.account, self.email, self.redirection_url, |
586 | + platform='desktop') |
587 | |
588 | self.assert_tokens() |
589 | self.assert_email_properly_formatted( |
590 | @@ -370,7 +372,8 @@ |
591 | def test_send_new_user_email_platform_mobile(self): |
592 | self.account = None |
593 | token, invalidate_token = send_new_user_email( |
594 | - self.account, self.email, self.redirection_url, platform='mobile') |
595 | + self.sso_root_url, self.account, self.email, self.redirection_url, |
596 | + platform='mobile') |
597 | |
598 | self.assert_tokens() |
599 | self.assert_email_properly_formatted( |
600 | @@ -381,7 +384,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.account, self.email, self.redirection_url, |
605 | + self.sso_root_url, self.account, self.email, self.redirection_url, |
606 | oid_token=oid_token) |
607 | |
608 | self.assert_tokens() |
609 | @@ -393,7 +396,7 @@ |
610 | |
611 | def test_send_password_reset_email_with_redirection_url(self): |
612 | token, invalidate_token = send_password_reset_email( |
613 | - self.account, self.email, self.redirection_url) |
614 | + self.sso_root_url, self.account, self.email, self.redirection_url) |
615 | |
616 | self.assert_tokens(requester_email=self.email) |
617 | self.assert_email_properly_formatted( |
618 | @@ -403,7 +406,7 @@ |
619 | |
620 | def test_send_password_reset_email_no_redirection_url(self): |
621 | token, invalidate_token = send_password_reset_email( |
622 | - self.account, self.email) |
623 | + self.sso_root_url, self.account, self.email) |
624 | |
625 | self.assert_tokens(requester_email=self.email, redirection_url=None) |
626 | self.assert_email_properly_formatted( |
627 | @@ -413,7 +416,8 @@ |
628 | |
629 | def test_send_password_reset_email_with_custom_reason(self): |
630 | token, invalidate_token = send_password_reset_email( |
631 | - self.account, self.email, reason='password_leak|adobe') |
632 | + self.sso_root_url, self.account, self.email, |
633 | + reason='password_leak|adobe') |
634 | |
635 | self.assert_tokens(requester_email=self.email, redirection_url=None) |
636 | token_type = AuthTokenType.PASSWORDRECOVERY |
637 | @@ -429,7 +433,8 @@ |
638 | |
639 | def test_send_password_reset_email_with_generic_leak_template(self): |
640 | token, invalidate_token = send_password_reset_email( |
641 | - self.account, self.email, reason='password_leak|foo') |
642 | + self.sso_root_url, self.account, self.email, |
643 | + reason='password_leak|foo') |
644 | |
645 | self.assert_tokens(requester_email=self.email, redirection_url=None) |
646 | token_type = AuthTokenType.PASSWORDRECOVERY |
647 | @@ -444,14 +449,15 @@ |
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.account, self.email, reason='invalid') |
652 | + send_password_reset_email(self.sso_root_url, self.account, self.email, |
653 | + 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.account, self.email, |
661 | + send_password_reset_email(self.sso_root_url, self.account, self.email, |
662 | reason='password_leak|adobe') |
663 | |
664 | self.assertEqual(len(mail.outbox), 1) |
665 | @@ -463,7 +469,7 @@ |
666 | assert self.account.preferredemail is not None |
667 | |
668 | token, invalidate_token = send_validation_email_request( |
669 | - self.account, self.email, self.redirection_url) |
670 | + self.sso_root_url, self.account, self.email, self.redirection_url) |
671 | |
672 | email = self.account.preferredemail.email |
673 | self.assert_tokens(requester_email=email) |
674 | @@ -478,7 +484,7 @@ |
675 | assert self.account.preferredemail is None |
676 | |
677 | token, invalidate_token = send_validation_email_request( |
678 | - self.account, self.email, self.redirection_url) |
679 | + self.sso_root_url, 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 | @@ -491,7 +497,7 @@ |
684 | |
685 | def test_send_validation_email_request_no_redirection_url(self): |
686 | token, invalidate_token = send_validation_email_request( |
687 | - self.account, self.email) |
688 | + self.sso_root_url, self.account, self.email) |
689 | |
690 | email = self.account.preferredemail.email |
691 | self.assert_tokens(requester_email=email, redirection_url=None) |
692 | @@ -503,7 +509,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.account, self.email, self.redirection_url, |
697 | + self.sso_root_url, self.account, self.email, self.redirection_url, |
698 | oid_token=oid_token) |
699 | |
700 | email = self.account.preferredemail.email |
701 | @@ -516,7 +522,8 @@ |
702 | |
703 | def _assert_send_invalidation_email_notice(self): |
704 | invalidated_email = 'invalid@example.com' |
705 | - send_invalidation_email_notice(self.account, invalidated_email) |
706 | + send_invalidation_email_notice(self.sso_root_url, self.account, |
707 | + invalidated_email) |
708 | |
709 | verify_emails_link = self.request.build_absolute_uri( |
710 | reverse('account-emails')) |
711 | @@ -554,7 +561,8 @@ |
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.account, |
716 | + send_notification_to_invalidated_email_address(self.sso_root_url, |
717 | + self.account, |
718 | invalidated_email) |
719 | context = dict( |
720 | display_name=self.account.displayname, |
721 | @@ -580,7 +588,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.email) |
726 | + send_invitation_after_password_reset(self.sso_root_url, self.email) |
727 | |
728 | context = { |
729 | 'email': self.email, 'signup': url, |
730 | @@ -599,7 +607,7 @@ |
731 | url = self.request.build_absolute_uri(reverse('account-emails')) |
732 | |
733 | token, invalidate_token = send_action_required_warning( |
734 | - self.account, days_of_warning=8, action=action) |
735 | + self.sso_root_url, 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 | @@ -647,7 +655,8 @@ |
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(self.account, [device]) |
744 | + send_printed_codes_renewal_email( |
745 | + self.sso_root_url, 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 | @@ -671,7 +680,8 @@ |
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(self.account, [device1, device2]) |
754 | + send_printed_codes_renewal_email( |
755 | + self.sso_root_url, 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 | @@ -702,7 +712,8 @@ |
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(self.account, [device]) |
764 | + send_printed_codes_renewal_email( |
765 | + self.sso_root_url, 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-08-14 20:27:59 +0000 |
772 | +++ src/webui/views/account.py 2018-08-17 18:50:19 +0000 |
773 | @@ -305,7 +305,8 @@ |
774 | |
775 | redirection_url = redirection_url_for_token(token) |
776 | |
777 | - send_validation_email_request(request.user, email, |
778 | + root_url = request.build_absolute_uri('/') |
779 | + send_validation_email_request(root_url, request.user, email, |
780 | redirection_url, oid_token=token) |
781 | set_session_email(request.session, email) |
782 | |
783 | @@ -415,13 +416,16 @@ |
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-08-14 20:27:59 +0000 |
803 | +++ src/webui/views/ui.py 2018-08-17 18:50:19 +0000 |
804 | @@ -360,8 +360,9 @@ |
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 | - request.user, paper_devices_needing_renewal) |
811 | + root_url, 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: |