mirror of https://github.com/jumpserver/jumpserver
merge: with dev
commit
0213154a19
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
DEFAULT_CITY = _("Unknown")
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django.db.models.signals import (
|
||||
post_save, post_delete, m2m_changed, pre_delete
|
||||
post_save, m2m_changed, pre_delete
|
||||
)
|
||||
from django.dispatch import receiver
|
||||
from django.conf import settings
|
||||
|
@ -14,25 +14,25 @@ from rest_framework.renderers import JSONRenderer
|
|||
from rest_framework.request import Request
|
||||
|
||||
from assets.models import Asset, SystemUser
|
||||
from common.const.signals import POST_ADD, POST_REMOVE, POST_CLEAR
|
||||
from authentication.signals import post_auth_failed, post_auth_success
|
||||
from authentication.utils import check_different_city_login
|
||||
from jumpserver.utils import current_request
|
||||
from common.utils import get_request_ip, get_logger, get_syslogger
|
||||
from users.models import User
|
||||
from users.signals import post_user_change_password
|
||||
from authentication.signals import post_auth_failed, post_auth_success
|
||||
from terminal.models import Session, Command
|
||||
from common.utils.encode import model_to_json
|
||||
from .utils import write_login_log
|
||||
from . import models
|
||||
from .models import OperateLog
|
||||
from orgs.utils import current_org
|
||||
from perms.models import AssetPermission, ApplicationPermission
|
||||
from common.const.signals import POST_ADD, POST_REMOVE, POST_CLEAR
|
||||
from common.utils import get_request_ip, get_logger, get_syslogger
|
||||
from common.utils.encode import model_to_json
|
||||
|
||||
logger = get_logger(__name__)
|
||||
sys_logger = get_syslogger(__name__)
|
||||
json_render = JSONRenderer()
|
||||
|
||||
|
||||
MODELS_NEED_RECORD = (
|
||||
# users
|
||||
'User', 'UserGroup',
|
||||
|
@ -165,7 +165,6 @@ M2M_NEED_RECORD = {
|
|||
),
|
||||
}
|
||||
|
||||
|
||||
M2M_ACTION = {
|
||||
POST_ADD: 'add',
|
||||
POST_REMOVE: 'remove',
|
||||
|
@ -305,6 +304,7 @@ def generate_data(username, request, login_type=None):
|
|||
@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(user, request)
|
||||
data = generate_data(user.username, request, login_type=login_type)
|
||||
data.update({'mfa': int(user.mfa_enabled), 'status': True})
|
||||
write_login_log(**data)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import csv
|
||||
import codecs
|
||||
from django.http import HttpResponse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from .const import DEFAULT_CITY
|
||||
from common.utils import validate_ip, get_ip_city
|
||||
|
||||
|
||||
|
@ -27,12 +27,12 @@ def write_content_to_excel(response, header=None, login_logs=None, fields=None):
|
|||
|
||||
def write_login_log(*args, **kwargs):
|
||||
from audits.models import UserLoginLog
|
||||
default_city = _("Unknown")
|
||||
|
||||
ip = kwargs.get('ip') or ''
|
||||
if not (ip and validate_ip(ip)):
|
||||
ip = ip[:15]
|
||||
city = default_city
|
||||
city = DEFAULT_CITY
|
||||
else:
|
||||
city = get_ip_city(ip) or default_city
|
||||
city = get_ip_city(ip) or DEFAULT_CITY
|
||||
kwargs.update({'ip': ip, 'city': city})
|
||||
UserLoginLog.objects.create(**kwargs)
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from notifications.notifications import UserMessage
|
||||
from settings.api import PublicSettingApi
|
||||
from common.utils import get_logger
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
EMAIL_TEMPLATE = _(
|
||||
""
|
||||
"<h3>{subject}</h3>"
|
||||
"<p>Dear {server_name} user, Hello!</p>"
|
||||
"<p>Your account has remote login behavior, please pay attention.</p>"
|
||||
"<p>User: {username}</p>"
|
||||
"<p>Login time: {time}</p>"
|
||||
"<p>Login location: {city} ({ip})</p>"
|
||||
"<p>If you suspect that the login behavior is abnormal, please modify "
|
||||
"<p>the account password in time.</p>"
|
||||
"<br>"
|
||||
"<p>Thank you for your attention to {server_name}!</p>")
|
||||
|
||||
|
||||
class DifferentCityLoginMessage(UserMessage):
|
||||
def __init__(self, user, ip, city):
|
||||
self.ip = ip
|
||||
self.city = city
|
||||
super().__init__(user)
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
return timezone.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
@property
|
||||
def subject(self):
|
||||
return _('Different city login reminder')
|
||||
|
||||
def get_text_msg(self) -> dict:
|
||||
message = _(
|
||||
""
|
||||
"{subject}\n"
|
||||
"Dear {server_name} user, Hello!\n"
|
||||
"Your account has remote login behavior, please pay attention.\n"
|
||||
"User: {username}\n"
|
||||
"Login time: {time}\n"
|
||||
"Login location: {city} ({ip})\n"
|
||||
"If you suspect that the login behavior is abnormal, please modify "
|
||||
"the account password in time.\n"
|
||||
"Thank you for your attention to {server_name}!\n"
|
||||
).format(
|
||||
subject=self.subject,
|
||||
server_name=PublicSettingApi.get_login_title(),
|
||||
username=self.user.username,
|
||||
ip=self.ip,
|
||||
time=self.time,
|
||||
city=self.city,
|
||||
)
|
||||
return {
|
||||
'subject': self.subject,
|
||||
'message': message
|
||||
}
|
||||
|
||||
def get_html_msg(self) -> dict:
|
||||
message = EMAIL_TEMPLATE.format(
|
||||
subject=self.subject,
|
||||
server_name=PublicSettingApi.get_login_title(),
|
||||
username=self.user.username,
|
||||
ip=self.ip,
|
||||
time=self.time,
|
||||
city=self.city,
|
||||
)
|
||||
return {
|
||||
'subject': self.subject,
|
||||
'message': message
|
||||
}
|
|
@ -4,6 +4,12 @@ import base64
|
|||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.Cipher import PKCS1_v1_5
|
||||
from Cryptodome import Random
|
||||
|
||||
from .notifications import DifferentCityLoginMessage
|
||||
from audits.models import UserLoginLog
|
||||
from audits.const import DEFAULT_CITY
|
||||
from common.utils import get_request_ip
|
||||
from common.utils import validate_ip, get_ip_city
|
||||
from common.utils import get_logger
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
@ -43,3 +49,16 @@ def rsa_decrypt(cipher_text, rsa_private_key=None):
|
|||
cipher_decoded = base64.b16decode(hex_fixed.upper())
|
||||
message = cipher.decrypt(cipher_decoded, b'error').decode()
|
||||
return message
|
||||
|
||||
|
||||
def check_different_city_login(user, request):
|
||||
ip = get_request_ip(request) or '0.0.0.0'
|
||||
|
||||
if not (ip and validate_ip(ip)):
|
||||
city = DEFAULT_CITY
|
||||
else:
|
||||
city = get_ip_city(ip) or DEFAULT_CITY
|
||||
|
||||
last_user_login = UserLoginLog.objects.filter(username=user.username, status=True).first()
|
||||
if last_user_login.city != city:
|
||||
DifferentCityLoginMessage(user, ip, city).publish_async()
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-09-29 14:42+0800\n"
|
||||
"POT-Creation-Date: 2021-09-29 14:51+0800\n"
|
||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
|
@ -552,7 +552,7 @@ msgstr "创建日期"
|
|||
msgid "AuthBook"
|
||||
msgstr "账号"
|
||||
|
||||
#: assets/models/base.py:30 assets/tasks/const.py:51 audits/utils.py:30
|
||||
#: assets/models/base.py:30 assets/tasks/const.py:51 audits/const.py:5
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
|
@ -1668,6 +1668,47 @@ msgstr "{} 需要 {} 复核"
|
|||
msgid "Expired"
|
||||
msgstr "过期时间"
|
||||
|
||||
#: authentication/notifications.py:11
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<h3>{subject}</h3><p>Dear {server_name} user, Hello!</p><p>Your account has "
|
||||
"remote login behavior, please pay attention.</p><p>User: {username}</"
|
||||
"p><p>Login time: {time}</p><p>Login location: {city} ({ip})</p><p>If you "
|
||||
"suspect that the login behavior is abnormal, please modify <p>the account "
|
||||
"password in time.</p><br><p>Thank you for your attention to {server_name}!</"
|
||||
"p>"
|
||||
msgstr ""
|
||||
"<h3>{subject}</h3><p>尊敬的{server_name}用户, 您好!</p><p>您的账"
|
||||
"号存在异地登录行为,请关注。</p><p>用户: {username}</p><p>登录时间: {time}</"
|
||||
"p><p>登录地点: {city} ({ip})</p><p>若怀疑此次登录行为异常,请及时修改账号密"
|
||||
"码。</p><br><p>感谢您对{server_name}的关注!</p>"
|
||||
|
||||
#: authentication/notifications.py:36
|
||||
msgid "Different city login reminder"
|
||||
msgstr "异地登录提醒"
|
||||
|
||||
#: authentication/notifications.py:40
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"{subject}\n"
|
||||
"Dear {server_name} user, Hello!\n"
|
||||
"Your account has remote login behavior, please pay attention.\n"
|
||||
"User: {username}\n"
|
||||
"Login time: {time}\n"
|
||||
"Login location: {city} ({ip})\n"
|
||||
"If you suspect that the login behavior is abnormal, please modify the "
|
||||
"account password in time.\n"
|
||||
"Thank you for your attention to {server_name}!\n"
|
||||
msgstr ""
|
||||
"{subject}\n"
|
||||
"尊敬的{server_name}用户, 您好!\n"
|
||||
"您的账号存在异地登录行为,请关注。\n"
|
||||
"用户: {username}\n"
|
||||
"登录时间: {time}\n"
|
||||
"登录地点: {city} ({ip})\n"
|
||||
"若怀疑此次登录行为异常,请及时修改账号密码。\n"
|
||||
"感谢您对{server_name}的关注!\n"
|
||||
|
||||
#: authentication/sms_verify_code.py:17
|
||||
msgid "The verification code has expired. Please resend it"
|
||||
msgstr "验证码已过期,请重新发送"
|
||||
|
@ -2853,12 +2894,16 @@ msgid "Enable WeCom Auth"
|
|||
msgstr "启用企业微信认证"
|
||||
|
||||
#: settings/serializers/basic.py:9
|
||||
#, fuzzy
|
||||
#| msgid "Object"
|
||||
msgid "Subject"
|
||||
msgstr "主题"
|
||||
msgstr "对象"
|
||||
|
||||
#: settings/serializers/basic.py:13
|
||||
#, fuzzy
|
||||
#| msgid "Target url"
|
||||
msgid "More url"
|
||||
msgstr "更多信息链接"
|
||||
msgstr "目标URL"
|
||||
|
||||
#: settings/serializers/basic.py:28
|
||||
msgid "Site url"
|
||||
|
@ -6126,8 +6171,6 @@ msgid "AP-Singapore"
|
|||
msgstr "亚太-新加坡"
|
||||
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:48
|
||||
#, fuzzy
|
||||
#| msgid "CN-Hong Kong"
|
||||
msgid "CN-Hong Kong"
|
||||
msgstr "中国-香港"
|
||||
|
||||
|
@ -6281,9 +6324,6 @@ msgstr "旗舰版"
|
|||
msgid "Community edition"
|
||||
msgstr "社区版"
|
||||
|
||||
#~ msgid "Announcement enabled"
|
||||
#~ msgstr "启用公告"
|
||||
|
||||
#~ msgid "OpenID"
|
||||
#~ msgstr "OpenID"
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ coreapi==2.3.3
|
|||
coreschema==0.0.4
|
||||
cryptography==3.3.2
|
||||
decorator==4.1.2
|
||||
Django==3.1.12
|
||||
Django==3.1.13
|
||||
django-auth-ldap==2.2.0
|
||||
django-bootstrap3==14.2.0
|
||||
django-celery-beat==2.0
|
||||
|
@ -31,7 +31,7 @@ docutils==0.14
|
|||
ecdsa==0.13.3
|
||||
enum-compat==0.0.2
|
||||
ephem==3.7.6.0
|
||||
eventlet==0.24.1
|
||||
eventlet==0.31.1
|
||||
future==0.16.0
|
||||
ForgeryPy3==0.3.1
|
||||
greenlet==0.4.14
|
||||
|
@ -49,7 +49,7 @@ olefile==0.44
|
|||
openapi-codec==1.3.2
|
||||
paramiko==2.7.2
|
||||
passlib==1.7.1
|
||||
Pillow==8.2.0
|
||||
Pillow==8.3.2
|
||||
pyasn1==0.4.8
|
||||
pycparser==2.19
|
||||
pycryptodome==3.10.1
|
||||
|
@ -59,7 +59,7 @@ PyNaCl==1.2.1
|
|||
python-dateutil==2.6.1
|
||||
#python-gssapi==0.6.4
|
||||
pytz==2018.3
|
||||
PyYAML==5.2
|
||||
PyYAML==5.4
|
||||
redis==3.5.3
|
||||
requests==2.25.1
|
||||
jms-storage==0.0.39
|
||||
|
|
Loading…
Reference in New Issue