Compare commits

...

24 Commits

Author SHA1 Message Date
fit2bot
3a18f34e15 feat: Update v3.5.5 2023-09-11 16:54:23 +08:00
ibuler
6c9c64a55f fix: 修复 private storage permission 2023-09-11 11:19:49 +08:00
Bai
24949c6013 perf: 优化飞书信息通知文案 2023-08-15 08:17:00 +05:00
Bai
d02e56da78 fix: 修复忘记密码不包含左侧 + 字符 2023-08-14 15:42:56 +05:00
“huailei000”
9b6c1806af perf: 优化任务日志页面时间显示兼容问题 2023-08-14 07:11:42 +05:00
Bai
ed640e094f fix: 修复 MAX_LIMIT_PER_PAGE, 默认值以及数据类型转换 2023-08-03 18:38:23 +08:00
吴小白
f21272af7d perf: 升级 PyYAML==6.0.1 2023-08-03 10:22:46 +08:00
feng
93cd00702d fix: k8s 支持网关 2023-08-03 10:19:13 +08:00
吴小白
115550793e fix: 修正 python-oracledb 构建错误 2023-08-01 19:52:59 +08:00
Bai
db28e98a02 perf: 升级 oracledb==1.3.2 2023-08-01 18:56:13 +08:00
Bai
1851783dbd perf: 升级 pymssql==2.2.8 2023-08-01 18:32:31 +08:00
Eric_Lee
8648b131f2 Merge pull request #11153 from jumpserver/revert-11152-pr@v3.5@fix_dockerfile_v3.5
Revert "perf: 锁定 Cython==0.29.35 增加 pip 选项 --use-deprecated=legacy-resolver"
2023-08-01 18:24:00 +08:00
Bryan
43112eaa8f Revert "perf: 锁定 Cython==0.29.35 增加 pip 选项 --use-deprecated=legacy-resolver"
This reverts commit 9dbbc57454.
2023-08-01 18:23:09 +08:00
Bai
9dbbc57454 perf: 锁定 Cython==0.29.35 增加 pip 选项 --use-deprecated=legacy-resolver 2023-08-01 18:18:24 +08:00
feng
a0d8c297b0 fix: ansible task 500 2023-08-01 15:43:53 +08:00
ibuler
e15c5b853e perf: 修改 ansible version 2023-08-01 10:51:19 +08:00
ibuler
e015dd7bcb perf: 修改 inventory 2023-08-01 10:50:01 +08:00
feng
8f59e49099 perf: 根据用户是否存在配置 改密参数 2023-07-31 19:54:02 +08:00
Aaron3S
316df6f9d9 fix: 禁止一些 ansible 变量 2023-07-31 19:48:06 +08:00
feng
fcfd7bb469 perf: 翻译 2023-07-26 19:34:35 +08:00
fit2bot
ed0932deea perf: 改密去掉sudo (#11094)
Co-authored-by: feng <1304903146@qq.com>
2023-07-26 19:18:06 +08:00
老广
c4f76c5512 Merge pull request #11092 from jumpserver/pr@v3.5@fix_user_account
fix: 修复同名账号用户名代填问题
2023-07-26 19:17:07 +08:00
fit2bot
7f3426fecf fix: 资产批量更新500 (#11098)
Co-authored-by: feng <1304903146@qq.com>
2023-07-26 19:16:43 +08:00
Eric
8e08e291a0 fix: 修复同名账号用户名代填问题 2023-07-26 09:15:06 +00:00
30 changed files with 162 additions and 65 deletions

View File

@@ -22,6 +22,7 @@ ARG DEPENDENCIES=" \
libpq-dev \
libffi-dev \
libjpeg-dev \
libkrb5-dev \
libldap2-dev \
libsasl2-dev \
libssl-dev \
@@ -95,7 +96,6 @@ RUN --mount=type=cache,target=/root/.cache/pip \
pip install https://download.jumpserver.org/pypi/simple/cryptography/cryptography-38.0.4-cp39-cp39-linux_loongarch64.whl; \
pip install https://download.jumpserver.org/pypi/simple/greenlet/greenlet-1.1.2-cp39-cp39-linux_loongarch64.whl; \
pip install https://download.jumpserver.org/pypi/simple/PyNaCl/PyNaCl-1.5.0-cp39-cp39-linux_loongarch64.whl; \
pip install https://download.jumpserver.org/pypi/simple/grpcio/grpcio-1.54.2-cp39-cp39-linux_loongarch64.whl; \
fi \
&& pip install $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install -r requirements/requirements.txt

View File

@@ -1,10 +1,21 @@
ARG VERSION
FROM registry.fit2cloud.com/jumpserver/xpack:${VERSION} as build-xpack
FROM jumpserver/core:${VERSION}
ARG TARGETARCH
COPY --from=build-xpack /opt/xpack /opt/jumpserver/apps/xpack
WORKDIR /opt/jumpserver
ARG ORACLE_VERSION=1.4.0b1
RUN --mount=type=cache,target=/root/.cache/pip \
set -ex \
&& \
if [ "${TARGETARCH}" == "amd64" ] || [ "${TARGETARCH}" == "arm64" ] || [ "${TARGETARCH}" == "loong64" ]; then \
pip install https://download.jumpserver.org/pypi/simple/oracledb/oracledb-${ORACLE_VERSION}-cp39-cp39-linux_$(uname -m).whl; \
fi \
&& \
if [ "${TARGETARCH}" == "loong64" ]; then \
pip install https://download.jumpserver.org/pypi/simple/grpcio/grpcio-1.54.2-cp39-cp39-linux_loongarch64.whl; \
fi \
&& pip install -r requirements/requirements_xpack.txt

1
GITSHA Normal file
View File

@@ -0,0 +1 @@
6c9c64a55f4480d96c2f722066d273c500067f3a

View File

@@ -1,10 +1,41 @@
- hosts: demo
gather_facts: no
tasks:
- name: Test privileged account
- name: "Test privileged {{ jms_account.username }} account"
ansible.builtin.ping:
- name: Change password
- name: "Check if {{ account.username }} user exists"
getent:
database: passwd
key: "{{ account.username }}"
register: user_info
ignore_errors: yes # 忽略错误如果用户不存在时不会导致playbook失败
- name: "Add {{ account.username }} user"
ansible.builtin.user:
name: "{{ account.username }}"
shell: "{{ params.shell }}"
home: "{{ params.home | default('/home/' + account.username, true) }}"
groups: "{{ params.groups }}"
expires: -1
state: present
when: user_info.failed
- name: "Add {{ account.username }} group"
ansible.builtin.group:
name: "{{ account.username }}"
state: present
when: user_info.failed
- name: "Add {{ account.username }} user to group"
ansible.builtin.user:
name: "{{ account.username }}"
groups: "{{ params.groups }}"
when:
- user_info.failed
- params.groups
- name: "Change {{ account.username }} password"
ansible.builtin.user:
name: "{{ account.username }}"
password: "{{ account.secret | password_hash('des') }}"
@@ -12,31 +43,37 @@
ignore_errors: true
when: account.secret_type == "password"
- name: create user If it already exists, no operation will be performed
ansible.builtin.user:
name: "{{ account.username }}"
when: account.secret_type == "ssh_key"
- name: remove jumpserver ssh key
ansible.builtin.lineinfile:
dest: "{{ ssh_params.dest }}"
regexp: "{{ ssh_params.regexp }}"
state: absent
when:
- account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms"
- account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms"
- name: Change SSH key
- name: "Change {{ account.username }} SSH key"
ansible.builtin.authorized_key:
user: "{{ account.username }}"
key: "{{ account.secret }}"
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection
- name: Verify password
- name: "Verify {{ account.username }} password"
ansible.builtin.ping:
become: no
vars:
@@ -45,7 +82,7 @@
ansible_become: no
when: account.secret_type == "password"
- name: Verify SSH key
- name: "Verify {{ account.username }} SSH key"
ansible.builtin.ping:
become: no
vars:

View File

@@ -9,7 +9,7 @@ params:
type: str
label: 'Sudo'
default: '/bin/whoami'
help_text: "{{ 'Params sudo help text' | trans }}"
help_text: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
- name: shell
type: str

View File

@@ -1,10 +1,17 @@
- hosts: demo
gather_facts: no
tasks:
- name: Test privileged account
- name: "Test privileged {{ jms_account.username }} account"
ansible.builtin.ping:
- name: Check user
- name: "Check if {{ account.username }} user exists"
getent:
database: passwd
key: "{{ account.username }}"
register: user_info
ignore_errors: yes # 忽略错误如果用户不存在时不会导致playbook失败
- name: "Add {{ account.username }} user"
ansible.builtin.user:
name: "{{ account.username }}"
shell: "{{ params.shell }}"
@@ -12,19 +19,23 @@
groups: "{{ params.groups }}"
expires: -1
state: present
when: user_info.failed
- name: "Add {{ account.username }} group"
ansible.builtin.group:
name: "{{ account.username }}"
state: present
when: user_info.failed
- name: Add user groups
- name: "Add {{ account.username }} user to group"
ansible.builtin.user:
name: "{{ account.username }}"
groups: "{{ params.groups }}"
when: params.groups
when:
- user_info.failed
- params.groups
- name: Change password
- name: "Change {{ account.username }} password"
ansible.builtin.user:
name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}"
@@ -32,11 +43,6 @@
ignore_errors: true
when: account.secret_type == "password"
- name: create user If it already exists, no operation will be performed
ansible.builtin.user:
name: "{{ account.username }}"
when: account.secret_type == "ssh_key"
- name: remove jumpserver ssh key
ansible.builtin.lineinfile:
dest: "{{ ssh_params.dest }}"
@@ -46,14 +52,14 @@
- account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms"
- name: Change SSH key
- name: "Change {{ account.username }} SSH key"
ansible.builtin.authorized_key:
user: "{{ account.username }}"
key: "{{ account.secret }}"
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: Set sudo setting
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
@@ -61,12 +67,13 @@
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection
- name: Verify password
- name: "Verify {{ account.username }} password"
ansible.builtin.ping:
become: no
vars:
@@ -75,7 +82,7 @@
ansible_become: no
when: account.secret_type == "password"
- name: Verify SSH key
- name: "Verify {{ account.username }} SSH key"
ansible.builtin.ping:
become: no
vars:

View File

@@ -10,7 +10,7 @@ params:
type: str
label: 'Sudo'
default: '/bin/whoami'
help_text: "{{ 'Params sudo help text' | trans }}"
help_text: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
- name: shell
type: str

View File

@@ -262,7 +262,7 @@ class BasePlaybookManager:
info = self.file_to_json(runner.inventory)
servers, not_valid = [], []
for k, host in info['all']['hosts'].items():
jms_asset, jms_gateway = host['jms_asset'], host.get('gateway')
jms_asset, jms_gateway = host.get('jms_asset'), host.get('gateway')
if not jms_gateway:
continue

View File

@@ -157,6 +157,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
def _extract_accounts(self):
if not getattr(self, 'initial_data', None):
return
if isinstance(self.initial_data, list):
return
accounts = self.initial_data.pop('accounts', None)
self._accounts = accounts

View File

@@ -22,7 +22,12 @@ class KubernetesClient:
@property
def api(self):
configuration = client.Configuration()
configuration.host = self.url
scheme = urlparse(self.url).scheme
if not self.server:
host = self.url
else:
host = f'{scheme}://127.0.0.1:{self.server.local_bind_port}'
configuration.host = host
configuration.verify_ssl = False
configuration.api_key = {"authorization": "Bearer " + self.token}
c = api_client.ApiClient(configuration=configuration)

View File

@@ -306,9 +306,6 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
if account.username != AliasAccount.INPUT:
data['input_username'] = ''
elif account.username == AliasAccount.USER:
data['input_username'] = user.username
ticket = self._validate_acl(user, asset, account)
if ticket:
data['from_ticket'] = ticket

View File

@@ -52,7 +52,11 @@ class UserResetPasswordSendCodeApi(CreateAPIView):
other_args = {}
target = serializer.validated_data[form_type]
query_key = 'phone' if form_type == 'sms' else form_type
if form_type == 'sms':
query_key = 'phone'
target = target.lstrip('+')
else:
query_key = form_type
user, err = self.is_valid_user(username=username, **{query_key: target})
if not user:
return Response({'error': err}, status=400)

View File

@@ -225,9 +225,20 @@ class ConnectionToken(JMSOrgBaseModel):
account.asset = self.asset
account.org_id = self.asset.org_id
if self.account in [AliasAccount.INPUT, AliasAccount.USER]:
# 手动账号
if self.account == AliasAccount.INPUT:
account.username = self.input_username
account.secret = self.input_secret
# 同名账号
elif self.account == AliasAccount.USER:
account.username = self.user.username
account.secret = self.input_secret
# 匿名账号
elif self.account == AliasAccount.ANON:
account.username = ''
account.secret = ''
else:
account = self.asset.accounts.filter(name=self.account).first()
if not account.secret and self.input_secret:

View File

@@ -12,7 +12,7 @@ from common.utils import get_object_or_none
from orgs.utils import tmp_to_root_org
class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
class IsValidUser(permissions.IsAuthenticated):
"""Allows access to valid user, is active and not expired"""
def has_permission(self, request, view):

View File

@@ -117,8 +117,8 @@ class FeiShu(RequestMixin):
}
body = {
'msg_type': 'text',
'content': json.dumps({'text': msg})
'msg_type': 'interactive',
'content': json.dumps({'elements': [{'tag': 'markdown', 'content': msg}]})
}
invalid_users = []

View File

@@ -561,6 +561,9 @@ class Config(dict):
# FTP 文件上传下载备份阈值,单位(M)当值小于等于0时不备份
'FTP_FILE_MAX_STORE': 100,
# API 请求次数限制
'MAX_LIMIT_PER_PAGE': 100
}
old_config_map = {

View File

@@ -3,4 +3,4 @@ from rest_framework.pagination import LimitOffsetPagination
class MaxLimitOffsetPagination(LimitOffsetPagination):
max_limit = settings.MAX_LIMIT_PER_PAGE or 100
max_limit = settings.MAX_LIMIT_PER_PAGE

View File

@@ -16,6 +16,8 @@ def allow_access(private_file):
path_base = path_list[1] if len(path_list) > 1 else None
path_perm = path_perms_map.get(path_base, None)
if ".." in request_path:
return False
if not path_perm:
return False
if path_perm == '*' or request.user.has_perms([path_perm]):

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-20 18:40+0800\n"
"POT-Creation-Date: 2023-07-26 19:26+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -646,7 +646,7 @@ msgstr "アカウントはすでに存在しています"
msgid "ID"
msgstr "ID"
#: accounts/serializers/account/account.py:427 acls/serializers/base.py:116
#: accounts/serializers/account/account.py:430 acls/serializers/base.py:116
#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49
#: audits/models.py:85 audits/models.py:163
#: authentication/models/connection_token.py:32
@@ -664,7 +664,7 @@ msgstr "ID"
msgid "User"
msgstr "ユーザー"
#: accounts/serializers/account/account.py:428
#: accounts/serializers/account/account.py:431
#: authentication/templates/authentication/_access_key_modal.html:33
#: terminal/notifications.py:158 terminal/notifications.py:207
msgid "Date"

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b88bc1c5216d7cfc2b0a72d889198bcab84ddd40dd3f5a13a5662dfcf8170ee
oid sha256:5a68f334539c7511584c11770699829dc709c7e1b453365964a3b3852d5edf92
size 121846

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-20 18:40+0800\n"
"POT-Creation-Date: 2023-07-26 19:26+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@@ -642,7 +642,7 @@ msgstr "账号已存在"
msgid "ID"
msgstr "ID"
#: accounts/serializers/account/account.py:427 acls/serializers/base.py:116
#: accounts/serializers/account/account.py:430 acls/serializers/base.py:116
#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49
#: audits/models.py:85 audits/models.py:163
#: authentication/models/connection_token.py:32
@@ -660,7 +660,7 @@ msgstr "ID"
msgid "User"
msgstr "用户"
#: accounts/serializers/account/account.py:428
#: accounts/serializers/account/account.py:431
#: authentication/templates/authentication/_access_key_modal.html:33
#: terminal/notifications.py:158 terminal/notifications.py:207
msgid "Date"
@@ -4798,7 +4798,7 @@ msgid ""
"Session, record, command will be delete if more than duration, only in "
"database, OSS will not be affected."
msgstr ""
"会话、录像,命令记录超过该时长将会被除(影响数据库存OSS 等不受影响)"
"会话、录像,命令记录超过该时长将会被除(影响数据库存OSS 等不受影响)"
#: settings/serializers/cleaning.py:36
msgid "Activity log keep days (day)"

View File

@@ -270,8 +270,13 @@ class JMSInventory:
name = host.pop('name')
name = name.replace('[', '_').replace(']', '_')
data['all']['hosts'][name] = host
if self.exclude_localhost and data['all']['hosts'].__contains__('localhost'):
data['all']['hosts'].update({'localhost': {'ansible_host': '255.255.255.255'}})
if not self.exclude_localhost:
data['all']['hosts'].update({
'localhost': {
'ansible_host': '127.0.0.1',
'ansible_connection': 'local'
}
})
return data
def write_to_file(self, path):

View File

@@ -43,8 +43,8 @@ def get_parent_keys(key, include_self=True):
class JMSPermedInventory(JMSInventory):
def __init__(self, assets, account_policy='privileged_first',
account_prefer='root,Administrator', host_callback=None, exclude_localhost=False, user=None):
super().__init__(assets, account_policy, account_prefer, host_callback, exclude_localhost)
account_prefer='root,Administrator', host_callback=None, user=None):
super().__init__(assets, account_policy, account_prefer, host_callback, exclude_localhost=True)
self.user = user
self.assets_accounts_mapper = self.get_assets_accounts_mapper()

View File

@@ -11,10 +11,15 @@ from ops.exception import PlaybookNoValidEntry
from orgs.mixins.models import JMSOrgBaseModel
dangerous_keywords = (
'hosts:localhost',
'hosts:127.0.0.1',
'hosts:::1',
'delegate_to:localhost',
'delegate_to:127.0.0.1',
'delegate_to:::1',
'local_action',
'connection:local',
'ansible_connection'
)
@@ -48,7 +53,14 @@ class Playbook(JMSOrgBaseModel):
with open(file, 'r') as f:
for line_num, line in enumerate(f):
for keyword in dangerous_keywords:
if keyword in line.replace(' ', ''):
clear_line = line.replace(' ', '')\
.replace('\n', '')\
.replace('\r', '')\
.replace('\t', '') \
.replace('\'', '') \
.replace('\"', '')\
.replace('\v', '')
if keyword in clear_line:
result.append((line_num, keyword))
return result

View File

@@ -135,7 +135,7 @@
method: "GET",
flash_message: false,
success(data) {
const dateStart = new Date(data.date_start).toLocaleString();
const dateStart = data.date_start ? new Date(data.date_start).toLocaleString() : '';
$('.task-id').html(data.id);
$('.task-type').html(data.task_name);
$('.date-start').html(dateStart);

View File

@@ -1,13 +1,15 @@
from rest_framework import permissions
from common.utils import get_logger
logger = get_logger(__file__)
__all__ = ['IsSessionAssignee']
class IsSessionAssignee(permissions.BasePermission):
class IsSessionAssignee(permissions.IsAuthenticated):
def has_permission(self, request, view):
return False
def has_object_permission(self, request, view, obj):
try:

View File

@@ -1,12 +1,12 @@
from rest_framework import permissions
class IsAssignee(permissions.BasePermission):
class IsAssignee(permissions.IsAuthenticated):
def has_object_permission(self, request, view, obj):
return obj.has_current_assignee(request.user)
class IsApplicant(permissions.BasePermission):
class IsApplicant(permissions.IsAuthenticated):
def has_object_permission(self, request, view, obj):
return obj.applicant == request.user

View File

@@ -1,6 +1,5 @@
from rest_framework import permissions
from rbac.builtin import BuiltinRole
from .utils import is_auth_password_time_valid
@@ -11,7 +10,7 @@ class IsAuthPasswdTimeValid(permissions.IsAuthenticated):
and is_auth_password_time_valid(request.session)
class UserObjectPermission(permissions.BasePermission):
class UserObjectPermission(permissions.IsAuthenticated):
def has_object_permission(self, request, view, obj):
if view.action not in ['update', 'partial_update', 'destroy']:

View File

@@ -1,6 +1,6 @@
aiofiles==22.1.0
amqp==5.0.9
git+https://github.com/jumpserver/ansible@master#egg=ansible-core
ansible-core@https://github.com/jumpserver/ansible/releases/download/v2.14.1.2/ansible-2.14.1.2.zip
ansible==7.1.0
ansible-runner==2.2.1
asn1crypto==0.24.0
@@ -35,7 +35,7 @@ itsdangerous==1.1.0
pyotp==2.6.0
PyNaCl==1.5.0
python-dateutil==2.8.2
PyYAML==6.0
PyYAML==6.0.1
requests==2.31.0
jms-storage==0.0.47
simplejson==3.17.6
@@ -118,7 +118,6 @@ kubernetes==21.7.0
# DB requirements
mysqlclient==2.1.0
PyMySQL==1.0.2
pymssql==2.2.5
django-mysql==3.9.0
django-redis==5.2.0
python-redis-lock==3.7.0

View File

@@ -18,9 +18,9 @@ huaweicloud-sdk-python==1.0.21
# huaweicloud-sdk-python need keystoneauth1<=3.4.0
keystoneauth1==3.4.0
# DB requirements
oracledb==1.0.1
# oracledb==1.3.2
psycopg2-binary==2.9.1
pymssql==2.2.5
pymssql==2.2.8
IPy==1.1
psycopg2==2.9.4
ucloud-sdk-python3==0.11.47