Merge lp:~maxiberta/canonical-identity-provider/drop-account-registration-captcha-api-v1 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/drop-account-registration-captcha-api-v1
Merge into: lp:canonical-identity-provider/release
Prerequisite: lp:~maxiberta/canonical-identity-provider/disable-user-registration-api
Diff against target: 341 lines (+19/-97)
6 files modified
src/api/templates/api/wadl1.0.xml (+2/-2)
src/api/templates/api/wadl1.1.xml (+2/-2)
src/api/v10/forms.py (+0/-23)
src/api/v10/handlers.py (+10/-22)
src/api/v10/tests/test_forms.py (+0/-24)
src/api/v10/tests/test_handlers.py (+5/-24)
To merge this branch: bzr merge lp:~maxiberta/canonical-identity-provider/drop-account-registration-captcha-api-v1
Reviewer Review Type Date Requested Status
Guillermo Gonzalez Approve
Review via email: mp+356876@code.launchpad.net

Commit message

Drop captcha from account registration API v1.x.

Description of the change

Account registration captcha has been disabled for a long time (years?). And the implementation depends on reCaptcha v1 which is dead since March 2018. So, let's just drop all captcha bits from there.

To post a comment you must log in.
Revision history for this message
Guillermo Gonzalez (verterok) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/api/templates/api/wadl1.0.xml'
--- src/api/templates/api/wadl1.0.xml 2017-06-12 16:00:39 +0000
+++ src/api/templates/api/wadl1.0.xml 2018-10-22 16:11:43 +0000
@@ -562,14 +562,14 @@
562 required="true" fixed="register">562 required="true" fixed="register">
563 <wadl:doc>The name of the operation being invoked.</wadl:doc>563 <wadl:doc>The name of the operation being invoked.</wadl:doc>
564 </wadl:param>564 </wadl:param>
565 <wadl:param style="query" required="true"565 <wadl:param style="query" required="false"
566 name="captcha_solution">566 name="captcha_solution">
567 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">567 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">
568Solution for the generated captcha.568Solution for the generated captcha.
569</wadl:doc>569</wadl:doc>
570 570
571 </wadl:param>571 </wadl:param>
572 <wadl:param style="query" required="true"572 <wadl:param style="query" required="false"
573 name="captcha_id">573 name="captcha_id">
574 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">574 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">
575ID for the generated captcha575ID for the generated captcha
576576
=== modified file 'src/api/templates/api/wadl1.1.xml'
--- src/api/templates/api/wadl1.1.xml 2017-06-12 16:00:39 +0000
+++ src/api/templates/api/wadl1.1.xml 2018-10-22 16:11:43 +0000
@@ -568,14 +568,14 @@
568 required="true" fixed="register">568 required="true" fixed="register">
569 <wadl:doc>The name of the operation being invoked.</wadl:doc>569 <wadl:doc>The name of the operation being invoked.</wadl:doc>
570 </wadl:param>570 </wadl:param>
571 <wadl:param style="query" required="true"571 <wadl:param style="query" required="false"
572 name="captcha_solution">572 name="captcha_solution">
573 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">573 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">
574Solution for the generated captcha.574Solution for the generated captcha.
575</wadl:doc>575</wadl:doc>
576 576
577 </wadl:param>577 </wadl:param>
578 <wadl:param style="query" required="true"578 <wadl:param style="query" required="false"
579 name="captcha_id">579 name="captcha_id">
580 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">580 <wadl:doc xmlns="http://www.w3.org/1999/xhtml">
581ID for the generated captcha581ID for the generated captcha
582582
=== modified file 'src/api/v10/forms.py'
--- src/api/v10/forms.py 2015-05-08 19:25:27 +0000
+++ src/api/v10/forms.py 2018-10-22 16:11:43 +0000
@@ -5,17 +5,12 @@
55
6from __future__ import unicode_literals6from __future__ import unicode_literals
77
8from django import forms
9from django.forms import fields8from django.forms import fields
10from django.utils.translation import ugettext_lazy as _
119
12from identityprovider.forms import NewAccountForm10from identityprovider.forms import NewAccountForm
13from identityprovider.models.captcha import Captcha
1411
1512
16class WebserviceCreateAccountForm(NewAccountForm):13class WebserviceCreateAccountForm(NewAccountForm):
17 captcha_id = fields.CharField(max_length=1024)
18 captcha_solution = fields.CharField(max_length=256)
19 remote_ip = fields.CharField(max_length=256)14 remote_ip = fields.CharField(max_length=256)
20 platform = fields.TypedChoiceField(choices=[15 platform = fields.TypedChoiceField(choices=[
21 ('web', 'Web'), ('desktop', 'Desktop'), ('mobile', 'Mobile')],16 ('web', 'Web'), ('desktop', 'Desktop'), ('mobile', 'Mobile')],
@@ -38,21 +33,3 @@
38 if not validate_redirect_to:33 if not validate_redirect_to:
39 validate_redirect_to = None34 validate_redirect_to = None
40 return validate_redirect_to35 return validate_redirect_to
41
42 def clean(self):
43 cleaned_data = super(WebserviceCreateAccountForm, self).clean()
44 captcha_id = cleaned_data.get('captcha_id')
45 captcha_solution = cleaned_data.get('captcha_solution')
46
47 # The remote IP address is absolutely required, and comes from
48 # SSO itself, not from the client. If it's missing, it's a
49 # programming error, and should not be returned to the client
50 # as a validation error. So, we use a normal key lookup here.
51 remote_ip = cleaned_data['remote_ip']
52
53 captcha = Captcha(captcha_id)
54 email = cleaned_data.get('email', '')
55 if captcha.verify(captcha_solution, remote_ip, email):
56 return cleaned_data
57 # not verified
58 raise forms.ValidationError(_("Wrong captcha solution."))
5936
=== modified file 'src/api/v10/handlers.py'
--- src/api/v10/handlers.py 2018-10-22 15:10:24 +0000
+++ src/api/v10/handlers.py 2018-10-22 16:11:43 +0000
@@ -36,9 +36,6 @@
36 EmailAddress,36 EmailAddress,
37 get_team_memberships_for_user,37 get_team_memberships_for_user,
38)38)
39from identityprovider.models.captcha import (
40 VerifyCaptchaError,
41)
42from identityprovider.models.const import AuthTokenType, EmailStatus39from identityprovider.models.const import AuthTokenType, EmailStatus
43from identityprovider.signals import (40from identityprovider.signals import (
44 account_created,41 account_created,
@@ -189,25 +186,16 @@
189 data = request.data186 data = request.data
190 data['remote_ip'] = request.environ['REMOTE_ADDR']187 data['remote_ip'] = request.environ['REMOTE_ADDR']
191 form = WebserviceCreateAccountForm(data)188 form = WebserviceCreateAccountForm(data)
192 try:189 if not form.is_valid():
193 if not form.is_valid():190 errors = dict((k, map(unicode, v))
194 errors = dict((k, map(unicode, v))191 for (k, v) in form.errors.items())
195 for (k, v) in form.errors.items())192 # XXX: cope with client trimming error messages
196 # XXX: cope with client trimming error messages193 if unicode(PASSWORD_LEAKED) in errors.get('password', ''):
197 if unicode(PASSWORD_LEAKED) in errors.get('password', ''):194 errors['password'] = unicode(_(
198 errors['password'] = unicode(_(195 'unsafe: leaked by security breach '
199 'unsafe: leaked by security breach '196 'on another website'))
200 'on another website'))197 result = {'status': 'error', 'errors': errors}
201 result = {'status': 'error', 'errors': errors}198 return result
202 return result
203 except VerifyCaptchaError:
204 logger.exception("reCaptcha connection error")
205 msg = unicode(
206 _('Unable to verify captcha. Please try again shortly.'))
207 return {
208 'status': 'error',
209 'errors': {'captcha_solution': [msg]}
210 }
211199
212 cleaned_data = form.cleaned_data200 cleaned_data = form.cleaned_data
213 requested_email = cleaned_data['email']201 requested_email = cleaned_data['email']
214202
=== modified file 'src/api/v10/tests/test_forms.py'
--- src/api/v10/tests/test_forms.py 2015-11-24 14:38:04 +0000
+++ src/api/v10/tests/test_forms.py 2018-10-22 16:11:43 +0000
@@ -5,23 +5,12 @@
55
6from __future__ import unicode_literals6from __future__ import unicode_literals
77
8from django.test.utils import override_settings
9
10from api.v10.forms import WebserviceCreateAccountForm8from api.v10.forms import WebserviceCreateAccountForm
11from identityprovider.tests.utils import SSOBaseTestCase9from identityprovider.tests.utils import SSOBaseTestCase
1210
1311
14@override_settings(CAPTCHA_PUBLIC_KEY='public', CAPTCHA_PRIVATE_KEY='private')
15class WebServiceCreateAccountFormTestCase(SSOBaseTestCase):12class WebServiceCreateAccountFormTestCase(SSOBaseTestCase):
1613
17 def setUp(self):
18 super(WebServiceCreateAccountFormTestCase, self).setUp()
19 # patch Captcha so it never hits the real network
20 self.mock_captcha_open = self.patch(
21 'identityprovider.models.captcha.Captcha._open')
22 self.mock_captcha_open.return_value.is_error = False
23 self.mock_captcha_open.return_value.data.return_value = 'true\nyey'
24
25 def test_nonascii_password(self):14 def test_nonascii_password(self):
26 data = {'password': 'Curuzú Cuatiá',15 data = {'password': 'Curuzú Cuatiá',
27 'remote_ip': '127.0.0.1'}16 'remote_ip': '127.0.0.1'}
@@ -46,19 +35,6 @@
46 self.assertTrue(form.is_valid())35 self.assertTrue(form.is_valid())
47 self.assertEqual(form.cleaned_data['platform'], 'desktop')36 self.assertEqual(form.cleaned_data['platform'], 'desktop')
4837
49 def test_captcha_checked_for_whitelist(self):
50 data = {
51 'email': 'canonicaltest@gmail.com',
52 'password': 'password1A',
53 'captcha_id': '1',
54 'captcha_solution': '2',
55 'remote_ip': '127.0.0.1',
56 }
57 pattern = '^canonicaltest(?:\+.+)?@gmail\.com$'
58 with self.settings(EMAIL_WHITELIST_REGEXP_LIST=[pattern]):
59 form = WebserviceCreateAccountForm(data)
60 self.assertTrue(form.is_valid())
61
62 def test_default_cleaned_validate_redirect_to(self):38 def test_default_cleaned_validate_redirect_to(self):
63 data = {39 data = {
64 'email': 'some@email.com',40 'email': 'some@email.com',
6541
=== modified file 'src/api/v10/tests/test_handlers.py'
--- src/api/v10/tests/test_handlers.py 2018-10-22 15:10:24 +0000
+++ src/api/v10/tests/test_handlers.py 2018-10-22 16:11:43 +0000
@@ -173,8 +173,7 @@
173 email_validated=False)173 email_validated=False)
174174
175 response = self.api.registrations.register(175 response = self.api.registrations.register(
176 email='register@example.com', password='blogdf3Daa',176 email='register@example.com', password='blogdf3Daa')
177 captcha_solution='solution', captcha_id='id')
178177
179 self.assertEqual(response['errors'],178 self.assertEqual(response['errors'],
180 {'email': ["Email already registered"]})179 {'email': ["Email already registered"]})
@@ -184,8 +183,7 @@
184 email = 'pepe@foo.com'183 email = 'pepe@foo.com'
185184
186 response = self.api.registrations.register(185 response = self.api.registrations.register(
187 email=email, password='MySecretPassword1',186 email=email, password='MySecretPassword1')
188 captcha_solution='foobar', captcha_id='id')
189 self.assertEqual(response['status'], 'ok')187 self.assertEqual(response['status'], 'ok')
190188
191 account = Account.objects.get_by_email(email)189 account = Account.objects.get_by_email(email)
@@ -208,8 +206,7 @@
208 self.factory.make_leaked_credential(email=email, password=password)206 self.factory.make_leaked_credential(email=email, password=password)
209207
210 response = self.api.registrations.register(208 response = self.api.registrations.register(
211 email=email, password=password,209 email=email, password=password)
212 captcha_solution='foobar', captcha_id='id')
213 self.assertEqual(response['status'], 'error')210 self.assertEqual(response['status'], 'error')
214 self.assertEqual(211 self.assertEqual(
215 response['errors'],212 response['errors'],
@@ -223,7 +220,6 @@
223220
224 response = self.api.registrations.register(221 response = self.api.registrations.register(
225 email=email, password='MySecretPassword1',222 email=email, password='MySecretPassword1',
226 captcha_solution='foobar', captcha_id='id',
227 displayname='Test User')223 displayname='Test User')
228 self.assertEqual(response['status'], 'ok')224 self.assertEqual(response['status'], 'ok')
229225
@@ -242,7 +238,6 @@
242238
243 response = self.api.registrations.register(239 response = self.api.registrations.register(
244 email=email, password='MySecretPassword1',240 email=email, password='MySecretPassword1',
245 captcha_solution='foobar', captcha_id='id',
246 displayname='Test User')241 displayname='Test User')
247242
248 self.assertEqual(response['status'], 'ok')243 self.assertEqual(response['status'], 'ok')
@@ -259,7 +254,6 @@
259 # password: 8 characters long (no uppercase or numbers, only lowercase)254 # password: 8 characters long (no uppercase or numbers, only lowercase)
260 response = self.api.registrations.register(255 response = self.api.registrations.register(
261 email=email, password='abcdefgh',256 email=email, password='abcdefgh',
262 captcha_solution='foobar', captcha_id='id',
263 displayname='Test User')257 displayname='Test User')
264 self.assertEqual(response['status'], 'ok')258 self.assertEqual(response['status'], 'ok')
265259
@@ -271,8 +265,7 @@
271 email = self.factory.make_email_address()265 email = self.factory.make_email_address()
272266
273 response = self.api.registrations.register(267 response = self.api.registrations.register(
274 email=email, password='MySecretPassword1',268 email=email, password='MySecretPassword1')
275 captcha_solution='foobar', captcha_id='id')
276 self.assertEqual(response['status'], 'ok')269 self.assertEqual(response['status'], 'ok')
277 self.assert_new_user_email_sent(email)270 self.assert_new_user_email_sent(email)
278271
@@ -281,7 +274,6 @@
281274
282 response = self.api.registrations.register(275 response = self.api.registrations.register(
283 email=email, password='MySecretPassword1',276 email=email, password='MySecretPassword1',
284 captcha_solution='foobar', captcha_id='id',
285 platform='mobile')277 platform='mobile')
286 self.assertEqual(response['status'], 'ok')278 self.assertEqual(response['status'], 'ok')
287 self.assert_new_user_email_sent(email, 'mobile')279 self.assert_new_user_email_sent(email, 'mobile')
@@ -291,7 +283,6 @@
291283
292 response = self.api.registrations.register(284 response = self.api.registrations.register(
293 email=email, password='MySecretPassword1',285 email=email, password='MySecretPassword1',
294 captcha_solution='foobar', captcha_id='id',
295 platform='foo')286 platform='foo')
296287
297 self.assertEqual(response['status'], 'error')288 self.assertEqual(response['status'], 'error')
@@ -303,7 +294,6 @@
303294
304 response = self.api.registrations.register(295 response = self.api.registrations.register(
305 email=email_address, password='MySecretPassword1',296 email=email_address, password='MySecretPassword1',
306 captcha_solution='foobar', captcha_id='id',
307 platform='desktop')297 platform='desktop')
308298
309 self.assertEqual(response['status'], 'ok')299 self.assertEqual(response['status'], 'ok')
@@ -314,7 +304,6 @@
314304
315 response = self.api.registrations.register(305 response = self.api.registrations.register(
316 email=email_address, password='MySecretPassword1',306 email=email_address, password='MySecretPassword1',
317 captcha_solution='foobar', captcha_id='id',
318 platform='desktop', validate_redirect_to='http://foo')307 platform='desktop', validate_redirect_to='http://foo')
319308
320 self.assertEqual(response['status'], 'ok')309 self.assertEqual(response['status'], 'ok')
@@ -327,7 +316,6 @@
327316
328 response = self.api.registrations.register(317 response = self.api.registrations.register(
329 email=email_address, password='MySecretPassword1',318 email=email_address, password='MySecretPassword1',
330 captcha_solution='foobar', captcha_id='id',
331 platform='mobile', validate_redirect_to='http://foo')319 platform='mobile', validate_redirect_to='http://foo')
332320
333 self.assertEqual(response['status'], 'ok')321 self.assertEqual(response['status'], 'ok')
@@ -341,7 +329,6 @@
341329
342 response = self.api.registrations.register(330 response = self.api.registrations.register(
343 email=email_address, password='MySecretPassword1',331 email=email_address, password='MySecretPassword1',
344 captcha_solution='foobar', captcha_id='id',
345 platform='mobile')332 platform='mobile')
346333
347 self.assertEqual(response['status'], 'ok')334 self.assertEqual(response['status'], 'ok')
@@ -385,9 +372,7 @@
385 self.url,372 self.url,
386 {'ws.op': 'register',373 {'ws.op': 'register',
387 'email': email_address,374 'email': email_address,
388 'password': 'MySecretPassword1',375 'password': 'MySecretPassword1'})
389 'captcha_solution': 'foobar',
390 'captcha_id': 'id'})
391376
392 @switches(USER_REGISTRATION_API_ENABLED=False)377 @switches(USER_REGISTRATION_API_ENABLED=False)
393 def test_feature_flag_disabled_with_internal_client(self):378 def test_feature_flag_disabled_with_internal_client(self):
@@ -396,7 +381,6 @@
396 data = {381 data = {
397 'ws.op': 'register', 'displayname': 'Test User', 'email': email,382 'ws.op': 'register', 'displayname': 'Test User', 'email': email,
398 'password': 'MySecretPassword1',383 'password': 'MySecretPassword1',
399 'captcha_solution': 'foobar', 'captcha_id': 'id',
400 }384 }
401385
402 response = self.client.get(self.url, data)386 response = self.client.get(self.url, data)
@@ -413,7 +397,6 @@
413 data = {397 data = {
414 'ws.op': 'register', 'displayname': 'Test User', 'email': email,398 'ws.op': 'register', 'displayname': 'Test User', 'email': email,
415 'password': 'MySecretPassword1',399 'password': 'MySecretPassword1',
416 'captcha_solution': 'foobar', 'captcha_id': 'id',
417 }400 }
418 headers = {'HTTP_X_FORWARDED_FOR': '127.0.0.1'}401 headers = {'HTTP_X_FORWARDED_FOR': '127.0.0.1'}
419402
@@ -429,7 +412,6 @@
429 data = {412 data = {
430 'ws.op': 'register', 'displayname': 'Test User', 'email': email,413 'ws.op': 'register', 'displayname': 'Test User', 'email': email,
431 'password': 'MySecretPassword1',414 'password': 'MySecretPassword1',
432 'captcha_solution': 'foobar', 'captcha_id': 'id',
433 }415 }
434416
435 response = self.client.get(self.url, data)417 response = self.client.get(self.url, data)
@@ -446,7 +428,6 @@
446 data = {428 data = {
447 'ws.op': 'register', 'displayname': 'Test User', 'email': email,429 'ws.op': 'register', 'displayname': 'Test User', 'email': email,
448 'password': 'MySecretPassword1',430 'password': 'MySecretPassword1',
449 'captcha_solution': 'foobar', 'captcha_id': 'id',
450 }431 }
451 headers = {'HTTP_X_FORWARDED_FOR': '127.0.0.1'}432 headers = {'HTTP_X_FORWARDED_FOR': '127.0.0.1'}
452433