mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-18 10:02:35 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98a5e97518 | ||
|
|
17be132497 | ||
|
|
0cbce5f07a | ||
|
|
26dfb729bc | ||
|
|
bbe03ddb73 | ||
|
|
c88645fa57 | ||
|
|
7271feb598 | ||
|
|
950183ca85 | ||
|
|
6b1aa752d6 |
@@ -33,7 +33,8 @@ class AuthValidateMixin(serializers.Serializer):
|
|||||||
return secret
|
return secret
|
||||||
elif secret_type == SecretType.SSH_KEY:
|
elif secret_type == SecretType.SSH_KEY:
|
||||||
passphrase = passphrase if passphrase else None
|
passphrase = passphrase if passphrase else None
|
||||||
return validate_ssh_key(secret, passphrase)
|
secret = validate_ssh_key(secret, passphrase)
|
||||||
|
return secret
|
||||||
else:
|
else:
|
||||||
return secret
|
return secret
|
||||||
|
|
||||||
@@ -41,8 +42,9 @@ class AuthValidateMixin(serializers.Serializer):
|
|||||||
secret_type = validated_data.get('secret_type')
|
secret_type = validated_data.get('secret_type')
|
||||||
passphrase = validated_data.get('passphrase')
|
passphrase = validated_data.get('passphrase')
|
||||||
secret = validated_data.pop('secret', None)
|
secret = validated_data.pop('secret', None)
|
||||||
self.handle_secret(secret, secret_type, passphrase)
|
validated_data['secret'] = self.handle_secret(
|
||||||
validated_data['secret'] = secret
|
secret, secret_type, passphrase
|
||||||
|
)
|
||||||
for field in ('secret',):
|
for field in ('secret',):
|
||||||
value = validated_data.get(field)
|
value = validated_data.get(field)
|
||||||
if not value:
|
if not value:
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class Protocol(ChoicesMixin, models.TextChoices):
|
|||||||
'port': 3389,
|
'port': 3389,
|
||||||
'secret_types': ['password'],
|
'secret_types': ['password'],
|
||||||
'setting': {
|
'setting': {
|
||||||
'console': True,
|
'console': False,
|
||||||
'security': 'any',
|
'security': 'any',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -34,8 +34,9 @@ def migrate_database_to_asset(apps, *args):
|
|||||||
_attrs = app.attrs or {}
|
_attrs = app.attrs or {}
|
||||||
attrs.update(_attrs)
|
attrs.update(_attrs)
|
||||||
|
|
||||||
|
name = 'DB-{}'.format(app.name)
|
||||||
db = db_model(
|
db = db_model(
|
||||||
id=app.id, name=app.name, address=attrs['host'],
|
id=app.id, name=name, address=attrs['host'],
|
||||||
protocols='{}/{}'.format(app.type, attrs['port']),
|
protocols='{}/{}'.format(app.type, attrs['port']),
|
||||||
db_name=attrs['database'] or '',
|
db_name=attrs['database'] or '',
|
||||||
platform=platforms_map[app.type],
|
platform=platforms_map[app.type],
|
||||||
@@ -61,8 +62,9 @@ def migrate_cloud_to_asset(apps, *args):
|
|||||||
for app in applications:
|
for app in applications:
|
||||||
attrs = app.attrs
|
attrs = app.attrs
|
||||||
print("\t- Create cloud: {}".format(app.name))
|
print("\t- Create cloud: {}".format(app.name))
|
||||||
|
name = 'Cloud-{}'.format(app.name)
|
||||||
cloud = cloud_model(
|
cloud = cloud_model(
|
||||||
id=app.id, name=app.name,
|
id=app.id, name=name,
|
||||||
address=attrs.get('cluster', ''),
|
address=attrs.get('cluster', ''),
|
||||||
protocols='k8s/443', platform=platform,
|
protocols='k8s/443', platform=platform,
|
||||||
org_id=app.org_id,
|
org_id=app.org_id,
|
||||||
|
|||||||
29
apps/assets/migrations/0110_auto_20230315_1741.py
Normal file
29
apps/assets/migrations/0110_auto_20230315_1741.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 3.2.17 on 2023-03-15 09:41
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def set_windows_platform_non_console(apps, schema_editor):
|
||||||
|
Platform = apps.get_model('assets', 'Platform')
|
||||||
|
names = ['Windows', 'Windows-RDP', 'Windows-TLS', 'RemoteAppHost']
|
||||||
|
windows = Platform.objects.filter(name__in=names)
|
||||||
|
if not windows:
|
||||||
|
return
|
||||||
|
|
||||||
|
for p in windows:
|
||||||
|
rdp = p.protocols.filter(name='rdp').first()
|
||||||
|
if not rdp:
|
||||||
|
continue
|
||||||
|
rdp.setting['console'] = False
|
||||||
|
rdp.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0109_alter_asset_options'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(set_windows_platform_non_console)
|
||||||
|
]
|
||||||
@@ -11,7 +11,7 @@ __all__ = ['Platform', 'PlatformProtocol', 'PlatformAutomation']
|
|||||||
|
|
||||||
class PlatformProtocol(models.Model):
|
class PlatformProtocol(models.Model):
|
||||||
SETTING_ATTRS = {
|
SETTING_ATTRS = {
|
||||||
'console': True,
|
'console': False,
|
||||||
'security': 'any,tls,rdp',
|
'security': 'any,tls,rdp',
|
||||||
'sftp_enabled': True,
|
'sftp_enabled': True,
|
||||||
'sftp_home': '/tmp'
|
'sftp_home': '/tmp'
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class AssetAccountSerializer(
|
|||||||
'is_active', 'version', 'secret_type',
|
'is_active', 'version', 'secret_type',
|
||||||
]
|
]
|
||||||
fields_write_only = [
|
fields_write_only = [
|
||||||
'secret', 'push_now', 'template'
|
'secret', 'passphrase', 'push_now', 'template'
|
||||||
]
|
]
|
||||||
fields = fields_mini + fields_write_only
|
fields = fields_mini + fields_write_only
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.core import validators
|
|
||||||
|
|
||||||
from assets.const.web import FillType
|
from assets.const.web import FillType
|
||||||
from common.serializers import WritableNestedModelSerializer
|
from common.serializers import WritableNestedModelSerializer
|
||||||
@@ -19,7 +18,7 @@ class ProtocolSettingSerializer(serializers.Serializer):
|
|||||||
("nla", "NLA"),
|
("nla", "NLA"),
|
||||||
]
|
]
|
||||||
# RDP
|
# RDP
|
||||||
console = serializers.BooleanField(required=False)
|
console = serializers.BooleanField(required=False, default=False)
|
||||||
security = serializers.ChoiceField(choices=SECURITY_CHOICES, default="any")
|
security = serializers.ChoiceField(choices=SECURITY_CHOICES, default="any")
|
||||||
|
|
||||||
# SFTP
|
# SFTP
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class FeiShuQRMixin(UserConfirmRequiredExceptionMixin, PermissionsMixin, View):
|
|||||||
'state': state,
|
'state': state,
|
||||||
'redirect_uri': redirect_uri,
|
'redirect_uri': redirect_uri,
|
||||||
}
|
}
|
||||||
url = URL.AUTHEN + '?' + urlencode(params)
|
url = URL().authen + '?' + urlencode(params)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -2,4 +2,3 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
# This will make sure the app is always imported when
|
# This will make sure the app is always imported when
|
||||||
# Django starts so that shared_task will use this app.
|
# Django starts so that shared_task will use this app.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
from werkzeug.local import Local
|
from werkzeug.local import Local
|
||||||
|
|
||||||
|
from django.utils import translation
|
||||||
|
|
||||||
|
|
||||||
thread_local = Local()
|
thread_local = Local()
|
||||||
encrypted_field_set = {'password'}
|
encrypted_field_set = {'password', 'secret'}
|
||||||
|
|
||||||
|
|
||||||
def _find(attr):
|
def _find(attr):
|
||||||
@@ -10,4 +13,5 @@ def _find(attr):
|
|||||||
|
|
||||||
def add_encrypted_field_set(label):
|
def add_encrypted_field_set(label):
|
||||||
if label:
|
if label:
|
||||||
encrypted_field_set.add(str(label))
|
with translation.override('en'):
|
||||||
|
encrypted_field_set.add(str(label))
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import json
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework.exceptions import APIException
|
from rest_framework.exceptions import APIException
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from common.utils.common import get_logger
|
from common.utils.common import get_logger
|
||||||
from common.sdk.im.utils import digest
|
from common.sdk.im.utils import digest
|
||||||
from common.sdk.im.mixin import RequestMixin, BaseRequest
|
from common.sdk.im.mixin import RequestMixin, BaseRequest
|
||||||
@@ -11,14 +12,30 @@ logger = get_logger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class URL:
|
class URL:
|
||||||
AUTHEN = 'https://open.feishu.cn/open-apis/authen/v1/index'
|
|
||||||
|
|
||||||
GET_TOKEN = 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/'
|
|
||||||
|
|
||||||
# https://open.feishu.cn/document/ukTMukTMukTM/uEDO4UjLxgDO14SM4gTN
|
# https://open.feishu.cn/document/ukTMukTMukTM/uEDO4UjLxgDO14SM4gTN
|
||||||
GET_USER_INFO_BY_CODE = 'https://open.feishu.cn/open-apis/authen/v1/access_token'
|
@property
|
||||||
|
def host(self):
|
||||||
|
if settings.FEISHU_VERSION == 'feishu':
|
||||||
|
h = 'https://open.feishu.cn'
|
||||||
|
else:
|
||||||
|
h = 'https://open.larksuite.com'
|
||||||
|
return h
|
||||||
|
|
||||||
SEND_MESSAGE = 'https://open.feishu.cn/open-apis/im/v1/messages'
|
@property
|
||||||
|
def authen(self):
|
||||||
|
return f'{self.host}/open-apis/authen/v1/index'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_token(self):
|
||||||
|
return f'{self.host}/open-apis/auth/v3/tenant_access_token/internal/'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_user_info_by_code(self):
|
||||||
|
return f'{self.host}/open-apis/authen/v1/access_token'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def send_message(self):
|
||||||
|
return f'{self.host}/open-apis/im/v1/messages'
|
||||||
|
|
||||||
|
|
||||||
class ErrorCode:
|
class ErrorCode:
|
||||||
@@ -51,7 +68,7 @@ class FeishuRequests(BaseRequest):
|
|||||||
|
|
||||||
def request_access_token(self):
|
def request_access_token(self):
|
||||||
data = {'app_id': self._app_id, 'app_secret': self._app_secret}
|
data = {'app_id': self._app_id, 'app_secret': self._app_secret}
|
||||||
response = self.raw_request('post', url=URL.GET_TOKEN, data=data)
|
response = self.raw_request('post', url=URL().get_token, data=data)
|
||||||
self.check_errcode_is_0(response)
|
self.check_errcode_is_0(response)
|
||||||
|
|
||||||
access_token = response['tenant_access_token']
|
access_token = response['tenant_access_token']
|
||||||
@@ -86,7 +103,7 @@ class FeiShu(RequestMixin):
|
|||||||
'code': code
|
'code': code
|
||||||
}
|
}
|
||||||
|
|
||||||
data = self._requests.post(URL.GET_USER_INFO_BY_CODE, json=body, check_errcode_is_0=False)
|
data = self._requests.post(URL().get_user_info_by_code, json=body, check_errcode_is_0=False)
|
||||||
|
|
||||||
self._requests.check_errcode_is_0(data)
|
self._requests.check_errcode_is_0(data)
|
||||||
return data['data']['user_id']
|
return data['data']['user_id']
|
||||||
@@ -107,7 +124,7 @@ class FeiShu(RequestMixin):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(f'Feishu send text: user_ids={user_ids} msg={msg}')
|
logger.info(f'Feishu send text: user_ids={user_ids} msg={msg}')
|
||||||
self._requests.post(URL.SEND_MESSAGE, params=params, json=body)
|
self._requests.post(URL().send_message, params=params, json=body)
|
||||||
except APIException as e:
|
except APIException as e:
|
||||||
# 只处理可预知的错误
|
# 只处理可预知的错误
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|||||||
@@ -274,4 +274,4 @@ def ensure_last_char_is_ascii(data):
|
|||||||
def data_to_json(data, sort_keys=True, indent=2, cls=None):
|
def data_to_json(data, sort_keys=True, indent=2, cls=None):
|
||||||
if cls is None:
|
if cls is None:
|
||||||
cls = DjangoJSONEncoder
|
cls = DjangoJSONEncoder
|
||||||
return json.dumps(data, sort_keys=sort_keys, indent=indent, cls=cls)
|
return json.dumps(data, ensure_ascii=False, sort_keys=sort_keys, indent=indent, cls=cls)
|
||||||
|
|||||||
@@ -376,6 +376,7 @@ class Config(dict):
|
|||||||
'AUTH_FEISHU': False,
|
'AUTH_FEISHU': False,
|
||||||
'FEISHU_APP_ID': '',
|
'FEISHU_APP_ID': '',
|
||||||
'FEISHU_APP_SECRET': '',
|
'FEISHU_APP_SECRET': '',
|
||||||
|
'FEISHU_VERSION': 'feishu',
|
||||||
|
|
||||||
'LOGIN_REDIRECT_TO_BACKEND': '', # 'OPENID / CAS / SAML2
|
'LOGIN_REDIRECT_TO_BACKEND': '', # 'OPENID / CAS / SAML2
|
||||||
'LOGIN_REDIRECT_MSG_ENABLED': True,
|
'LOGIN_REDIRECT_MSG_ENABLED': True,
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ DINGTALK_APPSECRET = CONFIG.DINGTALK_APPSECRET
|
|||||||
AUTH_FEISHU = CONFIG.AUTH_FEISHU
|
AUTH_FEISHU = CONFIG.AUTH_FEISHU
|
||||||
FEISHU_APP_ID = CONFIG.FEISHU_APP_ID
|
FEISHU_APP_ID = CONFIG.FEISHU_APP_ID
|
||||||
FEISHU_APP_SECRET = CONFIG.FEISHU_APP_SECRET
|
FEISHU_APP_SECRET = CONFIG.FEISHU_APP_SECRET
|
||||||
|
FEISHU_VERSION = CONFIG.FEISHU_VERSION
|
||||||
|
|
||||||
# Saml2 auth
|
# Saml2 auth
|
||||||
AUTH_SAML2 = CONFIG.AUTH_SAML2
|
AUTH_SAML2 = CONFIG.AUTH_SAML2
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ def migrate_app_perms_to_assets(apps, schema_editor):
|
|||||||
asset_permission = asset_permission_model()
|
asset_permission = asset_permission_model()
|
||||||
for attr in attrs:
|
for attr in attrs:
|
||||||
setattr(asset_permission, attr, getattr(app_perm, attr))
|
setattr(asset_permission, attr, getattr(app_perm, attr))
|
||||||
|
asset_permission.name = f"App-{app_perm.name}"
|
||||||
asset_permissions.append(asset_permission)
|
asset_permissions.append(asset_permission)
|
||||||
asset_permission_model.objects.bulk_create(asset_permissions, ignore_conflicts=True)
|
asset_permission_model.objects.bulk_create(asset_permissions, ignore_conflicts=True)
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ def migrate_system_user_to_accounts(apps, schema_editor):
|
|||||||
bulk_size = 10000
|
bulk_size = 10000
|
||||||
while True:
|
while True:
|
||||||
asset_permissions = asset_permission_model.objects \
|
asset_permissions = asset_permission_model.objects \
|
||||||
.prefetch_related('system_users')[count:bulk_size]
|
.prefetch_related('system_users')[count:bulk_size]
|
||||||
if not asset_permissions:
|
if not asset_permissions:
|
||||||
break
|
break
|
||||||
count += len(asset_permissions)
|
|
||||||
|
|
||||||
|
count += len(asset_permissions)
|
||||||
updated = []
|
updated = []
|
||||||
for asset_permission in asset_permissions:
|
for asset_permission in asset_permissions:
|
||||||
asset_permission.accounts = [s.username for s in asset_permission.system_users.all()]
|
asset_permission.accounts = [s.username for s in asset_permission.system_users.all()]
|
||||||
|
|||||||
@@ -9,6 +9,13 @@ __all__ = ['FeiShuSettingSerializer']
|
|||||||
class FeiShuSettingSerializer(serializers.Serializer):
|
class FeiShuSettingSerializer(serializers.Serializer):
|
||||||
PREFIX_TITLE = _('FeiShu')
|
PREFIX_TITLE = _('FeiShu')
|
||||||
|
|
||||||
|
VERSION_CHOICES = (
|
||||||
|
('feishu', _('FeiShu')),
|
||||||
|
('lark', 'Lark')
|
||||||
|
)
|
||||||
|
AUTH_FEISHU = serializers.BooleanField(default=False, label=_('Enable FeiShu Auth'))
|
||||||
FEISHU_APP_ID = serializers.CharField(max_length=256, required=True, label='App ID')
|
FEISHU_APP_ID = serializers.CharField(max_length=256, required=True, label='App ID')
|
||||||
FEISHU_APP_SECRET = EncryptedField(max_length=256, required=False, label='App Secret')
|
FEISHU_APP_SECRET = EncryptedField(max_length=256, required=False, label='App Secret')
|
||||||
AUTH_FEISHU = serializers.BooleanField(default=False, label=_('Enable FeiShu Auth'))
|
FEISHU_VERSION = serializers.ChoiceField(
|
||||||
|
choices=VERSION_CHOICES, default='feishu', label=_('Version')
|
||||||
|
)
|
||||||
|
|||||||
@@ -105,9 +105,13 @@ class Session(OrgModelMixin):
|
|||||||
def find_ok_relative_path_in_storage(self, storage):
|
def find_ok_relative_path_in_storage(self, storage):
|
||||||
session_paths = self.get_all_possible_relative_path()
|
session_paths = self.get_all_possible_relative_path()
|
||||||
for rel_path in session_paths:
|
for rel_path in session_paths:
|
||||||
if storage.exists(rel_path):
|
# storage 为多个外部存储时, 可能会因部分不可用,
|
||||||
return rel_path
|
# 抛出异常, 影响录像的获取
|
||||||
|
try:
|
||||||
|
if storage.exists(rel_path):
|
||||||
|
return rel_path
|
||||||
|
except:
|
||||||
|
pass
|
||||||
@property
|
@property
|
||||||
def asset_obj(self):
|
def asset_obj(self):
|
||||||
return Asset.objects.get(id=self.asset_id)
|
return Asset.objects.get(id=self.asset_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user