mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-16 17:12:53 +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
|
'private_key': auth_user.private_key_file
|
||||||
}
|
}
|
||||||
|
|
||||||
if not with_become:
|
if not with_become or self.is_windows():
|
||||||
return info
|
return info
|
||||||
|
|
||||||
if become_user:
|
if become_user:
|
||||||
|
|||||||
@@ -133,6 +133,15 @@ class AuthMixin:
|
|||||||
self.password = password
|
self.password = password
|
||||||
|
|
||||||
def load_app_more_auth(self, app_id=None, username=None, user_id=None):
|
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
|
from applications.models import Application
|
||||||
app = get_object_or_none(Application, pk=app_id)
|
app = get_object_or_none(Application, pk=app_id)
|
||||||
if app and app.category_remote_app:
|
if app and app.category_remote_app:
|
||||||
@@ -141,11 +150,6 @@ class AuthMixin:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Other app
|
# 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
|
from users.models import User
|
||||||
user = get_object_or_none(User, pk=user_id) if user_id else None
|
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,
|
'FTP_LOG_KEEP_DAYS': 200,
|
||||||
'CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS': 30,
|
'CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS': 30,
|
||||||
|
|
||||||
|
'TICKETS_ENABLED': True,
|
||||||
|
|
||||||
# 废弃的
|
# 废弃的
|
||||||
'DEFAULT_ORG_SHOW_ALL_USERS': True,
|
'DEFAULT_ORG_SHOW_ALL_USERS': True,
|
||||||
'ORG_CHANGE_TO_URL': '',
|
'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'
|
DATETIME_DISPLAY_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||||
|
|
||||||
|
TICKETS_ENABLED = CONFIG.TICKETS_ENABLED
|
||||||
REFERER_CHECK_ENABLED = CONFIG.REFERER_CHECK_ENABLED
|
REFERER_CHECK_ENABLED = CONFIG.REFERER_CHECK_ENABLED
|
||||||
|
|
||||||
CONNECTION_TOKEN_ENABLED = CONFIG.CONNECTION_TOKEN_ENABLED
|
CONNECTION_TOKEN_ENABLED = CONFIG.CONNECTION_TOKEN_ENABLED
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from ..filters import RoleFilter
|
|||||||
from ..serializers import RoleSerializer, RoleUserSerializer
|
from ..serializers import RoleSerializer, RoleUserSerializer
|
||||||
from ..models import Role, SystemRole, OrgRole
|
from ..models import Role, SystemRole, OrgRole
|
||||||
from .permission import PermissionViewSet
|
from .permission import PermissionViewSet
|
||||||
|
from common.mixins.api import PaginatedResponseMixin
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'RoleViewSet', 'SystemRoleViewSet', 'OrgRoleViewSet',
|
'RoleViewSet', 'SystemRoleViewSet', 'OrgRoleViewSet',
|
||||||
@@ -15,7 +16,7 @@ __all__ = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RoleViewSet(JMSModelViewSet):
|
class RoleViewSet(PaginatedResponseMixin, JMSModelViewSet):
|
||||||
queryset = Role.objects.all()
|
queryset = Role.objects.all()
|
||||||
serializer_classes = {
|
serializer_classes = {
|
||||||
'default': RoleSerializer,
|
'default': RoleSerializer,
|
||||||
@@ -54,7 +55,7 @@ class RoleViewSet(JMSModelViewSet):
|
|||||||
def users(self, *args, **kwargs):
|
def users(self, *args, **kwargs):
|
||||||
role = self.get_object()
|
role = self.get_object()
|
||||||
queryset = role.users
|
queryset = role.users
|
||||||
return self.get_paginated_response_with_query_set(queryset)
|
return self.get_paginated_response_from_queryset(queryset)
|
||||||
|
|
||||||
|
|
||||||
class SystemRoleViewSet(RoleViewSet):
|
class SystemRoleViewSet(RoleViewSet):
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ class BuiltinRole:
|
|||||||
org_user = PredefineRole(
|
org_user = PredefineRole(
|
||||||
'7', ugettext_noop('OrgUser'), Scope.org, user_perms
|
'7', ugettext_noop('OrgUser'), Scope.org, user_perms
|
||||||
)
|
)
|
||||||
|
system_role_mapper = None
|
||||||
|
org_role_mapper = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_roles(cls):
|
def get_roles(cls):
|
||||||
@@ -138,22 +140,24 @@ class BuiltinRole:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_system_role_by_old_name(cls, name):
|
def get_system_role_by_old_name(cls, name):
|
||||||
mapper = {
|
if not cls.system_role_mapper:
|
||||||
'App': cls.system_component,
|
cls.system_role_mapper = {
|
||||||
'Admin': cls.system_admin,
|
'App': cls.system_component.get_role(),
|
||||||
'User': cls.system_user,
|
'Admin': cls.system_admin.get_role(),
|
||||||
'Auditor': cls.system_auditor
|
'User': cls.system_user.get_role(),
|
||||||
}
|
'Auditor': cls.system_auditor.get_role()
|
||||||
return mapper[name].get_role()
|
}
|
||||||
|
return cls.system_role_mapper[name]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_org_role_by_old_name(cls, name):
|
def get_org_role_by_old_name(cls, name):
|
||||||
mapper = {
|
if not cls.org_role_mapper:
|
||||||
'Admin': cls.org_admin,
|
cls.org_role_mapper = {
|
||||||
'User': cls.org_user,
|
'Admin': cls.org_admin.get_role(),
|
||||||
'Auditor': cls.org_auditor,
|
'User': cls.org_user.get_role(),
|
||||||
}
|
'Auditor': cls.org_auditor.get_role(),
|
||||||
return mapper[name].get_role()
|
}
|
||||||
|
return cls.org_role_mapper[name]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def sync_to_db(cls, show_msg=False):
|
def sync_to_db(cls, show_msg=False):
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ exclude_permissions = (
|
|||||||
|
|
||||||
|
|
||||||
only_system_permissions = (
|
only_system_permissions = (
|
||||||
('assets', 'platform', '*', '*'),
|
('assets', 'platform', 'add,change,delete', 'platform'),
|
||||||
('users', 'user', 'delete', 'user'),
|
('users', 'user', 'delete', 'user'),
|
||||||
('rbac', 'role', 'delete,add,change', 'role'),
|
('rbac', 'role', 'delete,add,change', 'role'),
|
||||||
('rbac', 'systemrole', '*', '*'),
|
('rbac', 'systemrole', '*', '*'),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Generated by Django 3.1.13 on 2021-12-01 11:01
|
# Generated by Django 3.1.13 on 2021-12-01 11:01
|
||||||
|
|
||||||
|
import time
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
from rbac.builtin import BuiltinRole
|
from rbac.builtin import BuiltinRole
|
||||||
@@ -9,33 +10,61 @@ def migrate_system_role_binding(apps, schema_editor):
|
|||||||
db_alias = schema_editor.connection.alias
|
db_alias = schema_editor.connection.alias
|
||||||
user_model = apps.get_model('users', 'User')
|
user_model = apps.get_model('users', 'User')
|
||||||
role_binding_model = apps.get_model('rbac', 'SystemRoleBinding')
|
role_binding_model = apps.get_model('rbac', 'SystemRoleBinding')
|
||||||
users = user_model.objects.using(db_alias).all()
|
|
||||||
|
|
||||||
role_bindings = []
|
count = 0
|
||||||
for user in users:
|
bulk_size = 1000
|
||||||
role = BuiltinRole.get_system_role_by_old_name(user.role)
|
while True:
|
||||||
role_binding = role_binding_model(scope='system', user_id=user.id, role_id=role.id)
|
users = user_model.objects.using(db_alias) \
|
||||||
role_bindings.append(role_binding)
|
.only('role', 'id') \
|
||||||
role_binding_model.objects.bulk_create(role_bindings, ignore_conflicts=True)
|
.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):
|
def migrate_org_role_binding(apps, schema_editor):
|
||||||
db_alias = schema_editor.connection.alias
|
db_alias = schema_editor.connection.alias
|
||||||
org_member_model = apps.get_model('orgs', 'OrganizationMember')
|
org_member_model = apps.get_model('orgs', 'OrganizationMember')
|
||||||
role_binding_model = apps.get_model('rbac', 'RoleBinding')
|
role_binding_model = apps.get_model('rbac', 'RoleBinding')
|
||||||
members = org_member_model.objects.using(db_alias).all()
|
|
||||||
|
|
||||||
role_bindings = []
|
count = 0
|
||||||
for member in members:
|
bulk_size = 1000
|
||||||
role = BuiltinRole.get_org_role_by_old_name(member.role)
|
|
||||||
role_binding = role_binding_model(
|
while True:
|
||||||
scope='org',
|
members = org_member_model.objects.using(db_alias)\
|
||||||
user_id=member.user.id,
|
.only('role', 'user_id', 'org_id')\
|
||||||
role_id=role.id,
|
.all()[count:count+bulk_size]
|
||||||
org_id=member.org.id
|
if not members:
|
||||||
)
|
break
|
||||||
role_bindings.append(role_binding)
|
role_bindings = []
|
||||||
role_binding_model.objects.bulk_create(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):
|
class Migration(migrations.Migration):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from rest_framework.serializers 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]
|
system_bindings = [b for b in bindings if b.scope == Role.Scope.system.value]
|
||||||
# 工作台仅限于自己加入的组织
|
# 工作台仅限于自己加入的组织
|
||||||
if perm == 'rbac.view_workbench':
|
if perm == 'rbac.view_workbench':
|
||||||
all_orgs = user.orgs.all()
|
all_orgs = user.orgs.all().distinct()
|
||||||
else:
|
else:
|
||||||
all_orgs = Organization.objects.all()
|
all_orgs = Organization.objects.all()
|
||||||
|
|
||||||
|
if not settings.XPACK_ENABLED:
|
||||||
|
all_orgs = all_orgs.filter(id=Organization.DEFAULT_ID)
|
||||||
|
|
||||||
# 有系统级别的绑定,就代表在所有组织有这个权限
|
# 有系统级别的绑定,就代表在所有组织有这个权限
|
||||||
if system_bindings:
|
if system_bindings:
|
||||||
orgs = all_orgs
|
orgs = all_orgs
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class PublicSettingApi(generics.RetrieveAPIView):
|
|||||||
# Performance
|
# Performance
|
||||||
"LOGIN_TITLE": self.get_login_title(),
|
"LOGIN_TITLE": self.get_login_title(),
|
||||||
"LOGO_URLS": self.get_logo_urls(),
|
"LOGO_URLS": self.get_logo_urls(),
|
||||||
|
"TICKETS_ENABLED": settings.TICKETS_ENABLED,
|
||||||
"HELP_DOCUMENT_URL": settings.HELP_DOCUMENT_URL,
|
"HELP_DOCUMENT_URL": settings.HELP_DOCUMENT_URL,
|
||||||
"HELP_SUPPORT_URL": settings.HELP_SUPPORT_URL,
|
"HELP_SUPPORT_URL": settings.HELP_SUPPORT_URL,
|
||||||
# Auth
|
# Auth
|
||||||
|
|||||||
@@ -15,45 +15,33 @@ p {
|
|||||||
</style>
|
</style>
|
||||||
<div style="margin: 0 200px">
|
<div style="margin: 0 200px">
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<h2>JumpServer {% trans 'Client' %}</h2>
|
<h2>JumpServer {% trans 'Client' %} v1.1.4</h2>
|
||||||
<p>
|
<p>
|
||||||
{% trans 'JumpServer Client, currently used to launch the client, now only support launch RDP SSH client, The Telnet client will next' %}
|
{% 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>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li> <a href="/download/JumpServer-Client-Installer.msi">Windows {% 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.dmg">macOS {% trans 'Client' %}</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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="group">
|
<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>
|
<p>
|
||||||
{% trans 'macOS needs to download the client to connect RDP asset, which comes with Windows' %}
|
{% trans 'macOS needs to download the client to connect RDP asset, which comes with Windows' %}
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/download/Microsoft_Remote_Desktop_10.6.7_installer.pkg">Microsoft_Remote_Desktop_10.6.7_installer.pkg</a></li>
|
<li><a href="/download/Microsoft_Remote_Desktop_10.6.7_installer.pkg">microsoft-remote-desktop-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>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if XPACK_ENABLED %}
|
{% if XPACK_ENABLED %}
|
||||||
<div class="group">
|
<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>
|
<p>{% trans 'Jmservisor is the program used to pull up remote applications in Windows Remote Application publisher' %}</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/download/Jmservisor.msi">Jmservisor</a></li>
|
<li><a href="/download/Jmservisor.msi">jmservisor.msi</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ class SessionJoinRecordsViewSet(OrgModelViewSet):
|
|||||||
)
|
)
|
||||||
filterset_fields = search_fields
|
filterset_fields = search_fields
|
||||||
model = models.SessionJoinRecord
|
model = models.SessionJoinRecord
|
||||||
|
rbac_perms = {
|
||||||
|
'finished': 'terminal.change_sessionjoinrecord'
|
||||||
|
}
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -266,6 +266,9 @@ class QuerySet(DJQuerySet):
|
|||||||
self._command_store_config = command_store_config
|
self._command_store_config = command_store_config
|
||||||
self._storage = CommandStore(command_store_config)
|
self._storage = CommandStore(command_store_config)
|
||||||
|
|
||||||
|
# 命令列表模糊搜索时报错
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def _grouped_method_calls(self):
|
def _grouped_method_calls(self):
|
||||||
_method_calls = {k: list(v) for k, v in groupby(self._method_calls, lambda x: x[0])}
|
_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()
|
return Terminal.objects.filter(command_storage=self.name, is_deleted=False).exists()
|
||||||
|
|
||||||
def get_command_queryset(self):
|
def get_command_queryset(self):
|
||||||
|
if self.type_null:
|
||||||
|
return Command.objects.none()
|
||||||
|
|
||||||
if self.type_server:
|
if self.type_server:
|
||||||
qs = Command.objects.all()
|
return Command.objects.all()
|
||||||
else:
|
|
||||||
if self.type not in TYPE_ENGINE_MAPPING:
|
if self.type in TYPE_ENGINE_MAPPING:
|
||||||
logger.error(f'Command storage `{self.type}` not support')
|
|
||||||
return Command.objects.none()
|
|
||||||
engine_mod = import_module(TYPE_ENGINE_MAPPING[self.type])
|
engine_mod = import_module(TYPE_ENGINE_MAPPING[self.type])
|
||||||
qs = engine_mod.QuerySet(self.config)
|
qs = engine_mod.QuerySet(self.config)
|
||||||
qs.model = Command
|
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,
|
def save(self, force_insert=False, force_update=False, using=None,
|
||||||
update_fields=None):
|
update_fields=None):
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class PasswordExpirationReminderMsg(UserMessage):
|
|||||||
subject = _('Password is about expire')
|
subject = _('Password is about expire')
|
||||||
|
|
||||||
date_password_expired_local = timezone.localtime(user.date_password_expired)
|
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')
|
date_password_expired = date_password_expired_local.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
context = {
|
context = {
|
||||||
'name': user.name,
|
'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')
|
APPS_DIR = os.path.join(BASE_DIR, 'apps')
|
||||||
|
|
||||||
sys.path.insert(0, BASE_DIR)
|
sys.path.insert(0, BASE_DIR)
|
||||||
|
sys.path.insert(0, APPS_DIR)
|
||||||
from apps.jumpserver.const import CONFIG
|
from apps.jumpserver.const import CONFIG
|
||||||
|
from apps.jumpserver.settings import base as jms_settings
|
||||||
|
|
||||||
os.environ.setdefault('PYTHONOPTIMIZE', '1')
|
os.environ.setdefault('PYTHONOPTIMIZE', '1')
|
||||||
if os.getuid() == 0:
|
if os.getuid() == 0:
|
||||||
os.environ.setdefault('C_FORCE_ROOT', '1')
|
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 = {
|
params = {
|
||||||
'host': CONFIG.REDIS_HOST,
|
'host': CONFIG.REDIS_HOST,
|
||||||
'port': CONFIG.REDIS_PORT,
|
'port': CONFIG.REDIS_PORT,
|
||||||
'password': CONFIG.REDIS_PASSWORD,
|
'password': CONFIG.REDIS_PASSWORD,
|
||||||
"ssl": CONFIG.REDIS_USE_SSL,
|
"ssl": CONFIG.REDIS_USE_SSL,
|
||||||
'ssl_cert_reqs': CONFIG.REDIS_SSL_REQUIRED,
|
'ssl_cert_reqs': CONFIG.REDIS_SSL_REQUIRED,
|
||||||
"ssl_keyfile": REDIS_SSL_KEYFILE,
|
"ssl_keyfile": jms_settings.REDIS_SSL_KEYFILE,
|
||||||
"ssl_certfile": REDIS_SSL_CERTFILE,
|
"ssl_certfile": jms_settings.REDIS_SSL_CERTFILE,
|
||||||
"ssl_ca_certs": REDIS_SSL_CA_CERTS
|
"ssl_ca_certs": jms_settings.REDIS_SSL_CA_CERTS
|
||||||
}
|
}
|
||||||
redis = Redis(**params)
|
redis = Redis(**params)
|
||||||
scheduler = "django_celery_beat.schedulers:DatabaseScheduler"
|
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