Allow each instance to configure restrictions on allowed email addresses
This commit is contained in:
@@ -150,6 +150,8 @@ SESSION_SAVE_EVERY_REQUEST = ENV_TOKENS.get('SESSION_SAVE_EVERY_REQUEST', SESSIO
|
||||
# social sharing settings
|
||||
SOCIAL_SHARING_SETTINGS = ENV_TOKENS.get('SOCIAL_SHARING_SETTINGS', SOCIAL_SHARING_SETTINGS)
|
||||
|
||||
REGISTRATION_EMAIL_PATTERNS_ALLOWED = ENV_TOKENS.get('REGISTRATION_EMAIL_PATTERNS_ALLOWED')
|
||||
|
||||
# allow for environments to specify what cookie name our login subsystem should use
|
||||
# this is to fix a bug regarding simultaneous logins between edx.org and edge.edx.org which can
|
||||
# happen with some browsers (e.g. Firefox)
|
||||
|
||||
@@ -32,7 +32,7 @@ import lms.envs.common
|
||||
from lms.envs.common import (
|
||||
USE_TZ, TECH_SUPPORT_EMAIL, PLATFORM_NAME, BUGS_EMAIL, DOC_STORE_CONFIG, DATA_DIR, ALL_LANGUAGES, WIKI_ENABLED,
|
||||
update_module_store_settings, ASSET_IGNORE_REGEX, COPYRIGHT_YEAR,
|
||||
PARENTAL_CONSENT_AGE_LIMIT, COMPREHENSIVE_THEME_DIR,
|
||||
PARENTAL_CONSENT_AGE_LIMIT, COMPREHENSIVE_THEME_DIR, REGISTRATION_EMAIL_PATTERNS_ALLOWED,
|
||||
# The following PROFILE_IMAGE_* settings are included as they are
|
||||
# indirectly accessed through the email opt-in API, which is
|
||||
# technically accessible through the CMS via legacy URLs.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Utility functions for validating forms
|
||||
"""
|
||||
from importlib import import_module
|
||||
import re
|
||||
|
||||
from django import forms
|
||||
from django.forms import widgets
|
||||
@@ -17,6 +18,7 @@ from django.template import loader
|
||||
|
||||
from django.conf import settings
|
||||
from microsite_configuration import microsite
|
||||
from student.models import CourseEnrollmentAllowed
|
||||
from util.password_policy_validators import (
|
||||
validate_password_length,
|
||||
validate_password_complexity,
|
||||
@@ -227,6 +229,22 @@ class AccountCreationForm(forms.Form):
|
||||
raise ValidationError(_("Password: ") + "; ".join(err.messages))
|
||||
return password
|
||||
|
||||
def clean_email(self):
|
||||
""" Enforce email restrictions (if applicable) """
|
||||
email = self.cleaned_data["email"]
|
||||
if settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED is not None:
|
||||
# This Open edX instance has restrictions on what email addresses are allowed.
|
||||
allowed_patterns = settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED
|
||||
# We append a '$' to the regexs to prevent the common mistake of using a
|
||||
# pattern like '.*@edx\\.org' which would match 'bob@edx.org.badguy.com'
|
||||
if not any(re.match(pattern + "$", email) for pattern in allowed_patterns):
|
||||
# This email is not on the whitelist of allowed emails. Check if
|
||||
# they may have been manually invited by an instructor and if not,
|
||||
# reject the registration.
|
||||
if not CourseEnrollmentAllowed.objects.filter(email=email).exists():
|
||||
raise ValidationError(_("Unauthorized email address."))
|
||||
return email
|
||||
|
||||
def clean_year_of_birth(self):
|
||||
"""
|
||||
Parse year_of_birth to an integer, but just use None instead of raising
|
||||
|
||||
@@ -373,6 +373,36 @@ class TestCreateAccountValidation(TestCase):
|
||||
params["email"] = "not_an_email_address"
|
||||
assert_email_error("A properly formatted e-mail is required")
|
||||
|
||||
@override_settings(
|
||||
REGISTRATION_EMAIL_PATTERNS_ALLOWED=[
|
||||
r'.*@edx.org', # Naive regex omitting '^', '$' and '\.' should still work.
|
||||
r'^.*@(.*\.)?example\.com$',
|
||||
r'^(^\w+\.\w+)@school.tld$',
|
||||
]
|
||||
)
|
||||
@ddt.data(
|
||||
('bob@we-are.bad', False),
|
||||
('bob@edx.org.we-are.bad', False),
|
||||
('staff@edx.org', True),
|
||||
('student@example.com', True),
|
||||
('student@sub.example.com', True),
|
||||
('mr.teacher@school.tld', True),
|
||||
('student1234@school.tld', False),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_email_pattern_requirements(self, email, expect_success):
|
||||
"""
|
||||
Test the REGISTRATION_EMAIL_PATTERNS_ALLOWED setting, a feature which
|
||||
can be used to only allow people register if their email matches a
|
||||
against a whitelist of regexs.
|
||||
"""
|
||||
params = dict(self.minimal_params)
|
||||
params["email"] = email
|
||||
if expect_success:
|
||||
self.assert_success(params)
|
||||
else:
|
||||
self.assert_error(params, "email", "Unauthorized email address.")
|
||||
|
||||
def test_password(self):
|
||||
params = dict(self.minimal_params)
|
||||
|
||||
|
||||
@@ -159,6 +159,7 @@ SESSION_SAVE_EVERY_REQUEST = ENV_TOKENS.get('SESSION_SAVE_EVERY_REQUEST', SESSIO
|
||||
|
||||
REGISTRATION_EXTRA_FIELDS = ENV_TOKENS.get('REGISTRATION_EXTRA_FIELDS', REGISTRATION_EXTRA_FIELDS)
|
||||
REGISTRATION_EXTENSION_FORM = ENV_TOKENS.get('REGISTRATION_EXTENSION_FORM', REGISTRATION_EXTENSION_FORM)
|
||||
REGISTRATION_EMAIL_PATTERNS_ALLOWED = ENV_TOKENS.get('REGISTRATION_EMAIL_PATTERNS_ALLOWED')
|
||||
|
||||
# Set the names of cookies shared with the marketing site
|
||||
# These have the same cookie domain as the session, which in production
|
||||
|
||||
@@ -2136,6 +2136,10 @@ REGISTRATION_EXTRA_FIELDS = {
|
||||
'country': 'hidden',
|
||||
}
|
||||
|
||||
# Optional setting to restrict registration / account creation to only emails
|
||||
# that match a regex in this list. Set to None to allow any email (default).
|
||||
REGISTRATION_EMAIL_PATTERNS_ALLOWED = None
|
||||
|
||||
########################## CERTIFICATE NAME ########################
|
||||
CERT_NAME_SHORT = "Certificate"
|
||||
CERT_NAME_LONG = "Certificate of Achievement"
|
||||
|
||||
Reference in New Issue
Block a user