mirror of https://github.com/jumpserver/jumpserver
feat: 为rdp 添加一个api
parent
9be3cbb936
commit
bb9790a50f
|
@ -3,6 +3,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orgs.mixins.models import OrgModelMixin
|
from orgs.mixins.models import OrgModelMixin
|
||||||
from common.mixins import CommonModelMixin
|
from common.mixins import CommonModelMixin
|
||||||
|
from assets.models import Asset
|
||||||
from .. import const
|
from .. import const
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,3 +36,35 @@ class Application(CommonModelMixin, OrgModelMixin):
|
||||||
@property
|
@property
|
||||||
def category_remote_app(self):
|
def category_remote_app(self):
|
||||||
return self.category == const.ApplicationCategoryChoices.remote_app.value
|
return self.category == const.ApplicationCategoryChoices.remote_app.value
|
||||||
|
|
||||||
|
def get_rdp_remote_app_setting(self):
|
||||||
|
from applications.serializers.attrs import get_serializer_class_by_application_type
|
||||||
|
if not self.category_remote_app:
|
||||||
|
raise ValueError(f"Not a remote app application: {self.name}")
|
||||||
|
serializer_class = get_serializer_class_by_application_type(self.type)
|
||||||
|
fields = serializer_class().get_fields()
|
||||||
|
|
||||||
|
parameters = [self.type]
|
||||||
|
for field_name in list(fields.keys()):
|
||||||
|
if field_name in ['asset']:
|
||||||
|
continue
|
||||||
|
value = self.attrs.get(field_name)
|
||||||
|
if not value:
|
||||||
|
continue
|
||||||
|
if field_name == 'path':
|
||||||
|
value = '\"%s\"' % value
|
||||||
|
parameters.append(str(value))
|
||||||
|
|
||||||
|
parameters = ' '.join(parameters)
|
||||||
|
return {
|
||||||
|
'program': '||jmservisor',
|
||||||
|
'working_directory': '',
|
||||||
|
'parameters': parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_remote_app_asset(self):
|
||||||
|
asset_id = self.attrs.get('asset')
|
||||||
|
if not asset_id:
|
||||||
|
raise ValueError("Remote App not has asset attr")
|
||||||
|
asset = Asset.objects.filter(id=asset_id).first()
|
||||||
|
return asset
|
||||||
|
|
|
@ -27,31 +27,5 @@ class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer):
|
||||||
return obj.attrs.get('asset')
|
return obj.attrs.get('asset')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_parameters(obj):
|
def get_parameter_remote_app(obj):
|
||||||
"""
|
return obj.get_rdp_remote_app_setting()
|
||||||
返回Guacamole需要的RemoteApp配置参数信息中的parameters参数
|
|
||||||
"""
|
|
||||||
from .attrs import get_serializer_class_by_application_type
|
|
||||||
serializer_class = get_serializer_class_by_application_type(obj.type)
|
|
||||||
fields = serializer_class().get_fields()
|
|
||||||
|
|
||||||
parameters = [obj.type]
|
|
||||||
for field_name in list(fields.keys()):
|
|
||||||
if field_name in ['asset']:
|
|
||||||
continue
|
|
||||||
value = obj.attrs.get(field_name)
|
|
||||||
if not value:
|
|
||||||
continue
|
|
||||||
if field_name == 'path':
|
|
||||||
value = '\"%s\"' % value
|
|
||||||
parameters.append(str(value))
|
|
||||||
|
|
||||||
parameters = ' '.join(parameters)
|
|
||||||
return parameters
|
|
||||||
|
|
||||||
def get_parameter_remote_app(self, obj):
|
|
||||||
return {
|
|
||||||
'program': '||jmservisor',
|
|
||||||
'working_directory': '',
|
|
||||||
'parameters': self.get_parameters(obj)
|
|
||||||
}
|
|
||||||
|
|
|
@ -77,8 +77,6 @@ class GatewayWithAuthSerializer(GatewaySerializer):
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DomainWithGatewaySerializer(BulkOrgResourceModelSerializer):
|
class DomainWithGatewaySerializer(BulkOrgResourceModelSerializer):
|
||||||
gateways = GatewayWithAuthSerializer(many=True, read_only=True)
|
gateways = GatewayWithAuthSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,73 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
import uuid
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from rest_framework.serializers import ValidationError
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.generics import CreateAPIView
|
from rest_framework.viewsets import GenericViewSet
|
||||||
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
|
||||||
|
from common.utils import get_logger, random_string
|
||||||
|
from common.drf.api import SerializerMixin2
|
||||||
|
from common.permissions import IsSuperUserOrAppUser, IsValidUser, IsSuperUser
|
||||||
|
|
||||||
from common.utils import get_logger
|
|
||||||
from common.permissions import IsSuperUserOrAppUser
|
|
||||||
from orgs.mixins.api import RootOrgViewMixin
|
from orgs.mixins.api import RootOrgViewMixin
|
||||||
|
|
||||||
from ..serializers import ConnectionTokenSerializer
|
from ..serializers import ConnectionTokenSerializer, ConnectionTokenSecretSerializer
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
__all__ = ['UserConnectionTokenApi']
|
__all__ = ['UserConnectionTokenViewSet']
|
||||||
|
|
||||||
|
|
||||||
class UserConnectionTokenApi(RootOrgViewMixin, CreateAPIView):
|
class UserConnectionTokenViewSet(RootOrgViewMixin, SerializerMixin2, GenericViewSet):
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
serializer_class = ConnectionTokenSerializer
|
serializer_classes = {
|
||||||
|
'default': ConnectionTokenSerializer,
|
||||||
|
'get_secret_detail': ConnectionTokenSecretSerializer
|
||||||
|
}
|
||||||
|
CACHE_KEY_PREFIX = 'CONNECTION_TOKEN_{}'
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
@staticmethod
|
||||||
user = serializer.validated_data['user']
|
def check_resource_permission(user, asset, application, system_user):
|
||||||
asset = serializer.validated_data['asset']
|
from perms.utils.asset import has_asset_system_permission
|
||||||
system_user = serializer.validated_data['system_user']
|
from perms.utils.application import has_application_system_permission
|
||||||
token = str(uuid.uuid4())
|
if asset and not has_asset_system_permission(user, asset, system_user):
|
||||||
|
error = f'User not has this asset and system user permission: ' \
|
||||||
|
f'user={user.id} system_user={system_user.id} asset={asset.id}'
|
||||||
|
raise PermissionDenied(error)
|
||||||
|
if application and not has_application_system_permission(user, application, system_user):
|
||||||
|
error = f'User not has this application and system user permission: ' \
|
||||||
|
f'user={user.id} system_user={system_user.id} application={application.id}'
|
||||||
|
raise PermissionDenied(error)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def create_token(self, user, asset, application, system_user):
|
||||||
|
self.check_resource_permission(user, asset, application, system_user)
|
||||||
|
token = random_string(36)
|
||||||
value = {
|
value = {
|
||||||
'user': str(user.id),
|
'user': str(user.id),
|
||||||
'username': user.username,
|
'username': user.username,
|
||||||
'asset': str(asset.id),
|
|
||||||
'hostname': asset.hostname,
|
|
||||||
'system_user': str(system_user.id),
|
'system_user': str(system_user.id),
|
||||||
'system_user_name': system_user.name
|
'system_user_name': system_user.name
|
||||||
}
|
}
|
||||||
cache.set(token, value, timeout=20)
|
|
||||||
|
if asset:
|
||||||
|
value.update({
|
||||||
|
'type': 'asset',
|
||||||
|
'asset': str(asset.id),
|
||||||
|
'hostname': asset.hostname,
|
||||||
|
})
|
||||||
|
elif application:
|
||||||
|
value.update({
|
||||||
|
'type': 'application',
|
||||||
|
'application': application.id,
|
||||||
|
'application_name': str(application)
|
||||||
|
})
|
||||||
|
|
||||||
|
key = self.CACHE_KEY_PREFIX.format(token)
|
||||||
|
cache.set(key, value, timeout=20)
|
||||||
return token
|
return token
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
|
@ -42,18 +75,107 @@ class UserConnectionTokenApi(RootOrgViewMixin, CreateAPIView):
|
||||||
data = {'error': 'Connection token disabled'}
|
data = {'error': 'Connection token disabled'}
|
||||||
return Response(data, status=400)
|
return Response(data, status=400)
|
||||||
|
|
||||||
if not request.user.is_superuser:
|
|
||||||
data = {'error': 'Only super user can create token'}
|
|
||||||
return Response(data, status=403)
|
|
||||||
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
token = self.perform_create(serializer)
|
|
||||||
|
user = serializer.validated_data.get('user', None)
|
||||||
|
if not request.user.is_superuser and user:
|
||||||
|
raise PermissionDenied('Only super user can create user token')
|
||||||
|
if not request.user.is_superuser:
|
||||||
|
user = self.request.user
|
||||||
|
|
||||||
|
asset = serializer.validated_data.get('asset')
|
||||||
|
application = serializer.validated_data.get('application')
|
||||||
|
system_user = serializer.validated_data['system_user']
|
||||||
|
|
||||||
|
token = self.create_token(user, asset, application, system_user)
|
||||||
return Response({"token": token}, status=201)
|
return Response({"token": token}, status=201)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_application_secret_detail(value):
|
||||||
|
from applications.models import Application
|
||||||
|
from perms.models import Action
|
||||||
|
application = get_object_or_404(Application, id=value.get('application'))
|
||||||
|
gateway = None
|
||||||
|
|
||||||
|
if not application.category_remote_app:
|
||||||
|
actions = Action.NONE
|
||||||
|
remote_app = {}
|
||||||
|
asset = None
|
||||||
|
domain = application.domain
|
||||||
|
else:
|
||||||
|
remote_app = application.get_rdp_remote_app_setting()
|
||||||
|
actions = Action.CONNECT
|
||||||
|
asset = application.get_remote_app_asset()
|
||||||
|
domain = asset.domain
|
||||||
|
|
||||||
|
if domain and domain.has_gateway():
|
||||||
|
gateway = domain.random_gateway()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'asset': asset,
|
||||||
|
'application': application,
|
||||||
|
'gateway': gateway,
|
||||||
|
'remote_app': remote_app,
|
||||||
|
'actions': actions
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_asset_secret_detail(value, user, system_user):
|
||||||
|
from assets.models import Asset
|
||||||
|
from perms.utils.asset import get_asset_system_users_id_with_actions_by_user
|
||||||
|
asset = get_object_or_404(Asset, id=value.get('asset'))
|
||||||
|
systemuserid_actions_mapper = get_asset_system_users_id_with_actions_by_user(user, asset)
|
||||||
|
actions = systemuserid_actions_mapper.get(system_user.id, [])
|
||||||
|
gateway = None
|
||||||
|
if asset and asset.domain and asset.domain.has_gateway():
|
||||||
|
gateway = asset.domain.random_gateway()
|
||||||
|
return {
|
||||||
|
'asset': asset,
|
||||||
|
'application': None,
|
||||||
|
'gateway': gateway,
|
||||||
|
'remote_app': None,
|
||||||
|
'actions': actions,
|
||||||
|
}
|
||||||
|
|
||||||
|
@action(methods=['POST'], detail=False, permission_classes=[IsSuperUserOrAppUser], url_path='secret-info/detail')
|
||||||
|
def get_secret_detail(self, request, *args, **kwargs):
|
||||||
|
from users.models import User
|
||||||
|
from assets.models import SystemUser
|
||||||
|
|
||||||
|
token = request.data.get('token', '')
|
||||||
|
key = self.CACHE_KEY_PREFIX.format(token)
|
||||||
|
value = cache.get(key, None)
|
||||||
|
if not value:
|
||||||
|
return Response(status=404)
|
||||||
|
user = get_object_or_404(User, id=value.get('user'))
|
||||||
|
system_user = get_object_or_404(SystemUser, id=value.get('system_user'))
|
||||||
|
data = dict(user=user, system_user=system_user)
|
||||||
|
|
||||||
|
if value.get('type') == 'asset':
|
||||||
|
asset_detail = self._get_asset_secret_detail(value, user=user, system_user=system_user)
|
||||||
|
data['type'] = 'asset'
|
||||||
|
data.update(asset_detail)
|
||||||
|
else:
|
||||||
|
app_detail = self._get_application_secret_detail(value)
|
||||||
|
data['type'] = 'application'
|
||||||
|
data.update(app_detail)
|
||||||
|
|
||||||
|
serializer = self.get_serializer(data)
|
||||||
|
return Response(data=serializer.data, status=200)
|
||||||
|
|
||||||
|
def get_permissions(self):
|
||||||
|
if self.action == "create":
|
||||||
|
if self.request.data.get('user', None):
|
||||||
|
self.permission_classes = (IsSuperUser,)
|
||||||
|
else:
|
||||||
|
self.permission_classes = (IsValidUser,)
|
||||||
|
return super().get_permissions()
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
token = request.query_params.get('token')
|
token = request.query_params.get('token')
|
||||||
value = cache.get(token, None)
|
key = self.CACHE_KEY_PREFIX.format(token)
|
||||||
|
value = cache.get(key, None)
|
||||||
|
|
||||||
if not value:
|
if not value:
|
||||||
return Response('', status=404)
|
return Response('', status=404)
|
||||||
|
|
|
@ -4,14 +4,17 @@ from rest_framework import serializers
|
||||||
|
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
from assets.models import Asset, SystemUser, Gateway
|
||||||
|
from applications.models import Application
|
||||||
from users.serializers import UserProfileSerializer
|
from users.serializers import UserProfileSerializer
|
||||||
|
from perms.serializers.asset.permission import ActionsField
|
||||||
from .models import AccessKey, LoginConfirmSetting, SSOToken
|
from .models import AccessKey, LoginConfirmSetting, SSOToken
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AccessKeySerializer', 'OtpVerifySerializer', 'BearerTokenSerializer',
|
'AccessKeySerializer', 'OtpVerifySerializer', 'BearerTokenSerializer',
|
||||||
'MFAChallengeSerializer', 'LoginConfirmSettingSerializer', 'SSOTokenSerializer',
|
'MFAChallengeSerializer', 'LoginConfirmSettingSerializer', 'SSOTokenSerializer',
|
||||||
'ConnectionTokenSerializer',
|
'ConnectionTokenSerializer', 'ConnectionTokenSecretSerializer'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,9 +89,10 @@ class SSOTokenSerializer(serializers.Serializer):
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenSerializer(serializers.Serializer):
|
class ConnectionTokenSerializer(serializers.Serializer):
|
||||||
user = serializers.CharField(max_length=128, required=True)
|
user = serializers.CharField(max_length=128, required=False, allow_blank=True)
|
||||||
system_user = serializers.CharField(max_length=128, required=True)
|
system_user = serializers.CharField(max_length=128, required=True)
|
||||||
asset = serializers.CharField(max_length=128, required=True)
|
asset = serializers.CharField(max_length=128, required=False)
|
||||||
|
application = serializers.CharField(max_length=128, required=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_user(user_id):
|
def validate_user(user_id):
|
||||||
|
@ -113,3 +117,67 @@ class ConnectionTokenSerializer(serializers.Serializer):
|
||||||
if asset is None:
|
if asset is None:
|
||||||
raise serializers.ValidationError('asset id not exist')
|
raise serializers.ValidationError('asset id not exist')
|
||||||
return asset
|
return asset
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validate_application(app_id):
|
||||||
|
from applications.models import Application
|
||||||
|
app = Application.objects.filter(id=app_id).first()
|
||||||
|
if app is None:
|
||||||
|
raise serializers.ValidationError('app id not exist')
|
||||||
|
return app
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
asset = attrs.get('asset')
|
||||||
|
application = attrs.get('application')
|
||||||
|
if not asset and not application:
|
||||||
|
raise serializers.ValidationError('asset or application required')
|
||||||
|
if asset and application:
|
||||||
|
raise serializers.ValidationError('asset and application should only one')
|
||||||
|
return super().validate(attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenUserSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ['id', 'name', 'username', 'email']
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenAssetSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Asset
|
||||||
|
fields = ['id', 'hostname', 'ip', 'port', 'org_id']
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenSystemUserSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = SystemUser
|
||||||
|
fields = ['id', 'name', 'username', 'password', 'private_key']
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenGatewaySerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Gateway
|
||||||
|
fields = ['id', 'ip', 'port', 'username', 'password', 'private_key']
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenRemoteAppSerializer(serializers.Serializer):
|
||||||
|
program = serializers.CharField()
|
||||||
|
working_directory = serializers.CharField()
|
||||||
|
parameters = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenApplicationSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Application
|
||||||
|
fields = ['id', 'name', 'category', 'type']
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenSecretSerializer(serializers.Serializer):
|
||||||
|
type = serializers.ChoiceField(choices=[('application', 'Application'), ('asset', 'Asset')])
|
||||||
|
user = ConnectionTokenUserSerializer(read_only=True)
|
||||||
|
asset = ConnectionTokenAssetSerializer(read_only=True)
|
||||||
|
remote_app = ConnectionTokenRemoteAppSerializer(read_only=True)
|
||||||
|
application = ConnectionTokenApplicationSerializer(read_only=True)
|
||||||
|
system_user = ConnectionTokenSystemUserSerializer(read_only=True)
|
||||||
|
gateway = ConnectionTokenGatewaySerializer(read_only=True)
|
||||||
|
actions = ActionsField()
|
||||||
|
|
|
@ -9,6 +9,7 @@ app_name = 'authentication'
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register('access-keys', api.AccessKeyViewSet, 'access-key')
|
router.register('access-keys', api.AccessKeyViewSet, 'access-key')
|
||||||
router.register('sso', api.SSOViewSet, 'sso')
|
router.register('sso', api.SSOViewSet, 'sso')
|
||||||
|
router.register('connection-token', api.UserConnectionTokenViewSet, 'connection-token')
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -16,8 +17,6 @@ urlpatterns = [
|
||||||
path('auth/', api.TokenCreateApi.as_view(), name='user-auth'),
|
path('auth/', api.TokenCreateApi.as_view(), name='user-auth'),
|
||||||
path('tokens/', api.TokenCreateApi.as_view(), name='auth-token'),
|
path('tokens/', api.TokenCreateApi.as_view(), name='auth-token'),
|
||||||
path('mfa/challenge/', api.MFAChallengeApi.as_view(), name='mfa-challenge'),
|
path('mfa/challenge/', api.MFAChallengeApi.as_view(), name='mfa-challenge'),
|
||||||
path('connection-token/',
|
|
||||||
api.UserConnectionTokenApi.as_view(), name='connection-token'),
|
|
||||||
path('otp/verify/', api.UserOtpVerifyApi.as_view(), name='user-otp-verify'),
|
path('otp/verify/', api.UserOtpVerifyApi.as_view(), name='user-otp-verify'),
|
||||||
path('login-confirm-ticket/status/', api.TicketStatusApi.as_view(), name='login-confirm-ticket-status'),
|
path('login-confirm-ticket/status/', api.TicketStatusApi.as_view(), name='login-confirm-ticket-status'),
|
||||||
path('login-confirm-settings/<uuid:user_id>/', api.LoginConfirmSettingUpdateApi.as_view(), name='login-confirm-setting-update')
|
path('login-confirm-settings/<uuid:user_id>/', api.LoginConfirmSettingUpdateApi.as_view(), name='login-confirm-setting-update')
|
||||||
|
|
|
@ -64,7 +64,7 @@ msgstr "名称"
|
||||||
#: perms/serializers/application/user_permission.py:33
|
#: perms/serializers/application/user_permission.py:33
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "种类"
|
msgstr "类别"
|
||||||
|
|
||||||
#: applications/models/application.py:15
|
#: applications/models/application.py:15
|
||||||
#: applications/serializers/application.py:48 assets/models/cmd_filter.py:52
|
#: applications/serializers/application.py:48 assets/models/cmd_filter.py:52
|
||||||
|
@ -3160,7 +3160,7 @@ msgstr "关闭"
|
||||||
|
|
||||||
#: tickets/handler/apply_application.py:55
|
#: tickets/handler/apply_application.py:55
|
||||||
msgid "Applied category"
|
msgid "Applied category"
|
||||||
msgstr "申请的种类"
|
msgstr "申请的类别"
|
||||||
|
|
||||||
#: tickets/handler/apply_application.py:56
|
#: tickets/handler/apply_application.py:56
|
||||||
msgid "Applied type"
|
msgid "Applied type"
|
||||||
|
@ -3323,7 +3323,7 @@ msgstr "受理人 (显示名称)"
|
||||||
|
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
|
||||||
msgid "Category display"
|
msgid "Category display"
|
||||||
msgstr "种类 (显示名称)"
|
msgstr "类别 (显示名称)"
|
||||||
|
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31
|
||||||
#: tickets/serializers/ticket/ticket.py:19
|
#: tickets/serializers/ticket/ticket.py:19
|
||||||
|
|
|
@ -11,6 +11,7 @@ from rest_framework.generics import (
|
||||||
from orgs.utils import tmp_to_root_org
|
from orgs.utils import tmp_to_root_org
|
||||||
from applications.models import Application
|
from applications.models import Application
|
||||||
from perms.utils.application.permission import (
|
from perms.utils.application.permission import (
|
||||||
|
has_application_system_permission,
|
||||||
get_application_system_users_id
|
get_application_system_users_id
|
||||||
)
|
)
|
||||||
from perms.api.asset.user_permission.mixin import RoleAdminMixin, RoleUserMixin
|
from perms.api.asset.user_permission.mixin import RoleAdminMixin, RoleUserMixin
|
||||||
|
@ -71,8 +72,7 @@ class ValidateUserApplicationPermissionApi(APIView):
|
||||||
application = get_object_or_404(Application, id=application_id)
|
application = get_object_or_404(Application, id=application_id)
|
||||||
system_user = get_object_or_404(SystemUser, id=system_user_id)
|
system_user = get_object_or_404(SystemUser, id=system_user_id)
|
||||||
|
|
||||||
system_users_id = get_application_system_users_id(user, application)
|
if has_application_system_permission(user, application, system_user):
|
||||||
if system_user.id in system_users_id:
|
|
||||||
return Response({'msg': True}, status=200)
|
return Response({'msg': True}, status=200)
|
||||||
|
|
||||||
return Response({'msg': False}, status=403)
|
return Response({'msg': False}, status=403)
|
||||||
|
|
|
@ -128,12 +128,10 @@ def on_asset_permission_user_groups_changed(instance, action, pk_set, model,
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.system_users.through)
|
@receiver(m2m_changed, sender=ApplicationPermission.system_users.through)
|
||||||
def on_application_permission_system_users_changed(sender, instance: ApplicationPermission, action, reverse, pk_set, **kwargs):
|
def on_application_permission_system_users_changed(sender, instance: ApplicationPermission, action, reverse, pk_set, **kwargs):
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
|
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
if not instance.category_remote_app:
|
||||||
|
return
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -156,12 +154,12 @@ def on_application_permission_system_users_changed(sender, instance: Application
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.users.through)
|
@receiver(m2m_changed, sender=ApplicationPermission.users.through)
|
||||||
def on_application_permission_users_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
def on_application_permission_users_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
|
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
|
||||||
|
if not instance.category_remote_app:
|
||||||
|
return
|
||||||
|
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -176,12 +174,10 @@ def on_application_permission_users_changed(sender, instance, action, reverse, p
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.user_groups.through)
|
@receiver(m2m_changed, sender=ApplicationPermission.user_groups.through)
|
||||||
def on_application_permission_user_groups_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
def on_application_permission_user_groups_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
|
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
if not instance.category_remote_app:
|
||||||
|
return
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -196,12 +192,12 @@ def on_application_permission_user_groups_changed(sender, instance, action, reve
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.applications.through)
|
@receiver(m2m_changed, sender=ApplicationPermission.applications.through)
|
||||||
def on_application_permission_applications_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
def on_application_permission_applications_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
|
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
|
||||||
|
if not instance.category_remote_app:
|
||||||
|
return
|
||||||
|
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,14 @@ logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
def get_application_system_users_id(user, application):
|
def get_application_system_users_id(user, application):
|
||||||
queryset = ApplicationPermission.objects\
|
queryset = ApplicationPermission.objects.valid()\
|
||||||
.filter(Q(users=user) | Q(user_groups__users=user), Q(applications=application))\
|
.filter(
|
||||||
.valid()\
|
Q(users=user) | Q(user_groups__users=user),
|
||||||
.values_list('system_users', flat=True)
|
Q(applications=application)
|
||||||
|
).values_list('system_users', flat=True)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
def has_application_system_permission(user, application, system_user):
|
||||||
|
system_users_id = get_application_system_users_id(user, application)
|
||||||
|
return system_user.id in system_users_id
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.db.models import Q
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from perms.models import AssetPermission
|
from perms.models import AssetPermission
|
||||||
from perms.hands import Asset, User, UserGroup
|
from perms.hands import Asset, User, UserGroup, SystemUser
|
||||||
from perms.models.base import BasePermissionQuerySet
|
from perms.models.base import BasePermissionQuerySet
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
@ -19,10 +19,8 @@ def get_asset_system_users_id_with_actions(asset_perm_queryset: BasePermissionQu
|
||||||
ancestor_keys = node.get_ancestor_keys(with_self=True)
|
ancestor_keys = node.get_ancestor_keys(with_self=True)
|
||||||
node_keys.update(ancestor_keys)
|
node_keys.update(ancestor_keys)
|
||||||
|
|
||||||
queryset = AssetPermission.objects.filter(id__in=asset_perms_id).filter(
|
queryset = AssetPermission.objects.filter(id__in=asset_perms_id)\
|
||||||
Q(assets=asset) |
|
.filter(Q(assets=asset) | Q(nodes__key__in=node_keys))
|
||||||
Q(nodes__key__in=node_keys)
|
|
||||||
)
|
|
||||||
|
|
||||||
asset_protocols = asset.protocols_as_dict.keys()
|
asset_protocols = asset.protocols_as_dict.keys()
|
||||||
values = queryset.filter(
|
values = queryset.filter(
|
||||||
|
@ -44,8 +42,14 @@ def get_asset_system_users_id_with_actions_by_user(user: User, asset: Asset):
|
||||||
return get_asset_system_users_id_with_actions(queryset, asset)
|
return get_asset_system_users_id_with_actions(queryset, asset)
|
||||||
|
|
||||||
|
|
||||||
|
def has_asset_system_permission(user: User, asset: Asset, system_user: SystemUser):
|
||||||
|
systemuser_actions_mapper = get_asset_system_users_id_with_actions_by_user(user, asset)
|
||||||
|
actions = systemuser_actions_mapper.get(system_user.id, [])
|
||||||
|
if actions:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_asset_system_users_id_with_actions_by_group(group: UserGroup, asset: Asset):
|
def get_asset_system_users_id_with_actions_by_group(group: UserGroup, asset: Asset):
|
||||||
queryset = AssetPermission.objects.filter(
|
queryset = AssetPermission.objects.filter(user_groups=group).valid()
|
||||||
user_groups=group
|
|
||||||
).valid()
|
|
||||||
return get_asset_system_users_id_with_actions(queryset, asset)
|
return get_asset_system_users_id_with_actions(queryset, asset)
|
||||||
|
|
|
@ -16,11 +16,10 @@ router.register(r'users', api.UserViewSet, 'user')
|
||||||
router.register(r'groups', api.UserGroupViewSet, 'user-group')
|
router.register(r'groups', api.UserGroupViewSet, 'user-group')
|
||||||
router.register(r'users-groups-relations', api.UserUserGroupRelationViewSet, 'users-groups-relation')
|
router.register(r'users-groups-relations', api.UserUserGroupRelationViewSet, 'users-groups-relation')
|
||||||
router.register(r'service-account-registrations', api.ServiceAccountRegistrationViewSet, 'service-account-registration')
|
router.register(r'service-account-registrations', api.ServiceAccountRegistrationViewSet, 'service-account-registration')
|
||||||
|
router.register(r'connection-token', auth_api.UserConnectionTokenViewSet, 'connection-token')
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('connection-token/', auth_api.UserConnectionTokenApi.as_view(),
|
|
||||||
name='connection-token'),
|
|
||||||
path('profile/', api.UserProfileApi.as_view(), name='user-profile'),
|
path('profile/', api.UserProfileApi.as_view(), name='user-profile'),
|
||||||
path('profile/password/', api.UserPasswordApi.as_view(), name='user-password'),
|
path('profile/password/', api.UserPasswordApi.as_view(), name='user-password'),
|
||||||
path('profile/public-key/', api.UserPublicKeyApi.as_view(), name='user-public-key'),
|
path('profile/public-key/', api.UserPublicKeyApi.as_view(), name='user-public-key'),
|
||||||
|
|
Loading…
Reference in New Issue