@@ -61,44 +61,53 @@
{% block table_head %}
{% trans 'ID' %} |
-
{% trans 'Username' %} |
-
{% trans 'IP' %} |
+
{% trans 'User' %} |
+
{% trans 'Asset' %} |
{% trans 'System user' %} |
{% trans 'Command' %} |
{% trans 'Success' %} |
{% trans 'Finished' %} |
+
{% trans 'R/M' %} |
{% trans 'Date start' %} |
{% trans 'Time' %} |
{% endblock %}
{% block table_body %}
- {% for proxy_log in proxy_log_list %}
-
-
- {{ proxy_log.id }}
- |
- {{ proxy_log.username }} |
- {{ proxy_log.ip }} |
- {{ proxy_log.system_user }} |
- {{ proxy_log.commands.all|length}} |
-
- {% if proxy_log.was_failed %}
-
- {% else %}
-
- {% endif %}
- |
-
- {% if proxy_log.is_finished %}
-
- {% else %}
-
- {% endif %}
- |
- {{ proxy_log.date_start }} |
- {{ proxy_log.date_finished|timeuntil:proxy_log.date_start }} |
-
- {% endfor %}
+ {% for proxy_log in proxy_log_list %}
+
+
+ {{ proxy_log.id }}
+ |
+ {{ proxy_log.user }} |
+ {{ proxy_log.asset }} |
+ {{ proxy_log.system_user }} |
+ {{ proxy_log.commands.all|length}} |
+
+ {% if proxy_log.is_failed %}
+
+ {% else %}
+
+ {% endif %}
+ |
+ {% if proxy_log.is_finished %}
+
+
+ |
+
+
+ |
+ {% else %}
+
+
+ |
+
+
+ |
+ {% endif %}
+ {{ proxy_log.date_start }} |
+ {{ proxy_log.date_finished|timeuntil:proxy_log.date_start }} |
+
+ {% endfor %}
{% endblock %}
{% block custom_foot_js %}
diff --git a/apps/audits/urls/api_urls.py b/apps/audits/urls/api_urls.py
index 1f06cc3cc..ca8ed9c19 100644
--- a/apps/audits/urls/api_urls.py
+++ b/apps/audits/urls/api_urls.py
@@ -10,7 +10,8 @@ router.register(r'v1/proxy-log', api.ProxyLogViewSet, 'proxy-log')
router.register(r'v1/command-log', api.CommandLogViewSet, 'command-log')
urlpatterns = [
- url(r'^v1/proxy-log/receive/$', api.ProxyLogReceiveView.as_view(), name='proxy-log-receive'),
+ url(r'^v1/proxy-log/receive/$', api.ProxyLogReceiveView.as_view(),
+ name='proxy-log-receive'),
]
urlpatterns += router.urls
diff --git a/apps/audits/views.py b/apps/audits/views.py
index 8ff2fc6cf..144e8f35d 100644
--- a/apps/audits/views.py
+++ b/apps/audits/views.py
@@ -1,17 +1,23 @@
# ~*~ coding: utf-8 ~*~
#
-import datetime
+import time
+from datetime import datetime
+import pytz
from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView
from django.views.generic.edit import SingleObjectMixin
from django.utils.translation import ugettext as _
from django.utils import timezone
+from django.utils.module_loading import import_string
from django.urls import reverse_lazy
+from django.http import HttpResponse
from django.conf import settings
from django.db.models import Q
from .models import ProxyLog, CommandLog, LoginLog
from .hands import User, Asset, SystemUser, AdminUserRequiredMixin
+from audits.backends import command_store
+from audits.backends import CommandLogSerializer
class ProxyLogListView(AdminUserRequiredMixin, ListView):
@@ -19,42 +25,45 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
template_name = 'audits/proxy_log_list.html'
context_object_name = 'proxy_log_list'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
-
- keyword = username = ip = system_user = date_from_s = date_to_s = ''
+ keyword = user = asset = system_user = date_from_s = date_to_s = ''
+ ordering = ['is_finished', '-id']
+ date_format = '%m/%d/%Y'
def get_queryset(self):
date_now = timezone.localtime(timezone.now())
- now_s = date_now.strftime('%m/%d/%Y')
- seven_days_ago_s = (date_now-timezone.timedelta(7)).strftime('%m/%d/%Y')
+ date_to_default = date_now.strftime(self.date_format)
+ date_from_default = (date_now-timezone.timedelta(7))\
+ .strftime(self.date_format)
self.queryset = super(ProxyLogListView, self).get_queryset()
- self.keyword = keyword = self.request.GET.get('keyword', '')
- self.username = username = self.request.GET.get('username', '')
- self.ip = ip = self.request.GET.get('ip', '')
- self.system_user = system_user = self.request.GET.get('system_user', '')
- self.date_from_s = date_from_s = self.request.GET.get('date_from', '%s' % seven_days_ago_s)
- self.date_to_s = date_to_s = self.request.GET.get('date_to', '%s' % now_s)
+ self.keyword = self.request.GET.get('keyword', '')
+ self.user = self.request.GET.get('user')
+ self.asset = self.request.GET.get('asset')
+ self.system_user = self.request.GET.get('system_user')
+ self.date_from_s = self.request.GET.get('date_from', date_from_default)
+ self.date_to_s = self.request.GET.get('date_to', date_to_default)
- if date_from_s:
- date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
- self.queryset = self.queryset.filter(date_start__gt=date_from)
- if date_to_s:
- date_to = timezone.datetime.strptime(date_to_s + ' 23:59:59',
- '%m/%d/%Y %H:%M:%S')
- self.queryset = self.queryset.filter(date_start__lt=date_to)
- if username:
- self.queryset = self.queryset.filter(username=username)
- if ip:
- self.queryset = self.queryset.filter(ip=ip)
- if system_user:
- self.queryset = self.queryset.filter(system_user=system_user)
- if keyword:
+ filter_kwargs = {}
+ if self.date_from_s:
+ date_from = datetime.strptime(self.date_from_s, self.date_format)
+ date_from.replace(tzinfo=timezone.get_current_timezone())
+ filter_kwargs['date_start__gt'] = date_from
+ if self.date_to_s:
+ date_to = timezone.datetime.strptime(
+ self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
+ date_to.replace(tzinfo=timezone.get_current_timezone())
+ filter_kwargs['date_start__lt'] = date_to
+ if self.user:
+ filter_kwargs['user'] = self.user
+ if self.asset:
+ filter_kwargs['asset'] = self.asset
+ if self.system_user:
+ filter_kwargs['system_user'] = self.system_user
+ if self.keyword:
self.queryset = self.queryset.filter(
- Q(username__contains=keyword) |
- Q(name__icontains=keyword) |
- Q(hostname__icontains=keyword) |
- Q(ip__icontains=keyword) |
- Q(system_user__icontains=keyword)).distinct()
+ Q(user__icontains=self.keyword) |
+ Q(asset__icontains=self.keyword) |
+ Q(system_user__icontains=self.keyword)).distinct()
return self.queryset
def get_context_data(self, **kwargs):
@@ -62,16 +71,16 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
'app': _('Audits'),
'action': _('Proxy log list'),
'user_list': set(
- list(ProxyLog.objects.values_list('username', flat=True))),
+ list(ProxyLog.objects.values_list('user', flat=True))),
'asset_list': set(
- list(ProxyLog.objects.values_list('ip', flat=True))),
+ list(ProxyLog.objects.values_list('asset', flat=True))),
'system_user_list': set(
list(ProxyLog.objects.values_list('system_user', flat=True))),
'keyword': self.keyword,
'date_from': self.date_from_s,
'date_to': self.date_to_s,
- 'username': self.username,
- 'ip': self.ip,
+ 'user': self.user,
+ 'asset': self.asset,
'system_user': self.system_user,
}
kwargs.update(context)
@@ -90,7 +99,7 @@ class ProxyLogDetailView(AdminUserRequiredMixin,
return super(ProxyLogDetailView, self).get(request, *args, **kwargs)
def get_queryset(self):
- return list(self.object.commands.all())
+ return list(command_store.filter(proxy_log_id=self.object.id))
def get_context_data(self, **kwargs):
context = {
@@ -117,42 +126,49 @@ class ProxyLogCommandsListView(AdminUserRequiredMixin,
class CommandLogListView(AdminUserRequiredMixin, ListView):
- model = CommandLog
template_name = 'audits/command_log_list.html'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'command_list'
- keyword = username = ip = system_user = date_from_s = date_to_s = ''
+ user = asset = system_user = command = date_from_s = date_to_s = ''
+ date_format = '%m/%d/%Y'
+ ordering = ['-id']
def get_queryset(self):
date_now = timezone.localtime(timezone.now())
- now_s = date_now.strftime('%m/%d/%Y')
- seven_days_ago_s = (date_now-timezone.timedelta(7)).strftime('%m/%d/%Y')
- self.queryset = super(CommandLogListView, self).get_queryset()
- self.keyword = keyword = self.request.GET.get('keyword', '')
- self.username = username = self.request.GET.get('username', '')
- self.ip = ip = self.request.GET.get('ip', '')
- self.system_user = system_user = self.request.GET.get('system_user', '')
- self.date_from_s = date_from_s = \
- self.request.GET.get('date_from', '%s' % seven_days_ago_s)
- self.date_to_s = date_to_s = \
- self.request.GET.get('date_to', '%s' % now_s)
+ date_to_default = date_now.strftime(self.date_format)
+ date_from_default = (date_now - timezone.timedelta(7)) \
+ .strftime(self.date_format)
+ self.command = self.request.GET.get('command', '')
+ self.user = self.request.GET.get('user')
+ self.asset = self.request.GET.get('asset')
+ self.system_user = self.request.GET.get('system_user')
+ self.date_from_s = \
+ self.request.GET.get('date_from', date_from_default)
+ self.date_to_s = \
+ self.request.GET.get('date_to', date_to_default)
- if date_from_s:
- date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
- self.queryset = self.queryset.filter(datetime__gt=date_from)
- if date_to_s:
- date_to = timezone.datetime.strptime(
- date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
- self.queryset = self.queryset.filter(datetime__lt=date_to)
- if username:
- self.queryset = self.queryset.filter(proxy_log__username=username)
- if ip:
- self.queryset = self.queryset.filter(proxy_log__ip=ip)
- if system_user:
- self.queryset = self.queryset.filter(
- proxy_log__system_user=system_user)
- if keyword:
- self.queryset = self.queryset.filter(command=keyword)
+ filter_kwargs = {}
+ if self.date_from_s:
+ date_from = datetime.strptime(self.date_from_s, self.date_format)\
+ .replace(tzinfo=timezone.get_current_timezone())
+ # date_from_utc = date_from.astimezone(pytz.utc)
+ date_from_ts = time.mktime(date_from.timetuple())
+ filter_kwargs['date_from_ts'] = date_from_ts
+ if self.date_to_s:
+ date_to = datetime.strptime(
+ self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')\
+ .replace(tzinfo=timezone.get_current_timezone())
+ date_to_ts = time.mktime(date_to.timetuple())
+ filter_kwargs['date_to_ts'] = date_to_ts
+ if self.user:
+ filter_kwargs['user'] = self.user
+ if self.asset:
+ filter_kwargs['asset'] = self.asset
+ if self.system_user:
+ filter_kwargs['system_user'] = self.system_user
+ if self.command:
+ filter_kwargs['command'] = self.command
+ self.queryset = command_store.filter(**filter_kwargs).order_by(*self.ordering)
return self.queryset
def get_context_data(self, **kwargs):
@@ -161,12 +177,12 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
'action': _('Command log list'),
'user_list': User.objects.all().order_by('username'),
'asset_list': Asset.objects.all().order_by('ip'),
- 'system_user_list': SystemUser.objects.all().order_by('name'),
- 'keyword': self.keyword,
+ 'system_user_list': SystemUser.objects.all().order_by('username'),
+ 'command': self.command,
'date_from': self.date_from_s,
'date_to': self.date_to_s,
- 'username': self.username,
- 'ip': self.ip,
+ 'user': self.user,
+ 'asset': self.asset,
'system_user': self.system_user,
}
kwargs.update(context)
@@ -178,7 +194,6 @@ class LoginLogListView(AdminUserRequiredMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
template_name = 'audits/login_log_list.html'
context_object_name = 'login_log_list'
-
keyword = username = date_from_s = date_to_s = ''
def get_queryset(self):
diff --git a/apps/common/templatetags/common_tags.py b/apps/common/templatetags/common_tags.py
index f096df945..01d1ab8f3 100644
--- a/apps/common/templatetags/common_tags.py
+++ b/apps/common/templatetags/common_tags.py
@@ -3,7 +3,8 @@
from django import template
from django.utils import timezone
from django.conf import settings
-
+from django.utils.html import escape
+from audits.backends import command_store
register = template.Library()
@@ -41,10 +42,30 @@ def join_attr(seq, attr=None, sep=None):
sep = ', '
if attr is not None:
seq = [getattr(obj, attr) for obj in seq]
- print(seq)
return sep.join(seq)
@register.filter
def int_to_str(value):
- return str(value)
\ No newline at end of file
+ return str(value)
+
+
+@register.filter
+def ts_to_date(ts):
+ try:
+ ts = float(ts)
+ except TypeError:
+ ts = 0
+ dt = timezone.datetime.fromtimestamp(ts).\
+ replace(tzinfo=timezone.get_current_timezone())
+ return dt.strftime('%Y-%m-%d %H:%M:%S')
+
+
+@register.filter
+def to_html(s):
+ return escape(s).replace('\n', '
')
+
+
+@register.filter
+def proxy_log_commands(log_id):
+ return command_store.filter(proxy_log_id=log_id)
\ No newline at end of file
diff --git a/apps/common/utils.py b/apps/common/utils.py
index efc1b769d..a5f7d8c26 100644
--- a/apps/common/utils.py
+++ b/apps/common/utils.py
@@ -33,8 +33,10 @@ from .compat import to_bytes, to_string
SECRET_KEY = settings.SECRET_KEY
-def reverse(view_name, urlconf=None, args=None, kwargs=None, current_app=None, external=False):
- url = dj_reverse(view_name, urlconf=urlconf, args=args, kwargs=kwargs, current_app=current_app)
+def reverse(view_name, urlconf=None, args=None, kwargs=None,
+ current_app=None, external=False):
+ url = dj_reverse(view_name, urlconf=urlconf, args=args,
+ kwargs=kwargs, current_app=current_app)
if external:
url = settings.SITE_URL.strip('/') + url
@@ -44,8 +46,8 @@ def reverse(view_name, urlconf=None, args=None, kwargs=None, current_app=None, e
def get_object_or_none(model, **kwargs):
try:
obj = model.objects.get(**kwargs)
- except model.DoesNotExist:
- obj = None
+ except (model.FieldError, model.DoesNotExist):
+ return None
return obj
diff --git a/apps/jumpserver/middleware.py b/apps/jumpserver/middleware.py
new file mode 100644
index 000000000..2ed94c6a8
--- /dev/null
+++ b/apps/jumpserver/middleware.py
@@ -0,0 +1,14 @@
+# ~*~ coding: utf-8 ~*~
+
+import pytz
+from django.utils import timezone
+from django.utils.deprecation import MiddlewareMixin
+
+
+class TimezoneMiddleware(MiddlewareMixin):
+ def process_request(self, request):
+ tzname = request.META.get('TZ')
+ if tzname:
+ timezone.activate(pytz.timezone(tzname))
+ else:
+ timezone.deactivate()
diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py
index 8fa5a65c5..5f68ed231 100644
--- a/apps/jumpserver/settings.py
+++ b/apps/jumpserver/settings.py
@@ -79,6 +79,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'jumpserver.middleware.TimezoneMiddleware',
]
ROOT_URLCONF = 'jumpserver.urls'
@@ -323,3 +324,5 @@ CACHES = {
CAPTCHA_IMAGE_SIZE = (75, 33)
CAPTCHA_FOREGROUND_COLOR = '#001100'
+COMMAND_STORE_BACKEND = 'audits.backends.command.db'
+
diff --git a/apps/perms/api.py b/apps/perms/api.py
index ea4c9e05a..0854feb0a 100644
--- a/apps/perms/api.py
+++ b/apps/perms/api.py
@@ -14,6 +14,7 @@ from .models import AssetPermission
from .hands import AssetGrantedSerializer, User, UserGroup, AssetGroup, Asset, \
AssetGroup, AssetGroupSerializer, SystemUser
from . import serializers
+from .utils import associate_system_users_and_assets
class AssetPermissionViewSet(viewsets.ModelViewSet):
@@ -35,11 +36,32 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
queryset = get_user_group_asset_permissions(user_group)
return queryset
+ # Todo: 忘记为何要重写get_serializer_class了
def get_serializer_class(self):
if getattr(self, 'user_id', ''):
return serializers.UserAssetPermissionSerializer
return serializers.AssetPermissionSerializer
+ def associate_system_users_and_assets(self, serializer):
+ assets = serializer.validated_data.get('assets', [])
+ asset_groups = serializer.validated_data.get('asset_groups', [])
+ system_users = serializer.validated_data.get('system_users', [])
+ if serializer.partial:
+ instance = self.get_object()
+ assets.extend(list(instance.assets.all()))
+ asset_groups.extend(list(instance.asset_groups.all()))
+ system_users.extend(list(instance.system_users.all()))
+ print('Run')
+ associate_system_users_and_assets(system_users, assets, asset_groups)
+
+ def perform_create(self, serializer):
+ self.associate_system_users_and_assets(serializer)
+ return super(AssetPermissionViewSet, self).perform_create(serializer)
+
+ def perform_update(self, serializer):
+ self.associate_system_users_and_assets(serializer)
+ return super(AssetPermissionViewSet, self).perform_update(serializer)
+
class RevokeUserAssetPermission(APIView):
permission_classes = (IsSuperUser,)
@@ -58,6 +80,27 @@ class RevokeUserAssetPermission(APIView):
return Response({'msg': 'failed'}, status=404)
+class RemoveSystemUserAssetPermission(APIView):
+ """将系统用户从授权中移除, Detail页面会调用"""
+ permission_classes = (IsSuperUser,)
+
+ def put(self, request, *args, **kwargs):
+ response = []
+ asset_permission_id = kwargs.pop('pk')
+ system_users_id = request.data.get('system_users')
+ print(system_users_id)
+ asset_permission = get_object_or_404(
+ AssetPermission, id=asset_permission_id)
+ if not isinstance(system_users_id, list):
+ system_users_id = [system_users_id]
+ for system_user_id in system_users_id:
+ system_user = get_object_or_none(SystemUser, id=system_user_id)
+ if system_user:
+ asset_permission.system_users.remove(system_user)
+ response.append(system_user.to_json())
+ return Response(response, status=200)
+
+
class RevokeUserGroupAssetPermission(APIView):
permission_classes = (IsSuperUser,)
diff --git a/apps/perms/forms.py b/apps/perms/forms.py
index 27c8136c0..d99dfa3be 100644
--- a/apps/perms/forms.py
+++ b/apps/perms/forms.py
@@ -6,19 +6,9 @@ from django.utils.translation import ugettext_lazy as _
# from .hands import User, UserGroup, Asset, AssetGroup, SystemUser
from .models import AssetPermission
-from .hands import associate_system_users_with_assets
class AssetPermissionForm(forms.ModelForm):
- def save(self, commit=True):
- instance = super(AssetPermissionForm, self).save(commit=commit)
-
- assets = instance.assets.all()
- asset_groups = instance.asset_groups.all()
- system_users = instance.system_users.all()
- associate_system_users_with_assets(system_users, assets, asset_groups)
- return instance
-
class Meta:
model = AssetPermission
fields = [
@@ -48,4 +38,3 @@ class AssetPermissionForm(forms.ModelForm):
'asset_groups': '* Asset or Asset group at least one required',
'system_users': '* required',
}
-
diff --git a/apps/perms/hands.py b/apps/perms/hands.py
index eac38f7d0..dd8e61090 100644
--- a/apps/perms/hands.py
+++ b/apps/perms/hands.py
@@ -7,9 +7,9 @@ from assets.models import Asset, AssetGroup, SystemUser
from assets.serializers import AssetGrantedSerializer, AssetGroupSerializer
-def associate_system_users_with_assets(system_users, assets, asset_groups):
+def push_system_user(assets, system_user):
+ print('Push system user %s' % system_user.name)
for asset in assets:
- asset.system_users.add(*tuple(system_users))
+ print('\tAsset: %s' % asset.ip)
+
- for asset_group in asset_groups:
- asset_group.system_users.add(*tuple(system_users))
diff --git a/apps/perms/models.py b/apps/perms/models.py
index f1d4b4b1f..1cdd39558 100644
--- a/apps/perms/models.py
+++ b/apps/perms/models.py
@@ -4,6 +4,7 @@ import functools
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
+from django.db.models.signals import m2m_changed
from users.models import User, UserGroup
from assets.models import Asset, AssetGroup, SystemUser
@@ -16,18 +17,26 @@ class AssetPermission(models.Model):
# ('U', 'user'),
# ('G', 'user group'),
# )
- name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
- users = models.ManyToManyField(User, related_name='asset_permissions', blank=True)
- user_groups = models.ManyToManyField(UserGroup, related_name='asset_permissions', blank=True)
- assets = models.ManyToManyField(Asset, related_name='granted_by_permissions', blank=True)
- asset_groups = models.ManyToManyField(AssetGroup, related_name='granted_by_permissions', blank=True)
- system_users = models.ManyToManyField(SystemUser, related_name='granted_by_permissions')
- # private_for = models.CharField(choices=PRIVATE_FOR_CHOICE, max_length=1, default='N', blank=True,
- # verbose_name=_('Private for'))
- is_active = models.BooleanField(default=True, verbose_name=_('Active'))
- date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired'))
- created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by'))
- date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
+ name = models.CharField(
+ max_length=128, unique=True, verbose_name=_('Name'))
+ users = models.ManyToManyField(
+ User, related_name='asset_permissions', blank=True)
+ user_groups = models.ManyToManyField(
+ UserGroup, related_name='asset_permissions', blank=True)
+ assets = models.ManyToManyField(
+ Asset, related_name='granted_by_permissions', blank=True)
+ asset_groups = models.ManyToManyField(
+ AssetGroup, related_name='granted_by_permissions', blank=True)
+ system_users = models.ManyToManyField(
+ SystemUser, related_name='granted_by_permissions')
+ is_active = models.BooleanField(
+ default=True, verbose_name=_('Active'))
+ date_expired = models.DateTimeField(
+ default=date_expired_default, verbose_name=_('Date expired'))
+ created_by = models.CharField(
+ max_length=128, blank=True, verbose_name=_('Created by'))
+ date_created = models.DateTimeField(
+ auto_now_add=True, verbose_name=_('Date created'))
comment = models.TextField(verbose_name=_('Comment'), blank=True)
def __unicode__(self):
@@ -68,3 +77,15 @@ class AssetPermission(models.Model):
class Meta:
db_table = 'asset_permission'
+
+# def change_permission(sender, **kwargs):
+# print('Sender: %s' % sender)
+# for k, v in kwargs.items():
+# print('%s: %s' % (k, v))
+# print()
+
+#
+# m2m_changed.connect(change_permission, sender=AssetPermission.assets.through)
+
+
+
diff --git a/apps/perms/templates/perms/asset_permission_detail.html b/apps/perms/templates/perms/asset_permission_detail.html
index 4f6b7725e..1126b9705 100644
--- a/apps/perms/templates/perms/asset_permission_detail.html
+++ b/apps/perms/templates/perms/asset_permission_detail.html
@@ -169,16 +169,16 @@
-
+
|
{% for system_user in system_users %}
- {{ system_user.name }} |
+ {{ system_user.name }} |
-
+
|
{% endfor %}
@@ -196,8 +196,47 @@
{% endblock %}
{% block custom_foot_js %}
{% endblock %}
\ No newline at end of file
diff --git a/apps/perms/templates/perms/asset_permission_user.html b/apps/perms/templates/perms/asset_permission_user.html
index 02a571e9f..168bc1149 100644
--- a/apps/perms/templates/perms/asset_permission_user.html
+++ b/apps/perms/templates/perms/asset_permission_user.html
@@ -108,7 +108,7 @@
@@ -136,7 +136,7 @@
@@ -172,25 +172,29 @@
{% endblock %}
{% block custom_foot_js %}
{% endblock %}
\ No newline at end of file
diff --git a/apps/perms/tests.py b/apps/perms/tests.py
index 7ce503c2d..4fd76b0f2 100644
--- a/apps/perms/tests.py
+++ b/apps/perms/tests.py
@@ -1,3 +1,4 @@
from django.test import TestCase
-# Create your tests here.
+from django.contrib.sessions.backends import file, db, cache
+from django.contrib.auth.views import login
\ No newline at end of file
diff --git a/apps/perms/urls/api_urls.py b/apps/perms/urls/api_urls.py
index 0e97a441e..db2d74829 100644
--- a/apps/perms/urls/api_urls.py
+++ b/apps/perms/urls/api_urls.py
@@ -50,7 +50,12 @@ urlpatterns = [
# 验证用户是否有某个资产和系统用户的权限
url(r'v1/asset-permission/user/validate/$',
api.ValidateUserAssetPermissionView.as_view(),
- name='validate-user-asset-permission')
+ name='validate-user-asset-permission'),
+
+ # 删除asset permission中的某个系统用户
+ url(r'^v1/asset-permissions/(?P
[0-9]+)/system-user/remove/$',
+ api.RemoveSystemUserAssetPermission.as_view(),
+ name='remove-system-user-asset-permission'),
]
urlpatterns += router.urls
diff --git a/apps/perms/utils.py b/apps/perms/utils.py
index f01ae1779..efad6cbce 100644
--- a/apps/perms/utils.py
+++ b/apps/perms/utils.py
@@ -1,14 +1,18 @@
+# coding: utf-8
+
from __future__ import absolute_import, unicode_literals
from common.utils import setattr_bulk
-from .hands import User, UserGroup, Asset, AssetGroup, SystemUser
+from .hands import User, UserGroup, Asset, AssetGroup, SystemUser, \
+ push_system_user
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: {asset_group1: {system_user1, }, asset_group2: {system_user1, system_user2}}
+ :return: {asset_group1: {system_user1, },
+ asset_group2: {system_user1, system_user2}}
"""
asset_groups = {}
asset_permissions = user_group.asset_permissions.all()
@@ -50,7 +54,8 @@ def get_user_granted_asset_groups_direct(user):
"""Return asset groups granted of the user direct nor inherit from user group
:param user: Instance of :class: ``User``
- :return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]}
+ :return: {asset_group: {system_user1, },
+ asset_group2: {system_user1, system_user2]}
"""
asset_groups = {}
asset_permissions_direct = user.asset_permissions.all()
@@ -72,7 +77,8 @@ def get_user_granted_asset_groups_inherit_from_user_groups(user):
"""Return asset groups granted of the user and inherit from user group
:param user: Instance of :class: ``User``
- :return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]}
+ :return: {asset_group: {system_user1, },
+ asset_group2: {system_user1, system_user2]}
"""
asset_groups = {}
user_groups = user.groups.all()
@@ -103,7 +109,8 @@ def get_user_granted_asset_groups(user):
:return: {asset1: {system_user1, system_user2}, asset2: {...}}
"""
- asset_groups_inherit_from_user_groups = get_user_granted_asset_groups_inherit_from_user_groups(user)
+ asset_groups_inherit_from_user_groups = \
+ get_user_granted_asset_groups_inherit_from_user_groups(user)
asset_groups_direct = get_user_granted_asset_groups_direct(user)
asset_groups = asset_groups_inherit_from_user_groups
@@ -211,3 +218,27 @@ def get_user_groups_granted_in_asset_group(asset):
def get_users_granted_in_asset_group(asset):
pass
+
+
+def associate_system_users_and_assets(system_users, assets, asset_groups):
+ """关联系统用户和资产, 目的是保存它们的关系, 然后新加入的资产或系统
+ 用户时,推送系统用户到资产
+
+ Todo: 这里需要最终Api定下来更改一下, 现在策略是以系统用户为核心推送, 一个系统用户
+ 推送一次
+ """
+ assets_all = set(assets)
+
+ for asset_group in asset_groups:
+ assets_all |= set(asset_group.assets.all())
+
+ for system_user in system_users:
+ assets_need_push = []
+ if system_user.auto_push:
+ assets_need_push.extend(
+ [asset for asset in assets_all
+ if asset not in system_user.assets.all()
+ ]
+ )
+ system_user.assets.add(*(tuple(assets_all)))
+ push_system_user(assets_need_push, system_user)
diff --git a/apps/perms/views.py b/apps/perms/views.py
index 72db844c9..b1aac2f9a 100644
--- a/apps/perms/views.py
+++ b/apps/perms/views.py
@@ -6,16 +6,18 @@ import functools
from django.utils.translation import ugettext as _
from django.conf import settings
from django.db.models import Q
-from django.views.generic import TemplateView, ListView
-from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
+from django.views.generic import ListView, CreateView, UpdateView
+from django.views.generic.edit import DeleteView, FormView
from django.urls import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.detail import DetailView, SingleObjectMixin
from common.utils import search_object_attr
-from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, Asset, AssetGroup
+from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, \
+ Asset, AssetGroup
from .models import AssetPermission
from .forms import AssetPermissionForm
+from .utils import associate_system_users_and_assets
class AssetPermissionListView(AdminUserRequiredMixin, ListView):
@@ -79,6 +81,16 @@ class AssetPermissionCreateView(AdminUserRequiredMixin,
self.object.name,))
return success_message
+ def form_valid(self, form):
+ assets = form.cleaned_data['assets']
+ asset_groups = form.cleaned_data['asset_groups']
+ system_users = form.cleaned_data['system_users']
+ associate_system_users_and_assets(system_users, assets, asset_groups)
+ response = super(AssetPermissionCreateView, self).form_valid(form)
+ self.object.created_by = self.request.user.name
+ self.object.save()
+ return response
+
class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
model = AssetPermission
@@ -100,6 +112,13 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
kwargs={'pk': self.object.pk})
return success_url
+ def form_valid(self, form):
+ assets = form.cleaned_data['assets']
+ asset_groups = form.cleaned_data['asset_groups']
+ system_users = form.cleaned_data['system_users']
+ associate_system_users_and_assets(system_users, assets, asset_groups)
+ return super(AssetPermissionUpdateView, self).form_valid(form)
+
class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
template_name = 'perms/asset_permission_detail.html'
diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js
index f11416e90..2ad48ec86 100644
--- a/apps/static/js/jumpserver.js
+++ b/apps/static/js/jumpserver.js
@@ -187,28 +187,28 @@ function activeNav() {
}
function APIUpdateAttr(props) {
- // props = {url: .., body: , success: , error: , method: ,}
- props = props || {};
- var success_message = props.success_message || 'Update Successfully!';
- var fail_message = props.fail_message || 'Error occurred while updating.';
- $.ajax({
- url: props.url,
- type: props.method || "PATCH",
- data: props.body,
- 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);
- }
-
- }).fail(function(jqXHR, textStatue, errorThrown) {
- toastr.error(fail_message);
- if (typeof props.error === 'function') {
- return props.error(errorThrown);
- }
- });
+ // props = {url: .., body: , success: , error: , method: ,}
+ props = props || {};
+ var success_message = props.success_message || 'Update Successfully!';
+ var fail_message = props.fail_message || 'Error occurred while updating.';
+ $.ajax({
+ url: props.url,
+ type: props.method || "PATCH",
+ data: props.body,
+ 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);
+ }
+
+ }).fail(function(jqXHR, textStatue, errorThrown) {
+ toastr.error(fail_message);
+ if (typeof props.error === 'function') {
+ return props.error(errorThrown);
+ }
+ });
// return true;
}
diff --git a/apps/users/authentication.py b/apps/users/authentication.py
index 57cd89386..b8e2601e6 100644
--- a/apps/users/authentication.py
+++ b/apps/users/authentication.py
@@ -107,7 +107,6 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
if not access_key.user.is_active:
raise exceptions.AuthenticationFailed(_('User disabled.'))
-
return access_key.user, None
diff --git a/apps/users/forms.py b/apps/users/forms.py
index 56be49f0f..5521713fc 100644
--- a/apps/users/forms.py
+++ b/apps/users/forms.py
@@ -31,7 +31,9 @@ class UserCreateUpdateForm(forms.ModelForm):
'email': '* required',
}
widgets = {
- 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}),
+ 'groups': forms.SelectMultiple(
+ attrs={'class': 'select2',
+ 'data-placeholder': _('Join user groups')}),
}
@@ -41,29 +43,11 @@ class UserBulkImportForm(forms.ModelForm):
fields = ['username', 'email', 'enable_otp', 'role']
-# class UserUpdateForm(forms.ModelForm):
-#
-# class Meta:
-# model = User
-# fields = [
-# 'name', 'email', 'groups', 'wechat',
-# 'phone', 'enable_otp', 'role', 'date_expired', 'comment',
-# ]
-# help_texts = {
-# 'username': '* required',
-# 'email': '* required',
-# 'groups': '* required'
-# }
-# widgets = {
-# 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}),
-# }
-
-
class UserGroupForm(forms.ModelForm):
class Meta:
model = UserGroup
fields = [
- 'name', 'comment',
+ 'name', 'comment'
]
help_texts = {
'name': '* required'
@@ -87,7 +71,8 @@ class UserKeyForm(forms.Form):
def clean_public_key(self):
public_key = self.cleaned_data['public_key']
if self.user.public_key and public_key == self.user.public_key:
- raise forms.ValidationError(_('Public key should not be the same as your old one.'))
+ raise forms.ValidationError(_('Public key should not be the '
+ 'same as your old one.'))
if not validate_ssh_public_key(public_key):
raise forms.ValidationError(_('Not a valid ssh public key'))
@@ -97,7 +82,8 @@ class UserKeyForm(forms.Form):
class UserPrivateAssetPermissionForm(forms.ModelForm):
def save(self, commit=True):
- self.instance = super(UserPrivateAssetPermissionForm, self).save(commit=commit)
+ self.instance = super(UserPrivateAssetPermissionForm, self)\
+ .save(commit=commit)
self.instance.users = [self.user]
self.instance.save()
return self.instance
@@ -108,19 +94,23 @@ class UserPrivateAssetPermissionForm(forms.ModelForm):
'assets', 'asset_groups', 'system_users', 'name',
]
widgets = {
- 'assets': forms.SelectMultiple(attrs={'class': 'select2',
- 'data-placeholder': _('Select assets')}),
- 'asset_groups': forms.SelectMultiple(attrs={'class': 'select2',
- 'data-placeholder': _('Select asset groups')}),
- 'system_users': forms.SelectMultiple(attrs={'class': 'select2',
- 'data-placeholder': _('Select system users')}),
+ 'assets': forms.SelectMultiple(
+ attrs={'class': 'select2',
+ 'data-placeholder': _('Select assets')}),
+ 'asset_groups': forms.SelectMultiple(
+ attrs={'class': 'select2',
+ 'data-placeholder': _('Select asset groups')}),
+ 'system_users': forms.SelectMultiple(
+ attrs={'class': 'select2',
+ 'data-placeholder': _('Select system users')}),
}
class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
def save(self, commit=True):
- self.instance = super(UserGroupPrivateAssetPermissionForm, self).save(commit=commit)
+ self.instance = super(UserGroupPrivateAssetPermissionForm, self)\
+ .save(commit=commit)
self.instance.user_groups = [self.user_group]
self.instance.save()
return self.instance
@@ -131,12 +121,15 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
'assets', 'asset_groups', 'system_users', 'name',
]
widgets = {
- 'assets': forms.SelectMultiple(attrs={'class': 'select2',
- 'data-placeholder': _('Select assets')}),
- 'asset_groups': forms.SelectMultiple(attrs={'class': 'select2',
- 'data-placeholder': _('Select asset groups')}),
- 'system_users': forms.SelectMultiple(attrs={'class': 'select2',
- 'data-placeholder': _('Select system users')}),
+ 'assets': forms.SelectMultiple(
+ attrs={'class': 'select2',
+ 'data-placeholder': _('Select assets')}),
+ 'asset_groups': forms.SelectMultiple(
+ attrs={'class': 'select2',
+ 'data-placeholder': _('Select asset groups')}),
+ 'system_users': forms.SelectMultiple(
+ attrs={'class': 'select2',
+ 'data-placeholder': _('Select system users')}),
}
diff --git a/apps/users/views/group.py b/apps/users/views/group.py
index 48232b72a..fe04987a4 100644
--- a/apps/users/views/group.py
+++ b/apps/users/views/group.py
@@ -44,6 +44,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, CreateView):
'users': users})
return context
+ # 需要添加组下用户, 而user并不是group的多对多,所以需要手动建立关系
def form_valid(self, form):
user_group = form.save()
users_id_list = self.request.POST.getlist('users', [])
diff --git a/deb_requirements.txt b/requirements/deb_requirements.txt
similarity index 100%
rename from deb_requirements.txt
rename to requirements/deb_requirements.txt
diff --git a/requirements/mac_requirements.py b/requirements/mac_requirements.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/requirements.txt b/requirements/requirements.txt
similarity index 100%
rename from requirements.txt
rename to requirements/requirements.txt
diff --git a/rpm_requirements.txt b/requirements/rpm_requirements.txt
similarity index 100%
rename from rpm_requirements.txt
rename to requirements/rpm_requirements.txt