Compare commits

...

15 Commits
v3 ... v2.21

Author SHA1 Message Date
jiangweidong
dceef9c340 fix: 修复部署在无证书的Redis上,定时任务不执行的问题-v2.21 2022-06-28 12:34:16 +08:00
Jiangjie.Bai
5c174430df fix: 修复会话加入记录更新失败的问题 2022-06-16 16:51:10 +08:00
Jiangjie.Bai
8cbc8c0a34 fix: 修复命令列表模糊搜索报错500的问题
fix: 修复命令列表模糊搜索报错500的问题
2022-06-16 13:46:01 +08:00
Jiangjie.Bai
4520051d40 fix: 修复手动登录系统用户连接RemoteApp应用获取不到认证信息的问题 2022-06-16 10:41:59 +08:00
ibuler
b660d2c826 perf: 继续优化一波 2022-06-13 16:46:42 +08:00
ibuler
2085751cae perf: 优化迁移 rbac 速度
perf: migrate
2022-06-13 15:17:27 +08:00
feng626
76453c9a74 fix: 修复用户更新自己密码 url 不准确问题 2022-05-24 11:15:56 +08:00
ibuler
60af7a4e62 perf: 恢复 tickets 2022-05-17 18:00:37 +08:00
Jiangjie.Bai
622bef07ad fix: 修复获取类型为null的命令显示不支持的问题
fix: 修复获取类型为null的命令显示不支持的问题
2022-05-07 17:56:33 +08:00
fit2bot
a23bd4b3eb fix: 修复system-role获取users失败的问题 (#8197)
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2022-05-07 10:40:01 +08:00
Jiangjie.Bai
9bd9d443b4 fix: 修复windows执行ansible显示sudo失败的问题 2022-05-05 11:40:37 +08:00
feng626
e56fc93a6e fix: 组织管理员 添加 view platform perm 2022-04-28 19:10:15 +08:00
fit2bot
eb17183d97 fix: workbench_orgs 去重 (#8151)
Co-authored-by: feng626 <1304903146@qq.com>
2022-04-25 11:39:51 +08:00
feng626
b0057ecb9d perf: client download 2022-04-24 15:09:50 +08:00
ibuler
a141a8d2c2 fix: 修复社区版跳转问题 2022-04-21 22:48:34 +08:00
17 changed files with 186 additions and 84 deletions

View File

@@ -301,7 +301,7 @@ class Asset(AbsConnectivity, AbsHardwareInfo, ProtocolsMixin, NodesRelationMixin
'private_key': auth_user.private_key_file
}
if not with_become:
if not with_become or self.is_windows():
return info
if become_user:

View File

@@ -133,6 +133,15 @@ class AuthMixin:
self.password = password
def load_app_more_auth(self, app_id=None, username=None, user_id=None):
# 清除认证信息
self._clean_auth_info_if_manual_login_mode()
# 先加载临时认证信息
if self.login_mode == self.LOGIN_MANUAL:
self._load_tmp_auth_if_has(app_id, user_id)
return
# Remote app
from applications.models import Application
app = get_object_or_none(Application, pk=app_id)
if app and app.category_remote_app:
@@ -141,11 +150,6 @@ class AuthMixin:
return
# Other app
self._clean_auth_info_if_manual_login_mode()
# 加载临时认证信息
if self.login_mode == self.LOGIN_MANUAL:
self._load_tmp_auth_if_has(app_id, user_id)
return
# 更新用户名
from users.models import User
user = get_object_or_none(User, pk=user_id) if user_id else None

View File

@@ -387,6 +387,8 @@ class Config(dict):
'FTP_LOG_KEEP_DAYS': 200,
'CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS': 30,
'TICKETS_ENABLED': True,
# 废弃的
'DEFAULT_ORG_SHOW_ALL_USERS': True,
'ORG_CHANGE_TO_URL': '',

View File

@@ -119,6 +119,7 @@ CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED = CONFIG.CHANGE_AUTH_PLAN_SECURE_MODE_ENABL
DATETIME_DISPLAY_FORMAT = '%Y-%m-%d %H:%M:%S'
TICKETS_ENABLED = CONFIG.TICKETS_ENABLED
REFERER_CHECK_ENABLED = CONFIG.REFERER_CHECK_ENABLED
CONNECTION_TOKEN_ENABLED = CONFIG.CONNECTION_TOKEN_ENABLED

View File

@@ -8,6 +8,7 @@ from ..filters import RoleFilter
from ..serializers import RoleSerializer, RoleUserSerializer
from ..models import Role, SystemRole, OrgRole
from .permission import PermissionViewSet
from common.mixins.api import PaginatedResponseMixin
__all__ = [
'RoleViewSet', 'SystemRoleViewSet', 'OrgRoleViewSet',
@@ -15,7 +16,7 @@ __all__ = [
]
class RoleViewSet(JMSModelViewSet):
class RoleViewSet(PaginatedResponseMixin, JMSModelViewSet):
queryset = Role.objects.all()
serializer_classes = {
'default': RoleSerializer,
@@ -54,7 +55,7 @@ class RoleViewSet(JMSModelViewSet):
def users(self, *args, **kwargs):
role = self.get_object()
queryset = role.users
return self.get_paginated_response_with_query_set(queryset)
return self.get_paginated_response_from_queryset(queryset)
class SystemRoleViewSet(RoleViewSet):

View File

@@ -126,6 +126,8 @@ class BuiltinRole:
org_user = PredefineRole(
'7', ugettext_noop('OrgUser'), Scope.org, user_perms
)
system_role_mapper = None
org_role_mapper = None
@classmethod
def get_roles(cls):
@@ -138,22 +140,24 @@ class BuiltinRole:
@classmethod
def get_system_role_by_old_name(cls, name):
mapper = {
'App': cls.system_component,
'Admin': cls.system_admin,
'User': cls.system_user,
'Auditor': cls.system_auditor
}
return mapper[name].get_role()
if not cls.system_role_mapper:
cls.system_role_mapper = {
'App': cls.system_component.get_role(),
'Admin': cls.system_admin.get_role(),
'User': cls.system_user.get_role(),
'Auditor': cls.system_auditor.get_role()
}
return cls.system_role_mapper[name]
@classmethod
def get_org_role_by_old_name(cls, name):
mapper = {
'Admin': cls.org_admin,
'User': cls.org_user,
'Auditor': cls.org_auditor,
}
return mapper[name].get_role()
if not cls.org_role_mapper:
cls.org_role_mapper = {
'Admin': cls.org_admin.get_role(),
'User': cls.org_user.get_role(),
'Auditor': cls.org_auditor.get_role(),
}
return cls.org_role_mapper[name]
@classmethod
def sync_to_db(cls, show_msg=False):

View File

@@ -91,7 +91,7 @@ exclude_permissions = (
only_system_permissions = (
('assets', 'platform', '*', '*'),
('assets', 'platform', 'add,change,delete', 'platform'),
('users', 'user', 'delete', 'user'),
('rbac', 'role', 'delete,add,change', 'role'),
('rbac', 'systemrole', '*', '*'),

View File

@@ -1,5 +1,6 @@
# Generated by Django 3.1.13 on 2021-12-01 11:01
import time
from django.db import migrations
from rbac.builtin import BuiltinRole
@@ -9,33 +10,61 @@ def migrate_system_role_binding(apps, schema_editor):
db_alias = schema_editor.connection.alias
user_model = apps.get_model('users', 'User')
role_binding_model = apps.get_model('rbac', 'SystemRoleBinding')
users = user_model.objects.using(db_alias).all()
role_bindings = []
for user in users:
role = BuiltinRole.get_system_role_by_old_name(user.role)
role_binding = role_binding_model(scope='system', user_id=user.id, role_id=role.id)
role_bindings.append(role_binding)
role_binding_model.objects.bulk_create(role_bindings, ignore_conflicts=True)
count = 0
bulk_size = 1000
while True:
users = user_model.objects.using(db_alias) \
.only('role', 'id') \
.all()[count:count+bulk_size]
if not users:
break
role_bindings = []
start = time.time()
for user in users:
role = BuiltinRole.get_system_role_by_old_name(user.role)
role_binding = role_binding_model(scope='system', user_id=user.id, role_id=role.id)
role_bindings.append(role_binding)
role_binding_model.objects.bulk_create(role_bindings, ignore_conflicts=True)
print("Create role binding: {}-{} using: {:.2f}s".format(
count, count + len(users), time.time()-start
))
count += len(users)
def migrate_org_role_binding(apps, schema_editor):
db_alias = schema_editor.connection.alias
org_member_model = apps.get_model('orgs', 'OrganizationMember')
role_binding_model = apps.get_model('rbac', 'RoleBinding')
members = org_member_model.objects.using(db_alias).all()
role_bindings = []
for member in members:
role = BuiltinRole.get_org_role_by_old_name(member.role)
role_binding = role_binding_model(
scope='org',
user_id=member.user.id,
role_id=role.id,
org_id=member.org.id
)
role_bindings.append(role_binding)
role_binding_model.objects.bulk_create(role_bindings)
count = 0
bulk_size = 1000
while True:
members = org_member_model.objects.using(db_alias)\
.only('role', 'user_id', 'org_id')\
.all()[count:count+bulk_size]
if not members:
break
role_bindings = []
start = time.time()
for member in members:
role = BuiltinRole.get_org_role_by_old_name(member.role)
role_binding = role_binding_model(
scope='org',
user_id=member.user_id,
role_id=role.id,
org_id=member.org_id
)
role_bindings.append(role_binding)
role_binding_model.objects.bulk_create(role_bindings, ignore_conflicts=True)
print("Create role binding: {}-{} using: {:.2f}s".format(
count, count + len(members), time.time()-start
))
count += len(members)
class Migration(migrations.Migration):

View File

@@ -1,6 +1,7 @@
from django.utils.translation import gettext_lazy as _
from django.db import models
from django.db.models import Q
from django.conf import settings
from django.core.exceptions import ValidationError
from rest_framework.serializers import ValidationError
@@ -111,10 +112,13 @@ class RoleBinding(JMSModel):
system_bindings = [b for b in bindings if b.scope == Role.Scope.system.value]
# 工作台仅限于自己加入的组织
if perm == 'rbac.view_workbench':
all_orgs = user.orgs.all()
all_orgs = user.orgs.all().distinct()
else:
all_orgs = Organization.objects.all()
if not settings.XPACK_ENABLED:
all_orgs = all_orgs.filter(id=Organization.DEFAULT_ID)
# 有系统级别的绑定,就代表在所有组织有这个权限
if system_bindings:
orgs = all_orgs

View File

@@ -56,6 +56,7 @@ class PublicSettingApi(generics.RetrieveAPIView):
# Performance
"LOGIN_TITLE": self.get_login_title(),
"LOGO_URLS": self.get_logo_urls(),
"TICKETS_ENABLED": settings.TICKETS_ENABLED,
"HELP_DOCUMENT_URL": settings.HELP_DOCUMENT_URL,
"HELP_SUPPORT_URL": settings.HELP_SUPPORT_URL,
# Auth

View File

@@ -15,45 +15,33 @@ p {
</style>
<div style="margin: 0 200px">
<div class="group">
<h2>JumpServer {% trans 'Client' %}</h2>
<h2>JumpServer {% trans 'Client' %} v1.1.4</h2>
<p>
{% trans 'JumpServer Client, currently used to launch the client, now only support launch RDP SSH client, The Telnet client will next' %}
{# //JumpServer 客户端,支持 RDP 的本地拉起,后续会支持拉起 ssh。#}
</p>
<ul>
<li> <a href="/download/JumpServer-Client-Installer.msi">Windows {% trans 'Client' %}</a></li>
<li> <a href="/download/JumpServer-Client-Installer.dmg">macOS {% trans 'Client' %}</a></li>
<li> <a href="/download/JumpServer-Client-Installer-x86_64.msi">jumpserver-client-windows-x86_64.msi</a></li>
<li> <a href="/download/JumpServer-Client-Installer-arm64.msi">jumpserver-client-windows-arm64.msi</a></li>
<li> <a href="/download/JumpServer-Client-Installer.dmg">jumpserver-client-darwin.dmg</a></li>
</ul>
</div>
<div class="group">
<h2>{% trans 'Microsoft' %} RDP {% trans 'Official' %}{% trans 'Client' %}</h2>
<h2>{% trans 'Microsoft' %} RDP {% trans 'Official' %}{% trans 'Client' %} v10.6.7</h2>
<p>
{% trans 'macOS needs to download the client to connect RDP asset, which comes with Windows' %}
</p>
<ul>
<li><a href="/download/Microsoft_Remote_Desktop_10.6.7_installer.pkg">Microsoft_Remote_Desktop_10.6.7_installer.pkg</a></li>
</ul>
</div>
<div class="group">
<h2>SSH {% trans 'Client' %}</h2>
<p>
{% trans 'Windows needs to download the client to connect SSH assets, and the MacOS system uses its own terminal' %}
</p>
<ul>
<li><a href="/download/putty/w64/putty.exe">64-bit x86: Putty.exe</a></li>
<li><a href="/download/putty/wa64/putty.exe">64-bit Arm: Putty.exe</a></li>
<li><a href="/download/putty/w32/putty.exe">32-bit x86: Putty.exe</a></li>
<li><a href="/download/Microsoft_Remote_Desktop_10.6.7_installer.pkg">microsoft-remote-desktop-installer.pkg</a></li>
</ul>
</div>
{% if XPACK_ENABLED %}
<div class="group">
<h2>{% trans 'Windows Remote application publisher tools' %}</h2>
<h2>{% trans 'Windows Remote application publisher tools' %} v2.0</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>
<li><a href="/download/Jmservisor.msi">jmservisor.msi</a></li>
</ul>
</div>
{% endif %}

View File

@@ -43,6 +43,9 @@ class SessionJoinRecordsViewSet(OrgModelViewSet):
)
filterset_fields = search_fields
model = models.SessionJoinRecord
rbac_perms = {
'finished': 'terminal.change_sessionjoinrecord'
}
def create(self, request, *args, **kwargs):
try:

View File

@@ -266,6 +266,9 @@ class QuerySet(DJQuerySet):
self._command_store_config = command_store_config
self._storage = CommandStore(command_store_config)
# 命令列表模糊搜索时报错
super().__init__()
@lazyproperty
def _grouped_method_calls(self):
_method_calls = {k: list(v) for k, v in groupby(self._method_calls, lambda x: x[0])}

View File

@@ -89,16 +89,20 @@ class CommandStorage(CommonStorageModelMixin, CommonModelMixin):
return Terminal.objects.filter(command_storage=self.name, is_deleted=False).exists()
def get_command_queryset(self):
if self.type_null:
return Command.objects.none()
if self.type_server:
qs = Command.objects.all()
else:
if self.type not in TYPE_ENGINE_MAPPING:
logger.error(f'Command storage `{self.type}` not support')
return Command.objects.none()
return Command.objects.all()
if self.type in TYPE_ENGINE_MAPPING:
engine_mod = import_module(TYPE_ENGINE_MAPPING[self.type])
qs = engine_mod.QuerySet(self.config)
qs.model = Command
return qs
return qs
logger.error(f'Command storage `{self.type}` not support')
return Command.objects.none()
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):

View File

@@ -143,7 +143,7 @@ class PasswordExpirationReminderMsg(UserMessage):
subject = _('Password is about expire')
date_password_expired_local = timezone.localtime(user.date_password_expired)
update_password_url = urljoin(settings.SITE_URL, '/ui/#/users/profile/?activeTab=PasswordUpdate')
update_password_url = urljoin(settings.SITE_URL, '/ui/#/profile/setting/?activeTab=PasswordUpdate')
date_password_expired = date_password_expired_local.strftime('%Y-%m-%d %H:%M:%S')
context = {
'name': user.name,

View File

@@ -12,33 +12,23 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
APPS_DIR = os.path.join(BASE_DIR, 'apps')
sys.path.insert(0, BASE_DIR)
sys.path.insert(0, APPS_DIR)
from apps.jumpserver.const import CONFIG
from apps.jumpserver.settings import base as jms_settings
os.environ.setdefault('PYTHONOPTIMIZE', '1')
if os.getuid() == 0:
os.environ.setdefault('C_FORCE_ROOT', '1')
REDIS_SSL_KEYFILE = os.path.join(BASE_DIR, 'data', 'certs', 'redis_client.key')
if not os.path.exists(REDIS_SSL_KEYFILE):
REDIS_SSL_KEYFILE = None
REDIS_SSL_CERTFILE = os.path.join(BASE_DIR, 'data', 'certs', 'redis_client.crt')
if not os.path.exists(REDIS_SSL_CERTFILE):
REDIS_SSL_CERTFILE = None
REDIS_SSL_CA_CERTS = os.path.join(BASE_DIR, 'data', 'certs', 'redis_ca.crt')
if not os.path.exists(REDIS_SSL_CA_CERTS):
REDIS_SSL_CA_CERTS = os.path.join(BASE_DIR, 'data', 'certs', 'redis_ca.pem')
params = {
'host': CONFIG.REDIS_HOST,
'port': CONFIG.REDIS_PORT,
'password': CONFIG.REDIS_PASSWORD,
"ssl": CONFIG.REDIS_USE_SSL,
'ssl_cert_reqs': CONFIG.REDIS_SSL_REQUIRED,
"ssl_keyfile": REDIS_SSL_KEYFILE,
"ssl_certfile": REDIS_SSL_CERTFILE,
"ssl_ca_certs": REDIS_SSL_CA_CERTS
"ssl_keyfile": jms_settings.REDIS_SSL_KEYFILE,
"ssl_certfile": jms_settings.REDIS_SSL_CERTFILE,
"ssl_ca_certs": jms_settings.REDIS_SSL_CA_CERTS
}
redis = Redis(**params)
scheduler = "django_celery_beat.schedulers:DatabaseScheduler"

View File

@@ -0,0 +1,68 @@
# Generated by Django 3.1.13 on 2021-12-01 11:01
import os
import sys
import django
import time
app_path = '***** Change me *******'
sys.path.insert(0, app_path)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
django.setup()
from django.apps import apps
from django.db import connection
# ========================== 添加到需要测试的 migrations 上方 ==========================
from django.db import migrations
from rbac.builtin import BuiltinRole
def migrate_system_role_binding(apps, schema_editor):
db_alias = schema_editor.connection.alias
user_model = apps.get_model('users', 'User')
role_binding_model = apps.get_model('rbac', 'SystemRoleBinding')
count = 0
bulk_size = 1000
while True:
users = user_model.objects.using(db_alias) \
.only('role', 'id') \
.all()[count:count+bulk_size]
if not users:
break
role_bindings = []
start = time.time()
for user in users:
role = BuiltinRole.get_system_role_by_old_name(user.role)
role_binding = role_binding_model(scope='system', user_id=user.id, role_id=role.id)
role_bindings.append(role_binding)
role_binding_model.objects.bulk_create(role_bindings, ignore_conflicts=True)
print("Create role binding: {}-{} using: {:.2f}s".format(
count, count + len(users), time.time()-start
))
count += len(users)
class Migration(migrations.Migration):
dependencies = [
('rbac', '0003_auto_20211130_1037'),
]
operations = [
migrations.RunPython(migrate_system_role_binding),
]
# ================== 添加到下方 ======================
def main():
schema_editor = connection.schema_editor()
migrate_system_role_binding(apps, schema_editor)
# main()