def clean_password(self): """Enforce password policies (if applicable)""" password = self.cleaned_data["password"] if ( self.enforce_username_neq_password and "username" in self.cleaned_data and self.cleaned_data["username"] == password ): raise ValidationError(_("Username and password fields cannot match")) if self.enforce_password_policy: try: validate_password_length(password) validate_password_complexity(password) validate_password_dictionary(password) except ValidationError, err: raise ValidationError(_("Password: "******"; ".join(err.messages))
def create_account( request, post_override=None): # pylint: disable-msg=too-many-statements """ JSON call to create new edX account. Used by form in signup_modal.html, which is included into navigation.html """ js = {'success': False} # pylint: disable-msg=invalid-name post_vars = post_override if post_override else request.POST # allow for microsites to define their own set of required/optional/hidden fields extra_fields = microsite.get_value( 'REGISTRATION_EXTRA_FIELDS', getattr(settings, 'REGISTRATION_EXTRA_FIELDS', {})) if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH') and pipeline.running( request): post_vars = dict(post_vars.items()) post_vars.update({'password': pipeline.make_random_password()}) # if doing signup for an external authorization, then get email, password, name from the eamap # don't use the ones from the form, since the user could have hacked those # unless originally we didn't get a valid email or name from the external auth DoExternalAuth = 'ExternalAuthMap' in request.session if DoExternalAuth: eamap = request.session['ExternalAuthMap'] try: validate_email(eamap.external_email) email = eamap.external_email except ValidationError: email = post_vars.get('email', '') if eamap.external_name.strip() == '': name = post_vars.get('name', '') else: name = eamap.external_name password = eamap.internal_password post_vars = dict(post_vars.items()) post_vars.update(dict(email=email, name=name, password=password)) log.debug(u'In create_account with external_auth: user = %s, email=%s', name, email) # Confirm we have a properly formed request for a in ['username', 'email', 'password', 'name']: if a not in post_vars: js['value'] = _("Error (401 {field}). E-mail us.").format(field=a) js['field'] = a return JsonResponse(js, status=400) if extra_fields.get('honor_code', 'required') == 'required' and \ post_vars.get('honor_code', 'false') != u'true': js['value'] = _("To enroll, you must follow the honor code.").format( field=a) js['field'] = 'honor_code' return JsonResponse(js, status=400) # Can't have terms of service for certain SHIB users, like at Stanford tos_required = (not settings.FEATURES.get("AUTH_USE_SHIB") or not settings.FEATURES.get("SHIB_DISABLE_TOS") or not DoExternalAuth or not eamap.external_domain.startswith( external_auth.views.SHIBBOLETH_DOMAIN_PREFIX)) if tos_required: if post_vars.get('terms_of_service', 'false') != u'true': js['value'] = _("You must accept the terms of service.").format( field=a) js['field'] = 'terms_of_service' return JsonResponse(js, status=400) # Confirm appropriate fields are there. # TODO: Check e-mail format is correct. # TODO: Confirm e-mail is not from a generic domain (mailinator, etc.)? Not sure if # this is a good idea # TODO: Check password is sane required_post_vars = ['username', 'email', 'name', 'password'] required_post_vars += [ fieldname for fieldname, val in extra_fields.items() if val == 'required' ] if tos_required: required_post_vars.append('terms_of_service') for field_name in required_post_vars: if field_name in ('gender', 'level_of_education'): min_length = 1 else: min_length = 2 if field_name not in post_vars or len( post_vars[field_name]) < min_length: error_str = { 'username': _('Username must be minimum of two characters long'), 'email': _('A properly formatted e-mail is required'), 'name': _('Your legal name must be a minimum of two characters long'), 'password': _('A valid password is required'), 'terms_of_service': _('Accepting Terms of Service is required'), 'honor_code': _('Agreeing to the Honor Code is required'), 'level_of_education': _('A level of education is required'), 'gender': _('Your gender is required'), 'year_of_birth': _('Your year of birth is required'), 'mailing_address': _('Your mailing address is required'), 'goals': _('A description of your goals is required'), 'city': _('A city is required'), 'country': _('A country is required') } if field_name in error_str: js['value'] = error_str[field_name] else: js['value'] = _('You are missing one or more required fields') js['field'] = field_name return JsonResponse(js, status=400) max_length = 75 if field_name == 'username': max_length = 30 if field_name in ('email', 'username') and len( post_vars[field_name]) > max_length: error_str = { 'username': _('Username cannot be more than {0} characters long').format( max_length), 'email': _('Email cannot be more than {0} characters long').format( max_length) } js['value'] = error_str[field_name] js['field'] = field_name return JsonResponse(js, status=400) try: validate_email(post_vars['email']) email_domain = post_vars['email'].split('@')[-1] white_list_domain = settings.FEATURES.get('WHITE_LIST_DOMAIN', []) mth = [x for x in white_list_domain if re.search(x, email_domain)] if not mth: raise ValidationError(_(u'Enter a valid e-mail.'), code='invalid') except ValidationError: js['value'] = _("Valid e-mail is required.").format(field=a) js['field'] = 'email' return JsonResponse(js, status=400) try: validate_slug(post_vars['username']) except ValidationError: js['value'] = _( "Username should only consist of A-Z and 0-9, with no spaces." ).format(field=a) js['field'] = 'username' return JsonResponse(js, status=400) # enforce password complexity as an optional feature # but not if we're doing ext auth b/c those pws never get used and are auto-generated so might not pass validation if settings.FEATURES.get('ENFORCE_PASSWORD_POLICY', False) and not DoExternalAuth: try: password = post_vars['password'] validate_password_length(password) validate_password_complexity(password) validate_password_dictionary(password) except ValidationError, err: js['value'] = _('Password: '******'; '.join(err.messages) js['field'] = 'password' return JsonResponse(js, status=400)