mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-06-29 16:27:11 +00:00
commit
af827f3626
@ -2,7 +2,6 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from django_filters import rest_framework as filters
|
from django_filters import rest_framework as filters
|
||||||
from django.conf import settings
|
|
||||||
from django.db.models import F, Value, CharField
|
from django.db.models import F, Value, CharField
|
||||||
from django.db.models.functions import Concat
|
from django.db.models.functions import Concat
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
@ -31,11 +30,11 @@ class ApplicationAccountViewSet(JMSModelViewSet):
|
|||||||
filterset_class = AccountFilterSet
|
filterset_class = AccountFilterSet
|
||||||
filterset_fields = ['username', 'app_name', 'type', 'category']
|
filterset_fields = ['username', 'app_name', 'type', 'category']
|
||||||
serializer_class = serializers.ApplicationAccountSerializer
|
serializer_class = serializers.ApplicationAccountSerializer
|
||||||
|
|
||||||
http_method_names = ['get', 'put', 'patch', 'options']
|
http_method_names = ['get', 'put', 'patch', 'options']
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = ApplicationPermission.objects.exclude(system_users__isnull=True) \
|
queryset = ApplicationPermission.objects\
|
||||||
|
.exclude(system_users__isnull=True) \
|
||||||
.exclude(applications__isnull=True) \
|
.exclude(applications__isnull=True) \
|
||||||
.annotate(uid=Concat(
|
.annotate(uid=Concat(
|
||||||
'applications', Value('_'), 'system_users', output_field=CharField()
|
'applications', Value('_'), 'system_users', output_field=CharField()
|
||||||
@ -47,7 +46,7 @@ class ApplicationAccountViewSet(JMSModelViewSet):
|
|||||||
.annotate(app=F('applications')) \
|
.annotate(app=F('applications')) \
|
||||||
.annotate(app_name=F("applications__name")) \
|
.annotate(app_name=F("applications__name")) \
|
||||||
.values('username', 'password', 'systemuser', 'systemuser_display',
|
.values('username', 'password', 'systemuser', 'systemuser_display',
|
||||||
'app', 'app_name', 'category', 'type', 'uid')
|
'app', 'app_name', 'category', 'type', 'uid', 'org_id')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
@ -63,6 +62,11 @@ class ApplicationAccountViewSet(JMSModelViewSet):
|
|||||||
queryset_list = unique(queryset, key=lambda x: (x['app'], x['systemuser']))
|
queryset_list = unique(queryset, key=lambda x: (x['app'], x['systemuser']))
|
||||||
return queryset_list
|
return queryset_list
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def filter_spm_queryset(resource_ids, queryset):
|
||||||
|
queryset = queryset.filter(uid__in=resource_ids)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class ApplicationAccountSecretViewSet(ApplicationAccountViewSet):
|
class ApplicationAccountSecretViewSet(ApplicationAccountViewSet):
|
||||||
serializer_class = serializers.ApplicationAccountSecretSerializer
|
serializer_class = serializers.ApplicationAccountSecretSerializer
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orgs.models import Organization
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
from common.drf.serializers import MethodSerializer
|
from common.drf.serializers import MethodSerializer
|
||||||
from .attrs import category_serializer_classes_mapping, type_serializer_classes_mapping
|
from .attrs import category_serializer_classes_mapping, type_serializer_classes_mapping
|
||||||
@ -74,12 +76,14 @@ class ApplicationAccountSerializer(serializers.Serializer):
|
|||||||
systemuser = serializers.ReadOnlyField(label=_('System user'))
|
systemuser = serializers.ReadOnlyField(label=_('System user'))
|
||||||
systemuser_display = serializers.ReadOnlyField(label=_("System user display"))
|
systemuser_display = serializers.ReadOnlyField(label=_("System user display"))
|
||||||
app = serializers.ReadOnlyField(label=_('App'))
|
app = serializers.ReadOnlyField(label=_('App'))
|
||||||
uid = serializers.ReadOnlyField(label=_("Union id"))
|
|
||||||
app_name = serializers.ReadOnlyField(label=_("Application name"), read_only=True)
|
app_name = serializers.ReadOnlyField(label=_("Application name"), read_only=True)
|
||||||
category = serializers.ChoiceField(label=_('Category'), choices=const.AppCategory.choices, read_only=True)
|
category = serializers.ChoiceField(label=_('Category'), choices=const.AppCategory.choices, read_only=True)
|
||||||
category_display = serializers.SerializerMethodField(label=_('Category display'))
|
category_display = serializers.SerializerMethodField(label=_('Category display'))
|
||||||
type = serializers.ChoiceField(label=_('Type'), choices=const.AppType.choices, read_only=True)
|
type = serializers.ChoiceField(label=_('Type'), choices=const.AppType.choices, read_only=True)
|
||||||
type_display = serializers.SerializerMethodField(label=_('Type display'))
|
type_display = serializers.SerializerMethodField(label=_('Type display'))
|
||||||
|
uid = serializers.ReadOnlyField(label=_("Union id"))
|
||||||
|
org_id = serializers.ReadOnlyField(label=_("Organization"))
|
||||||
|
org_name = serializers.SerializerMethodField(label=_("Org name"))
|
||||||
|
|
||||||
category_mapper = dict(const.AppCategory.choices)
|
category_mapper = dict(const.AppCategory.choices)
|
||||||
type_mapper = dict(const.AppType.choices)
|
type_mapper = dict(const.AppType.choices)
|
||||||
@ -96,6 +100,11 @@ class ApplicationAccountSerializer(serializers.Serializer):
|
|||||||
def get_type_display(self, obj):
|
def get_type_display(self, obj):
|
||||||
return self.type_mapper.get(obj['type'])
|
return self.type_mapper.get(obj['type'])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_org_name(obj):
|
||||||
|
org = Organization.get_instance(obj['org_id'])
|
||||||
|
return org.name
|
||||||
|
|
||||||
|
|
||||||
class ApplicationAccountSecretSerializer(ApplicationAccountSerializer):
|
class ApplicationAccountSecretSerializer(ApplicationAccountSerializer):
|
||||||
password = serializers.CharField(write_only=False, label=_("Password"))
|
password = serializers.CharField(write_only=False, label=_("Password"))
|
||||||
|
@ -14,7 +14,7 @@ logger = get_logger(__file__)
|
|||||||
__all__ = ['RemoteAppSerializer']
|
__all__ = ['RemoteAppSerializer']
|
||||||
|
|
||||||
|
|
||||||
class AssetCharPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
class ExistAssetPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
instance = super().to_internal_value(data)
|
instance = super().to_internal_value(data)
|
||||||
@ -26,14 +26,14 @@ class AssetCharPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
|||||||
return self.pk_field.to_representation(_id)
|
return self.pk_field.to_representation(_id)
|
||||||
# 解决删除资产后,远程应用更新页面会显示资产ID的问题
|
# 解决删除资产后,远程应用更新页面会显示资产ID的问题
|
||||||
asset = get_object_or_none(Asset, id=_id)
|
asset = get_object_or_none(Asset, id=_id)
|
||||||
if asset:
|
if not asset:
|
||||||
return None
|
return None
|
||||||
return _id
|
return _id
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppSerializer(serializers.Serializer):
|
class RemoteAppSerializer(serializers.Serializer):
|
||||||
asset_info = serializers.SerializerMethodField()
|
asset_info = serializers.SerializerMethodField()
|
||||||
asset = AssetCharPrimaryKeyRelatedField(
|
asset = ExistAssetPrimaryKeyRelatedField(
|
||||||
queryset=Asset.objects, required=False, label=_("Asset"), allow_null=True
|
queryset=Asset.objects, required=False, label=_("Asset"), allow_null=True
|
||||||
)
|
)
|
||||||
path = serializers.CharField(
|
path = serializers.CharField(
|
||||||
|
@ -26,7 +26,7 @@ class SerializeToTreeNodeMixin:
|
|||||||
'isParent': True,
|
'isParent': True,
|
||||||
'open': node.is_org_root(),
|
'open': node.is_org_root(),
|
||||||
'meta': {
|
'meta': {
|
||||||
'node': {
|
'data': {
|
||||||
"id": node.id,
|
"id": node.id,
|
||||||
"key": node.key,
|
"key": node.key,
|
||||||
"value": node.value,
|
"value": node.value,
|
||||||
@ -65,7 +65,7 @@ class SerializeToTreeNodeMixin:
|
|||||||
'chkDisabled': not asset.is_active,
|
'chkDisabled': not asset.is_active,
|
||||||
'meta': {
|
'meta': {
|
||||||
'type': 'asset',
|
'type': 'asset',
|
||||||
'asset': {
|
'data': {
|
||||||
'id': asset.id,
|
'id': asset.id,
|
||||||
'hostname': asset.hostname,
|
'hostname': asset.hostname,
|
||||||
'ip': asset.ip,
|
'ip': asset.ip,
|
||||||
|
@ -200,6 +200,7 @@ class AssetTaskSerializer(AssetsTaskSerializer):
|
|||||||
('push_system_user', 'push_system_user'),
|
('push_system_user', 'push_system_user'),
|
||||||
('test_system_user', 'test_system_user')
|
('test_system_user', 'test_system_user')
|
||||||
])
|
])
|
||||||
|
action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True)
|
||||||
asset = serializers.PrimaryKeyRelatedField(
|
asset = serializers.PrimaryKeyRelatedField(
|
||||||
queryset=Asset.objects, required=False, allow_empty=True, many=False
|
queryset=Asset.objects, required=False, allow_empty=True, many=False
|
||||||
)
|
)
|
||||||
|
@ -112,7 +112,10 @@ class IDSpmFilter(filters.BaseFilterBackend):
|
|||||||
resource_ids = cache.get(cache_key)
|
resource_ids = cache.get(cache_key)
|
||||||
if resource_ids is None or not isinstance(resource_ids, list):
|
if resource_ids is None or not isinstance(resource_ids, list):
|
||||||
return queryset
|
return queryset
|
||||||
queryset = queryset.filter(id__in=resource_ids)
|
if hasattr(view, 'filter_spm_queryset'):
|
||||||
|
queryset = view.filter_spm_queryset(resource_ids, queryset)
|
||||||
|
else:
|
||||||
|
queryset = queryset.filter(id__in=resource_ids)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,10 +76,23 @@ class CommandStore():
|
|||||||
self._ensure_index_exists()
|
self._ensure_index_exists()
|
||||||
|
|
||||||
def _ensure_index_exists(self):
|
def _ensure_index_exists(self):
|
||||||
|
mappings = {
|
||||||
|
"mappings": {
|
||||||
|
"properties": {
|
||||||
|
"session": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.es.indices.create(self.index)
|
self.es.indices.create(self.index, body=mappings)
|
||||||
except RequestError:
|
except RequestError as e:
|
||||||
pass
|
logger.exception(e)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_data(command):
|
def make_data(command):
|
||||||
|
@ -209,6 +209,11 @@ class RoleMixin:
|
|||||||
from orgs.models import ROLE as ORG_ROLE
|
from orgs.models import ROLE as ORG_ROLE
|
||||||
return [str(role.label) for role in self.org_roles if role in ORG_ROLE]
|
return [str(role.label) for role in self.org_roles if role in ORG_ROLE]
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def org_roles_value_list(self):
|
||||||
|
from orgs.models import ROLE as ORG_ROLE
|
||||||
|
return [str(role.value) for role in self.org_roles if role in ORG_ROLE]
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def org_role_display(self):
|
def org_role_display(self):
|
||||||
return ' | '.join(self.org_roles_label_list)
|
return ' | '.join(self.org_roles_label_list)
|
||||||
|
@ -32,7 +32,7 @@ class UserUpdatePasswordSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
def validate_new_password(self, value):
|
def validate_new_password(self, value):
|
||||||
from ..utils import check_password_rules
|
from ..utils import check_password_rules
|
||||||
if not check_password_rules(value, user=self.instance):
|
if not check_password_rules(value, is_org_admin=self.instance.is_org_admin):
|
||||||
msg = _('Password does not match security rules')
|
msg = _('Password does not match security rules')
|
||||||
raise serializers.ValidationError(msg)
|
raise serializers.ValidationError(msg)
|
||||||
if self.instance.is_history_password(value):
|
if self.instance.is_history_password(value):
|
||||||
|
@ -116,6 +116,18 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
|
|||||||
raise serializers.ValidationError(msg)
|
raise serializers.ValidationError(msg)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_org_admin(self):
|
||||||
|
roles = []
|
||||||
|
role = self.initial_data.get('role')
|
||||||
|
if role:
|
||||||
|
roles.append(role)
|
||||||
|
org_roles = self.initial_data.get('org_roles')
|
||||||
|
if org_roles:
|
||||||
|
roles.extend(org_roles)
|
||||||
|
is_org_admin = User.ROLE.ADMIN.value in roles
|
||||||
|
return is_org_admin
|
||||||
|
|
||||||
def validate_password(self, password):
|
def validate_password(self, password):
|
||||||
from ..utils import check_password_rules
|
from ..utils import check_password_rules
|
||||||
password_strategy = self.initial_data.get('password_strategy')
|
password_strategy = self.initial_data.get('password_strategy')
|
||||||
@ -125,7 +137,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
|
|||||||
if self.instance and not password:
|
if self.instance and not password:
|
||||||
# 更新用户, 未设置密码
|
# 更新用户, 未设置密码
|
||||||
return
|
return
|
||||||
if not check_password_rules(password, user=self.instance):
|
if not check_password_rules(password, is_org_admin=self.is_org_admin):
|
||||||
msg = _('Password does not match security rules')
|
msg = _('Password does not match security rules')
|
||||||
raise serializers.ValidationError(msg)
|
raise serializers.ValidationError(msg)
|
||||||
return password
|
return password
|
||||||
|
@ -308,7 +308,7 @@ def get_password_check_rules(user):
|
|||||||
return check_rules
|
return check_rules
|
||||||
|
|
||||||
|
|
||||||
def check_password_rules(password, user):
|
def check_password_rules(password, is_org_admin=False):
|
||||||
pattern = r"^"
|
pattern = r"^"
|
||||||
if settings.SECURITY_PASSWORD_UPPER_CASE:
|
if settings.SECURITY_PASSWORD_UPPER_CASE:
|
||||||
pattern += '(?=.*[A-Z])'
|
pattern += '(?=.*[A-Z])'
|
||||||
@ -319,7 +319,7 @@ def check_password_rules(password, user):
|
|||||||
if settings.SECURITY_PASSWORD_SPECIAL_CHAR:
|
if settings.SECURITY_PASSWORD_SPECIAL_CHAR:
|
||||||
pattern += '(?=.*[`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?])'
|
pattern += '(?=.*[`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?])'
|
||||||
pattern += '[a-zA-Z\d`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?]'
|
pattern += '[a-zA-Z\d`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?]'
|
||||||
if user.is_org_admin:
|
if is_org_admin:
|
||||||
min_length = settings.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH
|
min_length = settings.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH
|
||||||
else:
|
else:
|
||||||
min_length = settings.SECURITY_PASSWORD_MIN_LENGTH
|
min_length = settings.SECURITY_PASSWORD_MIN_LENGTH
|
||||||
|
@ -101,7 +101,7 @@ class UserResetPasswordView(FormView):
|
|||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
|
|
||||||
password = form.cleaned_data['new_password']
|
password = form.cleaned_data['new_password']
|
||||||
is_ok = check_password_rules(password, user)
|
is_ok = check_password_rules(password, is_org_admin=user.is_org_admin)
|
||||||
if not is_ok:
|
if not is_ok:
|
||||||
error = _('* Your password does not meet the requirements')
|
error = _('* Your password does not meet the requirements')
|
||||||
form.add_error('new_password', error)
|
form.add_error('new_password', error)
|
||||||
|
Loading…
Reference in New Issue
Block a user