mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-06-26 15:01:59 +00:00
Merge remote-tracking branch 'origin/v3' into v3
This commit is contained in:
commit
e7dde616c0
111
Dockerfile
111
Dockerfile
@ -1,65 +1,77 @@
|
|||||||
|
FROM python:3.8-slim as stage-build
|
||||||
|
ARG TARGETARCH
|
||||||
|
|
||||||
|
ARG VERSION
|
||||||
|
ENV VERSION=$VERSION
|
||||||
|
|
||||||
|
WORKDIR /opt/jumpserver
|
||||||
|
ADD . .
|
||||||
|
RUN cd utils && bash -ixeu build.sh
|
||||||
|
|
||||||
FROM python:3.8-slim
|
FROM python:3.8-slim
|
||||||
|
ARG TARGETARCH
|
||||||
MAINTAINER JumpServer Team <ibuler@qq.com>
|
MAINTAINER JumpServer Team <ibuler@qq.com>
|
||||||
|
|
||||||
ARG BUILD_DEPENDENCIES=" \
|
ARG BUILD_DEPENDENCIES=" \
|
||||||
g++ \
|
g++ \
|
||||||
make \
|
make \
|
||||||
pkg-config"
|
pkg-config"
|
||||||
|
|
||||||
ARG DEPENDENCIES=" \
|
ARG DEPENDENCIES=" \
|
||||||
default-libmysqlclient-dev \
|
default-libmysqlclient-dev \
|
||||||
freetds-dev \
|
freetds-dev \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
libffi-dev \
|
libffi-dev \
|
||||||
libldap2-dev \
|
libjpeg-dev \
|
||||||
libsasl2-dev \
|
libldap2-dev \
|
||||||
libxml2-dev \
|
libsasl2-dev \
|
||||||
libxmlsec1-dev \
|
libxml2-dev \
|
||||||
libxmlsec1-openssl \
|
libxmlsec1-dev \
|
||||||
libaio-dev \
|
libxmlsec1-openssl \
|
||||||
openssh-client \
|
libaio-dev \
|
||||||
sshpass"
|
openssh-client \
|
||||||
|
sshpass"
|
||||||
|
|
||||||
ARG TOOLS=" \
|
ARG TOOLS=" \
|
||||||
curl \
|
ca-certificates \
|
||||||
default-mysql-client \
|
curl \
|
||||||
iproute2 \
|
default-mysql-client \
|
||||||
iputils-ping \
|
iputils-ping \
|
||||||
locales \
|
locales \
|
||||||
procps \
|
procps \
|
||||||
redis-tools \
|
redis-tools \
|
||||||
telnet \
|
telnet \
|
||||||
vim \
|
vim \
|
||||||
unzip \
|
unzip \
|
||||||
wget"
|
wget"
|
||||||
|
|
||||||
RUN sed -i 's@http://.*.debian.org@http://mirrors.ustc.edu.cn@g' /etc/apt/sources.list \
|
ARG APT_MIRROR=http://mirrors.ustc.edu.cn
|
||||||
|
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
|
||||||
|
sed -i "s@http://.*.debian.org@${APT_MIRROR}@g" /etc/apt/sources.list \
|
||||||
|
&& rm -f /etc/apt/apt.conf.d/docker-clean \
|
||||||
|
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get -y install --no-install-recommends ${BUILD_DEPENDENCIES} \
|
&& apt-get -y install --no-install-recommends ${BUILD_DEPENDENCIES} \
|
||||||
&& apt-get -y install --no-install-recommends ${DEPENDENCIES} \
|
&& apt-get -y install --no-install-recommends ${DEPENDENCIES} \
|
||||||
&& apt-get -y install --no-install-recommends ${TOOLS} \
|
&& apt-get -y install --no-install-recommends ${TOOLS} \
|
||||||
&& localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8 \
|
|
||||||
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
|
||||||
&& mkdir -p /root/.ssh/ \
|
&& mkdir -p /root/.ssh/ \
|
||||||
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null" > /root/.ssh/config \
|
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null" > /root/.ssh/config \
|
||||||
&& sed -i "s@# alias l@alias l@g" ~/.bashrc \
|
&& sed -i "s@# alias l@alias l@g" ~/.bashrc \
|
||||||
&& echo "set mouse-=a" > ~/.vimrc \
|
&& echo "set mouse-=a" > ~/.vimrc \
|
||||||
&& echo "no" | dpkg-reconfigure dash \
|
&& echo "no" | dpkg-reconfigure dash \
|
||||||
|
&& echo "zh_CN.UTF-8" | dpkg-reconfigure locales \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ARG TARGETARCH
|
ARG DOWNLOAD_URL=https://download.jumpserver.org
|
||||||
ARG ORACLE_LIB_MAJOR=19
|
|
||||||
ARG ORACLE_LIB_MINOR=10
|
|
||||||
ENV ORACLE_FILE="instantclient-basiclite-linux.${TARGETARCH:-amd64}-${ORACLE_LIB_MAJOR}.${ORACLE_LIB_MINOR}.0.0.0dbru.zip"
|
|
||||||
|
|
||||||
RUN mkdir -p /opt/oracle/ \
|
RUN mkdir -p /opt/oracle/ \
|
||||||
&& cd /opt/oracle/ \
|
&& cd /opt/oracle/ \
|
||||||
&& wget https://download.jumpserver.org/files/oracle/${ORACLE_FILE} \
|
&& wget ${DOWNLOAD_URL}/public/instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip \
|
||||||
&& unzip instantclient-basiclite-linux.${TARGETARCH-amd64}-19.10.0.0.0dbru.zip \
|
&& unzip instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip \
|
||||||
&& mv instantclient_${ORACLE_LIB_MAJOR}_${ORACLE_LIB_MINOR} instantclient \
|
&& sh -c "echo /opt/oracle/instantclient_19_10 > /etc/ld.so.conf.d/oracle-instantclient.conf" \
|
||||||
&& echo "/opt/oracle/instantclient" > /etc/ld.so.conf.d/oracle-instantclient.conf \
|
|
||||||
&& ldconfig \
|
&& ldconfig \
|
||||||
&& rm -f ${ORACLE_FILE}
|
&& rm -f instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip
|
||||||
|
|
||||||
WORKDIR /tmp/build
|
WORKDIR /tmp/build
|
||||||
COPY ./requirements ./requirements
|
COPY ./requirements ./requirements
|
||||||
@ -68,21 +80,18 @@ ARG PIP_MIRROR=https://pypi.douban.com/simple
|
|||||||
ENV PIP_MIRROR=$PIP_MIRROR
|
ENV PIP_MIRROR=$PIP_MIRROR
|
||||||
ARG PIP_JMS_MIRROR=https://pypi.douban.com/simple
|
ARG PIP_JMS_MIRROR=https://pypi.douban.com/simple
|
||||||
ENV PIP_JMS_MIRROR=$PIP_JMS_MIRROR
|
ENV PIP_JMS_MIRROR=$PIP_JMS_MIRROR
|
||||||
# 因为以 jms 或者 jumpserver 开头的 mirror 上可能没有
|
|
||||||
RUN pip install --upgrade pip==20.2.4 setuptools==49.6.0 wheel==0.34.2 -i ${PIP_MIRROR} \
|
|
||||||
&& pip install --no-cache-dir $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
|
|
||||||
&& pip install --no-cache-dir -r requirements/requirements.txt -i ${PIP_MIRROR} \
|
|
||||||
&& rm -rf ~/.cache/pip
|
|
||||||
|
|
||||||
ARG VERSION
|
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||||
ENV VERSION=$VERSION
|
set -ex \
|
||||||
|
&& pip config set global.index-url ${PIP_MIRROR} \
|
||||||
|
&& pip install --upgrade pip \
|
||||||
|
&& pip install --upgrade setuptools wheel \
|
||||||
|
&& pip install $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
|
||||||
|
&& pip install -r requirements/requirements.txt
|
||||||
|
|
||||||
ADD . .
|
COPY --from=stage-build /opt/jumpserver/release/jumpserver /opt/jumpserver
|
||||||
RUN cd utils \
|
RUN echo > /opt/jumpserver/config.yml \
|
||||||
&& bash -ixeu build.sh \
|
&& rm -rf /tmp/build
|
||||||
&& mv ../release/jumpserver /opt/jumpserver \
|
|
||||||
&& rm -rf /tmp/build \
|
|
||||||
&& echo > /opt/jumpserver/config.yml
|
|
||||||
|
|
||||||
WORKDIR /opt/jumpserver
|
WORKDIR /opt/jumpserver
|
||||||
VOLUME /opt/jumpserver/data
|
VOLUME /opt/jumpserver/data
|
||||||
|
@ -19,7 +19,6 @@ __all__ = [
|
|||||||
'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi',
|
'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi',
|
||||||
'UserGroupGrantedNodeAssetsApi',
|
'UserGroupGrantedNodeAssetsApi',
|
||||||
'UserGroupGrantedNodeChildrenAsTreeApi',
|
'UserGroupGrantedNodeChildrenAsTreeApi',
|
||||||
'UserGroupGrantedAssetAccountsApi',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -191,17 +190,3 @@ class UserGroupGrantedNodeChildrenAsTreeApi(SerializeToTreeNodeMixin, ListAPIVie
|
|||||||
nodes = self.get_nodes()
|
nodes = self.get_nodes()
|
||||||
nodes = self.serialize_nodes(nodes)
|
nodes = self.serialize_nodes(nodes)
|
||||||
return Response(data=nodes)
|
return Response(data=nodes)
|
||||||
|
|
||||||
|
|
||||||
class UserGroupGrantedAssetAccountsApi(uapi.UserGrantedAssetAccountsApi):
|
|
||||||
|
|
||||||
@lazyproperty
|
|
||||||
def user_group(self):
|
|
||||||
group_id = self.kwargs.get('pk')
|
|
||||||
return UserGroup.objects.get(id=group_id)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
accounts = PermAccountUtil().get_perm_accounts_for_user_group_asset(
|
|
||||||
self.user_group, self.asset, with_actions=True
|
|
||||||
)
|
|
||||||
return accounts
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework.generics import ListAPIView, get_object_or_404
|
from rest_framework.generics import ListAPIView, get_object_or_404
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger, lazyproperty
|
||||||
from perms import serializers
|
from perms import serializers
|
||||||
from perms.hands import Asset
|
from perms.hands import Asset
|
||||||
from perms.utils import PermAccountUtil
|
from perms.utils import PermAccountUtil
|
||||||
@ -10,14 +10,14 @@ from .mixin import SelfOrPKUserMixin
|
|||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'UserGrantedAssetAccountsApi',
|
'UserPermedAssetAccountsApi',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class UserGrantedAssetAccountsApi(SelfOrPKUserMixin, ListAPIView):
|
class UserPermedAssetAccountsApi(SelfOrPKUserMixin, ListAPIView):
|
||||||
serializer_class = serializers.AccountsGrantedSerializer
|
serializer_class = serializers.AccountsPermedSerializer
|
||||||
|
|
||||||
@property
|
@lazyproperty
|
||||||
def asset(self):
|
def asset(self):
|
||||||
asset_id = self.kwargs.get('asset_id')
|
asset_id = self.kwargs.get('asset_id')
|
||||||
kwargs = {'id': asset_id, 'is_active': True}
|
kwargs = {'id': asset_id, 'is_active': True}
|
||||||
|
@ -2,8 +2,11 @@
|
|||||||
#
|
#
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.http import is_true
|
from common.http import is_true
|
||||||
|
from common.utils import is_uuid
|
||||||
|
from common.exceptions import JMSObjectDoesNotExist
|
||||||
from common.mixins.api import RoleAdminMixin, RoleUserMixin
|
from common.mixins.api import RoleAdminMixin, RoleUserMixin
|
||||||
from perms.utils.user_permission import UserGrantedTreeRefreshController
|
from perms.utils.user_permission import UserGrantedTreeRefreshController
|
||||||
from rbac.permissions import RBACPermission
|
from rbac.permissions import RBACPermission
|
||||||
@ -43,6 +46,12 @@ class SelfOrPKUserMixin:
|
|||||||
request: Request
|
request: Request
|
||||||
permission_classes = (RBACPermission,)
|
permission_classes = (RBACPermission,)
|
||||||
|
|
||||||
|
def get_rbac_perms(self):
|
||||||
|
if self.request_user_is_self():
|
||||||
|
return self.self_rbac_perms
|
||||||
|
else:
|
||||||
|
return self.admin_rbac_perms
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def self_rbac_perms(self):
|
def self_rbac_perms(self):
|
||||||
return (
|
return (
|
||||||
@ -61,18 +70,15 @@ class SelfOrPKUserMixin:
|
|||||||
('GET', 'perms.view_userassets'),
|
('GET', 'perms.view_userassets'),
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_rbac_perms(self):
|
|
||||||
if self.request_user_is_self():
|
|
||||||
return self.self_rbac_perms
|
|
||||||
else:
|
|
||||||
return self.admin_rbac_perms
|
|
||||||
|
|
||||||
def request_user_is_self(self):
|
|
||||||
return self.kwargs.get('user') in ['my', 'self']
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user(self):
|
def user(self):
|
||||||
if self.request_user_is_self():
|
if self.request_user_is_self():
|
||||||
return self.request.user
|
user = self.request.user
|
||||||
|
elif is_uuid(self.kwargs.get('user')):
|
||||||
|
user = get_object_or_404(User, pk=self.kwargs.get('user'))
|
||||||
else:
|
else:
|
||||||
return get_object_or_404(User, pk=self.kwargs.get('user'))
|
raise JMSObjectDoesNotExist(object_name=_('User'))
|
||||||
|
return user
|
||||||
|
|
||||||
|
def request_user_is_self(self):
|
||||||
|
return self.kwargs.get('user') in ['my', 'self']
|
||||||
|
@ -6,15 +6,15 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from common.db.fields import BitChoices
|
from common.db.fields import BitChoices
|
||||||
from common.utils.integer import bit
|
from common.utils.integer import bit
|
||||||
|
|
||||||
__all__ = ["SpecialAccount", "ActionChoices"]
|
__all__ = ["ActionChoices"]
|
||||||
|
|
||||||
|
|
||||||
class ActionChoices(BitChoices):
|
class ActionChoices(BitChoices):
|
||||||
connect = bit(1), _("Connect")
|
connect = bit(0), _("Connect")
|
||||||
upload = bit(2), _("Upload")
|
upload = bit(1), _("Upload")
|
||||||
download = bit(3), _("Download")
|
download = bit(2), _("Download")
|
||||||
copy = bit(4), _("Copy")
|
copy = bit(3), _("Copy")
|
||||||
paste = bit(5), _("Paste")
|
paste = bit(4), _("Paste")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_tree(cls):
|
def is_tree(cls):
|
||||||
@ -23,6 +23,7 @@ class ActionChoices(BitChoices):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def branches(cls):
|
def branches(cls):
|
||||||
return (
|
return (
|
||||||
|
cls.connect,
|
||||||
(_("Transfer"), [cls.upload, cls.download]),
|
(_("Transfer"), [cls.upload, cls.download]),
|
||||||
(_("Clipboard"), [cls.copy, cls.paste]),
|
(_("Clipboard"), [cls.copy, cls.paste]),
|
||||||
)
|
)
|
||||||
@ -31,7 +32,3 @@ class ActionChoices(BitChoices):
|
|||||||
def has_perm(cls, action_name, total):
|
def has_perm(cls, action_name, total):
|
||||||
action_value = getattr(cls, action_name)
|
action_value = getattr(cls, action_name)
|
||||||
return action_value & total == action_value
|
return action_value & total == action_value
|
||||||
|
|
||||||
|
|
||||||
class SpecialAccount(models.TextChoices):
|
|
||||||
ALL = "@ALL", "All"
|
|
||||||
|
@ -11,7 +11,7 @@ from common.db.models import UnionQuerySet
|
|||||||
from common.utils import date_expired_default
|
from common.utils import date_expired_default
|
||||||
from orgs.mixins.models import OrgManager
|
from orgs.mixins.models import OrgManager
|
||||||
from orgs.mixins.models import OrgModelMixin
|
from orgs.mixins.models import OrgModelMixin
|
||||||
from perms.const import ActionChoices, SpecialAccount
|
from perms.const import ActionChoices
|
||||||
|
|
||||||
__all__ = ['AssetPermission', 'ActionChoices']
|
__all__ = ['AssetPermission', 'ActionChoices']
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ class AssetPermissionQuerySet(models.QuerySet):
|
|||||||
|
|
||||||
def filter_by_accounts(self, accounts):
|
def filter_by_accounts(self, accounts):
|
||||||
q = Q(accounts__contains=list(accounts)) | \
|
q = Q(accounts__contains=list(accounts)) | \
|
||||||
Q(accounts__contains=SpecialAccount.ALL.value)
|
Q(accounts__contains=Account.AliasAccount.ALL.value)
|
||||||
return self.filter(q)
|
return self.filter(q)
|
||||||
|
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ class AssetPermission(OrgModelMixin):
|
|||||||
"""
|
"""
|
||||||
asset_ids = self.get_all_assets(flat=True)
|
asset_ids = self.get_all_assets(flat=True)
|
||||||
q = Q(asset_id__in=asset_ids)
|
q = Q(asset_id__in=asset_ids)
|
||||||
if SpecialAccount.ALL in self.accounts:
|
if Account.AliasAccount.ALL in self.accounts:
|
||||||
q &= Q(username__in=self.accounts)
|
q &= Q(username__in=self.accounts)
|
||||||
accounts = Account.objects.filter(q).order_by('asset__name', 'name', 'username')
|
accounts = Account.objects.filter(q).order_by('asset__name', 'name', 'username')
|
||||||
if not flat:
|
if not flat:
|
||||||
|
@ -11,7 +11,7 @@ from perms.serializers.permission import ActionChoicesField
|
|||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'NodeGrantedSerializer', 'AssetGrantedSerializer',
|
'NodeGrantedSerializer', 'AssetGrantedSerializer',
|
||||||
'ActionsSerializer', 'AccountsGrantedSerializer'
|
'ActionsSerializer', 'AccountsPermedSerializer'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class ActionsSerializer(serializers.Serializer):
|
|||||||
actions = ActionChoicesField(read_only=True)
|
actions = ActionChoicesField(read_only=True)
|
||||||
|
|
||||||
|
|
||||||
class AccountsGrantedSerializer(serializers.ModelSerializer):
|
class AccountsPermedSerializer(serializers.ModelSerializer):
|
||||||
actions = ActionChoicesField(read_only=True)
|
actions = ActionChoicesField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -55,8 +55,9 @@ user_permission_urlpatterns = [
|
|||||||
name='my-ungrouped-assets'),
|
name='my-ungrouped-assets'),
|
||||||
|
|
||||||
# 获取授权给用户某个资产的所有账号
|
# 获取授权给用户某个资产的所有账号
|
||||||
path('<str:user>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccountsApi.as_view(),
|
# user params: ['my', 'self'] or user.id
|
||||||
name='user-asset-accounts'),
|
path('<str:user>/assets/<uuid:asset_id>/accounts/', api.UserPermedAssetAccountsApi.as_view(),
|
||||||
|
name='user-permed-asset-accounts'),
|
||||||
]
|
]
|
||||||
|
|
||||||
user_group_permission_urlpatterns = [
|
user_group_permission_urlpatterns = [
|
||||||
@ -68,10 +69,6 @@ user_group_permission_urlpatterns = [
|
|||||||
name='user-group-nodes-children-as-tree'),
|
name='user-group-nodes-children-as-tree'),
|
||||||
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(),
|
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(),
|
||||||
name='user-group-node-assets'),
|
name='user-group-node-assets'),
|
||||||
|
|
||||||
# 获取所有和资产-用户组关联的账号列表
|
|
||||||
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGroupGrantedAssetAccountsApi.as_view(),
|
|
||||||
name='user-group-asset-accounts'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
user_permission_urlpatterns = [
|
user_permission_urlpatterns = [
|
||||||
|
@ -9,8 +9,28 @@ __all__ = ['PermAccountUtil']
|
|||||||
class PermAccountUtil(AssetPermissionUtil):
|
class PermAccountUtil(AssetPermissionUtil):
|
||||||
""" 资产授权账号相关的工具 """
|
""" 资产授权账号相关的工具 """
|
||||||
|
|
||||||
|
def validate_permission(self, user, asset, account_username):
|
||||||
|
""" 校验用户有某个资产下某个账号名的权限
|
||||||
|
:param user: User
|
||||||
|
:param asset: Asset
|
||||||
|
:param account_username: 可能是 @USER @INPUT 字符串
|
||||||
|
"""
|
||||||
|
permed_accounts = self.get_permed_accounts_for_user(user, asset)
|
||||||
|
accounts_mapper = {account.username: account for account in permed_accounts}
|
||||||
|
|
||||||
|
account = accounts_mapper.get(account_username)
|
||||||
|
actions, date_expired = (account.actions, account.date_expired) if account else (False, None)
|
||||||
|
return actions, date_expired
|
||||||
|
|
||||||
|
def get_permed_accounts_for_user(self, user, asset):
|
||||||
|
""" 获取授权给用户某个资产的账号 """
|
||||||
|
perms = self.get_permissions_for_user_asset(user, asset)
|
||||||
|
permed_accounts = self.get_permed_accounts_from_perms(perms, user, asset)
|
||||||
|
return permed_accounts
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_permed_accounts_from_perms(perms, user, asset):
|
def get_permed_accounts_from_perms(perms, user, asset):
|
||||||
|
# alias: is a collection of account usernames and special accounts [@ALL, @INPUT, @USER]
|
||||||
alias_action_bit_mapper = defaultdict(int)
|
alias_action_bit_mapper = defaultdict(int)
|
||||||
alias_expired_mapper = defaultdict(list)
|
alias_expired_mapper = defaultdict(list)
|
||||||
|
|
||||||
@ -21,23 +41,26 @@ class PermAccountUtil(AssetPermissionUtil):
|
|||||||
|
|
||||||
asset_accounts = asset.accounts.all()
|
asset_accounts = asset.accounts.all()
|
||||||
username_account_mapper = {account.username: account for account in asset_accounts}
|
username_account_mapper = {account.username: account for account in asset_accounts}
|
||||||
|
|
||||||
cleaned_accounts_action_bit = defaultdict(int)
|
cleaned_accounts_action_bit = defaultdict(int)
|
||||||
cleaned_accounts_expired = defaultdict(list)
|
cleaned_accounts_expired = defaultdict(list)
|
||||||
|
|
||||||
# @ALL 账号先处理,后面的每个最多映射一个账号
|
# @ALL 账号先处理,后面的每个最多映射一个账号
|
||||||
all_action_bit = alias_action_bit_mapper.pop('@ALL', None)
|
all_action_bit = alias_action_bit_mapper.pop(Account.AliasAccount.ALL, None)
|
||||||
if all_action_bit:
|
if all_action_bit:
|
||||||
for account in asset_accounts:
|
for account in asset_accounts:
|
||||||
cleaned_accounts_action_bit[account] |= all_action_bit
|
cleaned_accounts_action_bit[account] |= all_action_bit
|
||||||
cleaned_accounts_expired[account].extend(alias_expired_mapper['@ALL'])
|
cleaned_accounts_expired[account].extend(
|
||||||
|
alias_expired_mapper[Account.AliasAccount.ALL]
|
||||||
|
)
|
||||||
|
|
||||||
for alias, action_bit in alias_action_bit_mapper.items():
|
for alias, action_bit in alias_action_bit_mapper.items():
|
||||||
if alias == '@USER':
|
if alias == Account.AliasAccount.USER:
|
||||||
if user.username in username_account_mapper:
|
if user.username in username_account_mapper:
|
||||||
account = username_account_mapper[user.username]
|
account = username_account_mapper[user.username]
|
||||||
else:
|
else:
|
||||||
account = Account.get_user_account(user.username)
|
account = Account.get_user_account(user.username)
|
||||||
elif alias == '@INPUT':
|
elif alias == Account.AliasAccount.INPUT:
|
||||||
account = Account.get_manual_account()
|
account = Account.get_manual_account()
|
||||||
elif alias in username_account_mapper:
|
elif alias in username_account_mapper:
|
||||||
account = username_account_mapper[alias]
|
account = username_account_mapper[alias]
|
||||||
@ -54,35 +77,3 @@ class PermAccountUtil(AssetPermissionUtil):
|
|||||||
account.date_expired = max(cleaned_accounts_expired[account])
|
account.date_expired = max(cleaned_accounts_expired[account])
|
||||||
accounts.append(account)
|
accounts.append(account)
|
||||||
return accounts
|
return accounts
|
||||||
|
|
||||||
def get_permed_accounts_for_user(self, user, asset):
|
|
||||||
""" 获取授权给用户某个资产的账号 """
|
|
||||||
perms = self.get_permissions_for_user_asset(user, asset)
|
|
||||||
permed_accounts = self.get_permed_accounts_from_perms(perms, user, asset)
|
|
||||||
return permed_accounts
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_accounts_for_permission(perm, with_actions=False):
|
|
||||||
""" 获取授权规则包含的账号 """
|
|
||||||
aid_actions_map = defaultdict(int)
|
|
||||||
# 这里不行,速度太慢, 别情有很多查询
|
|
||||||
account_ids = perm.get_all_accounts(flat=True)
|
|
||||||
actions = perm.actions
|
|
||||||
for aid in account_ids:
|
|
||||||
aid_actions_map[str(aid)] |= actions
|
|
||||||
account_ids = list(aid_actions_map.keys())
|
|
||||||
accounts = Account.objects.filter(id__in=account_ids)
|
|
||||||
return accounts
|
|
||||||
|
|
||||||
def validate_permission(self, user, asset, account_username):
|
|
||||||
""" 校验用户有某个资产下某个账号名的权限
|
|
||||||
:param account_username: 可能是 @USER @INPUT 的
|
|
||||||
"""
|
|
||||||
permed_accounts = self.get_permed_accounts_for_user(user, asset)
|
|
||||||
accounts_mapper = {account.username: account for account in permed_accounts}
|
|
||||||
|
|
||||||
account = accounts_mapper.get(account_username)
|
|
||||||
if not account:
|
|
||||||
return False, None
|
|
||||||
else:
|
|
||||||
return account.actions, account.date_expired
|
|
||||||
|
@ -11,6 +11,9 @@ action="${1-start}"
|
|||||||
service="${2-all}"
|
service="${2-all}"
|
||||||
|
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
rm -f /opt/jumpserver/tmp/*.pid
|
||||||
|
|
||||||
if [[ "$action" == "bash" || "$action" == "sh" ]];then
|
if [[ "$action" == "bash" || "$action" == "sh" ]];then
|
||||||
bash
|
bash
|
||||||
elif [[ "$action" == "sleep" ]];then
|
elif [[ "$action" == "sleep" ]];then
|
||||||
@ -19,4 +22,3 @@ elif [[ "$action" == "sleep" ]];then
|
|||||||
else
|
else
|
||||||
python jms "${action}" "${service}"
|
python jms "${action}" "${service}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user