From 94ff4506a347429596a7c4268b1ead7474fa87b7 Mon Sep 17 00:00:00 2001 From: Ryan James Date: Tue, 14 Aug 2018 12:41:56 -0700 Subject: [PATCH] Fire signal when user attempts to login with invalid password (#1) * Fire signal when user attempts to login with invalid password --- docs/source/includes/signals.txt | 1 + docs/source/recipes.rst | 15 +++++++++++++++ flask_user/forms.py | 12 +++++++++--- flask_user/signals.py | 3 +++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/source/includes/signals.txt b/docs/source/includes/signals.txt index 0e761318..716d8671 100644 --- a/docs/source/includes/signals.txt +++ b/docs/source/includes/signals.txt @@ -7,5 +7,6 @@ user_forgot_password # a user submitted a reset password request user_logged_in # a user logged in user_logged_out # a user logged out + user_password_failed # a user attempted to login but password verification failed user_registered # a user registered for a new account user_reset_password # a user reset their password (forgot password) diff --git a/docs/source/recipes.rst b/docs/source/recipes.rst index 96d3232f..153e8d6c 100644 --- a/docs/source/recipes.rst +++ b/docs/source/recipes.rst @@ -80,3 +80,18 @@ Here's an example of tracking login_count and last_login_ip: user.last_login_ip = request.remote_addr db.session.commit() +Here's an example of tracking an invalid password login attempt: + +:: + # This code has not been tested + + from datetime import datetime + from flask import request + from flask_user.signals import user_password_failed + + @user_password_failed.connect_via(app) + def _track_invalid_password_login_attempts(sender, user, **extra): + user.failed_login_attempts += 1 + if user.failed_login_attempts >= 5: + user.lockout = True + db.session.commit() diff --git a/flask_user/forms.py b/flask_user/forms.py index 19b5316e..a7da92de 100644 --- a/flask_user/forms.py +++ b/flask_user/forms.py @@ -19,6 +19,7 @@ from wtforms import BooleanField, HiddenField, PasswordField, SubmitField, StringField from wtforms import validators, ValidationError +from . import signals from .translation_utils import lazy_gettext as _ # map _() to lazy_gettext() @@ -198,9 +199,14 @@ def validate(self): # Find user by email address (email field) user, user_email = user_manager.db_manager.get_user_and_user_email_by_email(self.email.data) - # Handle successful authentication - if user and user_manager.verify_password(self.password.data, user.password): - return True # Successful authentication + if user: + # Handle successful authentication + if user_manager.verify_password(self.password.data, user.password): + return True # Successful authentication + + # Send user_password_failed signal + else: + signals.user_password_failed.send(current_app._get_current_object(), user=user) # Handle unsuccessful authentication # Email, Username or Email/Username depending on settings diff --git a/flask_user/signals.py b/flask_user/signals.py index a1d4c50d..5d974ad0 100644 --- a/flask_user/signals.py +++ b/flask_user/signals.py @@ -36,6 +36,9 @@ # Sent when a user logged out user_logged_out = _signals.signal('user.user_logged_out') +# Sent when a user attempted to login and password verification failed +user_password_failed = _signals.signal('user.password_failed') + # Sent when a user registered a new account user_registered = _signals.signal('user.user_registered')