mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-15 16:42:34 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dceef9c340 | ||
|
|
5c174430df | ||
|
|
8cbc8c0a34 | ||
|
|
4520051d40 | ||
|
|
b660d2c826 | ||
|
|
2085751cae | ||
|
|
76453c9a74 | ||
|
|
60af7a4e62 | ||
|
|
622bef07ad | ||
|
|
a23bd4b3eb | ||
|
|
9bd9d443b4 | ||
|
|
e56fc93a6e | ||
|
|
eb17183d97 | ||
|
|
b0057ecb9d | ||
|
|
a141a8d2c2 |
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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': '',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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', '*', '*'),
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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])}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
68
utils/test_run_migrations.py
Normal file
68
utils/test_run_migrations.py
Normal 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()
|
||||
Reference in New Issue
Block a user