@@ -306,6 +305,7 @@ function defaultCallback(action) {
$(document).ready(function () {
+ $('.treebox').css('height', window.innerHeight - 180);
})
.on('click', '.btn-show-current-asset', function(){
hideRMenu();
@@ -322,4 +322,4 @@ $(document).ready(function () {
location.reload();
})
-
\ No newline at end of file
+
diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html
index be267cc4d..fcc17c87d 100644
--- a/apps/assets/templates/assets/asset_list.html
+++ b/apps/assets/templates/assets/asset_list.html
@@ -426,13 +426,15 @@ $(document).ready(function(){
function success(data) {
url = setUrlParam(the_url, 'spm', data.spm);
requestApi({
- url:url,
- method:'DELETE',
- success:refreshPage,
- flash_message:false,
+ url: url,
+ method: 'DELETE',
+ success: function () {
+ var msg = "{% trans 'Asset Deleted.' %}";
+ swal("{% trans 'Asset Delete' %}", msg, "success");
+ refreshPage();
+ },
+ flash_message: false,
});
- var msg = "{% trans 'Asset Deleted.' %}";
- swal("{% trans 'Asset Delete' %}", msg, "success");
}
function fail() {
var msg = "{% trans 'Asset Deleting failed.' %}";
@@ -440,10 +442,11 @@ $(document).ready(function(){
}
requestApi({
url: "{% url 'api-common:resources-cache' %}",
- method:'POST',
- body:JSON.stringify(data),
- success:success,
- error:fail
+ method: 'POST',
+ body: JSON.stringify(data),
+ success: success,
+ error: fail,
+ flash_message: false
})
})
}
diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py
index 58ca170c6..f7f35c215 100644
--- a/apps/jumpserver/conf.py
+++ b/apps/jumpserver/conf.py
@@ -395,6 +395,7 @@ defaults = {
'FLOWER_URL': "127.0.0.1:5555",
'DEFAULT_ORG_SHOW_ALL_USERS': True,
'PERIOD_TASK_ENABLED': True,
+ 'WINDOWS_SKIP_ALL_MANUAL_PASSWORD': False,
}
diff --git a/apps/perms/signals_handler.py b/apps/perms/signals_handler.py
index eecd101e8..4a7fe389c 100644
--- a/apps/perms/signals_handler.py
+++ b/apps/perms/signals_handler.py
@@ -11,13 +11,6 @@ from .utils.asset_permission import AssetPermissionUtilV2
logger = get_logger(__file__)
-permission_m2m_senders = (
- AssetPermission.nodes.through,
- AssetPermission.assets.through,
- AssetPermission.users.through,
- AssetPermission.user_groups.through,
-)
-
@receiver([post_save, post_delete], sender=AssetPermission)
@on_transaction_commit
diff --git a/apps/settings/api.py b/apps/settings/api.py
index 22a295b68..426cdf76d 100644
--- a/apps/settings/api.py
+++ b/apps/settings/api.py
@@ -12,11 +12,14 @@ from django.conf import settings
from django.core.mail import send_mail
from django.utils.translation import ugettext_lazy as _
-from .models import Setting
-from .utils import LDAPUtil
from common.permissions import IsOrgAdmin, IsSuperUser
from common.utils import get_logger
-from .serializers import MailTestSerializer, LDAPTestSerializer, LDAPUserSerializer
+from .models import Setting
+from .utils import LDAPUtil
+from .serializers import (
+ MailTestSerializer, LDAPTestSerializer, LDAPUserSerializer,
+ PublicSettingSerializer,
+)
logger = get_logger(__file__)
@@ -245,3 +248,19 @@ class CommandStorageDeleteAPI(APIView):
storage_name = str(request.data.get('name'))
Setting.delete_storage('TERMINAL_COMMAND_STORAGE', storage_name)
return Response({"msg": _('Delete succeed')}, status=200)
+
+
+class PublicSettingApi(generics.RetrieveAPIView):
+ permission_classes = ()
+ serializer_class = PublicSettingSerializer
+
+ def get_object(self):
+ c = settings.CONFIG
+ instance = {
+ "data": {
+ "WINDOWS_SKIP_ALL_MANUAL_PASSWORD": c.WINDOWS_SKIP_ALL_MANUAL_PASSWORD
+ }
+ }
+ return instance
+
+
diff --git a/apps/settings/serializers.py b/apps/settings/serializers.py
index eb8a61679..f29b514d7 100644
--- a/apps/settings/serializers.py
+++ b/apps/settings/serializers.py
@@ -28,3 +28,6 @@ class LDAPUserSerializer(serializers.Serializer):
email = serializers.CharField()
existing = serializers.BooleanField(read_only=True)
+
+class PublicSettingSerializer(serializers.Serializer):
+ data = serializers.DictField(read_only=True)
diff --git a/apps/settings/urls/api_urls.py b/apps/settings/urls/api_urls.py
index bc2e4731f..026598206 100644
--- a/apps/settings/urls/api_urls.py
+++ b/apps/settings/urls/api_urls.py
@@ -15,4 +15,5 @@ urlpatterns = [
path('terminal/replay-storage/delete/', api.ReplayStorageDeleteAPI.as_view(), name='replay-storage-delete'),
path('terminal/command-storage/create/', api.CommandStorageCreateAPI.as_view(), name='command-storage-create'),
path('terminal/command-storage/delete/', api.CommandStorageDeleteAPI.as_view(), name='command-storage-delete'),
+ path('public/', api.PublicSettingApi.as_view(), name='public-setting'),
]
diff --git a/apps/users/forms.py b/apps/users/forms.py
index 98d7c9e09..649f66ab9 100644
--- a/apps/users/forms.py
+++ b/apps/users/forms.py
@@ -2,6 +2,7 @@
from django import forms
from django.utils.translation import gettext_lazy as _
+from django.conf import settings
from common.utils import validate_ssh_public_key
from orgs.mixins.forms import OrgModelForm
@@ -21,6 +22,20 @@ class UserCheckOtpCodeForm(forms.Form):
otp_code = forms.CharField(label=_('MFA code'), max_length=6)
+def get_source_choices():
+ choices_all = dict(User.SOURCE_CHOICES)
+ choices = [
+ (User.SOURCE_LOCAL, choices_all[User.SOURCE_LOCAL]),
+ ]
+ if settings.AUTH_LDAP:
+ choices.append((User.SOURCE_LDAP, choices_all[User.SOURCE_LDAP]))
+ if settings.AUTH_OPENID:
+ choices.append((User.SOURCE_OPENID, choices_all[User.SOURCE_OPENID]))
+ if settings.AUTH_RADIUS:
+ choices.append((User.SOURCE_RADIUS, choices_all[User.SOURCE_RADIUS]))
+ return choices
+
+
class UserCreateUpdateFormMixin(OrgModelForm):
role_choices = ((i, n) for i, n in User.ROLE_CHOICES if i != User.ROLE_APP)
password = forms.CharField(
@@ -31,6 +46,10 @@ class UserCreateUpdateFormMixin(OrgModelForm):
choices=role_choices, required=True,
initial=User.ROLE_USER, label=_("Role")
)
+ source = forms.ChoiceField(
+ choices=get_source_choices, required=True,
+ initial=User.SOURCE_LOCAL, label=_("Source")
+ )
public_key = forms.CharField(
label=_('ssh public key'), max_length=5000, required=False,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
@@ -41,7 +60,8 @@ class UserCreateUpdateFormMixin(OrgModelForm):
model = User
fields = [
'username', 'name', 'email', 'groups', 'wechat',
- 'phone', 'role', 'date_expired', 'comment', 'otp_level'
+ 'source', 'phone', 'role', 'date_expired',
+ 'comment', 'otp_level'
]
widgets = {
'otp_level': forms.RadioSelect(),
diff --git a/apps/users/serializers/__init__.py b/apps/users/serializers/__init__.py
index 94ef71f28..78a695e51 100644
--- a/apps/users/serializers/__init__.py
+++ b/apps/users/serializers/__init__.py
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
#
-from .v1 import *
\ No newline at end of file
+from .user import *
+from .group import *
diff --git a/apps/users/serializers/group.py b/apps/users/serializers/group.py
new file mode 100644
index 000000000..d27ddc19a
--- /dev/null
+++ b/apps/users/serializers/group.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+#
+from django.utils.translation import ugettext_lazy as _
+from rest_framework import serializers
+
+from common.fields import StringManyToManyField
+from common.serializers import AdaptedBulkListSerializer
+from orgs.mixins.serializers import BulkOrgResourceModelSerializer
+from ..models import User, UserGroup
+from .. import utils
+
+
+__all__ = [
+ 'UserGroupSerializer', 'UserGroupListSerializer',
+ 'UserGroupUpdateMemberSerializer'
+]
+
+
+class UserGroupSerializer(BulkOrgResourceModelSerializer):
+ users = serializers.PrimaryKeyRelatedField(
+ required=False, many=True, queryset=User.objects, label=_('User')
+ )
+
+ class Meta:
+ model = UserGroup
+ list_serializer_class = AdaptedBulkListSerializer
+ fields = [
+ 'id', 'name', 'users', 'comment', 'date_created',
+ 'created_by',
+ ]
+ extra_kwargs = {
+ 'created_by': {'label': _('Created by'), 'read_only': True}
+ }
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.set_fields_queryset()
+
+ def set_fields_queryset(self):
+ users_field = self.fields['users']
+ users_field.child_relation.queryset = utils.get_current_org_members()
+
+ def validate_users(self, users):
+ for user in users:
+ if user.is_super_auditor:
+ msg = _('Auditors cannot be join in the user group')
+ raise serializers.ValidationError(msg)
+ return users
+
+
+class UserGroupListSerializer(UserGroupSerializer):
+ users = StringManyToManyField(many=True, read_only=True)
+
+
+class UserGroupUpdateMemberSerializer(serializers.ModelSerializer):
+ users = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects)
+
+ class Meta:
+ model = UserGroup
+ fields = ['id', 'users']
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.set_fields_queryset()
+
+ def set_fields_queryset(self):
+ users_field = self.fields['users']
+ users_field.child_relation.queryset = utils.get_current_org_members()
+
diff --git a/apps/users/serializers/v1.py b/apps/users/serializers/user.py
similarity index 69%
rename from apps/users/serializers/v1.py
rename to apps/users/serializers/user.py
index 847afe885..57e2f43fa 100644
--- a/apps/users/serializers/v1.py
+++ b/apps/users/serializers/user.py
@@ -6,19 +6,14 @@ from rest_framework import serializers
from common.utils import validate_ssh_public_key
from common.mixins import BulkSerializerMixin
-from common.fields import StringManyToManyField
from common.serializers import AdaptedBulkListSerializer
from common.permissions import CanUpdateDeleteUser
-from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from ..models import User, UserGroup
-from .. import utils
__all__ = [
'UserSerializer', 'UserPKUpdateSerializer', 'UserUpdateGroupSerializer',
- 'UserGroupSerializer', 'UserGroupListSerializer',
- 'UserGroupUpdateMemberSerializer', 'ChangeUserPasswordSerializer',
- 'ResetOTPSerializer',
+ 'ChangeUserPasswordSerializer', 'ResetOTPSerializer',
]
@@ -49,7 +44,6 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
'is_valid': {'label': _('Is valid')},
'is_expired': {'label': _('Is expired')},
'avatar_url': {'label': _('Avatar url')},
- 'source': {'read_only': True},
'created_by': {'read_only': True, 'allow_blank': True},
'can_update': {'read_only': True},
'can_delete': {'read_only': True},
@@ -127,58 +121,6 @@ class UserUpdateGroupSerializer(serializers.ModelSerializer):
fields = ['id', 'groups']
-class UserGroupSerializer(BulkOrgResourceModelSerializer):
- users = serializers.PrimaryKeyRelatedField(
- required=False, many=True, queryset=User.objects, label=_('User')
- )
-
- class Meta:
- model = UserGroup
- list_serializer_class = AdaptedBulkListSerializer
- fields = [
- 'id', 'name', 'users', 'comment', 'date_created',
- 'created_by',
- ]
- extra_kwargs = {
- 'created_by': {'label': _('Created by'), 'read_only': True}
- }
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.set_fields_queryset()
-
- def set_fields_queryset(self):
- users_field = self.fields['users']
- users_field.child_relation.queryset = utils.get_current_org_members()
-
- def validate_users(self, users):
- for user in users:
- if user.is_super_auditor:
- msg = _('Auditors cannot be join in the user group')
- raise serializers.ValidationError(msg)
- return users
-
-
-class UserGroupListSerializer(UserGroupSerializer):
- users = StringManyToManyField(many=True, read_only=True)
-
-
-class UserGroupUpdateMemberSerializer(serializers.ModelSerializer):
- users = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects)
-
- class Meta:
- model = UserGroup
- fields = ['id', 'users']
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.set_fields_queryset()
-
- def set_fields_queryset(self):
- users_field = self.fields['users']
- users_field.child_relation.queryset = utils.get_current_org_members()
-
-
class ChangeUserPasswordSerializer(serializers.ModelSerializer):
class Meta:
diff --git a/apps/users/signals_handler.py b/apps/users/signals_handler.py
index 4c6afc663..a33d9eec9 100644
--- a/apps/users/signals_handler.py
+++ b/apps/users/signals_handler.py
@@ -2,11 +2,11 @@
#
from django.dispatch import receiver
-# from django.db.models.signals import post_save
+from django.db.models.signals import post_save, m2m_changed
from common.utils import get_logger
from .signals import post_user_create
-# from .models import User
+from .models import User
logger = get_logger(__file__)
@@ -28,3 +28,14 @@ def on_user_create(sender, user=None, **kwargs):
logger.info(" - Sending welcome mail ...".format(user.name))
if user.email:
send_user_created_mail(user)
+
+
+@receiver(m2m_changed, sender=User.groups.through)
+def on_user_groups_change(sender, instance=None, action='', **kwargs):
+ """
+ 资产节点发生变化时,刷新节点
+ """
+ if action.startswith('post'):
+ logger.debug("User group member change signal recv: {}".format(instance))
+ from perms.utils import AssetPermissionUtilV2
+ AssetPermissionUtilV2.expire_all_user_tree_cache()
diff --git a/apps/users/templates/users/_user.html b/apps/users/templates/users/_user.html
index 192dbfb70..ea0f76854 100644
--- a/apps/users/templates/users/_user.html
+++ b/apps/users/templates/users/_user.html
@@ -21,6 +21,7 @@
{% trans 'Auth' %}
{% block password %}{% endblock %}
{% bootstrap_field form.otp_level layout="horizontal" %}
+ {% bootstrap_field form.source layout="horizontal" %}
{% trans 'Security and Role' %}