def _validate_password(password, username=None, email=None): """Validate the format of the user's password. Passwords cannot be the same as the username of the account, so we create a temp_user using the username and email to test the password against. This user is never saved. Arguments: password (unicode): The proposed password. username (unicode): The username associated with the user's account. email (unicode): The email associated with the user's account. Returns: None Raises: errors.AccountPasswordInvalid """ try: _validate_type(password, six.string_types, accounts.PASSWORD_BAD_TYPE_MSG) temp_user = User(username=username, email=email) if username else None validate_password(password, user=temp_user) except errors.AccountDataBadType as invalid_password_err: raise errors.AccountPasswordInvalid(text_type(invalid_password_err)) except ValidationError as validation_err: raise errors.AccountPasswordInvalid(' '.join(validation_err.messages))
def password_reset_logistration(request, **kwargs): """Reset learner password using passed token and new credentials""" reset_status = False uidb36 = kwargs.get('uidb36') token = kwargs.get('token') has_required_values, uid_int = _check_token_has_required_values(uidb36, token) if not has_required_values: AUDIT_LOG.exception("Invalid password reset confirm token") return JsonResponse({'reset_status': reset_status}) request.POST = request.POST.copy() request.POST['new_password1'] = normalize_password(request.POST['new_password1']) request.POST['new_password2'] = normalize_password(request.POST['new_password2']) password = request.POST['new_password1'] try: user = User.objects.get(id=uid_int) if not default_token_generator.check_token(user, token): AUDIT_LOG.exception("Token validation failed") return JsonResponse({'reset_status': reset_status}) validate_password(password, user=user) form = SetPasswordForm(user, request.POST) if form.is_valid(): form.save() reset_status = True if 'is_account_recovery' in request.GET: try: old_primary_email = user.email user.email = user.account_recovery.secondary_email user.account_recovery.delete() # emit an event that the user changed their secondary email to the primary email tracker.emit( SETTING_CHANGE_INITIATED, { "setting": "email", "old": old_primary_email, "new": user.email, "user_id": user.id, } ) user.save() send_password_reset_success_email(user, request) except ObjectDoesNotExist: log.error('Account recovery process initiated without AccountRecovery instance for user {username}' .format(username=user.username)) except ValidationError as err: AUDIT_LOG.exception("Password validation failed") error_status = { 'reset_status': reset_status, 'err_msg': ' '.join(err.messages) } return JsonResponse(error_status) except Exception: # pylint: disable=broad-except AUDIT_LOG.exception("Setting new password failed") return JsonResponse({'reset_status': reset_status})
def _check_user_compliance(user, password): """ Returns a boolean indicating whether or not the user is compliant with password policy rules. """ try: validate_password(password, user=user) return True except Exception: # pylint: disable=broad-except # If anything goes wrong, we should assume the password is not compliant but we don't necessarily # need to prevent login. return False
def clean_password(self): """Enforce password policies (if applicable)""" password = self.cleaned_data["password"] if not self.do_third_party_auth: # Creating a temporary user object to test password against username # This user should NOT be saved username = self.cleaned_data.get('username') email = self.cleaned_data.get('email') temp_user = User(username=username, email=email) if username else None validate_password(password, temp_user) return password
def _validate_password(self, password, request): # lint-amnesty, pylint: disable=missing-function-docstring try: validate_password(password, user=self.user) except ValidationError as err: context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': ' '.join(err.messages), } context.update(self.platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context)
def validation_errors_checker(self, password, msg, user=None): """ This helper function is used to check the proper error messages are being displayed based on the password and validator. Parameters: password (unicode): the password to validate on user (django.contrib.auth.models.User): user object to use in validation. This is an optional parameter unless the validator requires a user object. msg (str): The expected ValidationError message """ if msg is None: validate_password(password, user) else: with pytest.raises(ValidationError) as cm: validate_password(password, user) assert msg in ' '.join(cm.value.messages)
def _validate_password(password, username=None, email=None, reset_password_page=False): """Validate the format of the user's password. Passwords cannot be the same as the username of the account, so we create a temp_user using the username and email to test the password against. This user is never saved. Arguments: password (unicode): The proposed password. username (unicode): The username associated with the user's account. email (unicode): The email associated with the user's account. reset_password_page (bool): The flag that determines the validation page. Returns: None Raises: errors.AccountPasswordInvalid """ try: _validate_type(password, str, accounts.PASSWORD_BAD_TYPE_MSG) temp_user = User(username=username, email=email) if username else None validate_password(password, user=temp_user) except errors.AccountDataBadType as invalid_password_err: raise errors.AccountPasswordInvalid(str(invalid_password_err)) except ValidationError as validation_err: raise errors.AccountPasswordInvalid(' '.join(validation_err.messages)) if ((settings.ENABLE_AUTHN_RESET_PASSWORD_HIBP_POLICY and reset_password_page) or (settings.ENABLE_AUTHN_REGISTER_HIBP_POLICY and not reset_password_page)): pwned_response = check_pwned_password(password) if pwned_response.get('vulnerability', 'no') == 'yes': if (reset_password_page or pwned_response.get('frequency', 0) >= settings.HIBP_REGISTRATION_PASSWORD_FREQUENCY_THRESHOLD): raise errors.AccountPasswordInvalid( accounts.AUTHN_PASSWORD_COMPROMISED_MSG)
def _validate_password(password, username=None, email=None, reset_password_page=False): """Validate the format of the user's password. Passwords cannot be the same as the username of the account, so we create a temp_user using the username and email to test the password against. This user is never saved. Arguments: password (unicode): The proposed password. username (unicode): The username associated with the user's account. email (unicode): The email associated with the user's account. reset_password_page (bool): The flag that determines the validation page. Returns: None Raises: errors.AccountPasswordInvalid """ try: _validate_type(password, str, accounts.PASSWORD_BAD_TYPE_MSG) temp_user = User(username=username, email=email) if username else None validate_password(password, user=temp_user) except errors.AccountDataBadType as invalid_password_err: raise errors.AccountPasswordInvalid(str(invalid_password_err)) except ValidationError as validation_err: raise errors.AccountPasswordInvalid(' '.join(validation_err.messages)) # TODO: VAN-666 - Restrict this feature to reset password page for now until it is # enabled on account sign in and register. if settings.ENABLE_AUTHN_RESET_PASSWORD_HIBP_POLICY and reset_password_page: pwned_response = check_pwned_password(password) if pwned_response.get('vulnerability', 'no') == 'yes': raise errors.AccountPasswordInvalid( accounts.AUTHN_PASSWORD_COMPROMISED_MSG)
def clean_password(self): """Enforce password policies (if applicable)""" password = self.cleaned_data["password"] if not self.do_third_party_auth: # Creating a temporary user object to test password against username # This user should NOT be saved username = self.cleaned_data.get('username') email = self.cleaned_data.get('email') temp_user = User(username=username, email=email) if username else None validate_password(password, temp_user) if settings.ENABLE_AUTHN_REGISTER_HIBP_POLICY: # Checks the Pwned Databases for password vulnerability. pwned_response = check_pwned_password(password) if (pwned_response.get('vulnerability', 'no') == 'yes' and pwned_response.get('frequency', 0) >= settings.HIBP_REGISTRATION_PASSWORD_FREQUENCY_THRESHOLD ): raise ValidationError( accounts.AUTHN_PASSWORD_COMPROMISED_MSG) return password
def post(self, request, **kwargs): """ Reset learner password using passed token and new credentials """ reset_status = False uidb36 = kwargs.get('uidb36') token = kwargs.get('token') has_required_values, uid_int = self._check_token_has_required_values( uidb36, token) if not has_required_values: AUDIT_LOG.exception("Invalid password reset confirm token") return Response({'reset_status': reset_status}) request.data._mutable = True # lint-amnesty, pylint: disable=protected-access request.data['new_password1'] = normalize_password( request.data['new_password1']) request.data['new_password2'] = normalize_password( request.data['new_password2']) password = request.data['new_password1'] try: user = User.objects.get(id=uid_int) if not default_token_generator.check_token(user, token): AUDIT_LOG.exception("Token validation failed") return Response({'reset_status': reset_status}) validate_password(password, user=user) if settings.ENABLE_AUTHN_RESET_PASSWORD_HIBP_POLICY: # Checks the Pwned Databases for password vulnerability. pwned_response = check_pwned_password(password) if pwned_response.get('vulnerability', 'no') == 'yes': error_status = { 'reset_status': reset_status, 'err_msg': accounts.AUTHN_PASSWORD_COMPROMISED_MSG } return Response(error_status) form = SetPasswordForm(user, request.data) if form.is_valid(): form.save() reset_status = True if 'is_account_recovery' in request.GET: try: old_primary_email = user.email user.email = user.account_recovery.secondary_email user.account_recovery.delete() # emit an event that the user changed their secondary email to the primary email tracker.emit( SETTING_CHANGE_INITIATED, { "setting": "email", "old": old_primary_email, "new": user.email, "user_id": user.id, }) user.save() except ObjectDoesNotExist: err = 'Account recovery process initiated without AccountRecovery instance for user {username}' log.error(err.format(username=user.username)) # Handles clearing the failed login counter upon password reset. if LoginFailures.is_feature_enabled(): LoginFailures.clear_lockout_counter(user) send_password_reset_success_email(user, request) update_session_auth_hash(request, user) except ValidationError as err: AUDIT_LOG.exception("Password validation failed") error_status = { 'reset_status': reset_status, 'err_msg': ' '.join(err.messages) } return Response(error_status) except Exception: # pylint: disable=broad-except AUDIT_LOG.exception("Setting new password failed") return Response({'reset_status': reset_status})