diff --git a/apps/assets/templates/assets/admin_user_list.html b/apps/assets/templates/assets/admin_user_list.html index 0451d989f..fec3e6368 100644 --- a/apps/assets/templates/assets/admin_user_list.html +++ b/apps/assets/templates/assets/admin_user_list.html @@ -32,7 +32,7 @@ $(document).ready(function(){ ele: $('#admin_user_list_table'), columnDefs: [ {targets: 1, createdCell: function (td, cellData, rowData) { - var detail_btn = '' + cellData + ''; + var detail_btn = '' + cellData + ''; $(td).html(detail_btn.replace('99991937', rowData.id)); }}, {targets: 5, createdCell: function (td, cellData) { diff --git a/apps/common/utils.py b/apps/common/utils.py index 2aa70507a..269455d09 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -248,4 +248,11 @@ def validate_ssh_public_key(text): return True +def setattr_bulk(seq, key, value): + def set_attr(obj): + setattr(obj, key, value) + return obj + return map(set_attr, seq) + + signer = Signer() \ No newline at end of file diff --git a/apps/perms/api.py b/apps/perms/api.py index fd9294500..9b95a1a1f 100644 --- a/apps/perms/api.py +++ b/apps/perms/api.py @@ -5,8 +5,10 @@ from rest_framework.views import APIView, Response from rest_framework.generics import ListCreateAPIView from rest_framework import viewsets from users.backends import IsValidUser, IsSuperUser -from .utils import get_user_granted_assets, get_user_granted_asset_groups +from common.utils import get_object_or_none +from .utils import get_user_granted_assets, get_user_granted_asset_groups, get_user_asset_permissions from .models import AssetPermission +from .hands import User from . import serializers @@ -18,11 +20,41 @@ class AssetPermissionViewSet(viewsets.ModelViewSet): def get_queryset(self): queryset = super(AssetPermissionViewSet, self).get_queryset() user_id = self.request.query_params.get('user', '') - if user_id: - queryset = queryset.filter(users__id=user_id) - + if user_id and user_id.isdigit(): + from users.models import User + self.user_id = user_id + user = get_object_or_none(User, id=int(user_id)) + if user: + queryset = get_user_asset_permissions(user) + print(queryset) return queryset + def get_serializer_class(self): + if getattr(self, 'user_id', ''): + return serializers.UserAssetPermissionSerializer + return serializers.AssetPermissionSerializer + + +class RevokeUserAssetPermission(APIView): + permission_classes = (IsSuperUser,) + + def put(self, request, *args, **kwargs): + permission_id = str(request.data.get('id', '')) + user_id = str(request.data.get('user_id', '')) + + if permission_id and user_id and permission_id.isdigit() and user_id.isdigit(): + permission_id = int(permission_id) + user_id = int(user_id) + asset_permission = get_object_or_none(AssetPermission, id=permission_id) + user = get_object_or_none(User, id=user_id) + print(asset_permission) + print(user) + + if asset_permission and user: + asset_permission.users.remove(user) + return Response({'msg': 'success'}) + return Response({'msg': 'failed'}, status=404) + class UserAssetsApi(APIView): permission_classes = (IsValidUser,) diff --git a/apps/perms/serializers.py b/apps/perms/serializers.py index 78857cf0c..34df76f29 100644 --- a/apps/perms/serializers.py +++ b/apps/perms/serializers.py @@ -1,34 +1,26 @@ # -*- coding: utf-8 -*- # -from rest_framework import serializers +from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers +from common.utils import get_object_or_none from .models import AssetPermission +from .hands import User class AssetPermissionSerializer(serializers.ModelSerializer): - # users_amount = serializers.SerializerMethodField() - # user_groups_amount = serializers.SerializerMethodField() - # assets_amount = serializers.SerializerMethodField() - # asset_groups_amount = serializers.SerializerMethodField() - class Meta: model = AssetPermission - fields = ['id', 'name', 'users', 'user_groups', 'assets', 'asset_groups', - 'system_users', 'is_active', 'comment', 'date_expired'] - # @staticmethod - # def get_users_amount(obj): - # return obj.users.count() - # - # @staticmethod - # def get_user_groups_amount(obj): - # return obj.user_groups.count() - # - # @staticmethod - # def get_assets_amount(obj): - # return obj.assets.count() - # - # @staticmethod - # def get_asset_groups_amount(obj): - # return obj.asset_groups.count() + +class UserAssetPermissionSerializer(AssetPermissionSerializer): + is_inherited = serializers.SerializerMethodField() + + @staticmethod + def get_is_inherited(obj): + if getattr(obj, 'inherited', ''): + return True + else: + return False + diff --git a/apps/perms/urls.py b/apps/perms/urls.py index ae1c9d60a..faf51c737 100644 --- a/apps/perms/urls.py +++ b/apps/perms/urls.py @@ -26,10 +26,10 @@ router = routers.DefaultRouter() router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'api-asset-permission') urlpatterns += [ - url(r'^v1/user/assets/$', api.UserAssetsApi.as_view(), - name='user-assets'), - url(r'^v1/user/asset-groups/$', api.UserAssetsGroupsApi.as_view(), - name='user-asset-groups'), + url(r'^v1/user/assets/$', api.UserAssetsApi.as_view(), name='user-assets'), + url(r'^v1/asset-permissions/user/revoke/', api.RevokeUserAssetPermission.as_view(), + name='revoke-user-asset-permission'), + url(r'^v1/user/asset-groups/$', api.UserAssetsGroupsApi.as_view(), name='user-asset-groups'), url(r'^v1/user/asset-groups/(?P[0-9]+)/assets/$', api.UserAssetsGroupAssetsApi.as_view(), name='user-asset-groups-assets'), ] diff --git a/apps/perms/utils.py b/apps/perms/utils.py index cbc6f823d..3bc9b246f 100644 --- a/apps/perms/utils.py +++ b/apps/perms/utils.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, unicode_literals +from common.utils import setattr_bulk from .hands import User, UserGroup, Asset, AssetGroup, SystemUser @@ -7,7 +8,7 @@ def get_user_group_granted_asset_groups(user_group): """Return asset groups granted of the user group :param user_group: Instance of :class: ``UserGroup`` - :return: {asset1: {system_user1, }, asset1: {system_user1, system_user2]} + :return: {asset_group1: {system_user1, }, asset_group2: {system_user1, system_user2]} """ asset_groups = {} asset_permissions = user_group.asset_permissions.all() @@ -41,7 +42,6 @@ def get_user_group_granted_assets(user_group): assets[asset] |= set(asset_permission.system_users.all()) else: assets[asset] = set(asset_permission.system_users.all()) - return assets @@ -112,7 +112,6 @@ def get_user_granted_asset_groups(user): asset_groups[asset_group] |= asset_groups_direct[asset_group] else: asset_groups[asset_group] = asset_groups_direct[asset_group] - return asset_groups @@ -175,10 +174,25 @@ def get_user_granted_assets(user): assets[asset] |= assets_direct[asset] else: assets[asset] = assets_direct[asset] - return assets +def get_user_group_asset_permissions(user_group): + permissions = user_group.asset_permissions.all() + return permissions + + +def get_user_asset_permissions(user): + user_group_permissions = set() + direct_permissions = set(setattr_bulk(user.asset_permissions.all(), 'inherited', 0)) + + for user_group in user.groups.all(): + permissions = get_user_group_asset_permissions(user_group) + user_group_permissions |= set(permissions) + user_group_permissions = set(setattr_bulk(user_group_permissions, 'inherited', 1)) + return direct_permissions | user_group_permissions + + def get_user_groups_granted_in_asset(asset): pass diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index 600cfa606..01d62b607 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -198,19 +198,18 @@ function APIUpdateAttr(props) { contentType: props.content_type || "application/json; charset=utf-8", dataType: props.data_type || "json" }).done(function(data, textStatue, jqXHR) { + toastr.success(success_message); if (typeof props.success === 'function') { return props.success(data); - } else { - toastr.success(success_message); - } + } + }).fail(function(jqXHR, textStatue, errorThrown) { + toastr.error(fail_message); if (typeof props.error === 'function') { return props.error(errorThrown); - } else { - toastr.error(textStatue); - } + } }); - return true; + // return true; } // Sweet Alert for Delete diff --git a/apps/users/forms.py b/apps/users/forms.py index 51947372d..bc8079f3b 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -6,8 +6,8 @@ from django.utils.translation import gettext_lazy as _ from captcha.fields import CaptchaField from common.utils import validate_ssh_public_key +from perms.models import AssetPermission from .models import User, UserGroup -from .hands import AssetPermission class UserLoginForm(AuthenticationForm): @@ -101,7 +101,7 @@ class UserPrivateAssetPermissionForm(forms.ModelForm): def save(self, commit=True): self.instance = super(UserPrivateAssetPermissionForm, self).save(commit=commit) - # self.instance.private_for = 'U' + self.instance.private_for = 'U' self.instance.users = [self.user] self.instance.save() return self.instance diff --git a/apps/users/hands.py b/apps/users/hands.py index ad44762a0..41ddbeb3a 100644 --- a/apps/users/hands.py +++ b/apps/users/hands.py @@ -11,5 +11,5 @@ """ from terminal.models import Terminal -from perms.models import AssetPermission -from perms.utils import get_user_granted_assets, get_user_granted_asset_groups +# from perms.models import AssetPermission +# from perms.utils import get_user_granted_assets, get_user_granted_asset_groups diff --git a/apps/users/templates/users/user_asset_permission.html b/apps/users/templates/users/user_asset_permission.html index 4240ecb0b..47cc45803 100644 --- a/apps/users/templates/users/user_asset_permission.html +++ b/apps/users/templates/users/user_asset_permission.html @@ -17,16 +17,16 @@
@@ -159,25 +130,69 @@ {% endblock %} {% block custom_foot_js %} {% endblock %} \ No newline at end of file diff --git a/apps/users/templates/users/user_detail.html b/apps/users/templates/users/user_detail.html index c1cdbc5f5..d4e328465 100644 --- a/apps/users/templates/users/user_detail.html +++ b/apps/users/templates/users/user_detail.html @@ -313,7 +313,6 @@ $(document).ready(function() { var user_groups = $('.bdg_user_group').map(function() { return $(this).data('gid'); }).get(); - console.log(user_groups); updateUserGroups(user_groups) }).on('click', '#btn_reset_password', function() { function doReset() { diff --git a/apps/users/templates/users/user_list.html b/apps/users/templates/users/user_list.html index 087d27db0..cf2c0d2b7 100644 --- a/apps/users/templates/users/user_list.html +++ b/apps/users/templates/users/user_list.html @@ -53,7 +53,7 @@ $(document).ready(function(){ $(td).html(detail_btn.replace('99991937', rowData.id)); }}, {targets: 4, createdCell: function (td, cellData) { - var innerHtml = cellData.length > 8 ? cellData.substring(0, 8) + '...': cellData; + var innerHtml = cellData.length > 20 ? cellData.substring(0, 20) + '...': cellData; $(td).html('' + innerHtml + ''); }}, {targets: 6, createdCell: function (td, cellData) { diff --git a/apps/users/urls.py b/apps/users/urls.py index 6fd732d8c..dd39c87e9 100644 --- a/apps/users/urls.py +++ b/apps/users/urls.py @@ -19,13 +19,13 @@ urlpatterns = [ url(r'^user/(?P[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'), url(r'^user/(?P[0-9]+)/asset-permission$', views.UserAssetPermissionView.as_view(), name='user-asset-permission'), - url(r'^user/(?P[0-9]+)/asset-permission/create$', views.UserAssetPermissionCreateView.as_view(), - name='user-asset-permission-create'), + # url(r'^user/(?P[0-9]+)/asset-permission/create$', views.UserAssetPermissionCreateView.as_view(), + # name='user-asset-permission-create'), url(r'^user/(?P[0-9]+)/granted-asset', views.UserGrantedAssetView.as_view(), name='user-granted-asset'), url(r'^user/(?P[0-9]+)/login-history', views.UserDetailView.as_view(), name='user-login-history'), url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'), url(r'^import/$', views.BulkImportUserView.as_view(), name='user-import'), - url(r'^user/(?P[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'), + # url(r'^user/(?P[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'), url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'), url(r'^user/(?P[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'), diff --git a/apps/users/utils.py b/apps/users/utils.py index 7ce37a463..9797b5fe4 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -120,60 +120,60 @@ def send_reset_ssh_key_mail(user): send_mail_async.delay(subject, message, recipient_list, html_message=message) -def validate_ssh_pk(text): - """ - Expects a SSH private key as string. - Returns a boolean and a error message. - If the text is parsed as private key successfully, - (True,'') is returned. Otherwise, - (False, ) is returned. - - from https://github.com/githubnemo/SSH-private-key-validator/blob/master/validate.py - - """ - - if not text: - return False, 'No text given' - - startPattern = re.compile("^-----BEGIN [A-Z]+ PRIVATE KEY-----") - optionPattern = re.compile("^.+: .+") - contentPattern = re.compile("^([a-zA-Z0-9+/]{64}|[a-zA-Z0-9+/]{1,64}[=]{0,2})$") - endPattern = re.compile("^-----END [A-Z]+ PRIVATE KEY-----") - - def contentState(text): - for i in range(0, len(text)): - line = text[i] - - if endPattern.match(line): - if i == len(text) - 1 or len(text[i + 1]) == 0: - return True, '' - else: - return False, 'At end but content coming' - - elif not contentPattern.match(line): - return False, 'Wrong string in content section' - - return False, 'No content or missing end line' - - def optionState(text): - for i in range(0, len(text)): - line = text[i] - - if line[-1:] == '\\': - return optionState(text[i + 2:]) - - if not optionPattern.match(line): - return contentState(text[i + 1:]) - - return False, 'Expected option, found nothing' - - def startState(text): - if len(text) == 0 or not startPattern.match(text[0]): - return False, 'Header is wrong' - return optionState(text[1:]) - - return startState([n.strip() for n in text.splitlines()]) +# def validate_ssh_pk(text): +# """ +# Expects a SSH private key as string. +# Returns a boolean and a error message. +# If the text is parsed as private key successfully, +# (True,'') is returned. Otherwise, +# (False, ) is returned. +# +# from https://github.com/githubnemo/SSH-private-key-validator/blob/master/validate.py +# +# """ +# +# if not text: +# return False, 'No text given' +# +# startPattern = re.compile("^-----BEGIN [A-Z]+ PRIVATE KEY-----") +# optionPattern = re.compile("^.+: .+") +# contentPattern = re.compile("^([a-zA-Z0-9+/]{64}|[a-zA-Z0-9+/]{1,64}[=]{0,2})$") +# endPattern = re.compile("^-----END [A-Z]+ PRIVATE KEY-----") +# +# def contentState(text): +# for i in range(0, len(text)): +# line = text[i] +# +# if endPattern.match(line): +# if i == len(text) - 1 or len(text[i + 1]) == 0: +# return True, '' +# else: +# return False, 'At end but content coming' +# +# elif not contentPattern.match(line): +# return False, 'Wrong string in content section' +# +# return False, 'No content or missing end line' +# +# def optionState(text): +# for i in range(0, len(text)): +# line = text[i] +# +# if line[-1:] == '\\': +# return optionState(text[i + 2:]) +# +# if not optionPattern.match(line): +# return contentState(text[i + 1:]) +# +# return False, 'Expected option, found nothing' + # def startState(text): + # if len(text) == 0 or not startPattern.match(text[0]): + # return False, 'Header is wrong' + # return optionState(text[1:]) + # + # return startState([n.strip() for n in text.splitlines()]) +# def check_user_valid(**kwargs): password = kwargs.pop('password', None) diff --git a/apps/users/views.py b/apps/users/views.py index 006df3328..5a07efbbc 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -21,14 +21,14 @@ from django.views.generic.list import ListView from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView, SingleObjectMixin, \ FormMixin from django.views.generic.detail import DetailView - from formtools.wizard.views import SessionWizardView from common.mixins import JSONResponseMixin from common.utils import get_object_or_none, get_logger +from perms.models import AssetPermission from .models import User, UserGroup from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_password_mail -from .hands import AssetPermission, get_user_granted_asset_groups, get_user_granted_assets +# from .hands import AssetPermission, get_user_granted_asset_groups, get_user_granted_assets from . import forms @@ -341,32 +341,33 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView): return form -class UserAssetPermissionView(AdminUserRequiredMixin, FormMixin, SingleObjectMixin, ListView): - paginate_by = settings.CONFIG.DISPLAY_PER_PAGE +class UserAssetPermissionView(AdminUserRequiredMixin, DetailView): + model = User template_name = 'users/user_asset_permission.html' - context_object_name = 'user_object' - form_class = forms.UserPrivateAssetPermissionForm + context_object_name = 'user' - def get(self, request, *args, **kwargs): - self.object = self.get_object(queryset=User.objects.all()) - return super(UserAssetPermissionView, self).get(request, *args, **kwargs) + # form_class = forms.UserPrivateAssetPermissionForm - def get_asset_permission_inherit_from_user_group(self): - asset_permissions = set() - user_groups = self.object.groups.all() + # def get(self, request, *args, **kwargs): + # self.object = self.get_object(queryset=User.objects.all()) + # return super(UserAssetPermissionView, self).get(request, *args, **kwargs) - for user_group in user_groups: - for asset_permission in user_group.asset_permissions.all(): - setattr(asset_permission, 'is_inherit_from_user_groups', True) - setattr(asset_permission, 'inherit_from_user_groups', - getattr(asset_permission, b'inherit_from_user_groups', set()).add(user_group)) - asset_permissions.add(asset_permission) - return asset_permissions - - def get_queryset(self): - asset_permissions = set(self.object.asset_permissions.all()) \ - | self.get_asset_permission_inherit_from_user_group() - return list(asset_permissions) + # def get_asset_permission_inherit_from_user_group(self): + # asset_permissions = set() + # user_groups = self.object.groups.all() + # + # for user_group in user_groups: + # for asset_permission in user_group.asset_permissions.all(): + # setattr(asset_permission, 'is_inherit_from_user_groups', True) + # setattr(asset_permission, 'inherit_from_user_groups', + # getattr(asset_permission, b'inherit_from_user_groups', set()).add(user_group)) + # asset_permissions.add(asset_permission) + # return asset_permissions + # + # def get_queryset(self): + # asset_permissions = set(self.object.asset_permissions.all()) \ + # | self.get_asset_permission_inherit_from_user_group() + # return list(asset_permissions) def get_context_data(self, **kwargs): context = { @@ -414,18 +415,19 @@ class UserGrantedAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView): def get_queryset(self): # Convert format from {'asset': ['system_users'], ..} to # [('asset', ['system_users']), ('asset', ['system_users'])) - assets_granted = [(asset, system_users) for asset, system_users in - get_user_granted_assets(self.object).items()] + # assets_granted = [(asset, system_users) for asset, system_users in + # get_user_granted_assets(self.object).items()] - return assets_granted + # return assets_granted + return [] def get_context_data(self, **kwargs): - asset_groups = [(asset_group, system_users) for asset_group, system_users in - get_user_granted_asset_groups(self.object).items()] + # asset_groups = [(asset_group, system_users) for asset_group, system_users in + # get_user_granted_asset_groups(self.object).items()] context = { 'app': 'User', 'action': 'User granted asset', - 'asset_groups': asset_groups, + # 'asset_groups': asset_groups, } kwargs.update(context) return super(UserGrantedAssetView, self).get_context_data(**kwargs)