mirror of https://github.com/jumpserver/jumpserver
parent
0f3ddc3bf1
commit
4065baf785
|
@ -7,3 +7,4 @@ class ActionChoices(models.TextChoices):
|
|||
accept = 'accept', _('Accept')
|
||||
review = 'review', _('Review')
|
||||
warning = 'warning', _('Warning')
|
||||
notice = 'notice', _('Notifications')
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from audits.models import UserLoginLog
|
||||
from notifications.notifications import UserMessage
|
||||
from users.models import User
|
||||
|
||||
|
||||
class UserLoginReminderMsg(UserMessage):
|
||||
subject = _('User login reminder')
|
||||
|
||||
def __init__(self, user, user_log: UserLoginLog):
|
||||
self.user_log = user_log
|
||||
super().__init__(user)
|
||||
|
||||
def get_html_msg(self) -> dict:
|
||||
user_log = self.user_log
|
||||
|
||||
context = {
|
||||
'ip': user_log.ip,
|
||||
'city': user_log.city,
|
||||
'username': user_log.username,
|
||||
'recipient': self.user.username,
|
||||
'user_agent': user_log.user_agent,
|
||||
}
|
||||
message = render_to_string('acls/user_login_reminder.html', context)
|
||||
|
||||
print('message', message)
|
||||
return {
|
||||
'subject': str(self.subject),
|
||||
'message': message
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def gen_test_msg(cls):
|
||||
user = User.objects.first()
|
||||
user_log = UserLoginLog.objects.first()
|
||||
return cls(user, user_log)
|
|
@ -0,0 +1,14 @@
|
|||
{% load i18n %}
|
||||
|
||||
<h3>{% trans 'Respectful' %}{{ recipient }},</h3>
|
||||
<hr>
|
||||
<p><strong>{% trans 'Username' %}:</strong> [{{ username }}]</p>
|
||||
<p><strong>IP:</strong> [{{ ip }}]</p>
|
||||
<p><strong>{% trans 'Login city' %}:</strong> [{{ city }}]</p>
|
||||
<p><strong>{% trans 'User agent' %}:</strong> [{{ user_agent }}]</p>
|
||||
<hr>
|
||||
|
||||
<p>{% trans 'The user has just successfully logged into the system. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}</p>
|
||||
|
||||
<p>{% trans 'Thank you' %}!</p>
|
||||
|
|
@ -11,6 +11,9 @@ from django.utils.functional import LazyObject
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.request import Request
|
||||
|
||||
from acls.const import ActionChoices
|
||||
from acls.models import LoginACL
|
||||
from acls.notifications import UserLoginReminderMsg
|
||||
from audits.models import UserLoginLog
|
||||
from authentication.signals import post_auth_failed, post_auth_success
|
||||
from authentication.utils import check_different_city_login_if_need
|
||||
|
@ -102,21 +105,37 @@ def create_user_session(request, user_id, instance: UserLoginLog):
|
|||
request.session['user_session_id'] = user_session.id
|
||||
|
||||
|
||||
def send_login_info_to_reviewers(instance: UserLoginLog, reviewers):
|
||||
for reviewer in reviewers:
|
||||
UserLoginReminderMsg(reviewer, instance).publish_async()
|
||||
|
||||
|
||||
@receiver(post_auth_success)
|
||||
def on_user_auth_success(sender, user, request, login_type=None, **kwargs):
|
||||
logger.debug('User login success: {}'.format(user.username))
|
||||
check_different_city_login_if_need(user, request)
|
||||
data = generate_data(
|
||||
user.username, request, login_type=login_type
|
||||
)
|
||||
request.session['login_time'] = data['datetime'].strftime("%Y-%m-%d %H:%M:%S")
|
||||
data = generate_data(user.username, request, login_type=login_type)
|
||||
request.session['login_time'] = data['datetime'].strftime('%Y-%m-%d %H:%M:%S')
|
||||
data.update({'mfa': int(user.mfa_enabled), 'status': True})
|
||||
instance = write_login_log(**data)
|
||||
|
||||
# TODO 目前只记录 web 登录的 session
|
||||
if instance.type != LoginTypeChoices.web:
|
||||
return
|
||||
create_user_session(request, user.id, instance)
|
||||
|
||||
auth_notice_required = request.session.get('auth_notice_required')
|
||||
if not auth_notice_required:
|
||||
return
|
||||
|
||||
auth_acl_id = request.session.get('auth_acl_id')
|
||||
acl = LoginACL.objects.filter(id=auth_acl_id, action=ActionChoices.notice).first()
|
||||
if not acl or not acl.reviewers.exists():
|
||||
return
|
||||
|
||||
reviewers = acl.reviewers.all()
|
||||
send_login_info_to_reviewers(instance, reviewers)
|
||||
|
||||
|
||||
@receiver(post_auth_failed)
|
||||
def on_user_auth_failed(sender, username, request, reason='', **kwargs):
|
||||
|
|
|
@ -355,6 +355,11 @@ class AuthACLMixin:
|
|||
self.request.session['auth_acl_id'] = str(acl.id)
|
||||
return
|
||||
|
||||
if acl.is_action(acl.ActionChoices.notice):
|
||||
self.request.session['auth_notice_required'] = '1'
|
||||
self.request.session['auth_acl_id'] = str(acl.id)
|
||||
return
|
||||
|
||||
def _check_third_party_login_acl(self):
|
||||
request = self.request
|
||||
error_message = getattr(request, 'error_message', None)
|
||||
|
@ -513,7 +518,7 @@ class AuthMixin(CommonMixin, AuthPreCheckMixin, AuthACLMixin, MFAMixin, AuthPost
|
|||
def clear_auth_mark(self):
|
||||
keys = [
|
||||
'auth_password', 'user_id', 'auth_confirm_required',
|
||||
'auth_ticket_id', 'auth_acl_id'
|
||||
'auth_notice_required', 'auth_ticket_id', 'auth_acl_id'
|
||||
]
|
||||
for k in keys:
|
||||
self.request.session.pop(k, '')
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2ffdd50c364a510b4f5cfe7922a5f1a604e8bc7b03aa43ece1dff0250ccde6d6
|
||||
size 160575
|
||||
oid sha256:47cea504e9acfdcc94a45f2ea96216dddde065d134a92a0ef3e92815a12df6fc
|
||||
size 162024
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:78fa10c674b853ebde73bbdef255beeb794a7a7b4bf5483ac1464c282aab0819
|
||||
size 131200
|
||||
oid sha256:096cdc44514bd9f43b5e0062d878625c220ed7826a57a27968db3cb97e7eb011
|
||||
size 132403
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -98,7 +98,7 @@ class BaseHandler:
|
|||
context = self._diff_prev_approve_context(state)
|
||||
context.update({'approve_info': approve_info})
|
||||
body = self.safe_html_script(
|
||||
render_to_string('tickets/ticket_approve_diff.html', context)
|
||||
render_to_string('tickets/user_login_reminder.html', context)
|
||||
)
|
||||
data = {
|
||||
'body': body,
|
||||
|
|
Loading…
Reference in New Issue