Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fire signal when password verification fails #230

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/includes/signals.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
15 changes: 15 additions & 0 deletions docs/source/recipes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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()
12 changes: 9 additions & 3 deletions flask_user/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()


Expand Down Expand Up @@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that more appropriate place for this code is somewhere around here. Actually user_logged_in is sent from that file too. So to not place this events (user logged in and authentication failed) too far from each other I would prefer both of them to be fired from user_manager__views.py.


# Handle unsuccessful authentication
# Email, Username or Email/Username depending on settings
Expand Down
3 changes: 3 additions & 0 deletions flask_user/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down