Commit 110714ee by Braden MacDonald

Allow each instance to configure restrictions on allowed email addresses

parent dfbcd84e
......@@ -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"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment