Merge lp:~maxiberta/canonical-identity-provider/drop-account-registration-captcha into lp:canonical-identity-provider/release
- drop-account-registration-captcha
- Merge into trunk
Proposed by
Maximiliano Bertacchini
Status: | Superseded |
---|---|
Proposed branch: | lp:~maxiberta/canonical-identity-provider/drop-account-registration-captcha |
Merge into: | lp:canonical-identity-provider/release |
Diff against target: |
1062 lines (+114/-562) 16 files modified
django_project/settings_base.py (+1/-1) django_project/settings_devel.py (+0/-1) src/api/v10/forms.py (+0/-23) src/api/v10/handlers.py (+18/-21) src/api/v10/tests/test_forms.py (+0/-24) src/api/v10/tests/test_handlers.py (+56/-0) src/api/v20/handlers.py (+5/-42) src/api/v20/tests/test_handlers.py (+27/-192) src/api/v20/utils.py (+5/-0) src/webui/templates/registration/_create_account_form.html (+0/-11) src/webui/templates/widgets/recaptcha.html (+0/-43) src/webui/tests/test_views_registration.py (+0/-51) src/webui/tests/test_views_ui.py (+1/-85) src/webui/views/registration.py (+0/-26) src/webui/views/ui.py (+1/-35) src/webui/views/utils.py (+0/-7) |
To merge this branch: | bzr merge lp:~maxiberta/canonical-identity-provider/drop-account-registration-captcha |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu One hackers | Pending | ||
Review via email: mp+356869@code.launchpad.net |
Commit message
Drop captcha from account registration (API & web).
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.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'django_project/settings_base.py' |
2 | --- django_project/settings_base.py 2018-10-11 19:31:10 +0000 |
3 | +++ django_project/settings_base.py 2018-10-16 20:29:23 +0000 |
4 | @@ -229,7 +229,7 @@ |
5 | 'raven.contrib.django.raven_compat', |
6 | 'canonical_raven', |
7 | ] |
8 | -INTERNAL_IPS = [] |
9 | +INTERNAL_IPS = ['127.0.0.1'] # Needed to tell user registration via WEB vs API |
10 | LANGUAGES = [ |
11 | ['ar', 'Arabic'], |
12 | ['az', 'Azerbaijani'], |
13 | |
14 | === modified file 'django_project/settings_devel.py' |
15 | --- django_project/settings_devel.py 2018-02-15 13:17:06 +0000 |
16 | +++ django_project/settings_devel.py 2018-10-16 20:29:23 +0000 |
17 | @@ -22,7 +22,6 @@ |
18 | 'TWOFACTOR': {'is_active': True}, |
19 | 'CAN_VIEW_SUPPORT_PHONE': {'is_active': True}, |
20 | 'CAPTCHA': {'is_active': False}, |
21 | - 'CAPTCHA_NEW_ACCOUNT': {'is_active': False}, |
22 | 'PREFLIGHT': {'is_active': True}, |
23 | 'LOGIN_BY_TOKEN': {'is_active': True}, |
24 | 'SSH_KEY_INTEGRATION': {'is_active': False}, |
25 | |
26 | === modified file 'src/api/v10/forms.py' |
27 | --- src/api/v10/forms.py 2015-05-08 19:25:27 +0000 |
28 | +++ src/api/v10/forms.py 2018-10-16 20:29:23 +0000 |
29 | @@ -5,17 +5,12 @@ |
30 | |
31 | from __future__ import unicode_literals |
32 | |
33 | -from django import forms |
34 | from django.forms import fields |
35 | -from django.utils.translation import ugettext_lazy as _ |
36 | |
37 | from identityprovider.forms import NewAccountForm |
38 | -from identityprovider.models.captcha import Captcha |
39 | |
40 | |
41 | class WebserviceCreateAccountForm(NewAccountForm): |
42 | - captcha_id = fields.CharField(max_length=1024) |
43 | - captcha_solution = fields.CharField(max_length=256) |
44 | remote_ip = fields.CharField(max_length=256) |
45 | platform = fields.TypedChoiceField(choices=[ |
46 | ('web', 'Web'), ('desktop', 'Desktop'), ('mobile', 'Mobile')], |
47 | @@ -38,21 +33,3 @@ |
48 | if not validate_redirect_to: |
49 | validate_redirect_to = None |
50 | return validate_redirect_to |
51 | - |
52 | - def clean(self): |
53 | - cleaned_data = super(WebserviceCreateAccountForm, self).clean() |
54 | - captcha_id = cleaned_data.get('captcha_id') |
55 | - captcha_solution = cleaned_data.get('captcha_solution') |
56 | - |
57 | - # The remote IP address is absolutely required, and comes from |
58 | - # SSO itself, not from the client. If it's missing, it's a |
59 | - # programming error, and should not be returned to the client |
60 | - # as a validation error. So, we use a normal key lookup here. |
61 | - remote_ip = cleaned_data['remote_ip'] |
62 | - |
63 | - captcha = Captcha(captcha_id) |
64 | - email = cleaned_data.get('email', '') |
65 | - if captcha.verify(captcha_solution, remote_ip, email): |
66 | - return cleaned_data |
67 | - # not verified |
68 | - raise forms.ValidationError(_("Wrong captcha solution.")) |
69 | |
70 | === modified file 'src/api/v10/handlers.py' |
71 | --- src/api/v10/handlers.py 2018-08-17 18:38:29 +0000 |
72 | +++ src/api/v10/handlers.py 2018-10-16 20:29:23 +0000 |
73 | @@ -17,6 +17,7 @@ |
74 | from django.shortcuts import render |
75 | from django.utils.timezone import now |
76 | from django.utils.translation import ugettext_lazy as _ |
77 | +from gargoyle import gargoyle |
78 | from oauth_backend.models import Token |
79 | from piston.emitters import Emitter |
80 | from piston.handler import BaseHandler |
81 | @@ -38,7 +39,6 @@ |
82 | from identityprovider.models.captcha import ( |
83 | Captcha, |
84 | NewCaptchaError, |
85 | - VerifyCaptchaError, |
86 | ) |
87 | from identityprovider.models.const import AuthTokenType, EmailStatus |
88 | from identityprovider.signals import ( |
89 | @@ -184,28 +184,25 @@ |
90 | |
91 | @named_operation |
92 | def register(self, request): |
93 | + remote_addr = request.environ['REMOTE_ADDR'] |
94 | + if (not gargoyle.is_active('USER_REGISTRATION_API_ENABLED', request) |
95 | + and remote_addr not in settings.INTERNAL_IPS): |
96 | + return api_error(HttpResponseForbidden, |
97 | + "User registration via API is disabled.") |
98 | + |
99 | data = request.data |
100 | - data['remote_ip'] = request.environ['REMOTE_ADDR'] |
101 | + data['remote_ip'] = remote_addr |
102 | form = WebserviceCreateAccountForm(data) |
103 | - try: |
104 | - if not form.is_valid(): |
105 | - errors = dict((k, map(unicode, v)) |
106 | - for (k, v) in form.errors.items()) |
107 | - # XXX: cope with client trimming error messages |
108 | - if unicode(PASSWORD_LEAKED) in errors.get('password', ''): |
109 | - errors['password'] = unicode(_( |
110 | - 'unsafe: leaked by security breach ' |
111 | - 'on another website')) |
112 | - result = {'status': 'error', 'errors': errors} |
113 | - return result |
114 | - except VerifyCaptchaError: |
115 | - logger.exception("reCaptcha connection error") |
116 | - msg = unicode( |
117 | - _('Unable to verify captcha. Please try again shortly.')) |
118 | - return { |
119 | - 'status': 'error', |
120 | - 'errors': {'captcha_solution': [msg]} |
121 | - } |
122 | + if not form.is_valid(): |
123 | + errors = dict((k, map(unicode, v)) |
124 | + for (k, v) in form.errors.items()) |
125 | + # XXX: cope with client trimming error messages |
126 | + if unicode(PASSWORD_LEAKED) in errors.get('password', ''): |
127 | + errors['password'] = unicode(_( |
128 | + 'unsafe: leaked by security breach ' |
129 | + 'on another website')) |
130 | + result = {'status': 'error', 'errors': errors} |
131 | + return result |
132 | |
133 | cleaned_data = form.cleaned_data |
134 | requested_email = cleaned_data['email'] |
135 | |
136 | === modified file 'src/api/v10/tests/test_forms.py' |
137 | --- src/api/v10/tests/test_forms.py 2015-11-24 14:38:04 +0000 |
138 | +++ src/api/v10/tests/test_forms.py 2018-10-16 20:29:23 +0000 |
139 | @@ -5,23 +5,12 @@ |
140 | |
141 | from __future__ import unicode_literals |
142 | |
143 | -from django.test.utils import override_settings |
144 | - |
145 | from api.v10.forms import WebserviceCreateAccountForm |
146 | from identityprovider.tests.utils import SSOBaseTestCase |
147 | |
148 | |
149 | -@override_settings(CAPTCHA_PUBLIC_KEY='public', CAPTCHA_PRIVATE_KEY='private') |
150 | class WebServiceCreateAccountFormTestCase(SSOBaseTestCase): |
151 | |
152 | - def setUp(self): |
153 | - super(WebServiceCreateAccountFormTestCase, self).setUp() |
154 | - # patch Captcha so it never hits the real network |
155 | - self.mock_captcha_open = self.patch( |
156 | - 'identityprovider.models.captcha.Captcha._open') |
157 | - self.mock_captcha_open.return_value.is_error = False |
158 | - self.mock_captcha_open.return_value.data.return_value = 'true\nyey' |
159 | - |
160 | def test_nonascii_password(self): |
161 | data = {'password': 'Curuzú Cuatiá', |
162 | 'remote_ip': '127.0.0.1'} |
163 | @@ -46,19 +35,6 @@ |
164 | self.assertTrue(form.is_valid()) |
165 | self.assertEqual(form.cleaned_data['platform'], 'desktop') |
166 | |
167 | - def test_captcha_checked_for_whitelist(self): |
168 | - data = { |
169 | - 'email': 'canonicaltest@gmail.com', |
170 | - 'password': 'password1A', |
171 | - 'captcha_id': '1', |
172 | - 'captcha_solution': '2', |
173 | - 'remote_ip': '127.0.0.1', |
174 | - } |
175 | - pattern = '^canonicaltest(?:\+.+)?@gmail\.com$' |
176 | - with self.settings(EMAIL_WHITELIST_REGEXP_LIST=[pattern]): |
177 | - form = WebserviceCreateAccountForm(data) |
178 | - self.assertTrue(form.is_valid()) |
179 | - |
180 | def test_default_cleaned_validate_redirect_to(self): |
181 | data = { |
182 | 'email': 'some@email.com', |
183 | |
184 | === modified file 'src/api/v10/tests/test_handlers.py' |
185 | --- src/api/v10/tests/test_handlers.py 2018-05-28 17:22:45 +0000 |
186 | +++ src/api/v10/tests/test_handlers.py 2018-10-16 20:29:23 +0000 |
187 | @@ -391,6 +391,62 @@ |
188 | 'captcha_solution': 'foobar', |
189 | 'captcha_id': 'id'}) |
190 | |
191 | + @switches(USER_REGISTRATION_API_ENABLED=False) |
192 | + @override_settings(INTERNAL_IPS=['127.0.0.1']) |
193 | + def test_feature_flag_disabled_with_internal_remote_addr(self): |
194 | + # Request uses 127.0.0.1, which is treated as an internal IP. |
195 | + email = self.factory.make_email_address() |
196 | + |
197 | + response = self.api.registrations.register( |
198 | + email=email, password='MySecretPassword1', |
199 | + captcha_solution='foobar', captcha_id='id', |
200 | + displayname='Test User') |
201 | + |
202 | + self.assertEqual(response['status'], 'ok') |
203 | + Account.objects.get_by_email(email) |
204 | + |
205 | + @switches(USER_REGISTRATION_API_ENABLED=False) |
206 | + @override_settings(INTERNAL_IPS=['10.0.0.1']) |
207 | + def test_feature_flag_disabled_with_external_remote_addr(self): |
208 | + # Request uses 127.0.0.1, which is treated as an *external* IP here. |
209 | + email = self.factory.make_email_address() |
210 | + |
211 | + with self.assertRaises(HTTPError) as ctx: |
212 | + self.api.registrations.register( |
213 | + email=email, password='MySecretPassword1', |
214 | + captcha_solution='foobar', captcha_id='id', |
215 | + displayname='Test User') |
216 | + |
217 | + self.assertEqual(ctx.exception.response.status, 403) |
218 | + |
219 | + @switches(USER_REGISTRATION_API_ENABLED=True) |
220 | + @override_settings(INTERNAL_IPS=['127.0.0.1']) |
221 | + def test_feature_flag_enabled_with_internal_remote_addr(self): |
222 | + # Request uses 127.0.0.1, which is treated as an internal IP. |
223 | + email = self.factory.make_email_address() |
224 | + |
225 | + response = self.api.registrations.register( |
226 | + email=email, password='MySecretPassword1', |
227 | + captcha_solution='foobar', captcha_id='id', |
228 | + displayname='Test User') |
229 | + |
230 | + self.assertEqual(response['status'], 'ok') |
231 | + Account.objects.get_by_email(email) |
232 | + |
233 | + @switches(USER_REGISTRATION_API_ENABLED=True) |
234 | + @override_settings(INTERNAL_IPS=['10.0.0.1']) |
235 | + def test_feature_flag_enabled_with_external_remote_addr(self): |
236 | + # Request uses 127.0.0.1, which is treated as an *external* IP here. |
237 | + email = self.factory.make_email_address() |
238 | + |
239 | + response = self.api.registrations.register( |
240 | + email=email, password='MySecretPassword1', |
241 | + captcha_solution='foobar', captcha_id='id', |
242 | + displayname='Test User') |
243 | + |
244 | + self.assertEqual(response['status'], 'ok') |
245 | + Account.objects.get_by_email(email) |
246 | + |
247 | |
248 | class AuthenticationTestCase(SSOBaseTestCase): |
249 | |
250 | |
251 | === modified file 'src/api/v20/handlers.py' |
252 | --- src/api/v20/handlers.py 2018-08-17 18:38:29 +0000 |
253 | +++ src/api/v20/handlers.py 2018-10-16 20:29:23 +0000 |
254 | @@ -52,7 +52,6 @@ |
255 | Token, |
256 | twofactor, |
257 | ) |
258 | -from identityprovider.models.captcha import Captcha, VerifyCaptchaError |
259 | from identityprovider.models.const import ( |
260 | AccountStatus, |
261 | AuthLogType, |
262 | @@ -61,7 +60,6 @@ |
263 | ) |
264 | from identityprovider.signals import login_failed, login_succeeded |
265 | from identityprovider.stats import stats |
266 | -from identityprovider.timeline_helpers import get_request_timing_function |
267 | from identityprovider.utils import redirection_url_for_token |
268 | from webservices.launchpad import get_lp_ssh_keys |
269 | |
270 | @@ -282,8 +280,12 @@ |
271 | @throttle() |
272 | def create(self, request): |
273 | """Create/register a new account.""" |
274 | + remote_addr = request.environ['REMOTE_ADDR'] |
275 | + if (not gargoyle.is_active('USER_REGISTRATION_API_ENABLED', request) |
276 | + and remote_addr not in settings.INTERNAL_IPS): |
277 | + return errors.FEATURE_DISABLED() |
278 | + |
279 | data = request.data |
280 | - |
281 | try: |
282 | email = data['email'] |
283 | password = data['password'] |
284 | @@ -294,43 +296,6 @@ |
285 | return errors.INVALID_DATA(**missing) |
286 | |
287 | username = data.get('username') |
288 | - captcha_required = (gargoyle.is_active('CAPTCHA', request) and |
289 | - gargoyle.is_active('CAPTCHA_NEW_ACCOUNT', request)) |
290 | - |
291 | - captcha_id = data.get('captcha_id') |
292 | - captcha_solution = data.get('captcha_solution') |
293 | - if not (captcha_solution and captcha_id) and captcha_required: |
294 | - extra = {} |
295 | - if data.get('create_captcha', True): |
296 | - timer = get_request_timing_function(request) |
297 | - try: |
298 | - extra = Captcha.new(timer=timer).serialize() |
299 | - except Exception: |
300 | - logger.exception('failed to create reCaptcha') |
301 | - return errors.CAPTCHA_REQUIRED(**extra) |
302 | - |
303 | - elif captcha_id: |
304 | - remote_addr = request.environ['REMOTE_ADDR'] |
305 | - captcha = Captcha(captcha_id) |
306 | - verified = False |
307 | - try: |
308 | - timer = get_request_timing_function(request) |
309 | - verified = captcha.verify( |
310 | - captcha_solution, remote_addr, data['email'], |
311 | - timer=timer) |
312 | - except VerifyCaptchaError as e: |
313 | - # only expose HTTP error codes to client |
314 | - code = e.response.code if e.response.code > 200 else None |
315 | - return errors.CAPTCHA_ERROR( |
316 | - recaptcha_reason=e.response.reason, |
317 | - recaptcha_status_code=code, |
318 | - recaptcha_body=e.response.body) |
319 | - except Exception: |
320 | - logger.exception("reCaptcha error") |
321 | - |
322 | - if not verified: |
323 | - message = getattr(captcha, 'message', '') |
324 | - return errors.CAPTCHA_FAILURE(captcha_message=message) |
325 | |
326 | root_url = request.build_absolute_uri('/') |
327 | try: |
328 | @@ -365,8 +330,6 @@ |
329 | The newly created account will be verified and passwordless, |
330 | and the owner will not be able to login until a password reset is done. |
331 | |
332 | - Captcha is completely ignored. |
333 | - |
334 | """ |
335 | data = request.data |
336 | |
337 | |
338 | === modified file 'src/api/v20/tests/test_handlers.py' |
339 | --- src/api/v20/tests/test_handlers.py 2018-09-13 20:19:21 +0000 |
340 | +++ src/api/v20/tests/test_handlers.py 2018-10-16 20:29:23 +0000 |
341 | @@ -7,9 +7,8 @@ |
342 | import time |
343 | import uuid |
344 | |
345 | -from StringIO import StringIO |
346 | from urllib import quote, urlencode |
347 | -from urlparse import parse_qsl, urlparse, urlunparse |
348 | +from urlparse import urlparse, urlunparse |
349 | |
350 | from django.conf import settings |
351 | from django.contrib.auth.hashers import make_password |
352 | @@ -35,7 +34,6 @@ |
353 | AuthToken, |
354 | EmailAddress, |
355 | Token, |
356 | - captcha, |
357 | ) |
358 | from identityprovider.models.const import ( |
359 | AccountCreationRationale, |
360 | @@ -616,195 +614,34 @@ |
361 | self.assert_bad_request( |
362 | data=self.data, extra={'email': ['Invalid email']}) |
363 | |
364 | - |
365 | -@override_settings(CAPTCHA_PUBLIC_KEY='public', CAPTCHA_PRIVATE_KEY='private') |
366 | -class AnonymousAccountRegistrationWithCaptchaHandlerTestCase(BaseTestCase): |
367 | - |
368 | - url = reverse('api-registration') |
369 | - |
370 | - def setUp(self): |
371 | - super(AnonymousAccountRegistrationWithCaptchaHandlerTestCase, |
372 | - self).setUp() |
373 | - p = switches(CAPTCHA=True, CAPTCHA_NEW_ACCOUNT=True) |
374 | - p.patch() |
375 | - self.addCleanup(p.unpatch) |
376 | - |
377 | - self.captcha_response = captcha.CaptchaResponse( |
378 | - code=42, response=StringIO("challenge: '999'")) |
379 | - self.mock_captcha_open = self.patch( |
380 | - 'api.v20.handlers.Captcha._open', |
381 | - return_value=self.captcha_response) |
382 | - |
383 | - self.data = { |
384 | - 'email': self.factory.make_email_address(), |
385 | - 'password': 'asdfASDF1', |
386 | - 'displayname': 'Ricardo the Magnificent', |
387 | - 'captcha_id': '999', |
388 | - 'captcha_solution': 'foo bar', |
389 | - } |
390 | - |
391 | - def test_register_captcha_required(self): |
392 | - captcha_data = { |
393 | - 'captcha_id': '999', |
394 | - 'image_url': settings.CAPTCHA_IMAGE_URL_PATTERN % '999'} |
395 | - del self.data['captcha_id'] |
396 | - del self.data['captcha_solution'] |
397 | - |
398 | - json_body = self.do_post(self.data, status_code=401) |
399 | - |
400 | - self.assertEqual(json_body['code'], "CAPTCHA_REQUIRED") |
401 | - self.assertIn('A captcha challenge is required', json_body['message']) |
402 | - self.assertIsNone(Account.objects.get_by_email(self.data['email'])) |
403 | - self.assertEqual(json_body['extra'], captcha_data) |
404 | - |
405 | - def test_register_captcha_success(self): |
406 | - self.captcha_response.response = StringIO('true\nok') |
407 | + @switches(USER_REGISTRATION_API_ENABLED=False) |
408 | + @override_settings(INTERNAL_IPS=['127.0.0.1']) |
409 | + def test_feature_flag_disabled_with_internal_remote_addr(self): |
410 | + # Request uses 127.0.0.1, which is treated as an internal IP. |
411 | json_body = self.do_post(self.data, status_code=201) |
412 | - |
413 | - url_request = self.mock_captcha_open.call_args[0][0] |
414 | - self.assertEqual( |
415 | - url_request.get_full_url(), settings.CAPTCHA_VERIFY_URL) |
416 | - data = dict(parse_qsl(url_request.data)) |
417 | - expected = { |
418 | - 'challenge': '999', 'privatekey': settings.CAPTCHA_PRIVATE_KEY, |
419 | - 'remoteip': '127.0.0.1', 'response': 'foo bar'} |
420 | - self.assertEqual(data, expected) |
421 | - |
422 | - self.assertIn('openid', json_body) |
423 | - self.assertIn('href', json_body) |
424 | - self.assertEqual(json_body['email'], self.data['email']) |
425 | - self.assertEqual(json_body['displayname'], self.data['displayname']) |
426 | - self.assertEqual(json_body['status'], 'Active') |
427 | - self.assertEqual(len(json_body['emails']), 1) |
428 | - self.assertIn(quote(self.data['email'], safe='@'), |
429 | - json_body['emails'][0]['href']) |
430 | - |
431 | - def test_register_captcha_failure(self): |
432 | - self.captcha_response.is_error = False |
433 | - |
434 | - self.data['captcha_id'] = '999' |
435 | - self.data['captcha_solution'] = 'foo bar' |
436 | - |
437 | + self.assert_correct_account_information(json_body) |
438 | + |
439 | + @switches(USER_REGISTRATION_API_ENABLED=False) |
440 | + @override_settings(INTERNAL_IPS=['10.0.0.1']) |
441 | + def test_feature_flag_disabled_with_external_remote_addr(self): |
442 | + # Request uses 127.0.0.1, which is treated as an *external* IP here. |
443 | json_body = self.do_post(self.data, status_code=403) |
444 | - |
445 | - url_request = self.mock_captcha_open.call_args[0][0] |
446 | - self.assertEqual( |
447 | - url_request.get_full_url(), settings.CAPTCHA_VERIFY_URL) |
448 | - data = dict(parse_qsl(url_request.data)) |
449 | - expected = { |
450 | - 'challenge': '999', 'privatekey': settings.CAPTCHA_PRIVATE_KEY, |
451 | - 'remoteip': '127.0.0.1', 'response': 'foo bar'} |
452 | - self.assertEqual(data, expected) |
453 | - |
454 | - self.assertEqual(json_body['code'], "CAPTCHA_FAILURE") |
455 | - self.assertIn( |
456 | - 'Failed response to captcha challenge.', json_body['message']) |
457 | - self.assertIsNone(Account.objects.get_by_email(self.data['email'])) |
458 | - |
459 | - def test_register_captcha_whitelist(self): |
460 | - self.data['email'] = 'canonicaltest@gmail.com' |
461 | - self.data['captcha_id'] = '999' |
462 | - self.data['captcha_solution'] = 'foo bar' |
463 | - |
464 | - with self.settings(**OVERRIDES): |
465 | - self.do_post(self.data, status_code=201) |
466 | - |
467 | - self.assertIsNotNone(Account.objects.get_by_email(self.data['email'])) |
468 | - self.assertFalse(self.mock_captcha_open.called) |
469 | - |
470 | - def test_register_captcha_whitelist_with_uuid(self): |
471 | - self.data['email'] = 'canonicaltest+something@gmail.com' |
472 | - self.data['captcha_id'] = '999' |
473 | - self.data['captcha_solution'] = 'foo bar' |
474 | - |
475 | - with self.settings(**OVERRIDES): |
476 | - self.do_post(self.data, status_code=201) |
477 | - |
478 | - self.assertIsNotNone(Account.objects.get_by_email(self.data['email'])) |
479 | - self.assertFalse(self.mock_captcha_open.called) |
480 | - |
481 | - def test_register_captcha_whitelist_fail(self): |
482 | - self.data['captcha_id'] = '999' |
483 | - self.data['captcha_solution'] = 'foo bar' |
484 | - self.data['email'] = 'notcanonicaltest@gmail.com' |
485 | - |
486 | - self.captcha_response.is_error = False |
487 | - self.captcha_response.response = StringIO('false\nmessage') |
488 | - |
489 | - with self.settings(**OVERRIDES): |
490 | - self.do_post(self.data, status_code=403) |
491 | - |
492 | - self.assertIsNone(Account.objects.get_by_email(self.data['email'])) |
493 | - self.assertTrue(self.mock_captcha_open.called) |
494 | - |
495 | - def test_register_captcha_http_error(self): |
496 | - response = captcha.CaptchaResponse( |
497 | - 500, None, "", "Server error", "Unexpected recaptcha error") |
498 | - error = captcha.VerifyCaptchaError(response) |
499 | - self.mock_captcha_open.side_effect = error |
500 | - |
501 | - self.data['captcha_id'] = '999' |
502 | - self.data['captcha_solution'] = 'foo bar' |
503 | - |
504 | - json_body = self.do_post(self.data, status_code=502) |
505 | - |
506 | - self.assertEqual(json_body['code'], "CAPTCHA_ERROR") |
507 | - self.assertIn('Unable to get a valid response from reCaptcha service', |
508 | - json_body['message']) |
509 | - extra = json_body['extra'] |
510 | - self.assertEqual(extra['recaptcha_reason'], "Server error") |
511 | - self.assertEqual(extra['recaptcha_status_code'], 500) |
512 | - self.assertEqual(extra['recaptcha_body'], "Unexpected recaptcha error") |
513 | - self.assertIsNone(Account.objects.get_by_email(self.data['email'])) |
514 | - |
515 | - def test_register_captcha_network_error(self): |
516 | - response = captcha.CaptchaResponse(111, None, "", "Connection refused") |
517 | - error = captcha.VerifyCaptchaError(response) |
518 | - self.mock_captcha_open.side_effect = error |
519 | - |
520 | - self.data['captcha_id'] = '999' |
521 | - self.data['captcha_solution'] = 'foo bar' |
522 | - |
523 | - json_body = self.do_post(self.data, status_code=502) |
524 | - |
525 | - self.assertEqual(json_body['code'], "CAPTCHA_ERROR") |
526 | - self.assertIn('Unable to get a valid response from reCaptcha service', |
527 | - json_body['message']) |
528 | - extra = json_body['extra'] |
529 | - self.assertEqual(extra['recaptcha_reason'], "Connection refused") |
530 | - self.assertEqual(extra['recaptcha_status_code'], None) |
531 | - self.assertEqual(extra['recaptcha_body'], None) |
532 | - self.assertIsNone(Account.objects.get_by_email(self.data['email'])) |
533 | - |
534 | - def test_timeline_for_captcha_generation(self): |
535 | - timeline = Timeline() |
536 | - meta = { |
537 | - 'timeline.timeline': timeline, |
538 | - } |
539 | - data = self.data.copy() |
540 | - data.pop('captcha_id') |
541 | - data.pop('captcha_solution') |
542 | - data['create_captcha'] = True |
543 | - |
544 | - self.do_post(data, status_code=401, **meta) |
545 | - |
546 | - self.assertEqual(1, len(timeline.actions)) |
547 | - self.assertEqual('captcha-new', timeline.actions[0].category) |
548 | - self.assertEqual(self.mock_captcha_open.call_args[0][0], |
549 | - timeline.actions[0].detail) |
550 | - |
551 | - def test_timeline_for_captcha_verification(self): |
552 | - self.mock_captcha_open.return_value = captcha.CaptchaResponse( |
553 | - 500, StringIO('false\nsomething')) |
554 | - timeline = Timeline() |
555 | - meta = { |
556 | - 'timeline.timeline': timeline, |
557 | - } |
558 | - |
559 | - self.do_post(self.data, status_code=403, **meta) |
560 | - |
561 | - self.assertEqual(1, len(timeline.actions)) |
562 | - self.assertEqual('captcha-verify', timeline.actions[0].category) |
563 | + self.assertEqual(json_body['code'], "FEATURE_DISABLED") |
564 | + self.assertEqual("Feature disabled.", json_body['message']) |
565 | + |
566 | + @switches(USER_REGISTRATION_API_ENABLED=True) |
567 | + @override_settings(INTERNAL_IPS=['127.0.0.1']) |
568 | + def test_feature_flag_enabled_with_internal_remote_addr(self): |
569 | + # Request uses 127.0.0.1, which is treated as an internal IP. |
570 | + json_body = self.do_post(self.data, status_code=201) |
571 | + self.assert_correct_account_information(json_body) |
572 | + |
573 | + @switches(USER_REGISTRATION_API_ENABLED=True) |
574 | + @override_settings(INTERNAL_IPS=['10.0.0.1']) |
575 | + def test_feature_flag_enabled_with_external_remote_addr(self): |
576 | + # Request uses 127.0.0.1, which is treated as an *external* IP here. |
577 | + json_body = self.do_post(self.data, status_code=201) |
578 | + self.assert_correct_account_information(json_body) |
579 | |
580 | |
581 | class AccountRegistrationHandlerTestCase(BaseTestCase): |
582 | @@ -2268,8 +2105,6 @@ |
583 | email = 'foo@foo.com' |
584 | |
585 | data = { |
586 | - 'captcha_id': 'some-id', |
587 | - 'captcha_solution': 'some solution', |
588 | 'email': 'foo@foo.com', |
589 | 'password': 'some-password-123', |
590 | 'displayname': 'Some User', |
591 | |
592 | === modified file 'src/api/v20/utils.py' |
593 | --- src/api/v20/utils.py 2018-05-28 17:22:45 +0000 |
594 | +++ src/api/v20/utils.py 2018-10-16 20:29:23 +0000 |
595 | @@ -67,6 +67,7 @@ |
596 | class ErrorCode: |
597 | ACCOUNT_NOT_READY = 'account-not-ready' |
598 | BAD_REQUEST = 'bad-request' |
599 | + FEATURE_DISABLED = 'feature-disabled' |
600 | INTERNAL_ERROR = 'internal-server-error' |
601 | INVALID_DATA = 'invalid-data' |
602 | INVALID_CREDENTIALS = 'invalid-credentials' |
603 | @@ -141,6 +142,10 @@ |
604 | 403, _("Insufficient permissions."), |
605 | ErrorCode.PERMISSION_REQUIRED), |
606 | |
607 | + FEATURE_DISABLED=( |
608 | + 403, _("Feature disabled."), |
609 | + ErrorCode.FEATURE_DISABLED), |
610 | + |
611 | RESOURCE_NOT_FOUND=( |
612 | 404, _("The resource requested was not found."), |
613 | ErrorCode.RESOURCE_NOT_FOUND), |
614 | |
615 | === modified file 'src/webui/templates/registration/_create_account_form.html' |
616 | --- src/webui/templates/registration/_create_account_form.html 2018-07-04 17:51:43 +0000 |
617 | +++ src/webui/templates/registration/_create_account_form.html 2018-10-16 20:29:23 +0000 |
618 | @@ -50,17 +50,6 @@ |
619 | |
620 | {% include "widgets/passwords.html" with fields=create_form %} |
621 | |
622 | - {% if captcha_required %} |
623 | - <div class="captcha" id="captcha"> |
624 | - {% if captcha_error_message %} |
625 | - <span class="error"> |
626 | - {{ captcha_error_message }} |
627 | - </span> |
628 | - {% endif %} |
629 | - {% include "widgets/recaptcha.html" %} |
630 | - </div> |
631 | - {% endif %} |
632 | - |
633 | <div class="input-row{% if create_form.accept_tos.errors %} haserrors{% endif %} accept-tos-input"> |
634 | |
635 | {% if create_form.accept_tos.errors %} |
636 | |
637 | === removed file 'src/webui/templates/widgets/recaptcha.html' |
638 | --- src/webui/templates/widgets/recaptcha.html 2014-12-11 17:44:29 +0000 |
639 | +++ src/webui/templates/widgets/recaptcha.html 1970-01-01 00:00:00 +0000 |
640 | @@ -1,43 +0,0 @@ |
641 | -{% comment %} |
642 | -Copyright 2010 Canonical Ltd. This software is licensed under the |
643 | -GNU Affero General Public License version 3 (see the file LICENSE). |
644 | -{% endcomment %} |
645 | - |
646 | -{% load i18n %} |
647 | -{% load static_url %} |
648 | -<script type="text/javascript"> |
649 | - var RecaptchaOptions = { |
650 | - theme: 'white', |
651 | - custom_translations: { |
652 | - visual_challenge : "{% trans "Get a visual challenge" %}", |
653 | - audio_challenge : "{% trans "Get an audio challenge" %}", |
654 | - refresh_btn : "{% trans "Get a new challenge" %}", |
655 | - instructions_visual : "{% trans "Type the two words:" %}", |
656 | - instructions_audio : "{% trans "Type what you hear:" %}", |
657 | - help_btn : "{% trans "Help" %}", |
658 | - play_again : "{% trans "Play sound again" %}", |
659 | - cant_hear_this : "{% trans "Download sound as MP3" %}", |
660 | - incorrect_try_again : "{% trans "Incorrect. Try again." %}" |
661 | - }, |
662 | - }; |
663 | -</script> |
664 | -<div {% if captcha_error %}class='captchaError'{% endif %}> |
665 | -{% ifequal captcha_error "&error=no-challenge" %} |
666 | -<p> |
667 | -{% blocktrans with "support_form"|static_url as support_form_url %} |
668 | -It appears that our captcha service was unable to load on this page. |
669 | -This may be caused by a plugin on your browser. |
670 | -Please correct this and try again. If the problem persists, please <a href="{{ support_form_url }}">contact support</a> |
671 | -{% endblocktrans %} |
672 | -</p> |
673 | -{% endifequal %} |
674 | -<script type="text/javascript" src="{{ CAPTCHA_API_URL_SECURE }}/challenge?k={{ CAPTCHA_PUBLIC_KEY }}{{ captcha_error }}"> |
675 | -</script> |
676 | -<noscript> |
677 | - <iframe src="{{ CAPTCHA_API_URL_SECURE }}/noscript?k={{ CAPTCHA_PUBLIC_KEY }}" height="300" width="500" frameborder="0" class="recaptcha-noscript"> |
678 | - </iframe> |
679 | - <textarea class="recaptcha-challenge-field" name="recaptcha_challenge_field" rows="3" cols="40"> |
680 | - </textarea> |
681 | - <input type="hidden" name="recaptcha_response_field" value="manual_challenge"> |
682 | -</noscript> |
683 | -</div> |
684 | |
685 | === modified file 'src/webui/tests/test_views_registration.py' |
686 | --- src/webui/tests/test_views_registration.py 2018-05-28 20:15:33 +0000 |
687 | +++ src/webui/tests/test_views_registration.py 2018-10-16 20:29:23 +0000 |
688 | @@ -161,16 +161,6 @@ |
689 | ctx = response.context_data |
690 | self.assertEqual(ctx['form']['email'].value(), 'test@test.com') |
691 | |
692 | - @switches(CAPTCHA=False) |
693 | - def test_get_optional_captcha_switch_off(self): |
694 | - response = self.get() |
695 | - self.assertEqual(response.context_data['captcha_required'], False) |
696 | - |
697 | - @switches(CAPTCHA=True, CAPTCHA_NEW_ACCOUNT=True) |
698 | - def test_get_optional_captcha_switch_on(self): |
699 | - response = self.get() |
700 | - self.assertEqual(response.context_data['captcha_required'], True) |
701 | - |
702 | def test_post_required_fields(self): |
703 | response = self.post() |
704 | self.assert_form_displayed( |
705 | @@ -213,9 +203,6 @@ |
706 | email=self.TESTDATA['email'], |
707 | password=self.TESTDATA['password'], |
708 | displayname=self.TESTDATA['displayname'], |
709 | - captcha_id=None, |
710 | - captcha_solution=None, |
711 | - create_captcha=False, |
712 | creation_source=WEB_CREATION_SOURCE, |
713 | ) |
714 | |
715 | @@ -242,9 +229,6 @@ |
716 | password=self.TESTDATA['password'], |
717 | displayname=self.TESTDATA['displayname'], |
718 | username=self.TESTDATA['username'], |
719 | - captcha_id=None, |
720 | - captcha_solution=None, |
721 | - create_captcha=False, |
722 | creation_source=WEB_CREATION_SOURCE, |
723 | ) |
724 | self.TESTDATA.pop('username') |
725 | @@ -337,9 +321,6 @@ |
726 | expected_args = dict(email=self.TESTDATA['email'], |
727 | password=self.TESTDATA['password'], |
728 | displayname=self.TESTDATA['displayname'], |
729 | - create_captcha=False, |
730 | - captcha_solution=None, |
731 | - captcha_id=None, |
732 | creation_source='web-flow', |
733 | oid_token=token) |
734 | self.mock_api_register.assert_called_once_with(**expected_args) |
735 | @@ -351,38 +332,6 @@ |
736 | self.assert_form_displayed(response, email=VERIFY_EMAIL_MESSAGE) |
737 | self.assert_stat_calls(['error.email']) |
738 | |
739 | - def test_post_captcha_required(self): |
740 | - exc = api_errors.CaptchaRequired(Mock()) |
741 | - self.mock_api_register.side_effect = exc |
742 | - response = self.post(**self.TESTDATA) |
743 | - self.assert_form_displayed(response) |
744 | - self.assertEqual(response.context_data['captcha_required'], True) |
745 | - |
746 | - def test_post_captcha_failure(self): |
747 | - mock_response = Mock() |
748 | - body = {'extra': {'captcha_message': 'XXX'}} |
749 | - exc = api_errors.CaptchaFailure(mock_response, body) |
750 | - self.mock_api_register.side_effect = exc |
751 | - |
752 | - response = self.post(**self.TESTDATA) |
753 | - self.assert_form_displayed(response) |
754 | - self.assertEqual(response.context_data['captcha_required'], True) |
755 | - self.assertEqual( |
756 | - response.context_data['captcha_error'], |
757 | - '&error=XXX') |
758 | - self.assert_stat_calls(['error.captcha']) |
759 | - |
760 | - def test_post_captcha_error(self): |
761 | - mock_response = Mock() |
762 | - body = {} |
763 | - exc = api_errors.CaptchaError(mock_response, body) |
764 | - self.mock_api_register.side_effect = exc |
765 | - |
766 | - response = self.post(**self.TESTDATA) |
767 | - self.assert_form_displayed(response) |
768 | - self.assertEqual(response.context_data['captcha_required'], True) |
769 | - self.assert_stat_calls(['error.captcha']) |
770 | - |
771 | |
772 | class RegisterTimelineTestCase( |
773 | SSOBaseTestCase, RegisterTestMixin, TimelineActionMixin): |
774 | |
775 | === modified file 'src/webui/tests/test_views_ui.py' |
776 | --- src/webui/tests/test_views_ui.py 2018-09-07 21:54:44 +0000 |
777 | +++ src/webui/tests/test_views_ui.py 2018-10-16 20:29:23 +0000 |
778 | @@ -10,7 +10,6 @@ |
779 | import urllib2 |
780 | from datetime import date |
781 | from functools import partial |
782 | -from StringIO import StringIO |
783 | from urlparse import urlsplit |
784 | |
785 | from django.conf import settings |
786 | @@ -29,7 +28,6 @@ |
787 | from django.test.utils import override_settings |
788 | from django.urls import reverse |
789 | from django.utils.html import escape |
790 | -from gargoyle import gargoyle |
791 | from gargoyle.testutils import switches |
792 | from mock import Mock, patch |
793 | from pyquery import PyQuery |
794 | @@ -50,11 +48,7 @@ |
795 | OpenIDRPConfig, |
796 | twofactor, |
797 | ) |
798 | -from identityprovider.models.captcha import ( |
799 | - Captcha, |
800 | - CaptchaResponse, |
801 | - CaptchaV2, |
802 | -) |
803 | +from identityprovider.models.captcha import CaptchaV2 |
804 | from identityprovider.models.const import ( |
805 | AccountStatus, |
806 | AuthLogType, |
807 | @@ -65,7 +59,6 @@ |
808 | from identityprovider.tests import DEFAULT_USER_PASSWORD |
809 | from identityprovider.tests.test_auth import AuthLogTestCaseMixin |
810 | from identityprovider.tests.utils import ( |
811 | - MockHandler, |
812 | SSOBaseTestCase, |
813 | TimelineActionMixin, |
814 | ) |
815 | @@ -115,9 +108,6 @@ |
816 | 'passwordconfirm': 'Testing123', |
817 | 'accept_tos': True |
818 | } |
819 | - if gargoyle.is_active('CAPTCHA'): |
820 | - data['recaptcha_challenge_field'] = 'ignored' |
821 | - data['recaptcha_response_field'] = 'ignored' |
822 | |
823 | return self.client.post(url, data, follow=follow) |
824 | |
825 | @@ -132,24 +122,6 @@ |
826 | assert self.client.login( |
827 | username=self.data['email'], password=self.data['password']) |
828 | |
829 | - def request_when_captcha_fails(self, url, data): |
830 | - class MockCaptcha(object): |
831 | - def __init__(self, *args): |
832 | - pass |
833 | - |
834 | - def verify(self, solution, ip_addr, email): |
835 | - self.message = 'no-challenge' |
836 | - return False |
837 | - |
838 | - @classmethod |
839 | - def new(cls, env): |
840 | - return cls() |
841 | - |
842 | - with patch.object(ui, 'Captcha', MockCaptcha): |
843 | - r = self.client.post(url, data) |
844 | - |
845 | - return r |
846 | - |
847 | |
848 | @override_settings(LANGUAGE_CODE='es') |
849 | class SpanishUIViewsTestCase(BaseTestCase): |
850 | @@ -1348,62 +1320,6 @@ |
851 | self.assertFalse(email.is_verified) |
852 | |
853 | |
854 | -@override_settings(CAPTCHA_PRIVATE_KEY='some-private-key') |
855 | -class CaptchaVerificationTestCase(BaseTestCase): |
856 | - |
857 | - success_status = 302 |
858 | - |
859 | - def setUp(self): |
860 | - super(CaptchaVerificationTestCase, self).setUp() |
861 | - mock_handler = MockHandler() |
862 | - mock_handler.set_next_response(200, 'false\nno-challenge') |
863 | - self.patch(Captcha, 'opener', new=urllib2.build_opener(mock_handler)) |
864 | - |
865 | - p = switches(CAPTCHA=True) |
866 | - p.patch() |
867 | - self.addCleanup(p.unpatch) |
868 | - |
869 | - def test_new_account_when_form_validation_fails(self): |
870 | - r = self.post_new_account() |
871 | - self.assertTemplateUsed(r, 'registration/new_account.html') |
872 | - msg = 'It appears that our captcha service was unable to load' |
873 | - self.assertContains(r, msg) |
874 | - |
875 | - def test_new_account_captcha_whitelist(self): |
876 | - email = 'canonicaltest@gmail.com' |
877 | - pattern = '^canonicaltest(?:\+.+)?@gmail\.com$' |
878 | - with self.settings(EMAIL_WHITELIST_REGEXP_LIST=[pattern]): |
879 | - response = self.post_new_account(email=email) |
880 | - self.assertEqual(response.status_code, self.success_status) |
881 | - |
882 | - def test_new_account_captcha_whitelist_with_uuid(self): |
883 | - email = 'canonicaltest+something@gmail.com' |
884 | - pattern = '^canonicaltest(?:\+.+)?@gmail\.com$' |
885 | - with self.settings(EMAIL_WHITELIST_REGEXP_LIST=[pattern]): |
886 | - response = self.post_new_account(email=email) |
887 | - self.assertEqual(response.status_code, self.success_status) |
888 | - |
889 | - def test_new_account_captcha_whitelist_fail(self): |
890 | - email = 'notcanonicaltest@gmail.com' |
891 | - pattern = '^canonicaltest(?:\+.+)?@gmail\.com$' |
892 | - with self.settings(EMAIL_WHITELIST_REGEXP_LIST=[pattern]): |
893 | - response = self.post_new_account(email=email) |
894 | - msg = 'It appears that our captcha service was unable to load' |
895 | - self.assertContains(response, msg) |
896 | - |
897 | - @patch.object(Captcha, '_open') |
898 | - def test_uses_timeline_from_request(self, mock_open): |
899 | - mock_open.return_value = CaptchaResponse(200, StringIO('true\na')) |
900 | - request = Mock() |
901 | - timeline = Timeline() |
902 | - request.META = {'timeline.timeline': timeline} |
903 | - request.POST = {'recaptcha_challenge_field': 'captcha-id'} |
904 | - request.environ = {'REMOTE_ADDR': '127.0.0.1'} |
905 | - ui._verify_captcha_response(None, request, None) |
906 | - self.assertEqual(1, len(timeline.actions)) |
907 | - self.assertEqual('captcha-verify', timeline.actions[0].category) |
908 | - |
909 | - |
910 | class CookiesTestCase(SSOBaseTestCase): |
911 | |
912 | def setUp(self): |
913 | |
914 | === modified file 'src/webui/views/registration.py' |
915 | --- src/webui/views/registration.py 2018-05-28 20:15:33 +0000 |
916 | +++ src/webui/views/registration.py 2018-10-16 20:29:23 +0000 |
917 | @@ -53,7 +53,6 @@ |
918 | requires_cookies, |
919 | ) |
920 | from webui.views.utils import ( |
921 | - add_captcha_settings, |
922 | display_email_sent, |
923 | set_session_email, |
924 | ) |
925 | @@ -87,10 +86,6 @@ |
926 | @requires_cookies |
927 | @require_http_methods(['GET', 'POST']) |
928 | def new_account(request, token=None): |
929 | - captcha_required = (gargoyle.is_active('CAPTCHA', request) and |
930 | - gargoyle.is_active('CAPTCHA_NEW_ACCOUNT', request)) |
931 | - captcha_error = '' |
932 | - captcha_error_message = None |
933 | rpconfig = get_rpconfig_from_request(request, token) |
934 | |
935 | def collect_stats(key): |
936 | @@ -108,14 +103,7 @@ |
937 | data = dict((k, v) for k, v in form.cleaned_data.items() |
938 | if k in ('email', 'password', 'displayname', |
939 | 'username')) |
940 | - data['captcha_id'] = request.POST.get( |
941 | - 'recaptcha_challenge_field' |
942 | - ) |
943 | - data['captcha_solution'] = request.POST.get( |
944 | - 'recaptcha_response_field' |
945 | - ) |
946 | # we'll handle our own capture generation |
947 | - data['create_captcha'] = False |
948 | data['creation_source'] = WEB_CREATION_SOURCE |
949 | if token: |
950 | data['oid_token'] = token |
951 | @@ -136,15 +124,6 @@ |
952 | collect_stats('error.email') |
953 | form._errors['email'] = [VERIFY_EMAIL_MESSAGE] |
954 | |
955 | - except api_errors.CaptchaRequired as e: |
956 | - captcha_required = True |
957 | - collect_stats('captcha_required') |
958 | - |
959 | - except (api_errors.CaptchaFailure, api_errors.CaptchaError) as e: |
960 | - captcha_required = True |
961 | - captcha_error = '&error=' + e.extra.get('captcha_message', '') |
962 | - captcha_error_message = _('Incorrect captcha solution') |
963 | - collect_stats('error.captcha') |
964 | except Exception as e: |
965 | return HttpResponseServerError("exception: " + str(e)) |
966 | else: |
967 | @@ -175,12 +154,7 @@ |
968 | 'form': form, |
969 | 'rpconfig': rpconfig, |
970 | 'token': token, |
971 | - 'captcha_required': captcha_required, |
972 | - 'captcha_error': captcha_error, |
973 | - 'captcha_error_message': captcha_error_message, |
974 | } |
975 | - if captcha_required: |
976 | - context = add_captcha_settings(context) |
977 | |
978 | if form.errors: |
979 | err = form.errors.get('email', [''])[0] |
980 | |
981 | === modified file 'src/webui/views/ui.py' |
982 | --- src/webui/views/ui.py 2018-08-24 15:30:53 +0000 |
983 | +++ src/webui/views/ui.py 2018-10-16 20:29:23 +0000 |
984 | @@ -56,11 +56,7 @@ |
985 | |
986 | ) |
987 | from identityprovider.models import twofactor |
988 | -from identityprovider.models.captcha import ( |
989 | - Captcha, |
990 | - CaptchaV2, |
991 | - VerifyCaptchaError |
992 | -) |
993 | +from identityprovider.models.captcha import CaptchaV2 |
994 | from identityprovider.models.const import AccountStatus, AuthTokenType |
995 | from identityprovider.signals import login_failed, login_succeeded |
996 | from identityprovider.signed import BadSignedValue |
997 | @@ -94,7 +90,6 @@ |
998 | requires_cookies, |
999 | ) |
1000 | from webui.views import registration |
1001 | -from webui.views.utils import add_captcha_settings |
1002 | |
1003 | |
1004 | ACCOUNT_CREATED = _("Your account was created successfully") |
1005 | @@ -150,11 +145,6 @@ |
1006 | self, request, token, rpconfig, form, create_account_form=None): |
1007 | context = super(LoginView, self).get_context( |
1008 | request, token=token, rpconfig=rpconfig, form=form) |
1009 | - # add captcha and account creation form |
1010 | - context['captcha_required'] = ( |
1011 | - gargoyle.is_active('CAPTCHA', request) and |
1012 | - gargoyle.is_active('CAPTCHA_NEW_ACCOUNT', request)) |
1013 | - context = add_captcha_settings(context) |
1014 | context['create_account_form'] = create_account_form |
1015 | return context |
1016 | |
1017 | @@ -503,30 +493,6 @@ |
1018 | return registration.new_account(request, token) |
1019 | |
1020 | |
1021 | -def _verify_captcha_response(template, request, form): |
1022 | - captcha = Captcha(request.POST.get('recaptcha_challenge_field')) |
1023 | - captcha_solution = request.POST.get('recaptcha_response_field') |
1024 | - email = request.POST.get('email', '') |
1025 | - ip_addr = request.environ["REMOTE_ADDR"] |
1026 | - try: |
1027 | - timer_fn = get_request_timing_function(request) |
1028 | - verified = captcha.verify(captcha_solution, ip_addr, email, |
1029 | - timer=timer_fn) |
1030 | - if verified: |
1031 | - return None |
1032 | - except VerifyCaptchaError: |
1033 | - logger.exception("reCaptcha connection error") |
1034 | - |
1035 | - # not verified |
1036 | - return render( |
1037 | - request, |
1038 | - template, |
1039 | - add_captcha_settings({ |
1040 | - 'form': form, |
1041 | - 'captcha_error': ('&error=%s' % captcha.message), |
1042 | - 'captcha_required': True})) |
1043 | - |
1044 | - |
1045 | @require_twofactor_authenticated( |
1046 | _("Please log in to use this confirmation code")) |
1047 | def confirm_email(request, authtoken, email_address, token=None): |
1048 | |
1049 | === modified file 'src/webui/views/utils.py' |
1050 | --- src/webui/views/utils.py 2015-05-08 19:25:27 +0000 |
1051 | +++ src/webui/views/utils.py 2018-10-16 20:29:23 +0000 |
1052 | @@ -43,10 +43,3 @@ |
1053 | def set_session_email(session, email): |
1054 | """Place information about the current token's email in the session""" |
1055 | session['token_email'] = email |
1056 | - |
1057 | - |
1058 | -def add_captcha_settings(context): |
1059 | - d = {'CAPTCHA_PUBLIC_KEY': settings.CAPTCHA_PUBLIC_KEY, |
1060 | - 'CAPTCHA_API_URL_SECURE': settings.CAPTCHA_API_URL_SECURE} |
1061 | - d.update(context) |
1062 | - return d |