diff --git a/api/main/auth.py b/api/main/auth.py index 93f14d86c..9a8d75087 100644 --- a/api/main/auth.py +++ b/api/main/auth.py @@ -46,10 +46,11 @@ def authenticate(self, request, username=None, password=None, **kwargs): user.save() lockout_lifted = user.last_failed_login + LOCKOUT_TIME time_left = lockout_lifted - now - msg = f" *SECURITY ALERT:* Attempt to login during lockout" - msg += f" User={user}/{user.id}" - msg += f" Attempt count = {user.failed_login_count}" - msg += f" Lockout will be lifted in '{time_left}' at '{lockout_lifted}'" + msg = ( + f" *SECURITY ALERT:* Attempt to login during lockout: User={user}/{user.id}, " + f" Attempt count = {user.failed_login_count}. Lockout will be lifted in " + f"'{time_left}' at '{lockout_lifted}'" + ) Notify.notify_admin_msg(msg) # Run the default password hasher once to reduce the timing # difference (#20760). @@ -59,30 +60,32 @@ def authenticate(self, request, username=None, password=None, **kwargs): if user.check_password(password) and self.user_can_authenticate(user): user.last_login = datetime.now(timezone.utc) if user.failed_login_count >= LOCKOUT_LIMIT: - msg = "Login proceeded after lock expiry" - msg += f" User={user}/{user.id}" + msg = "Login proceeded after lock expiry User={user}/{user.id}" Notify.notify_admin_msg(msg) user.failed_login_count = 0 user.save() return user - else: - user.last_failed_login = datetime.now(timezone.utc) - user.failed_login_count += 1 - user.save() - if user.failed_login_count >= LOCKOUT_LIMIT: - msg = f"*SECURITY ALERT:* Bad Login Attempt for {user}/{user.id}" - msg += f" Attempt count = {user.failed_login_count}" - Notify.notify_admin_msg(msg) - # Send an email if the failed login count has been reached. - if (user.failed_login_count == LOCKOUT_LIMIT) and settings.TATOR_EMAIL_ENABLED: - get_email_service().email( - sender=settings.TATOR_EMAIL_SENDER, - recipients=[user.email], - title=f"Tator account has been locked", - text="This message is to notify you that your Tator account (username " - f"{user.username}) has been locked due to {LOCKOUT_LIMIT} failed logins. " - "Your account will be unlocked automatically after 10 minutes, or you " - "can unlock your account now by resetting your password. To reset your " - "password, follow the procedure described here:\n\n" - "https://tator.io/tutorials/2021-06-11-reset-your-password/", - ) + + user.last_failed_login = datetime.now(timezone.utc) + user.failed_login_count += 1 + user.save() + if user.failed_login_count >= LOCKOUT_LIMIT: + msg = ( + f"*SECURITY ALERT:* Bad Login Attempt for {user}/{user.id}. Attempt count = " + f"{user.failed_login_count}" + ) + Notify.notify_admin_msg(msg) + # Send an email if the failed login count has been reached. + email_service = get_email_service() + if user.failed_login_count == LOCKOUT_LIMIT and email_service: + email_service.email( + sender=settings.TATOR_EMAIL_SENDER, + recipients=[user.email], + title=f"Tator account has been locked", + text="This message is to notify you that your Tator account (username " + f"{user.username}) has been locked due to {LOCKOUT_LIMIT} failed logins. " + "Your account will be unlocked automatically after 10 minutes, or you " + "can unlock your account now by resetting your password. To reset your " + "password, follow the procedure described here:\n\n" + "https://tator.io/tutorials/2021-06-11-reset-your-password/", + ) diff --git a/api/main/rest/password_reset.py b/api/main/rest/password_reset.py index 5ef86bd9b..d37079a54 100644 --- a/api/main/rest/password_reset.py +++ b/api/main/rest/password_reset.py @@ -1,15 +1,11 @@ -import uuid -import os import logging +import uuid -from django.db import transaction from django.conf import settings -from django.http import Http404 -from ..models import PasswordReset -from ..models import User -from ..schema import PasswordResetListSchema from ..mail import get_email_service +from ..models import PasswordReset, User +from ..schema import PasswordResetListSchema from ._base_views import BaseListView @@ -31,17 +27,21 @@ def _post(self, params): raise RuntimeError(f"Email {email} is in use by multiple users!") user = users[0] reset = PasswordReset(user=user, reset_token=uuid.uuid1()) - url = f"{os.getenv('MAIN_HOST')}/password-reset?reset_token={reset.reset_token}&user={user.id}" - if settings.TATOR_EMAIL_ENABLED: - get_email_service().email( + url = f"{settings.PROTO}://{settings.MAIN_HOST}/password-reset?reset_token={reset.reset_token}&user={user.id}" + email_service = get_email_service() + if email_service: + text = ( + f"A password reset has been requested for this email address ({email}). If you did " + f"not initiate the reset this message can be ignored. To reset your password, " + f"please visit: \n\n{url}\n\nThis URL will expire in 24 hours." + ) + failure_msg = f"Unable to send email to {email}! Password reset creation failed." + email_service.email( sender=settings.TATOR_EMAIL_SENDER, recipients=[email], title=f"Tator password reset", - text=f"A password reset has been requested for this email address ({email}). " - f"If you did not initiate the reset this message can be ignored. " - f"To reset your password, please visit: \n\n{url}\n\n" - "This URL will expire in 24 hours.", - raise_on_failure=f"Unable to send email to {email}! Password reset creation failed.", + text=text, + raise_on_failure=failure_msg, ) else: raise RuntimeError(