Projet

Général

Profil

0002-misc-use-email-domain-validation-40200.patch

Valentin Deniaud, 05 mars 2020 15:45

Télécharger (14,6 ko)

Voir les différences:

Subject: [PATCH 2/2] misc: use email domain validation (#40200)

 src/authentic2/forms/fields.py       |  9 +++++++-
 src/authentic2/forms/passwords.py    |  4 ++--
 src/authentic2/forms/profile.py      | 13 ++++++++---
 src/authentic2/forms/registration.py |  5 +++--
 src/authentic2/manager/forms.py      |  4 ++--
 tests/settings.py                    |  2 ++
 tests/test_manager.py                | 21 ++++++++++++++++++
 tests/test_registration.py           | 32 ++++++++++++++++------------
 tests/utils.py                       |  9 --------
 9 files changed, 66 insertions(+), 33 deletions(-)
src/authentic2/forms/fields.py
17 17
import warnings
18 18
import io
19 19

  
20
from django.forms import CharField, FileField, ValidationError
20
from django.forms import CharField, FileField, ValidationError, EmailField
21 21
from django.forms.fields import FILE_INPUT_CONTRADICTION
22 22
from django.utils.translation import ugettext_lazy as _
23 23
from django.core.files import File
......
26 26
from authentic2.passwords import password_help_text, validate_password
27 27
from authentic2.forms.widgets import (PasswordInput, NewPasswordInput,
28 28
                                      CheckPasswordInput, ProfileImageInput)
29
from authentic2.validators import email_validator
29 30

  
30 31
import PIL.Image
31 32

  
......
111 112

  
112 113
            image = image.crop(box)
113 114
        return image.resize([width, height], PIL.Image.ANTIALIAS)
115

  
116

  
117
class ValidatedEmailField(EmailField):
118
    def validate(self, value):
119
        super(ValidatedEmailField, self).validate(value)
120
        email_validator(value)
src/authentic2/forms/passwords.py
25 25

  
26 26
from .. import models, hooks, app_settings, utils
27 27
from ..backends import get_user_queryset
28
from .fields import PasswordField, NewPasswordField, CheckPasswordField
28
from .fields import PasswordField, NewPasswordField, CheckPasswordField, ValidatedEmailField
29 29
from .utils import NextUrlFormMixin
30 30

  
31 31

  
......
35 35
class PasswordResetForm(forms.Form):
36 36
    next_url = forms.CharField(widget=forms.HiddenInput, required=False)
37 37

  
38
    email = forms.EmailField(
38
    email = ValidatedEmailField(
39 39
        label=_("Email"), max_length=254)
40 40

  
41 41
    def save(self):
src/authentic2/forms/profile.py
20 20
from django import forms
21 21
from django.utils.translation import ugettext_lazy as _, ugettext
22 22

  
23
from ..custom_user.models import User
24
from .. import app_settings, models
23
from authentic2 import app_settings, models
24
from authentic2.custom_user.models import User
25
from authentic2.validators import email_validator
25 26
from .utils import NextUrlFormMixin
26 27
from .mixins import LockedFieldFormMixin
28
from .fields import ValidatedEmailField
27 29

  
28 30

  
29 31
class DeleteAccountForm(forms.Form):
......
41 43

  
42 44

  
43 45
class EmailChangeFormNoPassword(forms.Form):
44
    email = forms.EmailField(label=_('New email'))
46
    email = ValidatedEmailField(label=_('New email'))
45 47

  
46 48
    def __init__(self, user, *args, **kwargs):
47 49
        self.user = user
......
122 124
            self.save_m2m = save_m2m
123 125
        return result
124 126

  
127
    def clean_email(self):
128
        email = self.cleaned_data['email']
129
        email_validator(email)
130
        return email
131

  
125 132

  
126 133
class EditProfileForm(NextUrlFormMixin, BaseUserForm):
127 134
    pass
src/authentic2/forms/registration.py
19 19
from django.contrib.auth import get_user_model
20 20
from django.core.exceptions import ValidationError
21 21
from django.utils.translation import ugettext_lazy as _, ugettext
22
from django.forms import Form, EmailField
22
from django.forms import Form
23 23

  
24 24
from django.contrib.auth.models import BaseUserManager, Group
25 25

  
......
28 28

  
29 29
from .. import app_settings, models
30 30
from . import profile as profile_forms
31
from .fields import ValidatedEmailField
31 32

  
32 33
User = get_user_model()
33 34

  
......
36 37
    error_css_class = 'form-field-error'
37 38
    required_css_class = 'form-field-required'
38 39

  
39
    email = EmailField(label=_('Email'))
40
    email = ValidatedEmailField(label=_('Email'))
40 41

  
41 42
    def __init__(self, *args, **kwargs):
42 43
        super(RegistrationForm, self).__init__(*args, **kwargs)
src/authentic2/manager/forms.py
29 29

  
30 30
from authentic2.passwords import generate_password
31 31
from authentic2.utils import send_templated_mail
32
from authentic2.forms.fields import NewPasswordField, CheckPasswordField
32
from authentic2.forms.fields import NewPasswordField, CheckPasswordField, ValidatedEmailField
33 33

  
34 34
from django_rbac.models import Operation
35 35
from django_rbac.utils import get_ou_model, get_role_model, get_permission_model
......
678 678
# we need a model form so that we can use a BaseEditView, a simple Form
679 679
# would not work
680 680
class UserChangeEmailForm(CssClass, FormWithRequest, forms.ModelForm):
681
    new_email = forms.EmailField(label=_('Email'))
681
    new_email = ValidatedEmailField(label=_('Email'))
682 682

  
683 683
    def __init__(self, *args, **kwargs):
684 684
        initial = kwargs.setdefault('initial', {})
tests/settings.py
42 42
ALLOWED_HOSTS = ALLOWED_HOSTS + ['example.net', 'cache1.example.com', 'cache2.example.com']
43 43

  
44 44
A2_AUTH_KERBEROS_ENABLED = False
45

  
46
A2_VALIDATE_EMAIL_DOMAIN = False
tests/test_manager.py
24 24
from webtest import Upload
25 25

  
26 26
from authentic2.a2_rbac.utils import get_default_ou
27
from authentic2.validators import EmailValidator
27 28

  
28 29
from django_rbac.utils import get_ou_model, get_role_model
29 30
from django.contrib.auth import get_user_model
......
293 294
    assert urlparse(resp['Location']).path == url2
294 295

  
295 296

  
297
def test_manager_create_user_email_validation(superuser_or_admin, app, settings, monkeypatch):
298
    settings.A2_VALIDATE_EMAIL_DOMAIN = True
299
    monkeypatch.setattr(EmailValidator, 'check_mxs', lambda x, y: [])
300
    ou1 = OU.objects.create(name='OU1', slug='ou1')
301

  
302
    url = reverse('a2-manager-user-add', kwargs={'ou_pk': ou1.pk})
303
    resp = login(app, superuser_or_admin, url)
304
    resp.form.set('first_name', 'John')
305
    resp.form.set('last_name', 'Doe')
306
    resp.form.set('email', 'john.doe@entrouvert.com')
307
    resp.form.set('password1', 'ABcd1234')
308
    resp.form.set('password2', 'ABcd1234')
309
    resp = resp.form.submit()
310
    assert 'domain is invalid' in resp.text
311

  
312
    monkeypatch.setattr(EmailValidator, 'check_mxs', lambda x, y: ['mx1.entrouvert.org'])
313
    resp.form.submit()
314
    assert User.objects.filter(email='john.doe@entrouvert.com').count() == 1
315

  
316

  
296 317
def test_app_setting_login_url(app, settings):
297 318
    settings.A2_MANAGER_LOGIN_URL = '/other_login/'
298 319
    response = app.get('/manage/')
tests/test_registration.py
23 23
from django.utils.six.moves.urllib.parse import urlparse
24 24

  
25 25
from authentic2 import utils, models
26
from authentic2.validators import EmailValidator
26 27

  
27
from utils import can_resolve_dns, get_link_from_mail
28
from utils import get_link_from_mail
28 29

  
29 30

  
30 31
def test_registration(app, db, settings, mailoutbox, external_redirect):
31 32
    next_url, good_next_url = external_redirect
32 33

  
33 34
    settings.LANGUAGE_CODE = 'en-us'
34
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
35 35
    settings.DEFAULT_FROM_EMAIL = 'show only addr <noreply@example.net>'
36 36

  
37 37
    # disable existing attributes
......
102 102

  
103 103
def test_registration_realm(app, db, settings, mailoutbox):
104 104
    settings.LANGUAGE_CODE = 'en-us'
105
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
106 105
    settings.A2_REGISTRATION_REALM = 'realm'
107 106
    settings.A2_REDIRECT_WHITELIST = ['http://relying-party.org/']
108 107
    settings.A2_REQUIRED_FIELDS = ['username']
......
156 155
    assert urlparse(response['Location']).path == reverse('auth_homepage')
157 156

  
158 157

  
158
def test_registration_email_validation(app, db, monkeypatch, settings):
159
    settings.A2_VALIDATE_EMAIL_DOMAIN = True
160
    monkeypatch.setattr(EmailValidator, 'check_mxs', lambda x, y: ['mx1.entrouvert.org'])
161

  
162
    resp = app.get(reverse('registration_register'))
163
    resp.form.set('email', 'testbot@entrouvert.com')
164
    resp = resp.form.submit().follow()
165
    assert 'Follow the instructions' in resp.text
166

  
167
    monkeypatch.setattr(EmailValidator, 'check_mxs', lambda x, y: [])
168
    resp = app.get(reverse('registration_register'))
169
    resp.form.set('email', 'testbot@entrouvert.com')
170
    resp = resp.form.submit()
171
    assert 'domain is invalid' in resp.text
172

  
173

  
159 174
def test_username_settings(app, db, settings, mailoutbox):
160 175
    settings.LANGUAGE_CODE = 'en-us'
161
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
162 176
    settings.A2_REGISTRATION_FORM_USERNAME_REGEX = r'^(ab)+$'
163 177
    settings.A2_REGISTRATION_FORM_USERNAME_LABEL = 'Identifiant'
164 178
    settings.A2_REGISTRATION_FORM_USERNAME_HELP_TEXT = 'Bien remplir'
......
213 227

  
214 228
def test_username_is_unique(app, db, settings, mailoutbox):
215 229
    settings.LANGUAGE_CODE = 'en-us'
216
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
217 230
    settings.A2_REGISTRATION_FIELDS = ['username']
218 231
    settings.A2_REQUIRED_FIELDS = ['username']
219 232
    settings.A2_USERNAME_IS_UNIQUE = True
......
261 274

  
262 275
def test_email_is_unique(app, db, settings, mailoutbox):
263 276
    settings.LANGUAGE_CODE = 'en-us'
264
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
265 277
    settings.A2_EMAIL_IS_UNIQUE = True
266 278

  
267 279
    # disable existing attributes
......
307 319

  
308 320
def test_attribute_model(app, db, settings, mailoutbox):
309 321
    settings.LANGUAGE_CODE = 'en-us'
310
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
311 322
    # disable existing attributes
312 323
    models.Attribute.objects.update(disabled=True)
313 324

  
......
400 411

  
401 412

  
402 413
def test_registration_bad_email(app, db, settings):
403
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
404 414
    settings.LANGUAGE_CODE = 'en-us'
405 415

  
406 416
    response = app.post(reverse('registration_register'), params={'email': 'fred@0d..be'},
......
455 465

  
456 466
def test_revalidate_email(app, rf, db, settings, mailoutbox):
457 467
    settings.LANGUAGE_CODE = 'en-us'
458
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
459 468

  
460 469
    # disable existing attributes
461 470
    models.Attribute.objects.update(disabled=True)
......
482 491

  
483 492
def test_email_is_unique_multiple_objects_returned(app, db, settings, mailoutbox, rf):
484 493
    settings.LANGUAGE_CODE = 'en-us'
485
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
486 494
    settings.A2_REGISTRATION_EMAIL_IS_UNIQUE = True
487 495

  
488 496
    # Create two user objects
......
506 514

  
507 515
def test_username_is_unique_multiple_objects_returned(app, db, settings, mailoutbox, rf):
508 516
    settings.LANGUAGE_CODE = 'en-us'
509
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
510 517
    settings.A2_REGISTRATION_USERNAME_IS_UNIQUE = True
511 518
    settings.A2_REQUIRED_FIELDS = ['username', 'first_name', 'last_name']
512 519

  
......
535 542

  
536 543
    settings.A2_REGISTRATION_REDIRECT = 'http://cms/welcome/'
537 544
    settings.LANGUAGE_CODE = 'en-us'
538
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
539 545

  
540 546
    new_next_url = settings.A2_REGISTRATION_REDIRECT
541 547
    if good_next_url:
......
590 596
    next_url, good_next_url = external_redirect
591 597

  
592 598
    settings.A2_REGISTRATION_REDIRECT = 'http://cms/welcome/', 'target'
593
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
594 599

  
595 600
    new_next_url = settings.A2_REGISTRATION_REDIRECT[0]
596 601
    if good_next_url:
......
614 619

  
615 620
def test_registration_activate_passwords_not_equal(app, db, settings, mailoutbox):
616 621
    settings.LANGUAGE_CODE = 'en-us'
617
    settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
618 622
    settings.A2_EMAIL_IS_UNIQUE = True
619 623

  
620 624
    response = app.get(reverse('registration_register'))
tests/utils.py
162 162
        '%r not found in log records' % message
163 163

  
164 164

  
165
def can_resolve_dns():
166
    '''Verify that DNS resolving is available'''
167
    import socket
168
    try:
169
        return isinstance(socket.gethostbyname('entrouvert.com'), str)
170
    except:
171
        return False
172

  
173

  
174 165
def get_links_from_mail(mail):
175 166
    '''Extract links from mail sent by Django'''
176 167
    return re.findall('https?://[^ \n]*', mail.body)
177
-