mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-15 08:32:48 +00:00
Compare commits
6 Commits
ibuler-pat
...
v2.17.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e86f84aaee | ||
|
|
8b158d39b6 | ||
|
|
5adbbeb868 | ||
|
|
c8b049349c | ||
|
|
2ff92c5141 | ||
|
|
3260f0eba8 |
@@ -147,15 +147,37 @@ class AuthMixin:
|
||||
|
||||
def load_asset_special_auth(self, asset, username=''):
|
||||
"""
|
||||
AuthBook 的数据状态
|
||||
| asset | systemuser | username |
|
||||
1 | * | * | x |
|
||||
2 | * | x | * |
|
||||
|
||||
当前 AuthBook 只有以上两种状态,systemuser 与 username 不会并存。
|
||||
正常的资产与系统用户关联产生的是第1种状态,改密则产生第2种状态。改密之后
|
||||
只有 username 而没有 systemuser 。
|
||||
|
||||
Freq: 关联同一资产的多个系统用户指定同一用户名时,修改用户密码会影响所有系统用户
|
||||
|
||||
这里有一个不对称的行为,同名系统用户密码覆盖
|
||||
当有相同 username 的多个系统用户时,有改密动作之后,所有的同名系统用户都使用最后
|
||||
一次改动,但如果没有发生过改密,同名系统用户使用的密码还是各自的。
|
||||
|
||||
"""
|
||||
authbooks = list(AuthBook.objects.filter(asset=asset, systemuser=self))
|
||||
if len(authbooks) == 0:
|
||||
if username == '':
|
||||
username = self.username
|
||||
|
||||
authbook = AuthBook.objects.filter(
|
||||
asset=asset, username=username, systemuser__isnull=True
|
||||
).order_by('-date_created').first()
|
||||
|
||||
if not authbook:
|
||||
authbook = AuthBook.objects.filter(
|
||||
asset=asset, systemuser=self
|
||||
).order_by('-date_created').first()
|
||||
|
||||
if not authbook:
|
||||
return None
|
||||
elif len(authbooks) == 1:
|
||||
authbook = authbooks[0]
|
||||
else:
|
||||
authbooks.sort(key=lambda x: 1 if x.username == username else 0, reverse=True)
|
||||
authbook = authbooks[0]
|
||||
|
||||
authbook.load_auth()
|
||||
self.password = authbook.password
|
||||
self.private_key = authbook.private_key
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.db.models import Count
|
||||
|
||||
from common.mixins.serializers import BulkSerializerMixin
|
||||
from common.utils import ssh_pubkey_gen
|
||||
from common.validators import alphanumeric_re, alphanumeric_cn_re
|
||||
from common.validators import alphanumeric_re, alphanumeric_cn_re, alphanumeric_win_re
|
||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
from ..models import SystemUser, Asset
|
||||
from .utils import validate_password_contains_left_double_curly_bracket
|
||||
@@ -107,9 +107,12 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||
def validate_username(self, username):
|
||||
protocol = self.get_initial_value("protocol")
|
||||
if username:
|
||||
regx = alphanumeric_re
|
||||
if protocol == SystemUser.Protocol.telnet:
|
||||
regx = alphanumeric_cn_re
|
||||
elif protocol == SystemUser.Protocol.rdp:
|
||||
regx = alphanumeric_win_re
|
||||
else:
|
||||
regx = alphanumeric_re
|
||||
if not regx.match(username):
|
||||
raise serializers.ValidationError(_('Special char not allowed'))
|
||||
return username
|
||||
|
||||
@@ -4,10 +4,10 @@ from itertools import groupby
|
||||
from celery import shared_task
|
||||
from common.db.utils import get_object_if_need, get_objects
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.db.models import Empty, Q
|
||||
from django.db.models import Empty
|
||||
|
||||
from common.utils import encrypt_password, get_logger
|
||||
from assets.models import SystemUser, Asset, AuthBook
|
||||
from assets.models import SystemUser, Asset
|
||||
from orgs.utils import org_aware_func, tmp_to_root_org
|
||||
from . import const
|
||||
from .utils import clean_ansible_task_hosts, group_asset_by_platform
|
||||
@@ -178,6 +178,7 @@ def get_push_windows_system_user_tasks(system_user: SystemUser, username=None):
|
||||
|
||||
def get_push_system_user_tasks(system_user, platform="unixlike", username=None):
|
||||
"""
|
||||
获取推送系统用户的 ansible 命令,跟资产无关
|
||||
:param system_user:
|
||||
:param platform:
|
||||
:param username: 当动态时,近推送某个
|
||||
@@ -209,18 +210,10 @@ def push_system_user_util(system_user, assets, task_name, username=None):
|
||||
if not assets:
|
||||
return {}
|
||||
|
||||
# 资产按平台分类
|
||||
assets_sorted = sorted(assets, key=group_asset_by_platform)
|
||||
platform_hosts = groupby(assets_sorted, key=group_asset_by_platform)
|
||||
|
||||
def run_task(_tasks, _hosts):
|
||||
if not _tasks:
|
||||
return
|
||||
task, created = update_or_create_ansible_task(
|
||||
task_name=task_name, hosts=_hosts, tasks=_tasks, pattern='all',
|
||||
options=const.TASK_OPTIONS, run_as_admin=True,
|
||||
)
|
||||
task.run()
|
||||
|
||||
if system_user.username_same_with_user:
|
||||
if username is None:
|
||||
# 动态系统用户,但是没有指定 username
|
||||
@@ -232,6 +225,15 @@ def push_system_user_util(system_user, assets, task_name, username=None):
|
||||
assert username is None, 'Only Dynamic user can assign `username`'
|
||||
usernames = [system_user.username]
|
||||
|
||||
def run_task(_tasks, _hosts):
|
||||
if not _tasks:
|
||||
return
|
||||
task, created = update_or_create_ansible_task(
|
||||
task_name=task_name, hosts=_hosts, tasks=_tasks, pattern='all',
|
||||
options=const.TASK_OPTIONS, run_as_admin=True,
|
||||
)
|
||||
task.run()
|
||||
|
||||
for platform, _assets in platform_hosts:
|
||||
_assets = list(_assets)
|
||||
if not _assets:
|
||||
@@ -239,36 +241,11 @@ def push_system_user_util(system_user, assets, task_name, username=None):
|
||||
print(_("Start push system user for platform: [{}]").format(platform))
|
||||
print(_("Hosts count: {}").format(len(_assets)))
|
||||
|
||||
id_asset_map = {_asset.id: _asset for _asset in _assets}
|
||||
asset_ids = id_asset_map.keys()
|
||||
no_special_auth = []
|
||||
special_auth_set = set()
|
||||
|
||||
auth_books = AuthBook.objects.filter(asset_id__in=asset_ids).filter(
|
||||
Q(username__in=usernames) | Q(systemuser__username__in=usernames)
|
||||
).prefetch_related('systemuser')
|
||||
|
||||
for auth_book in auth_books:
|
||||
auth_book.load_auth()
|
||||
special_auth_set.add((auth_book.username, auth_book.asset_id))
|
||||
|
||||
for _username in usernames:
|
||||
no_special_assets = []
|
||||
for asset_id in asset_ids:
|
||||
if (_username, asset_id) not in special_auth_set:
|
||||
no_special_assets.append(id_asset_map[asset_id])
|
||||
if no_special_assets:
|
||||
no_special_auth.append((_username, no_special_assets))
|
||||
|
||||
for _username, no_special_assets in no_special_auth:
|
||||
tasks = get_push_system_user_tasks(system_user, platform, username=_username)
|
||||
run_task(tasks, no_special_assets)
|
||||
|
||||
for auth_book in auth_books:
|
||||
system_user._merge_auth(auth_book)
|
||||
tasks = get_push_system_user_tasks(system_user, platform, username=auth_book.username)
|
||||
asset = id_asset_map[auth_book.asset_id]
|
||||
run_task(tasks, [asset])
|
||||
for u in usernames:
|
||||
for a in _assets:
|
||||
system_user.load_asset_special_auth(a, u)
|
||||
tasks = get_push_system_user_tasks(system_user, platform, username=u)
|
||||
run_task(tasks, [a])
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
|
||||
@@ -157,7 +157,7 @@ class UserLoginView(mixins.AuthMixin, FormView):
|
||||
'name': 'SAML2',
|
||||
'enabled': settings.AUTH_SAML2,
|
||||
'url': reverse('authentication:saml2:saml2-login'),
|
||||
'logo': static('img/login_cas_logo.png'),
|
||||
'logo': static('img/login_saml2_logo.png'),
|
||||
'auto_redirect': True
|
||||
},
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ class RedisPubSub:
|
||||
def __init__(self, ch, db=10):
|
||||
self.ch = ch
|
||||
self.redis = get_redis_client(db)
|
||||
self.subscriber = None
|
||||
|
||||
def subscribe(self):
|
||||
ps = self.redis.pubsub()
|
||||
@@ -41,7 +42,9 @@ class RedisPubSub:
|
||||
:param handle: lambda item: do_something
|
||||
:return:
|
||||
"""
|
||||
self.close_handle_msg()
|
||||
sub = self.subscribe()
|
||||
self.subscriber = sub
|
||||
msgs = sub.listen()
|
||||
|
||||
try:
|
||||
@@ -65,3 +68,8 @@ class RedisPubSub:
|
||||
except Exception as e:
|
||||
logger.error("Redis observer close error: ", e)
|
||||
|
||||
def close_handle_msg(self):
|
||||
if self.subscriber:
|
||||
self.subscriber.close()
|
||||
self.subscriber = None
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ alphanumeric_re = re.compile(r'^[0-9a-zA-Z_@\-\.]*$')
|
||||
|
||||
alphanumeric_cn_re = re.compile(r'^[0-9a-zA-Z_@\-\.\u4E00-\u9FA5]*$')
|
||||
|
||||
alphanumeric_win_re = re.compile(r'^[0-9a-zA-Z_@#%&~\^\$\-\.\u4E00-\u9FA5]*$')
|
||||
|
||||
|
||||
class ProjectUniqueValidator(UniqueTogetherValidator):
|
||||
def __call__(self, attrs, serializer):
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2bf3340b7ca0dc3e698160fe8df980df07ebdecfd9312c5aca230d18a05fea18
|
||||
size 94929
|
||||
oid sha256:151597996418474bb0ec965084ef04c8e1f93b6546b6829a1e0174e9e1f2e43a
|
||||
size 95238
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-12-15 15:41+0800\n"
|
||||
"POT-Creation-Date: 2021-12-17 15:30+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"
|
||||
@@ -1919,7 +1919,7 @@ msgstr "你的账号存在异地登录行为,请关注。"
|
||||
msgid "Login time"
|
||||
msgstr "登录日期"
|
||||
|
||||
#: authentication/templates/authentication/_msg_different_city.html:15
|
||||
#: authentication/templates/authentication/_msg_different_city.html:16
|
||||
msgid ""
|
||||
"If you suspect that the login behavior is abnormal, please modify the "
|
||||
"account password in time."
|
||||
@@ -1935,13 +1935,13 @@ msgstr "请点击下面链接重置密码, 如果不是您申请的,请关
|
||||
msgid "Click here reset password"
|
||||
msgstr "点击这里重置密码"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:15
|
||||
#: users/templates/users/_msg_user_created.html:19
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:16
|
||||
#: users/templates/users/_msg_user_created.html:22
|
||||
msgid "This link is valid for 1 hour. After it expires"
|
||||
msgstr "这个链接有效期1小时, 超过时间您可以"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:17
|
||||
#: users/templates/users/_msg_user_created.html:20
|
||||
#: users/templates/users/_msg_user_created.html:23
|
||||
msgid "request new one"
|
||||
msgstr "重新申请"
|
||||
|
||||
@@ -1954,14 +1954,14 @@ msgstr "你的密码刚刚成功更新"
|
||||
msgid "Browser"
|
||||
msgstr "浏览器"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:12
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
msgid ""
|
||||
"If the password update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
msgstr "如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:14
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:14
|
||||
msgid "If you have any questions, you can contact the administrator"
|
||||
msgstr "如果有疑问或需求,请联系系统管理员"
|
||||
|
||||
@@ -1969,7 +1969,7 @@ msgstr "如果有疑问或需求,请联系系统管理员"
|
||||
msgid "Your public key has just been successfully updated"
|
||||
msgstr "你的公钥刚刚成功更新"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:12
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
msgid ""
|
||||
"If the public key update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
@@ -2389,7 +2389,7 @@ msgstr "邮件"
|
||||
msgid "Site message"
|
||||
msgstr "站内信"
|
||||
|
||||
#: notifications/notifications.py:172 ops/models/adhoc.py:246
|
||||
#: notifications/notifications.py:187 ops/models/adhoc.py:246
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:112
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:201
|
||||
#: xpack/plugins/gathered_user/models.py:79
|
||||
@@ -2767,7 +2767,7 @@ msgstr ""
|
||||
" 以下 %(item_type)s 即将在 3 天后过期\n"
|
||||
" "
|
||||
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:20
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:21
|
||||
msgid "If you have any question, please contact the administrator"
|
||||
msgstr "如果有疑问或需求,请联系系统管理员"
|
||||
|
||||
@@ -4212,6 +4212,16 @@ msgid ""
|
||||
"Windows"
|
||||
msgstr "macOS 需要下载客户端来连接 RDP 资产,Windows 系统默认安装了该程序"
|
||||
|
||||
#: templates/resource_download.html:41
|
||||
msgid "Windows Remote application publisher tools"
|
||||
msgstr "Windows 远程应用发布服务器工具"
|
||||
|
||||
#: templates/resource_download.html:42
|
||||
msgid ""
|
||||
"Jmservisor is the program used to pull up remote applications in Windows "
|
||||
"Remote Application publisher"
|
||||
msgstr "Jmservisor 是在 windows 远程应用发布服务器中用来拉起远程应用的程序"
|
||||
|
||||
#: templates/rest_framework/base.html:128
|
||||
msgid "Filters"
|
||||
msgstr "过滤"
|
||||
@@ -5744,6 +5754,10 @@ msgstr "执行次数"
|
||||
msgid "Currently only mail sending is supported"
|
||||
msgstr "当前只支持邮件发送"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:236
|
||||
msgid "After many attempts to change the secret, it still failed"
|
||||
msgstr "多次尝试改密后, 依然失败"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/serializers/base.py:57
|
||||
msgid "* Please enter the correct password length"
|
||||
msgstr "* 请输入正确的密码长度"
|
||||
@@ -5752,19 +5766,15 @@ msgstr "* 请输入正确的密码长度"
|
||||
msgid "* Password length range 6-30 bits"
|
||||
msgstr "* 密码长度范围 6-30 位"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:236
|
||||
msgid "After many attempts to change the secret, it still failed"
|
||||
msgstr "多次尝试改密后, 依然失败"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:255
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:249
|
||||
msgid "Invalid/incorrect password"
|
||||
msgstr "无效/错误 密码"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:257
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:251
|
||||
msgid "Failed to connect to the host"
|
||||
msgstr "连接主机失败"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:259
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:253
|
||||
msgid "Data could not be sent to remote"
|
||||
msgstr "无法将数据发送到远程"
|
||||
|
||||
@@ -6229,12 +6239,3 @@ msgstr "旗舰版"
|
||||
#: xpack/plugins/license/models.py:77
|
||||
msgid "Community edition"
|
||||
msgstr "社区版"
|
||||
|
||||
#~ msgid "Please enter the password of"
|
||||
#~ msgstr "请输入"
|
||||
|
||||
#~ msgid "account"
|
||||
#~ msgstr "账户"
|
||||
|
||||
#~ msgid "to complete the binding operation"
|
||||
#~ msgstr "的密码完成绑定操作"
|
||||
|
||||
@@ -5,7 +5,7 @@ from channels.generic.websocket import JsonWebsocketConsumer
|
||||
from common.utils import get_logger
|
||||
from common.db.utils import safe_db_connection
|
||||
from .site_msg import SiteMessageUtil
|
||||
from .signals_handler import new_site_msg_chan
|
||||
from .signals_handler import NewSiteMsgSubPub
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -13,6 +13,10 @@ logger = get_logger(__name__)
|
||||
class SiteMsgWebsocket(JsonWebsocketConsumer):
|
||||
refresh_every_seconds = 10
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SiteMsgWebsocket, self).__init__(*args, **kwargs)
|
||||
self.subscriber = None
|
||||
|
||||
def connect(self):
|
||||
user = self.scope["user"]
|
||||
if user.is_authenticated:
|
||||
@@ -23,6 +27,10 @@ class SiteMsgWebsocket(JsonWebsocketConsumer):
|
||||
else:
|
||||
self.close()
|
||||
|
||||
def disconnect(self, code):
|
||||
if self.subscriber:
|
||||
self.subscriber.close_handle_msg()
|
||||
|
||||
def receive(self, text_data=None, bytes_data=None, **kwargs):
|
||||
data = json.loads(text_data)
|
||||
refresh_every_seconds = data.get('refresh_every_seconds')
|
||||
@@ -56,4 +64,6 @@ class SiteMsgWebsocket(JsonWebsocketConsumer):
|
||||
if user_id in users:
|
||||
ws.send_unread_msg_count()
|
||||
|
||||
new_site_msg_chan.keep_handle_msg(handle_new_site_msg_recv)
|
||||
subscriber = NewSiteMsgSubPub()
|
||||
self.subscriber = subscriber
|
||||
subscriber.keep_handle_msg(handle_new_site_msg_recv)
|
||||
|
||||
BIN
apps/static/img/login_saml2_logo.png
Normal file
BIN
apps/static/img/login_saml2_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
@@ -35,6 +35,16 @@ p {
|
||||
<li><a href="/download/Microsoft_Remote_Desktop_10.6.7_installer.pkg">Microsoft_Remote_Desktop_10.6.7_installer.pkg</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% if XPACK_ENABLED %}
|
||||
<div class="group">
|
||||
<h2>{% trans 'Windows Remote application publisher tools' %}</h2>
|
||||
<p>{% trans 'Jmservisor is the program used to pull up remote applications in Windows Remote Application publisher' %}</p>
|
||||
<ul>
|
||||
<li><a href="/download/Jmservisor.msi">Jmservisor</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<style>
|
||||
ul {
|
||||
|
||||
Reference in New Issue
Block a user