예제 #1
0
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))
예제 #2
0
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})
예제 #3
0
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
예제 #5
0
 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)
예제 #6
0
    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)
예제 #7
0
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)
예제 #8
0
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)
예제 #9
0
    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
예제 #10
0
    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})