diff --git a/apps/common/utils/common.py b/apps/common/utils/common.py
index fc9137814..63a5afff9 100644
--- a/apps/common/utils/common.py
+++ b/apps/common/utils/common.py
@@ -164,6 +164,11 @@ def get_request_ip_or_data(request):
return ip
+def get_request_user_agent(request):
+ user_agent = request.META.get('HTTP_USER_AGENT', '')
+ return user_agent
+
+
def validate_ip(ip):
try:
ipaddress.ip_address(ip)
diff --git a/apps/users/models/user.py b/apps/users/models/user.py
index f0f2ec896..22adab238 100644
--- a/apps/users/models/user.py
+++ b/apps/users/models/user.py
@@ -393,16 +393,20 @@ class TokenMixin:
@classmethod
def validate_reset_password_token(cls, token):
+ if not token:
+ return None
+ key = cls.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
+ value = cache.get(key)
+ if not value:
+ return None
try:
- key = cls.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
- value = cache.get(key)
user_id = value.get('id', '')
email = value.get('email', '')
user = cls.objects.get(id=user_id, email=email)
+ return user
except (AttributeError, cls.DoesNotExist) as e:
logger.error(e, exc_info=True)
- user = None
- return user
+ return None
def set_cache(self, token):
key = self.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
diff --git a/apps/users/utils.py b/apps/users/utils.py
index cf6be4c67..99bdb5902 100644
--- a/apps/users/utils.py
+++ b/apps/users/utils.py
@@ -13,7 +13,7 @@ from django.core.cache import cache
from datetime import datetime
from common.tasks import send_mail_async
-from common.utils import reverse, get_object_or_none
+from common.utils import reverse, get_object_or_none, get_request_ip_or_data, get_request_user_agent
from .models import User
@@ -112,6 +112,45 @@ def send_reset_password_mail(user):
send_mail_async.delay(subject, message, recipient_list, html_message=message)
+def send_reset_password_success_mail(request, user):
+ subject = _('Reset password success')
+ recipient_list = [user.email]
+ message = _("""
+
+ Hi %(name)s:
+
+
+
+
+ Your JumpServer password has just been successfully updated.
+
+
+
+ If the password update was not initiated by you, your account may have security issues.
+ It is recommended that you log on to the JumpServer immediately and change your password.
+
+
+
+ If you have any questions, you can contact the administrator.
+
+
+ ---
+
+
+ IP Address: %(ip_address)s
+
+
+ Browser: %(browser)s
+
+
+ """) % {
+ 'name': user.name,
+ 'ip_address': get_request_ip_or_data(request),
+ 'browser': get_request_user_agent(request),
+ }
+ send_mail_async.delay(subject, message, recipient_list, html_message=message)
+
+
def send_password_expiration_reminder_mail(user):
subject = _('Security notice')
recipient_list = [user.email]
diff --git a/apps/users/views/profile/reset.py b/apps/users/views/profile/reset.py
index 32b44f861..c25726561 100644
--- a/apps/users/views/profile/reset.py
+++ b/apps/users/views/profile/reset.py
@@ -16,7 +16,8 @@ from common.utils import get_object_or_none
from common.permissions import PermissionsMixin, IsValidUser
from ...models import User
from ...utils import (
- send_reset_password_mail, get_password_check_rules, check_password_rules
+ send_reset_password_mail, get_password_check_rules, check_password_rules,
+ send_reset_password_success_mail
)
from ... import forms
@@ -126,6 +127,7 @@ class UserResetPasswordView(FormView):
user.reset_password(password)
User.expired_reset_password_token(token)
+ send_reset_password_success_mail(self.request, user)
return redirect('authentication:reset-password-success')