merge: with dev

pull/6973/head
ibuler 2021-09-29 14:53:42 +08:00
commit 0213154a19
7 changed files with 163 additions and 24 deletions

5
apps/audits/const.py Normal file
View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
DEFAULT_CITY = _("Unknown")

View File

@ -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)

View File

@ -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)

View File

@ -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
}

View File

@ -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()

View File

@ -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}用户,&nbsp; &nbsp;您好!</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"

View File

@ -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