Commit 52d09615 authored by ibuler's avatar ibuler

Merge branch 'dev' of github.com:jumpserver/jumpserver into dev

parents e0934753 13822cbf
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from rest_framework import generics from rest_framework import generics, status
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
...@@ -59,6 +59,13 @@ class NodeViewSet(OrgModelViewSet): ...@@ -59,6 +59,13 @@ class NodeViewSet(OrgModelViewSet):
raise ValidationError({"error": msg}) raise ValidationError({"error": msg})
return super().perform_update(serializer) return super().perform_update(serializer)
def destroy(self, request, *args, **kwargs):
node = self.get_object()
if node.has_children_or_contains_assets():
msg = _("Deletion failed and the node contains children or assets")
return Response(data={'msg': msg}, status=status.HTTP_403_FORBIDDEN)
return super().destroy(request, *args, **kwargs)
class NodeListAsTreeApi(generics.ListAPIView): class NodeListAsTreeApi(generics.ListAPIView):
""" """
......
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
GENERAL_LIMIT_SPECIAL_CHARACTERS_HELP_TEXT = _(
'Only Numbers、letters、 chinese and characters ( {} ) are allowed'
).format(" ".join(['.', '_', '@', '-']))
GENERAL_LIMIT_SPECIAL_CHARACTERS_PATTERN = r"^[\._@\w-]+$"
GENERAL_LIMIT_SPECIAL_CHARACTERS_ERROR_MSG = \
_("* The contains characters that are not allowed")
...@@ -7,6 +7,7 @@ from common.utils import get_logger ...@@ -7,6 +7,7 @@ from common.utils import get_logger
from orgs.mixins.forms import OrgModelForm from orgs.mixins.forms import OrgModelForm
from ..models import Asset, Node from ..models import Asset, Node
from ..const import GENERAL_LIMIT_SPECIAL_CHARACTERS_HELP_TEXT
logger = get_logger(__file__) logger = get_logger(__file__)
...@@ -14,10 +15,6 @@ __all__ = [ ...@@ -14,10 +15,6 @@ __all__ = [
'AssetCreateForm', 'AssetUpdateForm', 'AssetBulkUpdateForm', 'ProtocolForm', 'AssetCreateForm', 'AssetUpdateForm', 'AssetBulkUpdateForm', 'ProtocolForm',
] ]
HELP_TEXTS_ASSET_HOSTNAME = _(
'Only Numbers、letters、 chinese and characters ( {} ) are allowed'
).format(" ".join(['.', '_', '@']))
class ProtocolForm(forms.Form): class ProtocolForm(forms.Form):
name = forms.ChoiceField( name = forms.ChoiceField(
...@@ -72,7 +69,7 @@ class AssetCreateForm(OrgModelForm): ...@@ -72,7 +69,7 @@ class AssetCreateForm(OrgModelForm):
'nodes': _("Node"), 'nodes': _("Node"),
} }
help_texts = { help_texts = {
'hostname': HELP_TEXTS_ASSET_HOSTNAME, 'hostname': GENERAL_LIMIT_SPECIAL_CHARACTERS_HELP_TEXT,
'admin_user': _( 'admin_user': _(
'root or other NOPASSWD sudo privilege user existed in asset,' 'root or other NOPASSWD sudo privilege user existed in asset,'
'If asset is windows or other set any one, more see admin user left menu' 'If asset is windows or other set any one, more see admin user left menu'
...@@ -119,7 +116,7 @@ class AssetUpdateForm(OrgModelForm): ...@@ -119,7 +116,7 @@ class AssetUpdateForm(OrgModelForm):
'nodes': _("Node"), 'nodes': _("Node"),
} }
help_texts = { help_texts = {
'hostname': HELP_TEXTS_ASSET_HOSTNAME, 'hostname': GENERAL_LIMIT_SPECIAL_CHARACTERS_HELP_TEXT,
'admin_user': _( 'admin_user': _(
'root or other NOPASSWD sudo privilege user existed in asset,' 'root or other NOPASSWD sudo privilege user existed in asset,'
'If asset is windows or other set any one, more see admin user left menu' 'If asset is windows or other set any one, more see admin user left menu'
......
...@@ -6,6 +6,7 @@ from django.utils.translation import gettext_lazy as _ ...@@ -6,6 +6,7 @@ from django.utils.translation import gettext_lazy as _
from common.utils import validate_ssh_private_key, ssh_pubkey_gen, get_logger from common.utils import validate_ssh_private_key, ssh_pubkey_gen, get_logger
from orgs.mixins.forms import OrgModelForm from orgs.mixins.forms import OrgModelForm
from ..models import AdminUser, SystemUser from ..models import AdminUser, SystemUser
from ..const import GENERAL_LIMIT_SPECIAL_CHARACTERS_HELP_TEXT
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
...@@ -98,6 +99,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): ...@@ -98,6 +99,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm):
}), }),
} }
help_texts = { help_texts = {
'name': GENERAL_LIMIT_SPECIAL_CHARACTERS_HELP_TEXT,
'auto_push': _('Auto push system user to asset'), 'auto_push': _('Auto push system user to asset'),
'priority': _('1-100, High level will be using login asset as default, ' 'priority': _('1-100, High level will be using login asset as default, '
'if user was granted more than 2 system user'), 'if user was granted more than 2 system user'),
......
...@@ -470,8 +470,13 @@ class Node(OrgModelMixin, SomeNodesMixin, TreeMixin, FamilyMixin, FullValueMixin ...@@ -470,8 +470,13 @@ class Node(OrgModelMixin, SomeNodesMixin, TreeMixin, FamilyMixin, FullValueMixin
tree_node = TreeNode(**data) tree_node = TreeNode(**data)
return tree_node return tree_node
def delete(self, using=None, keep_parents=False): def has_children_or_contains_assets(self):
if self.children or self.get_assets(): if self.children or self.get_assets():
return True
return False
def delete(self, using=None, keep_parents=False):
if self.has_children_or_contains_assets():
return return
return super().delete(using=using, keep_parents=keep_parents) return super().delete(using=using, keep_parents=keep_parents)
......
...@@ -8,6 +8,10 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -8,6 +8,10 @@ from django.utils.translation import ugettext_lazy as _
from orgs.mixins.serializers import BulkOrgResourceModelSerializer from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from common.serializers import AdaptedBulkListSerializer from common.serializers import AdaptedBulkListSerializer
from ..models import Asset, Node, Label from ..models import Asset, Node, Label
from ..const import (
GENERAL_LIMIT_SPECIAL_CHARACTERS_PATTERN,
GENERAL_LIMIT_SPECIAL_CHARACTERS_ERROR_MSG
)
from .base import ConnectivitySerializer from .base import ConnectivitySerializer
__all__ = [ __all__ = [
...@@ -94,10 +98,10 @@ class AssetSerializer(BulkOrgResourceModelSerializer): ...@@ -94,10 +98,10 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
@staticmethod @staticmethod
def validate_hostname(hostname): def validate_hostname(hostname):
pattern = r"^[\._@\w-]+$" pattern = GENERAL_LIMIT_SPECIAL_CHARACTERS_PATTERN
res = re.match(pattern, hostname) res = re.match(pattern, hostname)
if res is None: if res is None:
msg = _("* The hostname contains characters that are not allowed") msg = GENERAL_LIMIT_SPECIAL_CHARACTERS_ERROR_MSG
raise serializers.ValidationError(msg) raise serializers.ValidationError(msg)
return hostname return hostname
...@@ -136,6 +140,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer): ...@@ -136,6 +140,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
class AssetSimpleSerializer(serializers.ModelSerializer): class AssetSimpleSerializer(serializers.ModelSerializer):
connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity"))
class Meta: class Meta:
model = Asset model = Asset
......
import re
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 _
...@@ -6,6 +7,10 @@ from common.serializers import AdaptedBulkListSerializer ...@@ -6,6 +7,10 @@ from common.serializers import AdaptedBulkListSerializer
from common.utils import ssh_pubkey_gen from common.utils import ssh_pubkey_gen
from orgs.mixins.serializers import BulkOrgResourceModelSerializer from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from ..models import SystemUser from ..models import SystemUser
from ..const import (
GENERAL_LIMIT_SPECIAL_CHARACTERS_PATTERN,
GENERAL_LIMIT_SPECIAL_CHARACTERS_ERROR_MSG
)
from .base import AuthSerializer, AuthSerializerMixin from .base import AuthSerializer, AuthSerializerMixin
...@@ -33,6 +38,15 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): ...@@ -33,6 +38,15 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
'created_by': {'read_only': True}, 'created_by': {'read_only': True},
} }
@staticmethod
def validate_name(name):
pattern = GENERAL_LIMIT_SPECIAL_CHARACTERS_PATTERN
res = re.match(pattern, name)
if res is None:
msg = GENERAL_LIMIT_SPECIAL_CHARACTERS_ERROR_MSG
raise serializers.ValidationError(msg)
return name
def validate_auto_push(self, value): def validate_auto_push(self, value):
login_mode = self.initial_data.get("login_mode") login_mode = self.initial_data.get("login_mode")
protocol = self.initial_data.get("protocol") protocol = self.initial_data.get("protocol")
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
<li> <li>
<a href="{% url 'assets:asset-user-list' pk=asset.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset user list' %} </a> <a href="{% url 'assets:asset-user-list' pk=asset.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset user list' %} </a>
</li> </li>
{% if user.is_superuser %}
<li class="pull-right"> <li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a> <a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
</li> </li>
...@@ -31,7 +30,6 @@ ...@@ -31,7 +30,6 @@
<i class="fa fa-trash-o"></i>{% trans 'Delete' %} <i class="fa fa-trash-o"></i>{% trans 'Delete' %}
</a> </a>
</li> </li>
{% endif %}
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
......
...@@ -32,6 +32,13 @@ class LDAPAuthorizationBackend(LDAPBackend): ...@@ -32,6 +32,13 @@ class LDAPAuthorizationBackend(LDAPBackend):
if not username: if not username:
logger.info('Authenticate failed: username is None') logger.info('Authenticate failed: username is None')
return None return None
if settings.AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS:
user_model = self.get_user_model()
exist = user_model.objects.filter(username=username).exists()
if not exist:
msg = 'Authentication failed: user ({}) is not in the user list'
logger.info(msg.format(username))
return None
ldap_user = LDAPUser(self, username=username.strip(), request=request) ldap_user = LDAPUser(self, username=username.strip(), request=request)
user = self.authenticate_ldap_user(ldap_user, password) user = self.authenticate_ldap_user(ldap_user, password)
logger.info('Authenticate user: {}'.format(user)) logger.info('Authenticate user: {}'.format(user))
......
...@@ -378,6 +378,7 @@ defaults = { ...@@ -378,6 +378,7 @@ defaults = {
'AUTH_LDAP_SYNC_IS_PERIODIC': False, 'AUTH_LDAP_SYNC_IS_PERIODIC': False,
'AUTH_LDAP_SYNC_INTERVAL': None, 'AUTH_LDAP_SYNC_INTERVAL': None,
'AUTH_LDAP_SYNC_CRONTAB': None, 'AUTH_LDAP_SYNC_CRONTAB': None,
'AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS': False,
'HTTP_BIND_HOST': '0.0.0.0', 'HTTP_BIND_HOST': '0.0.0.0',
'HTTP_LISTEN_PORT': 8080, 'HTTP_LISTEN_PORT': 8080,
'WS_LISTEN_PORT': 8070, 'WS_LISTEN_PORT': 8070,
......
...@@ -429,6 +429,7 @@ AUTH_LDAP_SEARCH_PAGED_SIZE = CONFIG.AUTH_LDAP_SEARCH_PAGED_SIZE ...@@ -429,6 +429,7 @@ AUTH_LDAP_SEARCH_PAGED_SIZE = CONFIG.AUTH_LDAP_SEARCH_PAGED_SIZE
AUTH_LDAP_SYNC_IS_PERIODIC = CONFIG.AUTH_LDAP_SYNC_IS_PERIODIC AUTH_LDAP_SYNC_IS_PERIODIC = CONFIG.AUTH_LDAP_SYNC_IS_PERIODIC
AUTH_LDAP_SYNC_INTERVAL = CONFIG.AUTH_LDAP_SYNC_INTERVAL AUTH_LDAP_SYNC_INTERVAL = CONFIG.AUTH_LDAP_SYNC_INTERVAL
AUTH_LDAP_SYNC_CRONTAB = CONFIG.AUTH_LDAP_SYNC_CRONTAB AUTH_LDAP_SYNC_CRONTAB = CONFIG.AUTH_LDAP_SYNC_CRONTAB
AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS = CONFIG.AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS
AUTH_LDAP_SERVER_URI = 'ldap://localhost:389' AUTH_LDAP_SERVER_URI = 'ldap://localhost:389'
AUTH_LDAP_BIND_DN = 'cn=admin,dc=jumpserver,dc=org' AUTH_LDAP_BIND_DN = 'cn=admin,dc=jumpserver,dc=org'
......
This diff is collapsed.
import re
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework import serializers from rest_framework import serializers
from users.models import User, UserGroup from users.models import User, UserGroup
from assets.models import Asset, Domain, AdminUser, SystemUser, Label from assets.models import Asset, Domain, AdminUser, SystemUser, Label
from assets.const import (
GENERAL_LIMIT_SPECIAL_CHARACTERS_PATTERN,
GENERAL_LIMIT_SPECIAL_CHARACTERS_ERROR_MSG
)
from perms.models import AssetPermission from perms.models import AssetPermission
from common.serializers import AdaptedBulkListSerializer from common.serializers import AdaptedBulkListSerializer
from .utils import set_current_org, get_current_org from .utils import set_current_org, get_current_org
...@@ -18,6 +22,15 @@ class OrgSerializer(ModelSerializer): ...@@ -18,6 +22,15 @@ class OrgSerializer(ModelSerializer):
fields = '__all__' fields = '__all__'
read_only_fields = ['created_by', 'date_created'] read_only_fields = ['created_by', 'date_created']
@staticmethod
def validate_name(name):
pattern = GENERAL_LIMIT_SPECIAL_CHARACTERS_PATTERN
res = re.match(pattern, name)
if res is None:
msg = GENERAL_LIMIT_SPECIAL_CHARACTERS_ERROR_MSG
raise serializers.ValidationError(msg)
return name
class OrgReadSerializer(ModelSerializer): class OrgReadSerializer(ModelSerializer):
admins = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True) admins = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
......
...@@ -72,13 +72,18 @@ REDIS_PORT: 6379 ...@@ -72,13 +72,18 @@ REDIS_PORT: 6379
# RADIUS_PORT: 1812 # RADIUS_PORT: 1812
# RADIUS_SECRET: # RADIUS_SECRET:
# LDAP/AD 设置定时同步参数 # LDAP/AD settings
# 定时同步用户
# 启用/禁用 # 启用/禁用
# AUTH_LDAP_SYNC_IS_PERIODIC: True # AUTH_LDAP_SYNC_IS_PERIODIC: True
# 单位: 时 # 单位: 时
# AUTH_LDAP_SYNC_INTERVAL: 12 # AUTH_LDAP_SYNC_INTERVAL: 12
# Crontab 表达式 # Crontab 表达式
# AUTH_LDAP_SYNC_CRONTAB: * 6 * * * # AUTH_LDAP_SYNC_CRONTAB: * 6 * * *
#
# LDAP 用户登录时仅允许在用户列表中的用户执行 LDAP Server 认证
# AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS: False
# OTP settings # OTP settings
# OTP/MFA 配置 # OTP/MFA 配置
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment