def clean(self): username = self.cleaned_data.get('username') password = self.cleaned_data.get('password') if username and password: self.user_cache = authenticate(username=username, password=password) key, timeout = generate_key(self.request, username, 'login') attempts, timeout = set_attempts_to_cache(key, timeout) if self.user_cache is None or attempts > 3 or ( settings.SECURITY_OWASP_AT_002 and not self.user_cache.is_active): if attempts > 3: logger.warning( 'Ignoring login request from user "%s", %s attempts lock will expire in %s seconds.', username, attempts, timeout) if not settings.SECURITY_OWASP_AT_002: self.error_messages['invalid_login'] = _( 'You made %(attempts)s wrong login attempts, all ' 'further attempts will be ignored for %(timeout)s ' 'seconds.') % { 'attempts': attempts, 'timeout': timeout } raise forms.ValidationError( self.error_messages['invalid_login'], code='invalid_login', params={'username': self.username_field.verbose_name}) elif not self.user_cache.is_active: raise forms.ValidationError(self.error_messages['inactive'], code='inactive') return self.cleaned_data
def clean_email(self, *args, **kwargs): """ We never raise an ValidationError, because user Enumeration and Guessable User Account OWASP-AT-002. Change this behaviour with settings.SECURITY_OWASP_AT_002. """ email = self.cleaned_data['email'] users = User.objects.filter( email__iexact=email, is_active=True).exclude(password=UNUSABLE_PASSWORD) self.users_cache = [] # Check for valid user: if users: key, timeout = generate_key(self.request, email, 'forgot') attempts, timeout = set_attempts_to_cache(key, timeout) # Don't allow a password reset if user is trying more than 2 time in calculated timeout if attempts > 2: logger.warning( 'Ignoring password reset request from user "%s", %s attempts lock will expire in %s ' 'seconds.', email, attempts, timeout) if settings.SECURITY_OWASP_AT_002: return email else: raise forms.ValidationError( _('You have requested password reset %(attempts)s times. ' 'All further attempts will be ignored for %(timeout)s ' 'seconds.') % { 'attempts': attempts, 'timeout': timeout }) else: logger.warning( 'Ignoring password reset request from invalid user "%s"', email) if settings.SECURITY_OWASP_AT_002: return email else: raise forms.ValidationError( _("That email address doesn't have an associated user account. Are you " "sure you've registered?")) # A valid user is part of a self.users_cache list used in save() # noinspection PyAttributeOutsideInit self.users_cache = users return email