perf: 优化系统用户,支持用户设置临时密码

perf: 优化rdp file下载

perf: 修改密码途观选项

perf: 优化api获取
pull/6225/head
ibuler 2021-05-31 15:01:14 +08:00 committed by 老广
parent adae509bc0
commit e8b3ee4565
10 changed files with 156 additions and 29 deletions

View File

@ -1,16 +1,15 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.exceptions import ValidationError
from common.utils import get_logger from common.utils import get_logger
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser, IsValidUser
from common.drf.filters import CustomFilter
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from orgs.mixins import generics from orgs.mixins import generics
from orgs.utils import tmp_to_org
from ..models import SystemUser, Asset from ..models import SystemUser, Asset
from .. import serializers from .. import serializers
from ..serializers import SystemUserWithAuthInfoSerializer from ..serializers import SystemUserWithAuthInfoSerializer, SystemUserTempAuthSerializer
from ..tasks import ( from ..tasks import (
push_system_user_to_assets_manual, test_system_user_connectivity_manual, push_system_user_to_assets_manual, test_system_user_connectivity_manual,
push_system_user_to_assets push_system_user_to_assets
@ -21,6 +20,7 @@ logger = get_logger(__file__)
__all__ = [ __all__ = [
'SystemUserViewSet', 'SystemUserAuthInfoApi', 'SystemUserAssetAuthInfoApi', 'SystemUserViewSet', 'SystemUserAuthInfoApi', 'SystemUserAssetAuthInfoApi',
'SystemUserCommandFilterRuleListApi', 'SystemUserTaskApi', 'SystemUserAssetsListView', 'SystemUserCommandFilterRuleListApi', 'SystemUserTaskApi', 'SystemUserAssetsListView',
'SystemUserTempAuthInfoApi', 'SystemUserAppAuthInfoApi',
] ]
@ -57,6 +57,23 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView):
return Response(status=204) return Response(status=204)
class SystemUserTempAuthInfoApi(generics.CreateAPIView):
model = SystemUser
permission_classes = (IsValidUser,)
serializer_class = SystemUserTempAuthSerializer
def create(self, request, *args, **kwargs):
serializer = super().get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
pk = kwargs.get('pk')
instance = get_object_or_404(SystemUser, pk=pk)
data = serializer.validated_data
user = self.request.user
instance_id = data.get('instance_id')
instance.set_temp_auth(instance_id, user, data)
return Response(serializer.data, status=201)
class SystemUserAssetAuthInfoApi(generics.RetrieveAPIView): class SystemUserAssetAuthInfoApi(generics.RetrieveAPIView):
""" """
Get system user with asset auth info Get system user with asset auth info
@ -65,22 +82,30 @@ class SystemUserAssetAuthInfoApi(generics.RetrieveAPIView):
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = SystemUserWithAuthInfoSerializer serializer_class = SystemUserWithAuthInfoSerializer
def get_exception_handler(self): def get_object(self):
def handler(e, context): instance = super().get_object()
return Response({"error": str(e)}, status=400) asset_id = self.kwargs.get('asset_id')
return handler user_id = self.request.query_params.get("user_id")
username = self.request.query_params.get("username")
instance.load_asset_more_auth(asset_id=asset_id, user_id=user_id, username=username)
return instance
class SystemUserAppAuthInfoApi(generics.RetrieveAPIView):
"""
Get system user with asset auth info
"""
model = SystemUser
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = SystemUserWithAuthInfoSerializer
def get_object(self): def get_object(self):
instance = super().get_object() instance = super().get_object()
username = instance.username app_id = self.kwargs.get('app_id')
if instance.username_same_with_user: user_id = self.request.query_params.get("user_id")
username = self.request.query_params.get("username") if user_id:
asset_id = self.kwargs.get('aid') instance.load_app_more_auth(app_id, user_id)
asset = get_object_or_404(Asset, pk=asset_id) return instance
with tmp_to_org(asset.org_id):
instance.load_asset_special_auth(asset=asset, username=username)
return instance
class SystemUserTaskApi(generics.CreateAPIView): class SystemUserTaskApi(generics.CreateAPIView):

View File

@ -11,8 +11,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
from common.db.models import ChoiceSet from common.utils import random_string, signer
from common.utils import random_string
from common.utils import ( from common.utils import (
ssh_key_string_to_obj, ssh_key_gen, get_logger, lazyproperty ssh_key_string_to_obj, ssh_key_gen, get_logger, lazyproperty
) )

View File

@ -7,9 +7,10 @@ import logging
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from django.core.cache import cache
from common.utils import signer from common.utils import signer, get_object_or_none
from common.fields.model import JsonListCharField from common.exceptions import JMSException
from .base import BaseUser from .base import BaseUser
from .asset import Asset from .asset import Asset
@ -185,6 +186,81 @@ class SystemUser(BaseUser):
if self.username_same_with_user: if self.username_same_with_user:
self.username = other.username self.username = other.username
def set_temp_auth(self, asset_or_app_id, user_id, auth, ttl=300):
if not auth:
raise ValueError('Auth not set')
key = 'TEMP_PASSWORD_{}_{}_{}'.format(self.id, asset_or_app_id, user_id)
logger.debug(f'Set system user temp auth: {key}')
cache.set(key, auth, ttl)
def get_temp_auth(self, asset_or_app_id, user_id):
key = 'TEMP_PASSWORD_{}_{}_{}'.format(self.id, asset_or_app_id, user_id)
logger.debug(f'Get system user temp auth: {key}')
password = cache.get(key)
return password
def load_tmp_auth_if_has(self, asset_or_app_id, user):
if not asset_or_app_id or not user:
return
if self.login_mode != self.LOGIN_MANUAL:
pass
auth = self.get_temp_auth(asset_or_app_id, user)
if not auth:
return
username = auth.get('username')
password = auth.get('password')
if username:
self.username = username
if password:
self.password = password
def load_app_more_auth(self, app_id=None, user_id=None):
from users.models import User
if self.login_mode == self.LOGIN_MANUAL:
self.password = ''
self.private_key = ''
if not user_id:
return
user = get_object_or_none(User, pk=user_id)
if not user:
return
self.load_tmp_auth_if_has(app_id, user)
def load_asset_more_auth(self, asset_id=None, username=None, user_id=None):
from users.models import User
if self.login_mode == self.LOGIN_MANUAL:
self.password = ''
self.private_key = ''
asset = None
if asset_id:
asset = get_object_or_none(Asset, pk=asset_id)
# 没有资产就没有必要继续了
if not asset:
logger.debug('Asset not found, pass')
return
user = None
if user_id:
user = get_object_or_none(User, pk=user_id)
if self.username_same_with_user:
if user and not username:
username = user.username
# 加载某个资产的特殊配置认证信息
try:
self.load_asset_special_auth(asset, username)
except Exception as e:
logger.error('Load special auth Error: ', e)
pass
self.load_tmp_auth_if_has(asset_id, user)
@property @property
def cmd_filter_rules(self): def cmd_filter_rules(self):
from .cmd_filter import CommandFilterRule from .cmd_filter import CommandFilterRule

View File

@ -14,6 +14,7 @@ __all__ = [
'SystemUserSimpleSerializer', 'SystemUserAssetRelationSerializer', 'SystemUserSimpleSerializer', 'SystemUserAssetRelationSerializer',
'SystemUserNodeRelationSerializer', 'SystemUserTaskSerializer', 'SystemUserNodeRelationSerializer', 'SystemUserTaskSerializer',
'SystemUserUserRelationSerializer', 'SystemUserWithAuthInfoSerializer', 'SystemUserUserRelationSerializer', 'SystemUserWithAuthInfoSerializer',
'SystemUserTempAuthSerializer',
] ]
@ -272,3 +273,10 @@ class SystemUserTaskSerializer(serializers.Serializer):
many=True many=True
) )
task = serializers.CharField(read_only=True) task = serializers.CharField(read_only=True)
class SystemUserTempAuthSerializer(SystemUserSerializer):
instance_id = serializers.CharField()
class Meta(SystemUserSerializer.Meta):
fields = ['instance_id', 'username', 'password']

View File

@ -46,7 +46,9 @@ urlpatterns = [
path('system-users/<uuid:pk>/auth-info/', api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'), path('system-users/<uuid:pk>/auth-info/', api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'),
path('system-users/<uuid:pk>/assets/', api.SystemUserAssetsListView.as_view(), name='system-user-assets'), path('system-users/<uuid:pk>/assets/', api.SystemUserAssetsListView.as_view(), name='system-user-assets'),
path('system-users/<uuid:pk>/assets/<uuid:aid>/auth-info/', api.SystemUserAssetAuthInfoApi.as_view(), name='system-user-asset-auth-info'), path('system-users/<uuid:pk>/assets/<uuid:asset_id>/auth-info/', api.SystemUserAssetAuthInfoApi.as_view(), name='system-user-asset-auth-info'),
path('system-users/<uuid:pk>/applications/<uuid:app_id>/auth-info/', api.SystemUserAppAuthInfoApi.as_view(), name='system-user-app-auth-info'),
path('system-users/<uuid:pk>/temp-auth/', api.SystemUserTempAuthInfoApi.as_view(), name='system-user-asset-temp-info'),
path('system-users/<uuid:pk>/tasks/', api.SystemUserTaskApi.as_view(), name='system-user-task-create'), path('system-users/<uuid:pk>/tasks/', api.SystemUserTaskApi.as_view(), name='system-user-task-create'),
path('system-users/<uuid:pk>/cmd-filter-rules/', api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'), path('system-users/<uuid:pk>/cmd-filter-rules/', api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'),

View File

@ -93,7 +93,7 @@ class UserConnectionTokenViewSet(RootOrgViewMixin, SerializerMixin2, GenericView
token = self.create_token(user, asset, application, system_user) token = self.create_token(user, asset, application, system_user)
return Response({"token": token}, status=201) return Response({"token": token}, status=201)
@action(methods=['POST', 'GET'], detail=False, url_path='rdp/file') @action(methods=['POST', 'GET'], detail=False, url_path='rdp/file', permission_classes=[IsValidUser])
def get_rdp_file(self, request, *args, **kwargs): def get_rdp_file(self, request, *args, **kwargs):
options = { options = {
'full address:s': '', 'full address:s': '',
@ -134,13 +134,15 @@ class UserConnectionTokenViewSet(RootOrgViewMixin, SerializerMixin2, GenericView
asset = serializer.validated_data.get('asset') asset = serializer.validated_data.get('asset')
application = serializer.validated_data.get('application') application = serializer.validated_data.get('application')
system_user = serializer.validated_data['system_user'] system_user = serializer.validated_data['system_user']
user = serializer.validated_data.get('user')
height = serializer.validated_data.get('height') height = serializer.validated_data.get('height')
width = serializer.validated_data.get('width') width = serializer.validated_data.get('width')
user = request.user
token = self.create_token(user, asset, application, system_user) token = self.create_token(user, asset, application, system_user)
# Todo: 上线后地址是 JumpServerAddr:3389 # Todo: 上线后地址是 JumpServerAddr:3389
address = self.request.query_params.get('address') or '1.1.1.1' address = settings.RDP_ADDR
if address == 'localhost:3389':
address = request.get_host().split(':')[0] + ':3389'
options['full address:s'] = address options['full address:s'] = address
options['username:s'] = '{}|{}'.format(user.username, token) options['username:s'] = '{}|{}'.format(user.username, token)
options['desktopwidth:i'] = width options['desktopwidth:i'] = width
@ -217,10 +219,16 @@ class UserConnectionTokenViewSet(RootOrgViewMixin, SerializerMixin2, GenericView
if value.get('type') == 'asset': if value.get('type') == 'asset':
asset_detail = self._get_asset_secret_detail(value, user=user, system_user=system_user) asset_detail = self._get_asset_secret_detail(value, user=user, system_user=system_user)
asset = asset_detail.get('asset')
if asset:
system_user.load_asset_more_auth(asset.id, user.username, user.id)
data['type'] = 'asset' data['type'] = 'asset'
data.update(asset_detail) data.update(asset_detail)
else: else:
app_detail = self._get_application_secret_detail(value) app_detail = self._get_application_secret_detail(value)
app = app_detail.get("application")
if app:
system_user.load_app_more_auth(app.id, user.id)
data['type'] = 'application' data['type'] = 'application'
data.update(app_detail) data.update(app_detail)

View File

@ -199,5 +199,5 @@ class ConnectionTokenSecretSerializer(serializers.Serializer):
class RDPFileSerializer(ConnectionTokenSerializer): class RDPFileSerializer(ConnectionTokenSerializer):
width = serializers.IntegerField(default=1280) width = serializers.IntegerField(default=1600)
height = serializers.IntegerField(default=800) height = serializers.IntegerField(default=900)

View File

@ -300,7 +300,9 @@ class Config(dict):
'SESSION_SAVE_EVERY_REQUEST': True, 'SESSION_SAVE_EVERY_REQUEST': True,
'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False, 'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False,
'FORGOT_PASSWORD_URL': '', 'FORGOT_PASSWORD_URL': '',
'HEALTH_CHECK_TOKEN': '' 'HEALTH_CHECK_TOKEN': '',
'RDP_ADDR': 'localhost:3389'
} }
def compatible_auth_openid_of_key(self): def compatible_auth_openid_of_key(self):

View File

@ -125,3 +125,5 @@ FORGOT_PASSWORD_URL = CONFIG.FORGOT_PASSWORD_URL
# 自定义默认组织名 # 自定义默认组织名
GLOBAL_ORG_DISPLAY_NAME = CONFIG.GLOBAL_ORG_DISPLAY_NAME GLOBAL_ORG_DISPLAY_NAME = CONFIG.GLOBAL_ORG_DISPLAY_NAME
HEALTH_CHECK_TOKEN = CONFIG.HEALTH_CHECK_TOKEN HEALTH_CHECK_TOKEN = CONFIG.HEALTH_CHECK_TOKEN
RDP_ADDR = CONFIG.RDP_ADDR

View File

@ -13,7 +13,12 @@ __all__ = [
class BasicSettingSerializer(serializers.Serializer): class BasicSettingSerializer(serializers.Serializer):
SITE_URL = serializers.URLField( SITE_URL = serializers.URLField(
required=True, label=_("Site url"), required=True, label=_("Site url"),
help_text=_('eg: http://demo.jumpserver.org:8080') help_text=_('eg: http://dev.jumpserver.org:8080')
)
RDP_ADDR = serializers.CharField(
required=True, label=_("RDP address"),
max_length=1024,
help_text=_('RDP visit address, eg: dev.jumpserver.org:3389')
) )
USER_GUIDE_URL = serializers.URLField( USER_GUIDE_URL = serializers.URLField(
required=False, allow_blank=True, allow_null=True, label=_("User guide url"), required=False, allow_blank=True, allow_null=True, label=_("User guide url"),