mirror of https://github.com/jumpserver/jumpserver
commit
714b6b1233
|
@ -15,7 +15,7 @@ class TempTokenViewSet(JMSModelViewSet):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
username = self.request.user.username
|
username = self.request.user.username
|
||||||
return TempToken.objects.filter(username=username)
|
return TempToken.objects.filter(username=username).order_by('-date_created')
|
||||||
|
|
||||||
@action(methods=['PATCH'], detail=True, url_path='expire')
|
@action(methods=['PATCH'], detail=True, url_path='expire')
|
||||||
def expire(self, *args, **kwargs):
|
def expire(self, *args, **kwargs):
|
||||||
|
@ -24,4 +24,3 @@ class TempTokenViewSet(JMSModelViewSet):
|
||||||
instance.save()
|
instance.save()
|
||||||
serializer = self.get_serializer(instance)
|
serializer = self.get_serializer(instance)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Migration(migrations.Migration):
|
||||||
('secret', models.CharField(max_length=64, verbose_name='Secret')),
|
('secret', models.CharField(max_length=64, verbose_name='Secret')),
|
||||||
('verified', models.BooleanField(default=False, verbose_name='Verified')),
|
('verified', models.BooleanField(default=False, verbose_name='Verified')),
|
||||||
('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')),
|
('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')),
|
||||||
('date_expired', models.DateTimeField(verbose_name='Date verified')),
|
('date_expired', models.DateTimeField(verbose_name='Date expired')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Temporary token',
|
'verbose_name': 'Temporary token',
|
||||||
|
|
|
@ -4,6 +4,7 @@ from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
|
||||||
from common.drf.api import JMSModelViewSet
|
from common.drf.api import JMSModelViewSet
|
||||||
|
from ..filters import RoleFilter
|
||||||
from ..serializers import RoleSerializer, RoleUserSerializer
|
from ..serializers import RoleSerializer, RoleUserSerializer
|
||||||
from ..models import Role, SystemRole, OrgRole
|
from ..models import Role, SystemRole, OrgRole
|
||||||
from .permission import PermissionViewSet
|
from .permission import PermissionViewSet
|
||||||
|
@ -20,8 +21,8 @@ class RoleViewSet(JMSModelViewSet):
|
||||||
'default': RoleSerializer,
|
'default': RoleSerializer,
|
||||||
'users': RoleUserSerializer,
|
'users': RoleUserSerializer,
|
||||||
}
|
}
|
||||||
filterset_fields = ['name', 'scope', 'builtin']
|
filterset_class = RoleFilter
|
||||||
search_fields = filterset_fields
|
search_fields = ('name', 'scope', 'builtin')
|
||||||
rbac_perms = {
|
rbac_perms = {
|
||||||
'users': 'rbac.view_rolebinding'
|
'users': 'rbac.view_rolebinding'
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,13 @@ from django.utils.translation import ugettext_noop
|
||||||
|
|
||||||
from .const import Scope, system_exclude_permissions, org_exclude_permissions
|
from .const import Scope, system_exclude_permissions, org_exclude_permissions
|
||||||
|
|
||||||
|
system_user_perms = (
|
||||||
|
('authentication', 'connectiontoken', 'add', 'connectiontoken'),
|
||||||
|
('authentication', 'temptoken', 'add', 'temptoken'),
|
||||||
|
('tickets', 'ticket', 'view', 'ticket'),
|
||||||
|
('orgs', 'organization', 'view', 'rootorg'),
|
||||||
|
)
|
||||||
|
|
||||||
# Todo: 获取应该区分 系统用户,和组织用户的权限
|
# Todo: 获取应该区分 系统用户,和组织用户的权限
|
||||||
# 工作台也区分组织后再考虑
|
# 工作台也区分组织后再考虑
|
||||||
user_perms = (
|
user_perms = (
|
||||||
|
@ -15,10 +22,6 @@ user_perms = (
|
||||||
('assets', 'node', 'match', 'node'),
|
('assets', 'node', 'match', 'node'),
|
||||||
('applications', 'application', 'match', 'application'),
|
('applications', 'application', 'match', 'application'),
|
||||||
('ops', 'commandexecution', 'add', 'commandexecution'),
|
('ops', 'commandexecution', 'add', 'commandexecution'),
|
||||||
('authentication', 'connectiontoken', 'add', 'connectiontoken'),
|
|
||||||
('authentication', 'temptoken', 'add', 'temptoken'),
|
|
||||||
('tickets', 'ticket', 'view', 'ticket'),
|
|
||||||
('orgs', 'organization', 'view', 'rootorg'),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
auditor_perms = user_perms + (
|
auditor_perms = user_perms + (
|
||||||
|
@ -104,7 +107,7 @@ class BuiltinRole:
|
||||||
'4', ugettext_noop('SystemComponent'), Scope.system, app_exclude_perms, 'exclude'
|
'4', ugettext_noop('SystemComponent'), Scope.system, app_exclude_perms, 'exclude'
|
||||||
)
|
)
|
||||||
system_user = PredefineRole(
|
system_user = PredefineRole(
|
||||||
'3', ugettext_noop('User'), Scope.system, user_perms
|
'3', ugettext_noop('User'), Scope.system, system_user_perms
|
||||||
)
|
)
|
||||||
org_admin = PredefineRole(
|
org_admin = PredefineRole(
|
||||||
'5', ugettext_noop('OrgAdmin'), Scope.org, []
|
'5', ugettext_noop('OrgAdmin'), Scope.org, []
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
from django_filters import rest_framework as filters
|
||||||
|
|
||||||
|
from common.drf.filters import BaseFilterSet
|
||||||
|
from rbac.models import Role
|
||||||
|
|
||||||
|
|
||||||
|
class RoleFilter(BaseFilterSet):
|
||||||
|
name = filters.CharFilter(method='filter_name')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Role
|
||||||
|
fields = ('name', 'scope', 'builtin')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def filter_name(queryset, name, value):
|
||||||
|
builtin_ids = []
|
||||||
|
for role in queryset.filter(builtin=True):
|
||||||
|
if value in role.display_name:
|
||||||
|
builtin_ids.append(role.id)
|
||||||
|
if builtin_ids:
|
||||||
|
builtin_qs = queryset.model.objects.filter(id__in=builtin_ids)
|
||||||
|
else:
|
||||||
|
builtin_qs = queryset.model.objects.none()
|
||||||
|
queryset = queryset.filter(name__icontains=value)
|
||||||
|
return queryset | builtin_qs
|
|
@ -90,4 +90,3 @@ class Permission(DjangoPermission):
|
||||||
permissions = cls.objects.all()
|
permissions = cls.objects.all()
|
||||||
permissions = cls.clean_permissions(permissions, scope=scope)
|
permissions = cls.clean_permissions(permissions, scope=scope)
|
||||||
return permissions
|
return permissions
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,20 @@ class Role(JMSModel):
|
||||||
def is_org(self):
|
def is_org(self):
|
||||||
return self.scope == const.Scope.org
|
return self.scope == const.Scope.org
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_roles_by_perm(cls, perm):
|
||||||
|
app_label, codename = perm.split('.')
|
||||||
|
p = Permission.objects.filter(
|
||||||
|
codename=codename,
|
||||||
|
content_type__app_label=app_label
|
||||||
|
).first()
|
||||||
|
if not p:
|
||||||
|
return p.roles.none()
|
||||||
|
role_ids = list(p.roles.all().values_list('id', flat=True))
|
||||||
|
admin_ids = [BuiltinRole.system_admin.id, BuiltinRole.org_admin.id]
|
||||||
|
role_ids += admin_ids
|
||||||
|
return cls.objects.filter(id__in=role_ids)
|
||||||
|
|
||||||
|
|
||||||
class SystemRole(Role):
|
class SystemRole(Role):
|
||||||
objects = SystemRoleManager()
|
objects = SystemRoleManager()
|
||||||
|
|
|
@ -100,6 +100,28 @@ class RoleBinding(JMSModel):
|
||||||
def is_scope_org(self):
|
def is_scope_org(self):
|
||||||
return self.scope == Scope.org
|
return self.scope == Scope.org
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_user_has_the_perm_orgs(cls, perm, user):
|
||||||
|
from orgs.models import Organization
|
||||||
|
|
||||||
|
roles = Role.get_roles_by_perm(perm)
|
||||||
|
bindings = list(cls.objects.root_all().filter(role__in=roles, user=user))
|
||||||
|
system_bindings = [b for b in bindings if b.scope == Role.Scope.system.value]
|
||||||
|
|
||||||
|
if perm == 'rbac.view_workbench':
|
||||||
|
all_orgs = user.orgs.all()
|
||||||
|
else:
|
||||||
|
all_orgs = Organization.objects.all()
|
||||||
|
|
||||||
|
if system_bindings:
|
||||||
|
orgs = all_orgs
|
||||||
|
else:
|
||||||
|
org_ids = [b.org.id for b in bindings if b.org]
|
||||||
|
orgs = all_orgs.filter(id__in=org_ids)
|
||||||
|
if orgs and user.has_perm('orgs.view_rootorg'):
|
||||||
|
orgs = [Organization.root(), *list(orgs)]
|
||||||
|
return orgs
|
||||||
|
|
||||||
|
|
||||||
class OrgRoleBindingManager(RoleBindingManager):
|
class OrgRoleBindingManager(RoleBindingManager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
|
|
@ -59,10 +59,15 @@ class CommandStore(object):
|
||||||
data = self.es.indices.get_mapping(self.index)
|
data = self.es.indices.get_mapping(self.index)
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
return False
|
return False
|
||||||
|
info = self.es.info()
|
||||||
|
version = info['version']['number'].split('.')[0]
|
||||||
try:
|
try:
|
||||||
# 检测索引是不是新的类型
|
if version == '6':
|
||||||
properties = data[self.index]['mappings']['properties']
|
# 检测索引是不是新的类型 es6
|
||||||
|
properties = data[self.index]['mappings']['data']['properties']
|
||||||
|
else:
|
||||||
|
# 检测索引是不是新的类型 es7 default index type: _doc
|
||||||
|
properties = data[self.index]['mappings']['properties']
|
||||||
if properties['session']['type'] == 'keyword' \
|
if properties['session']['type'] == 'keyword' \
|
||||||
and properties['org_id']['type'] == 'keyword':
|
and properties['org_id']['type'] == 'keyword':
|
||||||
return True
|
return True
|
||||||
|
@ -75,27 +80,30 @@ class CommandStore(object):
|
||||||
self._ensure_index_exists()
|
self._ensure_index_exists()
|
||||||
|
|
||||||
def _ensure_index_exists(self):
|
def _ensure_index_exists(self):
|
||||||
mappings = {
|
properties = {
|
||||||
"mappings": {
|
"session": {
|
||||||
"properties": {
|
"type": "keyword"
|
||||||
"session": {
|
},
|
||||||
"type": "keyword"
|
"org_id": {
|
||||||
},
|
"type": "keyword"
|
||||||
"org_id": {
|
},
|
||||||
"type": "keyword"
|
"@timestamp": {
|
||||||
},
|
"type": "date"
|
||||||
"@timestamp": {
|
},
|
||||||
"type": "date"
|
"timestamp": {
|
||||||
},
|
"type": "long"
|
||||||
"timestamp": {
|
|
||||||
"type": "long"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info = self.es.info()
|
||||||
|
version = info['version']['number'].split('.')[0]
|
||||||
|
if version == '6':
|
||||||
|
mappings = {'mappings': {'data': {'properties': properties}}}
|
||||||
|
else:
|
||||||
|
mappings = {'mappings': {'properties': properties}}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.es.indices.create(self.index, body=mappings)
|
self.es.indices.create(self.index, body=mappings)
|
||||||
|
return
|
||||||
except RequestError as e:
|
except RequestError as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ def migrate_endpoints(apps, schema_editor):
|
||||||
'http_port': 0,
|
'http_port': 0,
|
||||||
'created_by': 'System'
|
'created_by': 'System'
|
||||||
}
|
}
|
||||||
default_endpoint = Endpoint.objects.create(**default_data)
|
Endpoint.objects.create(**default_data)
|
||||||
|
|
||||||
if not settings.XRDP_ENABLED:
|
if not settings.XRDP_ENABLED:
|
||||||
return
|
return
|
||||||
|
@ -81,8 +81,8 @@ class Migration(migrations.Migration):
|
||||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||||
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=128, unique=True, blank=True, verbose_name='Name')),
|
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
|
||||||
('host', models.CharField(max_length=256, verbose_name='Host')),
|
('host', models.CharField(max_length=256, verbose_name='Host', blank=True)),
|
||||||
('https_port', common.fields.model.PortField(default=443, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(65535)], verbose_name='HTTPS Port')),
|
('https_port', common.fields.model.PortField(default=443, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(65535)], verbose_name='HTTPS Port')),
|
||||||
('http_port', common.fields.model.PortField(default=80, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(65535)], verbose_name='HTTP Port')),
|
('http_port', common.fields.model.PortField(default=80, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(65535)], verbose_name='HTTP Port')),
|
||||||
('ssh_port', common.fields.model.PortField(default=2222, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(65535)], verbose_name='SSH Port')),
|
('ssh_port', common.fields.model.PortField(default=2222, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(65535)], verbose_name='SSH Port')),
|
||||||
|
|
|
@ -863,23 +863,20 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
|
||||||
return None
|
return None
|
||||||
return self.SOURCE_BACKEND_MAPPING.get(self.source, [])
|
return self.SOURCE_BACKEND_MAPPING.get(self.source, [])
|
||||||
|
|
||||||
@property
|
@lazyproperty
|
||||||
def all_orgs(self):
|
def console_orgs(self):
|
||||||
from rbac.builtin import BuiltinRole
|
from rbac.models import RoleBinding
|
||||||
has_system_role = self.system_roles.all() \
|
return RoleBinding.get_user_has_the_perm_orgs('rbac.view_console', self)
|
||||||
.exclude(name=BuiltinRole.system_user.name) \
|
|
||||||
.exists()
|
|
||||||
if has_system_role:
|
|
||||||
orgs = list(Organization.objects.all())
|
|
||||||
else:
|
|
||||||
orgs = list(self.orgs.distinct())
|
|
||||||
if self.has_perm('orgs.view_rootorg'):
|
|
||||||
orgs = [Organization.root()] + orgs
|
|
||||||
return orgs
|
|
||||||
|
|
||||||
@property
|
@lazyproperty
|
||||||
def my_orgs(self):
|
def audit_orgs(self):
|
||||||
return list(self.orgs.distinct())
|
from rbac.models import RoleBinding
|
||||||
|
return RoleBinding.get_user_has_the_perm_orgs('rbac.view_audit', self)
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def workbench_orgs(self):
|
||||||
|
from rbac.models import RoleBinding
|
||||||
|
return RoleBinding.get_user_has_the_perm_orgs('rbac.view_workbench', self)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['username']
|
ordering = ['username']
|
||||||
|
|
|
@ -121,14 +121,16 @@ class UserProfileSerializer(UserSerializer):
|
||||||
mfa_level = serializers.ChoiceField(choices=MFA_LEVEL_CHOICES, label=_('MFA'), required=False)
|
mfa_level = serializers.ChoiceField(choices=MFA_LEVEL_CHOICES, label=_('MFA'), required=False)
|
||||||
guide_url = serializers.SerializerMethodField()
|
guide_url = serializers.SerializerMethodField()
|
||||||
receive_backends = serializers.ListField(child=serializers.CharField(), read_only=True)
|
receive_backends = serializers.ListField(child=serializers.CharField(), read_only=True)
|
||||||
orgs = UserOrgSerializer(many=True, read_only=True, source='all_orgs')
|
console_orgs = UserOrgSerializer(many=True, read_only=True)
|
||||||
myorgs = UserOrgSerializer(many=True, read_only=True, source='my_orgs')
|
audit_orgs = UserOrgSerializer(many=True, read_only=True)
|
||||||
|
workbench_orgs = UserOrgSerializer(many=True, read_only=True)
|
||||||
perms = serializers.ListField(label=_("Perms"), read_only=True)
|
perms = serializers.ListField(label=_("Perms"), read_only=True)
|
||||||
|
|
||||||
class Meta(UserSerializer.Meta):
|
class Meta(UserSerializer.Meta):
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
'date_joined', 'last_login', 'created_by', 'source',
|
'date_joined', 'last_login', 'created_by', 'source',
|
||||||
'receive_backends', 'orgs', 'myorgs', 'perms',
|
'console_orgs', 'audit_orgs', 'workbench_orgs',
|
||||||
|
'receive_backends', 'perms',
|
||||||
]
|
]
|
||||||
fields = UserSerializer.Meta.fields + [
|
fields = UserSerializer.Meta.fields + [
|
||||||
'public_key_comment', 'public_key_hash_md5', 'guide_url',
|
'public_key_comment', 'public_key_hash_md5', 'guide_url',
|
||||||
|
|
Loading…
Reference in New Issue