Compare commits

...

542 Commits
v3.2 ... v3.5

Author SHA1 Message Date
ibuler
d2a4e79b31 fix: pubkey auth require svc sign 2023-09-25 23:31:08 +08:00
ibuler
f65e2ac15f fix: 修复暴力校验验证码 2023-09-25 23:06:00 +08:00
Bai
96f69c821b fix: 修复系统用户同步同时包含pwd/ssh-key导致创建账号id冲突报错的问题 2023-09-25 16:24:19 +08:00
Bai
13fffa52dd fix: 解决节点资产数量方法计算不准确的问题 2023-09-22 15:19:12 +08:00
Aaron3S
fe37913ed9 perf: 优化 Playbook 文件创建逻辑 2023-09-19 18:48:43 +08:00
ibuler
4009457000 fix: 修复 random error 2023-09-19 18:19:13 +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
Bryan
e90e61e8dd Merge pull request #11035 from jumpserver/dev
v3.5.0
2023-07-20 19:03:31 +08:00
fit2bot
4c48204e16 perf: translate (#11036)
Co-authored-by: feng <1304903146@qq.com>
2023-07-20 18:46:34 +08:00
老广
bddcd8475d Merge pull request #11034 from jumpserver/pr@dev@chore_change_readme
perf: 修改 README, 添加 GPT
2023-07-20 18:11:10 +08:00
ibuler
5f8d84df66 perf: 修改图标 2023-07-20 18:10:28 +08:00
ibuler
cee87ae4d7 perf: 修改 README, 添加 GPT 2023-07-20 17:59:58 +08:00
老广
79a2d4e039 Merge pull request #11033 from jumpserver/pr@dev@fix_create_serializer_default
perf: 优化动态创建 serializer
2023-07-20 15:48:11 +08:00
ibuler
4f5e360991 perf: 优化动态创建 serializer 2023-07-20 15:44:52 +08:00
Eric
8e86173cb8 perf: 修复手动输入的同名账号问题 2023-07-20 15:38:51 +08:00
ibuler
08bc3d14aa fix: 修复 json m2m field 中正则有问题匹配不正确 2023-07-20 15:38:04 +08:00
fit2bot
19b91a6c1f perf: 修复资产导入账号模版失败问题 导入文件不区分大小写 (#11031)
Co-authored-by: feng <1304903146@qq.com>
2023-07-20 14:57:51 +08:00
Bai
c50330e055 fix: 修复删除Oracle数据库时报错提示问题 2023-07-20 11:56:49 +08:00
Bai
f5d9dedae1 fix: 修复 Endpoint 获取 Oracle port 的逻辑 2023-07-20 11:51:02 +08:00
Bai
ffb400d70d fix: 修复创建 Oracle 数据库端口超过范围后报错 500 并且不回滚的问题; 2023-07-20 11:23:57 +08:00
Bai
2291cfeaae fix: 修复 ConnectionToken 默认值类型没有转化的问题 2023-07-20 10:42:23 +08:00
老广
400d37ffca Merge pull request #11024 from jumpserver/pr@dev@fix_perm_accounts_only_one
fix: 修复授权的账号,用户名相同的,只有一个的情况
2023-07-19 21:24:45 +08:00
ibuler
14efd9afc1 perf: 修复可能导致的问题 2023-07-19 20:27:06 +08:00
ibuler
cfca519158 fix: 修复授权的账号,用户名相同的,只有一个的情况 2023-07-19 20:16:40 +08:00
Bai
23361fdba9 fix: 修复资产平台导入失败的问题(ID没有返回) 2023-07-19 19:56:18 +08:00
fit2bot
1b0d23fbf4 fix: playbook 批量删除 500 (#11022)
Co-authored-by: feng <1304903146@qq.com>
2023-07-19 19:37:55 +08:00
fit2bot
de4ef7d1b5 perf: GPT资产修改节点导致资产协议变多 (#11021)
Co-authored-by: feng <1304903146@qq.com>
2023-07-19 19:00:15 +08:00
ibuler
046342ceee perf: 平台创建自动化设置默认值 2023-07-19 18:23:18 +08:00
Bai
47195e2c44 fix: 修复客户端方式访问资产 Endpoint 标签匹配策略不生效的问题 2023-07-19 18:14:30 +08:00
老广
947c9e6216 Merge pull request #11018 from jumpserver/pr@dev@perf_coreworker
perf: 优化 Core Worker 数量
2023-07-19 17:17:07 +08:00
Bai
e1af380ad5 perf: 优化 Core Worker 数量 2023-07-19 17:12:44 +08:00
fit2bot
9e8579d5b4 perf: proxy 添加校验 修改翻译 (#11017)
Co-authored-by: feng <1304903146@qq.com>
2023-07-19 17:05:42 +08:00
老广
b8397e7db9 Merge pull request #11012 from jumpserver/pr@dev@perf_change_ui_route
perf: 优化 url
2023-07-19 11:37:51 +08:00
ibuler
8ed8d6f01c perf: 优化 url 2023-07-19 11:36:42 +08:00
Bai
ea607c6177 fix: 优化命令告警,不增加跳转链接 2023-07-19 08:27:34 +05:00
Bai
fa52e2bf5e perf: 优化批量命令告警问题 2023-07-19 08:09:45 +05:00
fangfang.dong
02fc9a730b feat: 快速命令新增告警级别: Warning 2023-07-19 08:09:45 +05:00
Bai
aa744c0fec fix: 修复账号模版切换时报错的问题 2023-07-19 07:34:55 +05:00
fit2bot
02d0c7e4e7 perf: ansible 错误信息优化 (#11005)
Co-authored-by: feng <1304903146@qq.com>
2023-07-18 18:55:18 +08:00
老广
0c34a41381 Merge pull request #11003 from jumpserver/pr@dev@fix_ansiblejobrunerror
fix: 修复批量执行命令时资产名称包含 [ 特殊字符执行报错的问题(issue: 10986)
2023-07-18 18:14:32 +08:00
Bai
8ed3da85f2 fix: 修复批量执行命令时资产名称包含 [ 特殊字符执行报错的问题(issue: 10986) 2023-07-18 10:06:40 +00:00
feng
de5b501ebf fix: 工单时区错乱问题 2023-07-18 16:56:22 +08:00
Bai
ea5a54f9c7 fix: 修复命令告警的问题 2023-07-18 15:21:40 +08:00
halo
6338ecc6fe perf: 优化邮件参数 2023-07-18 15:21:18 +08:00
Bai
be17fe6c31 perf: 邮件同步发送 2023-07-18 15:21:18 +08:00
halo
a18c97aec0 perf: 异步发送 2023-07-18 15:21:18 +08:00
halo
27c10fcae1 fix: 邮件主题前缀设置不生效的问题 2023-07-18 15:21:18 +08:00
fangfang.dong
539babcc97 fix: 修复参数取值错误 2023-07-18 15:17:34 +08:00
fit2bot
0436487bdb fix: 替换ssh key 生成密钥方法 (#10995)
Co-authored-by: feng <1304903146@qq.com>
2023-07-18 15:01:47 +08:00
Bai
f466904a1c perf: 优化 LDAP 用户导入/同步时支持 is_active 为 -1 的情况 2023-07-18 11:03:32 +08:00
老广
1d6bdc9b6b Merge pull request #10990 from jumpserver/pr@dev@perf_gunicorn_max_request
perf: gunicon添加重启参数
2023-07-18 11:02:58 +08:00
ibuler
d965ac0781 perf: 修改参数值 2023-07-18 11:00:43 +08:00
ibuler
6035241efb perf: gunicon添加重启参数 2023-07-18 10:44:12 +08:00
fit2bot
0771b804d1 refactor: 重构危险命令告警类型: Warning (#10970)
* refactor: 重构危险命令告警类型: Warning

* Update _msg_command_warning.html

* Update _msg_command_warning.html

* Update command.py

* Update django.po

* perf: 优化 command acl warning 的代码逻辑

* perf: 优化 command acl warning 的代码逻辑

* perf: 优化 CommandWarningMessage 逻辑

---------

Co-authored-by: fangfang.dong <fangfang.dong@fit2cloud.com>
Co-authored-by: Bai <baijiangjie@gmail.com>
2023-07-17 20:52:54 +08:00
老广
a2c6e5f3fb Merge pull request #10985 from jumpserver/pr@dev@feat_db_mariadb_web_db_support
feat: mariadb 支持 webdb
2023-07-17 18:02:42 +08:00
Aaron3S
c39041fe7b feat: mariadb 支持 webdb 2023-07-17 17:55:05 +08:00
ibuler
22588c52a9 fix: 修复 json field value 可能为 None 导致的问题 2023-07-17 17:25:44 +08:00
ibuler
daef154622 perf: 优化 host api 和 gunicorn 参数 2023-07-17 17:16:18 +08:00
Bai
7b9c4b300d perf: 优化控制 ACL Action Choices 的选项 2023-07-17 16:02:27 +08:00
Bai
819853eae4 feat: 增加 DEBUG_ANSIBLE 配置项支持打印 Ansible 详细日志 2023-07-17 14:11:09 +08:00
老广
f686f9f107 Merge pull request #10978 from jumpserver/pr@dev@fix_platform_setting
perf: 优化平台创建时,协议 setting 必填
2023-07-17 14:02:24 +08:00
ibuler
8a89ee7ac0 perf: 优化平台创建时,协议 setting 必填 2023-07-17 13:53:27 +08:00
老广
696295cf0d Merge pull request #10973 from jumpserver/pr@dev@fix_reset_password_bug
fix: 忘记密码token失效发送验证码报错的问题
2023-07-17 10:54:21 +08:00
老广
d99a3455cd Merge pull request #10966 from jumpserver/pr@dev@perf_chrome_plugins
perf: 优化 chrome 插件
2023-07-17 10:48:22 +08:00
老广
7f5b0618c6 Merge pull request #10969 from jumpserver/pr@dev@fix_ansibletesterror
fix: 修复 Ansible 测试资产可连接性报错的问题(Connection to UNKNOWN port 65535 timed out)
2023-07-17 10:27:48 +08:00
halo
0f1d9bc3eb fix: 忘记密码token失效发送验证码报错的问题 2023-07-15 16:30:45 +08:00
fit2bot
8f6b8b5a11 perf: settings logo (#10971)
Co-authored-by: feng <1304903146@qq.com>
2023-07-14 23:01:48 +08:00
Bai
4da0fadcc4 fix: 修复 Ansible 测试资产可连接性报错的问题(Connection to UNKNOWN port 65535 timed out) 2023-07-14 11:19:31 +00:00
fit2bot
f504413d7f feat: 添加logo api (#10965)
Co-authored-by: feng <1304903146@qq.com>
2023-07-14 16:54:42 +08:00
ibuler
9b5803f2a2 perf: 修改版本号 2023-07-13 20:02:28 +08:00
ibuler
d95e7c2e24 perf: 优化 chrome 插件 2023-07-13 20:01:06 +08:00
ibuler
a1ded0c737 perf: 优化一些 rbac 权限位,着重 connection token 的 2023-07-13 19:57:26 +08:00
老广
bedc83bd3a Merge pull request #10961 from jumpserver/pr@dev@perf_readme
perf: 修改 readme
2023-07-13 14:34:15 +08:00
ibuler
c9f3e4b28d perf: 修改 readme 2023-07-13 14:29:47 +08:00
老广
05bbd22c44 Merge pull request #10959 from jumpserver/pr@dev@perf_add_url
perf: 修改 log 的位置
2023-07-13 14:13:24 +08:00
老广
d00ef2b051 Merge pull request #10960 from maninhill/patch-10
chore: 更新 README
2023-07-13 12:51:19 +08:00
maninhill
efc538a569 chore: 更新 README 2023-07-13 11:55:12 +08:00
ibuler
c1de9151b8 perf: 修改地址 2023-07-13 11:46:47 +08:00
ibuler
2898d25bf8 perf: 修改 log 的位置 2023-07-13 11:45:15 +08:00
jiangweidong
68e2de81d8 perf: windows winrm使用ntlm认证 2023-07-12 20:22:44 +08:00
fit2bot
dd5802316d perf: 修改 connect methods 支持 (#10945)
Co-authored-by: ibuler <ibuler@qq.com>
2023-07-11 19:29:56 +08:00
老广
6f1ab1e09a Merge pull request #10944 from jumpserver/pr@dev@perf_add_protocol_support
perf: 修改 protocols 默认值
2023-07-11 18:00:23 +08:00
ibuler
6096ccc30a perf: 修改 protocols 默认值 2023-07-11 17:59:18 +08:00
老广
ddbd142ea3 Merge pull request #10943 from jumpserver/pr@dev@perf_connect_method
perf: 修改组件支持
2023-07-11 17:29:05 +08:00
ibuler
61d8328337 perf: 修改 protocol 定义 2023-07-11 17:27:47 +08:00
ibuler
4caa704abe perf: 修改组件支持 2023-07-11 17:04:43 +08:00
fit2bot
b75d69de5d feat: 新增危险命令告警类型: Warning (#10929)
* feat: 新增危险命令告警类型: Warning

* feat: 新增危险命令告警类型: Warning

* feat: 新增危险命令告警类型: Warning

* feat: 新增危险命令告警类型: Warning

* feat: 新增危险命令告警类型: Warning

* perf: 优化命令告警 View 处理逻辑

---------

Co-authored-by: fangfang.dong <fangfang.dong@fit2cloud.com>
Co-authored-by: Bai <baijiangjie@gmail.com>
2023-07-11 12:06:11 +08:00
fangfang.dong
10fa122e2f perf: 清理无用代码 2023-07-11 11:59:02 +08:00
老广
00ff1644cb Merge pull request #10941 from jumpserver/pr@dev@add_help_text
perf: 修改 api mode 和 i18n
2023-07-11 11:47:06 +08:00
ibuler
2b51a7590e perf: 修改 api mode 和 i18n 2023-07-11 11:28:09 +08:00
老广
30d07820c7 Merge pull request #10914 from jumpserver/dependabot/pip/requirements/django-3.2.20
build(deps): bump django from 3.2.19 to 3.2.20 in /requirements
2023-07-11 10:55:54 +08:00
老广
c51ebd62df Merge pull request #10936 from jumpserver/pr@dev@fix_beat-task-repeated
fix: 修复 beat 定时任务重复执行的问题
2023-07-11 10:47:41 +08:00
老广
593e28d7fa Merge pull request #10938 from jumpserver/pr@dev@perf_add_kael
perf: 添加 kael terminal 类型
2023-07-11 10:38:32 +08:00
ibuler
89f1a1653d perf: 添加 kael terminal 类型 2023-07-11 10:31:36 +08:00
Bai
ad311c15ca fix: 增加 TypeError 捕获 2023-07-11 10:19:31 +08:00
老广
b10623c970 Merge pull request #10879 from jumpserver/pr@dev@feat_chatgpt_support
feat: 支持 chatgpt 资产
2023-07-11 09:59:04 +08:00
Bai
7d17c1a450 fix: 修复 beat 定时任务重复执行的问题 2023-07-10 19:28:19 +08:00
老广
100b1553b6 Merge pull request #10931 from jumpserver/pr@dev@perf_change_platform
perf: 修改 Platform 约束
2023-07-07 19:48:15 +08:00
ibuler
76af71bbbe perf: 修改 Platform 约束 2023-07-07 19:47:12 +08:00
fit2bot
9607ab5164 perf: 修改支持 AD (#10926)
* stash

* perf: 修改支持 AD

* perf: 优化 default

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-07-07 16:15:32 +08:00
Eric
61078ee2ed perf: 更新 Chrome 的 ChangeLog 路径 2023-07-06 19:41:11 +08:00
Eric
6a720cde0a perf: 更新 chrome 支持匿名账号 2023-07-06 19:41:11 +08:00
老广
a2a5d5e08b Merge pull request #10925 from jumpserver/pr@dev@wechat
perf: 去除readme 中的微信
2023-07-06 18:27:03 +08:00
feng
9c2cc65ce8 perf: 去除readme 中的微信 2023-07-06 18:26:05 +08:00
feng
ee3cdcd9e4 fix: 有默认值 required 为false 2023-07-06 10:33:36 +08:00
feng
89492410aa fix: 推送账号 不填写home 推送失败 2023-07-06 10:33:36 +08:00
dependabot[bot]
b324c6cc8a build(deps): bump django from 3.2.19 to 3.2.20 in /requirements
Bumps [django](https://github.com/django/django) from 3.2.19 to 3.2.20.
- [Commits](https://github.com/django/django/compare/3.2.19...3.2.20)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 23:26:55 +00:00
Bai
6b189e6162 fix: 修复导入LDAP数据库超时导致 Lock wait timeout 的问题 2023-07-05 18:49:01 +08:00
吴小白
a07cab9ae7 Merge pull request #10910 from jumpserver/pr@dev@perf_chrome
perf: 修正 Chrome driver 路径
2023-07-05 18:38:18 +08:00
Eric
751bd35349 perf: 修正 Chrome driver 路径 2023-07-05 18:28:31 +08:00
Bai
d6aaf23abb fix: 修复用户导入时手机号为dict类型报错的问题 2023-07-05 16:49:52 +08:00
Eric
f096014d03 perf: 移除针对端点 host 的校验 2023-07-05 15:39:54 +08:00
Eric
7f03639c34 perf: 更新翻译 2023-07-04 19:14:53 +08:00
Eric
3963881226 perf: 日文翻译更正 2023-07-04 19:14:53 +08:00
Eric
fb279dbc39 perf: 新增 SFTP 会话类型 2023-07-04 19:14:53 +08:00
fangfang.dong
785e4cc3e4 perf: 接口sql优化 /api/v1/perms/asset-permissions/<uuid:pk>/assets/all/ 2023-07-04 19:14:21 +08:00
jiangweidong
dd846d4183 feat: 云同步支持公有云 2023-07-04 18:48:07 +08:00
Eric_Lee
9169f3546a Revert "perf: rdp7 可使用 web gui方式连接" 2023-07-04 18:09:33 +08:00
Eric_Lee
7e2c0d0a2d Merge pull request #10896 from jumpserver/revert-10880-pr@dev@perf_xrdp_rdp7
Revert "perf: add xrdp rdp7 port 3390"
2023-07-04 17:57:33 +08:00
老广
66c60ef5be Revert "perf: add xrdp rdp7 port 3390" 2023-07-04 17:35:58 +08:00
fit2bot
f095998096 perf: 改密与推送保持一致 (#10812)
* perf: 改密与推送保持一致

* perf: 增加 i18n

---------

Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: Bai <baijiangjie@gmail.com>
2023-07-04 17:34:31 +08:00
老广
d06e5d0001 Merge pull request #10826 from jumpserver/pr@dev@perf_account_template
perf: 接口sql优化 /api/v1/accounts/account-templates/su-from-account-templates/
2023-07-04 13:42:04 +08:00
老广
c8f420f62d Merge pull request #10893 from jumpserver/pr@dev@perf_rdp7_web
perf: rdp7 可使用 web gui方式连接
2023-07-04 13:39:28 +08:00
Eric
02550b38f8 perf: rdp7 可使用 web gui方式连接 2023-07-04 12:52:36 +08:00
老广
50531d3b97 Merge pull request #10829 from jumpserver/pr@dev@perf_support_anonymous_account
perf: web 和 自定义类型资产支持匿名账号
2023-07-04 11:46:24 +08:00
ibuler
db7ad81103 merge: 合并 dev 2023-07-04 11:45:20 +08:00
ibuler
d72ec653f4 merge: 合并 dev 2023-07-04 11:43:33 +08:00
老广
7950718582 Merge pull request #10825 from jumpserver/pr@dev@perf_asset_node
perf: 接口sql优化 /api/v1/assets/nodes/children/tree/
2023-07-04 11:28:45 +08:00
老广
998321f090 Merge pull request #10882 from jumpserver/pr@dev@perf_dockerfile
feat: 合并 Dockerfile
2023-07-04 11:26:23 +08:00
老广
1fa258da3e Merge pull request #10889 from jumpserver/pr@dev@perf_connectiontoken
perf: 修复 ConnectionToken 中 account id 的问题
2023-07-04 11:18:25 +08:00
ibuler
8dbe61100b perf: 优化协议,支持 port from addr 2023-07-04 10:29:27 +08:00
Eric
d7f9f3b670 perf: 修复 ConnectionToken 中 account id 的问题 2023-07-03 19:19:25 +08:00
老广
8b18f46613 Merge pull request #10880 from jumpserver/pr@dev@perf_xrdp_rdp7
perf: add xrdp rdp7 port 3390
2023-07-03 16:29:06 +08:00
吴小白
eb49beaf46 fix: 修正 oracle 路径 2023-07-03 10:37:42 +08:00
吴小白
3971fce561 feat: 合并 Dockerfile 2023-07-03 10:28:25 +08:00
Eric
2f81196874 perf: 更新 rdp7 protocol 设置 2023-07-03 10:22:49 +08:00
Eric
411102ed85 perf: 完善 protocol 匹配 2023-07-03 10:14:39 +08:00
Eric
125dc2adf5 perf: 针对 rdp7 端口特殊处理 2023-07-03 10:14:39 +08:00
Eric
6001175629 perf: add xrdp rdp7 port 3390 2023-07-03 10:14:39 +08:00
ibuler
41e39c9614 perf: 修改 chatgpt 协议 2023-06-30 18:33:18 +08:00
ibuler
19de79fadf feat: 支持 chatgpt 资产 2023-06-30 17:35:49 +08:00
老广
6b7df10d50 Merge pull request #10877 from jumpserver/pr@dev@perf_applet_chrome
perf: 更新 Python
2023-06-30 16:01:18 +08:00
吴小白
ce269e315a perf: 更新 Python 2023-06-30 15:58:20 +08:00
老广
dfc8654d96 Merge pull request #10876 from jumpserver/pr@dev@perf_applet_chrome
perf: 更新 Chrome
2023-06-30 15:58:18 +08:00
吴小白
ea07f9e56a perf: 更新 Chrome 2023-06-30 15:55:32 +08:00
fit2bot
bbbd011cc2 perf: 修改 protocol setting (#10875)
* feat: 新增账号配置

* perf: 修改 platform protocol define

* perf: 修改 account config

* perf: 修改协议设置

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-06-30 15:54:06 +08:00
老广
6962430e6a Merge pull request #10874 from jumpserver/pr@dev@perf_accountsearch
perf: 账号搜索支持通过 secret_type 过滤
2023-06-30 15:22:14 +08:00
Bai
ca1b82330e perf: 账号搜索支持通过 secret_type 过滤 2023-06-30 11:12:23 +08:00
fit2bot
f4bd06b970 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(12) (#10870)
Co-authored-by: Bai <baijiangjie@gmail.com>
Co-authored-by: Bryan <jiangjie.bai@fit2cloud.com>
2023-06-29 17:15:19 +08:00
Bai
d0bf5b46f6 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(11) 2023-06-29 17:12:21 +08:00
Bai
3c707996e0 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(10) 2023-06-29 17:05:38 +08:00
Bai
ac0a673818 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(9) 2023-06-29 17:00:36 +08:00
Bai
1ed6c7e01d feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(8) 2023-06-29 16:54:28 +08:00
Bai
adcabf69ed feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(7) 2023-06-29 16:43:00 +08:00
Bai
0b92e43e20 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(6) 2023-06-29 16:43:00 +08:00
Bai
9c1a6b8565 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(5) 2023-06-29 16:07:04 +08:00
Bai
fc8d226005 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(4) 2023-06-29 15:42:14 +08:00
Bai
f3955a47f6 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(3) 2023-06-29 15:25:08 +08:00
Bai
0020fe7be0 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(2) 2023-06-29 15:18:54 +08:00
Bai
cea56a2f7e feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签(1) 2023-06-29 14:50:27 +08:00
Bai
e3cf6cc476 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签 2023-06-29 14:28:38 +08:00
Bai
57fccc9baf feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签 2023-06-29 14:18:23 +08:00
Aaron3S
fbcb0da349 feat: 支持sqlserver 通过chen 链接 2023-06-29 11:41:06 +08:00
Bai
877a053717 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签 2023-06-29 11:40:43 +08:00
Bai
d293a03649 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签 2023-06-29 11:30:04 +08:00
Bai
08e0c5fdf5 feat: 优化 Issue GitHub Actions,当研发团队成员评论后再移除 待处理 标签 2023-06-29 11:17:37 +08:00
nut
ac906a5d52 Update api.py 2023-06-28 17:52:23 +08:00
fangfang.dong
9ad8e53743 perf: 接口sql优化 /api/v1/index/ 2023-06-28 17:52:23 +08:00
ibuler
a67ee976b4 perf: 修改翻译 2023-06-27 16:03:19 +08:00
ibuler
dfa12239d6 perf: 修改翻译 2023-06-27 16:00:45 +08:00
ibuler
4737e2cf4a perf: 优化 匿名账号 2023-06-27 15:22:18 +08:00
ibuler
d3d8fcbbb3 perf: 修改经常遇到的登录超时 2023-06-27 14:50:04 +08:00
Eric
a64aa89b3f fix: 修复自定义远程应用的连接问题 2023-06-27 14:43:00 +08:00
ibuler
a22f36a06a perf: 去掉 debug 2023-06-27 14:31:20 +08:00
Bryan
17fa139bc9 feat: Update ----.md 2023-06-27 14:24:27 +08:00
ibuler
77bcb05d80 perf: web 和 自定义类型资产支持匿名账号 2023-06-27 11:23:56 +08:00
fangfang.dong
4e9012cc07 perf: 接口sql优化 /api/v1/accounts/account-templates/su-from-account-templates/ 2023-06-27 10:45:50 +08:00
fangfang.dong
b3dce27309 perf: 接口sql优化 /api/v1/assets/nodes/children/tree/ 2023-06-27 10:24:47 +08:00
老广
bccf3a0340 Merge pull request #10819 from jumpserver/pr@dev@perf_asset_asset
perf: 接口sql优化 /api/v1/assets/assets/
2023-06-27 09:55:11 +08:00
nut
358b3a1891 Update asset.py 2023-06-26 23:51:59 +08:00
feng
5a2f6bdfc9 perf: ldap sync任务开始时 先检查可连接性 2023-06-25 18:25:15 +08:00
feng
768eb033eb fix: 修复自动化任务原子性error 导致整个任务失败问题 2023-06-25 18:20:49 +08:00
fangfang.dong
d7d554daf5 perf: 接口sql优化 /api/v1/assets/assets/ 2023-06-25 18:08:59 +08:00
jiangweidong
780b1104de perf: 优化飞书接收到的工单审批的连接无法点击的问题 2023-06-25 11:08:14 +08:00
老广
eeba0a4bfc Merge pull request #10806 from jumpserver/pr@dev@feat_terminal_endpointrule
feat: 系统设置 - 终端设置 - 端点规则: 新增字段is_active控制是否启用
2023-06-21 18:36:37 +08:00
fangfang.dong
b2ee8c8216 feat: 系统设置 - 终端设置 - 端点规则: 新增字段is_active控制是否启用 2023-06-21 18:33:58 +08:00
ibuler
26edd2f040 perf: 修改去掉一些 debug 2023-06-21 17:49:16 +08:00
ibuler
270ed5e2f8 perf: 修改 logging 避免冲突 2023-06-21 17:49:16 +08:00
Eric
b2bff22387 fix: 修复远程应用会话无法监控的问题 2023-06-21 14:48:18 +08:00
ibuler
1ca71f78ed perf: 优化一下,去掉 rbac 引起的 sql查询 2023-06-21 14:46:59 +08:00
ibuler
fa24a8e2f3 perf: 添加 sql debug 2023-06-21 12:02:56 +08:00
Bai
b9c1a89f51 fix: 修复迁移文件时触发信号记录操作日志导致迁移失败的问题 2023-06-21 11:02:42 +08:00
ibuler
a2bbf11f9d perf: 添加 migrate debug msg 2023-06-21 11:01:21 +08:00
ibuler
1d084311c5 perf: 统一 connect token 配置名称 2023-06-20 16:40:21 +08:00
ibuler
cb0fd937c8 perf: 资产连接可以指定 AppletHost 2023-06-20 16:37:54 +08:00
ibuler
13fc2aa73c perf: 优化rbac 迁移 2023-06-20 16:35:01 +08:00
Eric
5d9979ec03 perf: 修复 terminal 显示问题 2023-06-20 16:34:03 +08:00
Eric
e4f21b8a5f perf: 移除 omnidb 2023-06-19 18:31:59 +08:00
feng
9403b76333 fix: 修改 push_account_params 数据迁移逻辑,不在导入公共方法生成数据 2023-06-19 18:23:57 +08:00
fit2bot
666df6ffef perf: 接口 /api/v1/tickets/tickets/ sql优化 (#10762)
* perf: 接口 /api/v1/tickets/tickets/ sql优化

* Update general.py

* Update general.py

* Update general.py

---------

Co-authored-by: fangfang.dong <fangfang.dong@fit2cloud.com>
Co-authored-by: nut <evicwork@gmail.com>
2023-06-19 18:19:52 +08:00
Chenyang Shen
9cc3942b3d Merge pull request #10779 from jumpserver/pr@dev@perf_terminal_chen
perf: 新增 chen 终端类型
2023-06-19 18:18:12 +08:00
Eric
42852c368c perf: 新增 chen 终端类型 2023-06-19 18:06:23 +08:00
ibuler
4d4644dddd fix: 修改原来 platform 为 device 时,导致的 asset 类型不对 2023-06-19 17:54:42 +08:00
cui fliter
471411a1aa fix some typos
Signed-off-by: cui fliter <imcusg@gmail.com>
2023-06-19 15:19:41 +08:00
老广
db12bc07e8 Merge pull request #10760 from jumpserver/pr@dev@perf_assets_domain
perf: 接口 /api/v1/assets/domains/ sql优化
2023-06-19 10:25:20 +08:00
老广
618ee0b2f9 Merge pull request #10761 from jumpserver/pr@dev@perf_assets_label
perf: 接口 /api/v1/assets/label/ sql优化
2023-06-19 10:24:52 +08:00
fangfang.dong
39ba52e4de perf: 接口 /api/v1/assets/label/ sql优化 2023-06-18 20:26:19 +08:00
fangfang.dong
a8ef405939 perf: 接口 /api/v1/assets/domains/ sql优化 2023-06-18 20:24:14 +08:00
老广
09f7ddd28a Merge pull request #10756 from jumpserver/pr@dev@fix_custom_asset_detail_error
perf: 修复自定义资产详情没有 auto_config 的问题
2023-06-16 18:48:24 +08:00
ibuler
da4337168f perf: 修复自定义资产详情没有 auto_config 的问题 2023-06-16 18:44:13 +08:00
老广
f13966e061 Merge pull request #10754 from jumpserver/pr@dev@fix_permed_asset_duplicate
fix: 修复授权资产根据协议搜索重复的问题
2023-06-16 16:53:43 +08:00
ibuler
f4b5a302a1 fix: 修复授权资产根据协议搜索重复的问题 2023-06-16 16:44:05 +08:00
老广
dd955530f1 Merge pull request #10746 from jumpserver/pr@dev@perf_category_api_sql
perf: 修改 category 引起的 sql 查询过多
2023-06-16 15:55:27 +08:00
ibuler
50b64f6cf5 perf: 修改 category 引起的 sql 查询过多
pref: stash

perf: 添加装饰器

perf: 优化 category api
2023-06-16 15:53:48 +08:00
老广
a5b21f94c2 Merge pull request #10752 from jumpserver/pr@dev@perf_custom_field_required
perf: 优化自定义 platform field
2023-06-16 15:16:58 +08:00
ibuler
9e3e183f95 perf: 优化自定义 platform field 2023-06-16 15:07:17 +08:00
ibuler
9ec3147b5f perf: 修改 login acls 迁移冲突问题
perf: 修改 login acls 迁移,避免冲突
2023-06-16 13:59:15 +08:00
老广
79fa134621 Merge pull request #10742 from jumpserver/pr@dev@windows_rdp_ping
feat: 添加自动化任务rdp ping
2023-06-15 18:34:45 +08:00
feng
ef4132d2c5 feat: 添加自动化任务rdp ping 2023-06-15 18:33:05 +08:00
老广
b31a08ed8d Merge pull request #10741 from jumpserver/pr@dev@fix_acl_migrate_not_work
perf: 修复 acl 迁移后无法使用
2023-06-15 18:32:34 +08:00
ibuler
cdd47f4bc6 perf: 修复 acl 迁移后无法使用 2023-06-15 18:13:51 +08:00
ibuler
269a5e9d52 perf: 龙芯使用 buster 镜像 2023-06-15 17:39:21 +08:00
老广
dd0d1d3592 Merge pull request #10735 from jumpserver/pr@dev@change_docker_base_image
perf: 修改基础镜像
2023-06-15 16:59:58 +08:00
ibuler
c06368d812 perf: 修改基础镜像 2023-06-15 16:53:28 +08:00
fit2bot
96ef56da67 perf: 修改翻译 (#10733)
Co-authored-by: feng <1304903146@qq.com>
2023-06-15 15:41:07 +08:00
Jiangjie.Bai
0a1b379dcd Merge pull request #10731 from jumpserver/dev
v3.4.0
2023-06-15 14:16:39 +08:00
老广
54926f7c70 Merge pull request #10729 from jumpserver/pr@dev@perf_custom_asset_support_required_field
perf: 自定义 field 支持 required
2023-06-15 13:18:06 +08:00
ibuler
a48d0046a9 perf: 自定义 field 支持 required 2023-06-15 13:14:02 +08:00
fit2bot
852435c7d5 perf: user 序列化添加is_org_admin 字段 (#10728)
Co-authored-by: feng <1304903146@qq.com>
2023-06-15 12:15:04 +08:00
老广
b19d9c8754 Merge pull request #10727 from jumpserver/pr@dev@perf_acl_ordering
perf: 优化 acl 默认排序
2023-06-15 10:49:07 +08:00
ibuler
e92c82568d perf: 优化 acl 默认排序 2023-06-15 10:45:07 +08:00
老广
c6e19a2989 Merge pull request #10726 from jumpserver/pr@dev@perf_json_field_re_error
perf: 优化 json field re 报错问题
2023-06-15 10:32:12 +08:00
ibuler
58edf02179 perf: 优化 json field re 报错问题 2023-06-15 10:27:52 +08:00
老广
3e9bafadec Merge pull request #10725 from jumpserver/pr@dev@perf_json_attr_m2m_filter
perf: 优化修改 rule vlaue
2023-06-15 10:17:36 +08:00
ibuler
70af478f66 perf: 优化修改 rule vlaue 2023-06-15 10:16:18 +08:00
ibuler
d7121296f2 perf: 优化使用 bool 2023-06-15 10:14:59 +08:00
老广
a76b243226 Merge pull request #10724 from jumpserver/pr@dev@fix_image
fix: 修正基础镜像名称
2023-06-15 10:14:03 +08:00
吴小白
5bd276b9ce fix: 修正基础镜像名称 2023-06-15 10:02:08 +08:00
老广
abd4e87bc2 Merge pull request #10723 from jumpserver/pr@dev@perf_json_attr_m2m_filter
perf: 优化 json m2m filter
2023-06-15 09:40:39 +08:00
ibuler
40d8a71bf8 perf: 优化 json m2m filter 2023-06-15 09:37:00 +08:00
老广
aad804f1af Merge pull request #10722 from jumpserver/pr@dev@perf_json_filter_m2m
perf: 优化 json m2m filter
2023-06-14 21:11:41 +08:00
ibuler
ee15f2d3d7 perf: 优化 json m2m filter 2023-06-14 21:10:35 +08:00
fit2bot
7c31b4ee30 perf: 修改翻译 (#10721)
Co-authored-by: feng <1304903146@qq.com>
2023-06-14 20:42:29 +08:00
ibuler
25e7249957 perf: 优化正则匹配 2023-06-14 20:41:14 +08:00
Aaron3S
d10db0aa62 fix: 修复任务被黑名单拦截后没有更新状态的问题 2023-06-14 20:40:40 +08:00
老广
d87ece00bd Merge pull request #10718 from jumpserver/pr@dev@perf_phone
perf: 优化 phone
2023-06-14 20:23:59 +08:00
ibuler
fca3936a79 perf: 优化 phone 2023-06-14 20:22:41 +08:00
Aaron3S
2c2334b618 perf: 优化报错内容 2023-06-14 20:16:42 +08:00
Aaron3S
9e31a5064b perf: 优化黑名单命令提示 2023-06-14 20:16:42 +08:00
Bai
954f86f8a9 fix: 修复执行任务中心报错的问题 2023-06-14 19:57:55 +08:00
老广
a3d32c901d Merge pull request #10715 from jumpserver/pr@dev@perf_filter_q_name
perf: 优化 filter name
2023-06-14 19:12:54 +08:00
ibuler
ce5ddf7873 perf: 优化 filter name 2023-06-14 19:10:34 +08:00
老广
29ebdb03e7 Merge pull request #10711 from jumpserver/pr@dev@perf_json_field_select
perf: 优化查询 acls
2023-06-14 18:19:42 +08:00
ibuler
53c3c90e2d perf: 优化查询 acls 2023-06-14 18:17:20 +08:00
nut
4bcd47df64 Update mixins.py 2023-06-14 17:10:38 +08:00
nut
d51323faef Update mixins.py 2023-06-14 17:10:38 +08:00
fangfang.dong
e8163167c5 修复: 控制台 - 账号 - 账号列表 - 查看账号详情时的500错误 2023-06-14 17:10:38 +08:00
Eric
e762a5d8ae perf: 更新发布机的单用户单会话策略 2023-06-14 16:49:37 +08:00
老广
dd85e2d74f Merge pull request #10707 from jumpserver/pr@dev@perf_connect_methods
perf: 优化连接方式
2023-06-14 15:14:45 +08:00
ibuler
96a66e555f perf: 优化连接方式 2023-06-14 14:48:50 +08:00
fit2bot
120f0dd3ad perf: asset web autofill 添加LabeledChoiceField (#10706)
Co-authored-by: feng <1304903146@qq.com>
2023-06-14 14:42:53 +08:00
Bai
de43df8370 perf: 修改 LDAP 用户导入任务名称 2023-06-14 11:07:38 +08:00
ibuler
459176550d perf: 修改 applet 是否支持并发,也依赖于 host 2023-06-13 19:44:59 +08:00
Eric
4112ad21c3 perf: 增加 terminal 显示字段 2023-06-13 19:44:39 +08:00
Eric
df8baede43 perf: 修复部分录像播放问题 2023-06-13 19:44:39 +08:00
fit2bot
5bd4a882cc fix: 平台导入无协议port (#10702)
Co-authored-by: feng <1304903146@qq.com>
2023-06-13 17:57:48 +08:00
老广
370d944396 Merge pull request #10698 from jumpserver/pr@dev@perf_applethost_options
perf: 修正发布机部署单用户单会话选项
2023-06-13 15:56:01 +08:00
fit2bot
c056cde2b7 perf: 修改翻译 (#10697)
Co-authored-by: feng <1304903146@qq.com>
2023-06-13 15:51:52 +08:00
Eric
93c0f11a5f perf: 修正发布机部署单用户单会话选项 2023-06-13 15:50:21 +08:00
老广
91ea738dcd Merge pull request #10695 from jumpserver/pr@dev@perf_acl_account_migrate
perf: 优化 acl 迁移中的 accounts
2023-06-13 14:41:02 +08:00
ibuler
0d3478c728 perf: 优化 acl 迁移中的 accounts 2023-06-13 14:38:52 +08:00
老广
c271d3276a Merge pull request #10693 from O-Jiangweidong/pr@dev@perf_ftp_log_field_same_as_session
perf: 字段含义和Session model保持一致
2023-06-13 13:59:59 +08:00
jiangweidong
dfd1ececdb perf: 删除翻译信息 2023-06-13 13:58:27 +08:00
jiangweidong
4683ae8c09 perf: 修改迁移文件中的字段信息 2023-06-13 13:54:59 +08:00
老广
db3fca0409 Merge pull request #10694 from jumpserver/pr@dev@perf_acls_filter
perf: 优化 json m2m field 正向查询
2023-06-13 13:50:31 +08:00
老广
9f4cb2e790 Merge pull request #10691 from O-Jiangweidong/pr@dev@fix_upgrade_34_error
fix: 解决migrate文件中迁移数据会触发信号导致字段不对应错误引发迁移失败问题
2023-06-13 13:49:31 +08:00
ibuler
7e9d1fc945 perf: 优化 json m2m field 正向查询 2023-06-13 13:48:32 +08:00
jiangweidong
af018ea262 perf: 字段含义和Session model保持一致 2023-06-13 13:18:50 +08:00
jiangweidong
71ccfe66ec fix: 解决migrate文件中迁移数据会触发信号导致字段不对应错误引发迁移失败问题 2023-06-13 13:14:38 +08:00
jiangweidong
a991a6c56c perf: 优化变量名 2023-06-13 11:36:32 +08:00
jiangweidong
9a29cda210 fix: 提供给luna的录像地址不能为本地local地址,应该为url 2023-06-13 11:36:32 +08:00
老广
aee20a6c05 Merge pull request #10686 from jumpserver/pr@dev@perf_applet_import
perf: 优化 applet 导入
2023-06-13 10:04:02 +08:00
老广
499c52800e Merge pull request #10689 from jumpserver/pr@dev@perf_ticket_request_login
perf: 优化登录 ticket 创建
2023-06-13 10:03:36 +08:00
ibuler
4a2f7d21f6 perf: 优化登录 ticket 创建 2023-06-13 09:54:03 +08:00
ibuler
44d92b9dec perf: 修改 acl user review 2023-06-12 19:12:11 +08:00
ibuler
1e9310bf0c perf: 优化 applet 导入 2023-06-12 19:00:59 +08:00
老广
1b750cf51d Merge pull request #10682 from jumpserver/pr@dev@allow_chrome_some_shortcut
perf: 放行快捷键 ctrl-c-v
2023-06-12 18:36:16 +08:00
ibuler
e9125d1228 perf: 修改 chrome error 2023-06-12 18:35:27 +08:00
老广
c85df4cf42 Merge pull request #10685 from jumpserver/pr@dev@fix_command_filter_acls_error
perf: 优化命令过滤 acl 获取
2023-06-12 18:28:52 +08:00
ibuler
09a5b63240 perf: 修改 acl filter 2023-06-12 18:28:04 +08:00
ibuler
f9bc7ec4aa perf: 优化命令过滤 acl 获取 2023-06-12 18:20:30 +08:00
fit2bot
d59a293bb9 perf: 修改用户组添加全部用户api的权限位 (#10683)
Co-authored-by: feng <1304903146@qq.com>
2023-06-12 18:16:09 +08:00
ibuler
cb2b8bb70b perf: 放行快捷键 ctrl-c-v 2023-06-12 16:37:12 +08:00
老广
86c81c42de Merge pull request #10681 from jumpserver/pr@dev@perf_global_acl
perf: 优化 manager 和 acl 的 组织
2023-06-12 16:02:45 +08:00
ibuler
5c2b54ad3b perf: 优化 manager 和 acl 的 组织 2023-06-12 16:00:14 +08:00
Eric
b79aaff4a0 perf: 资产根据 ssh 协议过滤是否启用 sftp 2023-06-12 15:42:24 +08:00
jiangweidong
3fd8e5755d fix: 修改变量 2023-06-12 15:41:25 +08:00
jiangweidong
3604ef4228 fix: 解决录像无法在线观看的问题 2023-06-12 15:41:25 +08:00
Bai
24272d3162 fix: 修复 Token API 获取命令过滤器失败的问题 2023-06-12 14:11:44 +08:00
ibuler
a99d22708c perf: 修改 migrations 2023-06-12 14:10:37 +08:00
ibuler
dc35a8c52b perf: 优化 acl 默认排序和manager 2023-06-12 14:10:37 +08:00
老广
fc90ced2b0 Merge pull request #10675 from jumpserver/pr@dev@json_field_add_requirement
perf: m2m json field 字段必填
2023-06-12 13:41:34 +08:00
老广
7bfe8816a3 Merge pull request #10674 from jumpserver/pr@dev@perf_config
perf: 优化配置
2023-06-12 13:36:49 +08:00
Bai
b4008338c6 perf: 优化配置 2023-06-12 11:24:12 +08:00
ibuler
6058f1bdc0 perf: m2m json field 字段必填 2023-06-12 11:03:04 +08:00
ibuler
5708e57631 perf: m2m json field 字段必填 2023-06-12 10:25:14 +08:00
老广
ba353271ad Merge pull request #10667 from jumpserver/pr@dev@fix_login_regex_error
perf: 修复 正则匹配的 bug
2023-06-09 18:35:23 +08:00
ibuler
adfc22ae85 perf: 修复 正则匹配的 bug 2023-06-09 18:32:56 +08:00
jiangweidong
ef2ecb225a fix: 资产登录规则操作日志显示优化 2023-06-09 18:25:00 +08:00
ibuler
9574d03c12 fix: 修复连接方式选择 2023-06-09 18:22:35 +08:00
Bai
00d3caf80c perf: 删除不用代码 2023-06-09 18:22:04 +08:00
fit2bot
2333a29a56 perf: 优化数据库改密原子性 (#10663)
Co-authored-by: feng <1304903146@qq.com>
2023-06-09 16:52:54 +08:00
fit2bot
b3c5674213 fix: 资产用模版创建账号无切换至 (#10662)
Co-authored-by: feng <1304903146@qq.com>
2023-06-09 16:23:44 +08:00
老广
f372f1e417 Merge pull request #10659 from jumpserver/pr@dev@perf_applet
perf: 添加 edition 字段
2023-06-09 16:05:10 +08:00
ibuler
a86378601a perf: 修改插件 2023-06-09 15:58:30 +08:00
ibuler
6a73cd6b77 perf: 添加 edition 字段 2023-06-09 15:40:41 +08:00
Eric
3022ca983c perf: Dockerfile 增加依赖 2023-06-08 22:09:37 +08:00
老广
8f8e781376 Merge pull request #10655 from jumpserver/pr@dev@fix_login_acl_uniq
perf: 优化 LoginACL 迁移,避免 uniq error
2023-06-08 18:35:23 +08:00
ibuler
998505e999 perf: 修改 acl 登录 2023-06-08 18:33:43 +08:00
ibuler
1c95b67154 perf: 优化 LoginACL 迁移,避免 uniq error 2023-06-08 18:19:32 +08:00
jiangweidong
2837dcf40e feat: 支持文件上传下载备份 (#10438)
* feat: 支持文件上传下载备份

* perf: 抽离replay和ftpfile存储代码

* perf: FTPLog增加session字段

* fix: 修改变量名
2023-06-08 18:04:07 +08:00
ibuler
271ec1bfe0 perf: 优化刚才修改导致的 acls 过滤没有过滤组织 2023-06-08 18:03:49 +08:00
老广
41e147d4b2 Revert "chore(deps): bump cryptography from 38.0.4 to 41.0.0 in /requirements"
This reverts commit 0025b2483e.
2023-06-08 14:57:34 +08:00
老广
d2f1309900 Merge pull request #10644 from jumpserver/pr@dev@perf_acls_connect_methods
perf: 优化 connect method acls 和登录 acls
2023-06-08 14:52:10 +08:00
dependabot[bot]
0025b2483e chore(deps): bump cryptography from 38.0.4 to 41.0.0 in /requirements
Bumps [cryptography](https://github.com/pyca/cryptography) from 38.0.4 to 41.0.0.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/38.0.4...41.0.0)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-08 14:19:06 +08:00
fangfang.dong
a6d586efb4 feat: 系统设置 - 短信服务 - 多平台配置测试手机号: 增加区号显示与修改功能 2023-06-08 11:01:55 +08:00
jiangweidong
f0c0ba3653 fix: 解决lina不显示json格式参数,优化DictSerializer改为JSONSerialzer, 2023-06-08 10:26:33 +08:00
ibuler
d6eb4bcbd2 perf: 优化 connect method acls 和登录 acls 2023-06-07 17:39:56 +08:00
fit2bot
bfd77aa1b0 feat: automation windows pyrdp ping (#10602)
* feat: automation windows pyrdp ping

* perf: add pyfreerdp deps

---------

Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: Eric <xplzv@126.com>
2023-06-07 17:28:35 +08:00
老广
cc57fcacce Merge pull request #10621 from jumpserver/pr@dev@fix_static_js
fix: 修复 jumpserver.js 文件中 rules_id_map_label 变量缺失引起的用户初次登录修改密码表单无法校验提示的错误
2023-06-07 10:36:25 +08:00
Eric
7d3b60232c perf: 优化翻译 2023-06-06 19:13:22 +08:00
Eric
10996f573a perf: 翻译 i18n 信息 2023-06-06 19:13:22 +08:00
老广
a7ca9ccfe9 Merge pull request #10629 from jumpserver/pr@dev@feat_connect_support_options
perf: 连接时支持连接参数
2023-06-05 18:00:44 +08:00
ibuler
c6f92a462f perf: 连接时支持连接参数 2023-06-05 17:27:44 +08:00
fit2bot
a341b55f43 perf: 一些资产没有默认节点+ (#10622)
Co-authored-by: feng <1304903146@qq.com>
2023-06-05 15:10:33 +08:00
fangfangdong
3c68b880a7 fix: 修复 jumpserver.js 文件中 rules_id_map_label 变量缺失引起的用户初次登录修改密码表单无法校验提示的错误 2023-06-05 15:00:25 +08:00
Eric
42c35b0271 perf: chrome 脚本增加 sleep 等待指令,单位秒 2023-06-02 16:14:49 +08:00
Eric
8d8f479da6 perf: dbeaver 支持使用网关连接数据库 2023-06-02 16:13:10 +08:00
fit2bot
9d8c1bb317 perf: 账号模版更新时, 优化同步更新账号逻辑 (#10611)
Co-authored-by: feng <1304903146@qq.com>
2023-06-02 10:56:00 +08:00
Bai
ed117ceac3 perf: 优化创建节点时校验同级节点名称不允许重复(API方式) 2023-06-01 16:39:44 +08:00
fit2bot
1ac9d727ef perf: 修改翻译 (#10604)
Co-authored-by: feng <1304903146@qq.com>
2023-05-31 18:19:11 +08:00
fangfangdong
a0bb25e558 feat: 系统设置-安全设置 支持配置 作业中心命令黑名单 2023-05-31 17:43:05 +08:00
Bai
51d6090fdc perf: 优化支持账号列表搜索资产名称 2023-05-31 16:50:37 +08:00
ibuler
d402de012b perf: 优化写法,避免重复 2023-05-31 16:48:50 +08:00
ibuler
2a183e34ac perf: 修改去掉 debug 2023-05-31 16:48:50 +08:00
ibuler
7d111b6efb perf: 优化自定义平台和 applet 导入 2023-05-31 16:48:50 +08:00
Bai
0ba7ca6373 perf: 升级依赖 certifi==2022.12.7 2023-05-31 14:20:59 +08:00
jiangweidong
51e5733f1c fix: 具有超级工单权限的用户申请工单可以指定给某人 (#10596) 2023-05-31 10:20:37 +08:00
fit2bot
3626bf8df6 feat: 命令及录像存储可连接性定时检查 (#10594)
Co-authored-by: feng <1304903146@qq.com>
2023-05-30 18:45:51 +08:00
ibuler
312213f1c5 perf: 允许 web 同时打开 2023-05-30 18:43:04 +08:00
ibuler
d285daa1c1 perf: 资产支持根据协议搜索 2023-05-30 17:55:34 +08:00
ibuler
f4c29a262a perf: 优化自动化任务在平台中的名称显示 2023-05-30 17:17:47 +08:00
fangfangdong
b98ccf8b3d style: 调整国际化文件中时间单位显示方式 2023-05-30 17:04:50 +08:00
Bai
ef7886b25b perf: 升级依赖 jms-storage==0.0.46 2023-05-30 15:08:04 +08:00
火星小刘
89b42ce51b 企业微信扫描登录修改为新版接口,在PC登录企业微信客户端的情况下,不再需要手机扫码。
企业微信官方api
https://developer.work.weixin.qq.com/document/path/98151
2023-05-30 14:58:58 +08:00
老广
e5c93dc50f Merge pull request #10585 from jumpserver/pr@dev@perf_chrome_extensions
perf: 优化 chrome 插件
2023-05-30 11:01:25 +08:00
ibuler
50d8389fff perf: 优化 chrome 插件 2023-05-30 10:59:16 +08:00
老广
5edacf369b Merge pull request #10583 from jumpserver/pr@dev@perf_perm_action_helptext
perf: 优化授权中动作的说明
2023-05-30 09:52:38 +08:00
ibuler
7a39552bb2 merge: with dev 2023-05-30 09:47:59 +08:00
fit2bot
e61227d694 perf: 登录资产的 ACL 支持 ip 控制 (#10581)
Co-authored-by: ibuler <ibuler@qq.com>
2023-05-29 19:45:55 +08:00
ibuler
0901b95ce0 perf: 优化授权中动作的说明 2023-05-29 18:23:26 +08:00
feng
fd7e821f11 feat: 用户组绑定所有用户 2023-05-29 16:27:51 +08:00
Eric
ac3415d95c perf: 完善远程应用 chrome 启动方式 2023-05-29 15:25:32 +08:00
Eric
b0b174bb2a perf: connection token 的 account 增加 asset 属性 2023-05-29 15:14:31 +08:00
dependabot[bot]
3c568510cf chore(deps): bump requests from 2.28.0 to 2.31.0 in /requirements
Bumps [requests](https://github.com/psf/requests) from 2.28.0 to 2.31.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.28.0...v2.31.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 11:17:18 +08:00
halo
a1ed59d116 perf: yaml文件读取使用utf-8编码 2023-05-29 11:16:29 +08:00
Bai
7708812556 perf: 优化终端端点 Host 字段帮助 2023-05-26 17:20:50 +08:00
Bai
24a98eb747 perf: 优化短信设置的字段名称显示 2023-05-26 15:19:11 +08:00
老广
60fd5a2e91 Merge pull request #10556 from jumpserver/pr@dev@fix_chrome_path
fix: 修正 Chrome 环境变量
2023-05-25 19:19:45 +08:00
ibuler
9932e7eadd perf: 资产授权支持 delete 控制 2023-05-25 19:15:48 +08:00
fit2bot
73102fceb0 fix: 修复禁用平台的账号切换功能,历史创建的切换账号依然可以正常切换 (#10560)
Co-authored-by: feng <1304903146@qq.com>
2023-05-25 18:38:14 +08:00
Bai
5e177b6ce5 fix: 修复用户登录认证 MFA 输入错误时没有记录具体错误信息的问题 2023-05-25 18:26:04 +08:00
吴小白
38b121421f fix: 修正 Chrome 环境变量 2023-05-25 17:42:19 +08:00
fit2bot
a6366a2dd4 perf: ldap 能多组织同步用户 (#10543)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2023-05-25 17:35:36 +08:00
ibuler
fa21c83db3 perf: LDAP 测试 api 改为异步的 2023-05-25 16:54:22 +08:00
feng
f20a4beef3 fix: 自定义平台无自动化任务 2023-05-25 16:53:56 +08:00
ibuler
cc2e42c77a perf: chrome 添加插件 2023-05-25 14:20:05 +08:00
jiangweidong
bcb4e04200 perf: 忽略自定义短信认证请求证书校验 2023-05-25 14:13:48 +08:00
jiangweidong
848ea0cf3c perf: 修改翻译 2023-05-25 14:13:48 +08:00
jiangweidong
20cc4ea320 perf: 支持自定义短信认证 2023-05-25 14:13:48 +08:00
fit2bot
5e7d474bb7 perf: RemoteAppHost 平台支持 winrm (#10542)
Co-authored-by: ibuler <ibuler@qq.com>
2023-05-25 13:57:02 +08:00
halo
b72f8a7241 perf: 优化账号收集,使用正则处理结果 2023-05-25 13:40:25 +08:00
老广
35e9c21ec5 Merge pull request #10547 from jumpserver/pr@dev@perf_json_filter
perf: 修改 filter_q
2023-05-25 12:30:13 +08:00
ibuler
dcd35310cd perf: 修改 filter_q 2023-05-25 11:42:39 +08:00
fit2bot
32a8e150da perf: 删除全部用户错误提示 (#10546)
Co-authored-by: feng <1304903146@qq.com>
2023-05-25 11:38:20 +08:00
Bai
cabdc3ad42 fix: 修复终端端点使用资产标签匹配机制时 500 的问题 2023-05-24 17:36:51 +08:00
fit2bot
653b996d84 perf: 账号推送支持设置推送账号的 home 目录 (#10541)
Co-authored-by: feng <1304903146@qq.com>
2023-05-24 17:35:14 +08:00
老广
2262b0ecb5 Merge pull request #10327 from jumpserver/pr@dev@json_m2m_field
pref: 自定义 ORM Field,使用 JSONField 完成
2023-05-24 15:27:47 +08:00
ibuler
eccbf46300 merge: with dev 2023-05-24 15:26:59 +08:00
Eric
440cd13fcc perf: 同一个协作会话链接,限制同一用户仅可使用一次 2023-05-24 14:40:01 +08:00
feng
20c1f4a293 perf: 改密过程原子性优化 2023-05-24 14:31:27 +08:00
Bai
feb42961ef feat: 资产列表搜索支持 comment 模糊搜索 2023-05-22 18:27:07 +08:00
jiangweidong
3eaed62186 验证账号可连接性(自定义ssh)使用的key值错误 (#10523) 2023-05-22 17:29:17 +08:00
jiangweidong
a3f472137f perf: 优化命令过滤规则操作日志显示问题 2023-05-22 15:07:55 +08:00
feng
d4bb501ef9 fix: 账号导入500 2023-05-22 14:13:55 +08:00
ibuler
c4b25fbdbd fix: 修复 applet 账号选择问题 2023-05-19 17:01:29 +08:00
ibuler
197364d42d perf: 暂存一下 2023-05-19 11:30:50 +08:00
ibuler
6eb9986c75 perf: 修改过期默认值 2023-05-19 10:58:04 +08:00
老广
e40d65871b Merge pull request #10501 from jingzhaoyang/dev
fix: when request access_token is post method, http body has no json …
2023-05-19 10:43:32 +08:00
老广
a236de1eff Merge pull request #10489 from O-Jiangweidong/pr@dev@fix_mfa_bypass
fix: 修复某待审核用户返回时,登录其他用户可绕开mfa的问题
2023-05-19 10:41:19 +08:00
ibuler
a261d69cd2 perf: 修改 m2m json field 2023-05-18 21:34:19 +08:00
景朝阳
efb31d6f37 fix: when request access_token is post method, http body has no json data 2023-05-18 20:40:41 +08:00
Jiangjie.Bai
4a56875bda Merge pull request #10500 from jumpserver/dev
v3.3.0
2023-05-18 19:37:10 +08:00
Eric
48fca8f0f3 perf: 修复 rdp option 参数设置 2023-05-18 19:36:30 +08:00
Jiangjie.Bai
2f5d094abb Merge pull request #10498 from jumpserver/dev
v3.3.0
2023-05-18 19:17:08 +08:00
Eric
31600ba66c perf: rdp 设置分辨率不生效问题 2023-05-18 19:13:57 +08:00
Eric
a17fa5a518 perf: remoteapp rdp文件参数禁用复用连接 2023-05-18 19:09:12 +08:00
Bai
59d964d57a perf: 优化组织管理员不能更新系统管理员 2023-05-18 19:03:51 +08:00
fit2bot
2981bfffb1 fix: 给 view 增加 export 属性 (#10495)
Co-authored-by: feng <1304903146@qq.com>
2023-05-18 18:33:22 +08:00
fit2bot
0596b74fa1 fix: 账号创建ssh key 校验 (#10494)
Co-authored-by: feng <1304903146@qq.com>
2023-05-18 18:00:58 +08:00
ibuler
ebaa8d2637 perf: 优化 json error 2023-05-18 17:31:40 +08:00
吴小白
b368b6aef4 perf: 优化发布机部署脚本 2023-05-18 16:31:55 +08:00
fit2bot
44967b1af1 fix: 平台局部更新会自动关闭其他属性 (#10484)
Co-authored-by: feng <1304903146@qq.com>
2023-05-18 15:43:23 +08:00
fit2bot
6c19fd4192 fix: 修复 luna 类型树数量计算不准确bug (#10492)
Co-authored-by: feng <1304903146@qq.com>
2023-05-18 15:42:30 +08:00
jiangweidong
bb27be0924 fix: 修复某待审核用户返回时,登录其他用户可绕开mfa的问题 2023-05-18 14:45:17 +08:00
ibuler
4e5ab5a605 perf: 修改过滤的 q 2023-05-18 13:14:32 +08:00
fit2bot
b0b14fe2e1 fix: openid 三方登录限制bug (#10480)
Co-authored-by: feng <1304903146@qq.com>
2023-05-17 19:05:28 +08:00
Aaron3S
36aa0d301b perf: 优化 ops 用户提示 2023-05-17 18:37:54 +08:00
Aaron3S
3fa80351e0 fix: 修复作业中心提示用户名排序每次不一样的问题 2023-05-17 18:37:54 +08:00
fit2bot
1fef273669 fix: 修复工单日期不能为null settings 文件没有权限bug (#10479)
Co-authored-by: feng <1304903146@qq.com>
2023-05-17 17:29:34 +08:00
Bai
04e95d378c perf: 优化账号列表-添加账号切换自用户字段必填的问题 2023-05-17 14:11:21 +08:00
fit2bot
9058a79c5c fix: 修复三方用户登录登录限制提示错误问题 (#10475)
Co-authored-by: feng <1304903146@qq.com>
2023-05-17 11:11:39 +08:00
fit2bot
a7fed21819 perf: 翻译 (#10472)
Co-authored-by: feng <1304903146@qq.com>
2023-05-16 18:35:48 +08:00
jiangweidong
cfc91047fd perf: 自动化任务执行错误日志在DEBUG_DEV下打印 2023-05-16 18:15:55 +08:00
fit2bot
4ce2d991dd perf: 收集mysql账号username 优化 (#10470)
Co-authored-by: feng <1304903146@qq.com>
2023-05-16 18:15:42 +08:00
Bai
449e7ce454 fix: 修复删除组织时组织根节点未被删除的问题 2023-05-16 16:37:47 +08:00
fit2bot
9cc9600a4c fix: 批量添加账号su_from 错乱 (#10463)
Co-authored-by: feng <1304903146@qq.com>
2023-05-16 15:44:02 +08:00
Bai
f7e0f533e0 perf: 优化安全设置登录限制帮助文案信息 2023-05-16 15:25:57 +08:00
fit2bot
c7c3f711bf perf: 优化发布机不显示task信息问题 (#10450)
* perf: 优化发布机不显示task信息问题

* perf: 添加celery task execution api的task_name字段

---------

Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: feng <1304903146@qq.com>
2023-05-16 14:48:00 +08:00
fit2bot
ec10ee3298 fix: 模版批量添加提示异常(core 代码bug) (#10455)
Co-authored-by: feng <1304903146@qq.com>
2023-05-15 18:58:06 +08:00
fit2bot
155c241ef7 fix: 修复账号模版更新时 添加密码密钥500 (#10454)
Co-authored-by: feng <1304903146@qq.com>
2023-05-15 18:47:39 +08:00
Bai
341dd6adfb perf: 修改 ansible-core 源 gitee -> github 2023-05-15 15:16:37 +08:00
吴小白
89b75835a6 perf: 优化一些问题 2023-05-15 13:43:44 +08:00
吴小白
ee2172ca82 Merge pull request #10449 from jumpserver/pr@dev@perf_grpcio
perf: 升级依赖 grpcio==1.54.2
2023-05-15 11:30:38 +08:00
Bai
98802e21a0 perf: 升级依赖 grpcio==1.54.2 2023-05-15 11:23:36 +08:00
ibuler
7c850a8a1e perf: 修改 json field query 2023-05-12 19:16:55 +08:00
feng
5b4979bdb1 perf: 修改仅允许已存在用户登录 判断的函数名 2023-05-12 18:13:11 +08:00
fit2bot
6afcf7bf42 perf: 第三方用户认证错误信息提示(尤其是第三方认证跳转的情况) (#10446)
Co-authored-by: feng <1304903146@qq.com>
2023-05-12 17:22:18 +08:00
jiangweidong
afb49f4040 fix: oracle Ping 失败 2023-05-12 15:41:03 +08:00
老广
4e20cf6036 Merge pull request #10443 from maninhill/patch-9
Update README.md
2023-05-12 14:43:23 +08:00
maninhill
9ecde3024a Update README.md 2023-05-12 14:42:07 +08:00
老广
daf6dbaf73 Merge pull request #10442 from maninhill/patch-8
chore: 更新 README
2023-05-12 14:36:57 +08:00
maninhill
7edb024abe chore: 更新 README 2023-05-12 14:35:45 +08:00
huailei
1c7634b394 Merge pull request #10432 from jumpserver/pr@dev@perf_task_log
perf: 优化task执行数据显示
2023-05-11 17:22:52 +08:00
“huailei000”
ff4f01fb56 perf: 优化task执行数据显示 2023-05-11 17:19:21 +08:00
老广
fd5f57d9b7 Merge pull request #10425 from jumpserver/pr@dev@perf_dbasset
perf: 平台协议支持更改 public 字段
2023-05-11 10:50:33 +08:00
fit2bot
f06059837d perf: 授权类型树 (#10390)
Co-authored-by: feng <1304903146@qq.com>
2023-05-11 10:15:40 +08:00
Bai
b98aa377b6 perf: 数据库资产 默认数据库 是必填项 2023-05-10 16:47:03 +08:00
Bai
42abad75d9 perf: 平台协议支持更改 public 字段 2023-05-10 16:46:10 +08:00
Aaron3S
ebb0e796ce feat: 作业中心根据当前选择的资产提示用户名 2023-05-10 15:41:17 +08:00
Bai
24fd87f7bc perf: 平台协议API返回public字段 2023-05-10 15:36:18 +08:00
“huailei000”
90cc2a2519 perf: 展示执行详情数据 2023-05-10 15:24:40 +08:00
feng
9802aec881 perf: 自动化执行详情数据 2023-05-10 15:24:40 +08:00
ibuler
737032418a perf: 优化写法 2023-05-10 11:10:21 +08:00
ibuler
2aa03d5b79 perf: connect token 允许复用 2023-05-10 11:10:21 +08:00
老广
926550bf26 Merge pull request #10416 from jumpserver/pr@dev@fix_categorytree1
fix: 修复资产类型树循环显示的问题
2023-05-10 11:07:39 +08:00
ibuler
240f700b92 perf: 修改账号生成 2023-05-10 11:04:33 +08:00
ibuler
4000986d1d perf: 优化选择账号 2023-05-10 11:04:33 +08:00
ibuler
0e98990e17 perf: 远程应用调度优先调度的上个主机,使用上个账号,并支持同名账号 2023-05-10 11:04:33 +08:00
Bai
8309f00e5e fix: 修复资产类型树循环显示的问题 2023-05-10 02:53:19 +00:00
老广
ad96fd2a96 Merge pull request #10412 from jumpserver/dependabot/pip/requirements/django-3.2.19
chore(deps): bump django from 3.2.17 to 3.2.19 in /requirements
2023-05-10 09:55:16 +08:00
dependabot[bot]
e6bbaac7de chore(deps): bump django from 3.2.17 to 3.2.19 in /requirements
Bumps [django](https://github.com/django/django) from 3.2.17 to 3.2.19.
- [Commits](https://github.com/django/django/compare/3.2.17...3.2.19)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-09 22:15:13 +00:00
Bai
f0cc64c74e perf: 优化账号用户名字段提示信息(null 的情况) 2023-05-09 18:41:28 +08:00
Chenyang Shen
65ca953f5b Merge pull request #10409 from jumpserver/pr@dev@perf_job_permission
perf: 优化 job permission
2023-05-09 17:25:36 +08:00
ibuler
873c019b58 perf: 修改 job list 2023-05-09 17:23:21 +08:00
ibuler
b5599fd3a6 perf: 优化 job permission 2023-05-09 17:18:52 +08:00
fit2bot
1933e82587 feat: 账号模版切换至 (#10396)
Co-authored-by: feng <1304903146@qq.com>
2023-05-09 15:29:02 +08:00
fit2bot
6b6900cfd4 perf: 导出account 列表需对文件进行加密 (#10366)
Co-authored-by: feng <1304903146@qq.com>
2023-05-08 17:02:55 +08:00
jiangweidong
185f33c3e0 perf: 企业微信、钉钉、飞书本地没有用户即创建 2023-05-08 16:58:39 +08:00
jiangweidong
3f1858a105 将配置改到类属性中 2023-05-08 16:58:39 +08:00
jiangweidong
1fef9a2cf0 perf: 去掉不用的导包 2023-05-08 16:58:39 +08:00
jiangweidong
38a9b90a8b fix: flash_message 带上返回值 2023-05-08 16:58:39 +08:00
jiangweidong
b376491020 perf: 优化user_type默认值 2023-05-08 16:58:39 +08:00
jiangweidong
3367f65b02 perf: 优化逻辑,抽离callback_base类 2023-05-08 16:58:39 +08:00
jiangweidong
7a97496f70 perf: 变量名还原 2023-05-08 16:58:39 +08:00
jiangweidong
bda748d547 feat: 支持钉钉、飞书、企业微信扫码登录无用户时自动创建用户 2023-05-08 16:58:39 +08:00
feng
7ff22cbc34 fix: /prometheus/metrics/ api 500 2023-05-08 14:47:56 +08:00
ibuler
1ec4cbdf38 perf: 优化 m2m json field 2023-05-08 14:09:44 +08:00
Eric_Lee
ccd6b8c48a Merge pull request #10394 from jumpserver/pr@dev@perf_replay_mp4
perf: 支持 mp4 录像文件上传和新增 video worker 类型
2023-05-07 09:06:18 +08:00
ibuler
a112d3c99d perf: 修改 accounts 字段 2023-05-06 19:52:03 +08:00
Eric
ee7f1f8f5e perf: 支持 mp4 录像文件上传和新增 video worker 类型 2023-05-06 14:01:25 +08:00
Bai
127f6730f6 perf: 优化迁移后的 Redis 数据库平台从 Redis6+ 修改为 Redis6 2023-05-04 17:31:45 +08:00
Bai
22b56d73b6 fix: 修复迁移应用时(组织下只有根节点,同步后的应用资产没有设置节点的问题) 2023-05-04 16:39:24 +08:00
Bai
9934456af4 fix: 修复迁移redis资产账号丢失的问题(系统用户用户名为空字符串) 2023-05-04 15:44:31 +08:00
Bai
3585ca2d49 perf: 优化文案: 清除离线会话 2023-05-04 10:33:16 +08:00
fit2bot
f842546042 perf: 平台导出过滤掉automation (#10367)
Co-authored-by: feng <1304903146@qq.com>
2023-04-28 17:13:43 +08:00
ibuler
5a6e13721d perf: 优化 json m2m field 2023-04-27 18:05:16 +08:00
Eric
a0151b8d44 fix: 修复旧 ssh 私钥,解析失败的问题 2023-04-27 17:50:16 +08:00
老广
62e5389f80 Update README.md 2023-04-27 17:49:07 +08:00
老广
a1d24f030e Merge pull request #10360 from maninhill/patch-7
chore(docs):更新 README
2023-04-27 17:42:59 +08:00
maninhill
78ddb75b7a chore(docs):更新 README 2023-04-27 17:38:26 +08:00
ibuler
90090a7fc7 perf: 添加 JSONManyToManyFieldSerializer 2023-04-27 14:13:40 +08:00
fit2bot
ea1c94c6db perf: 用户组织按照name 进行排序 (#10354)
Co-authored-by: feng <1304903146@qq.com>
2023-04-27 11:38:33 +08:00
ibuler
338ab5c634 perf: 优化 acl 2023-04-26 19:11:53 +08:00
fit2bot
58d055f114 perf: 改密 推送 可以对自己操作 同时设置su_enabled 可提权 (#10349)
Co-authored-by: feng <1304903146@qq.com>
2023-04-26 18:50:30 +08:00
Bai
9eec2909ed fix: 修改'账号备份列表-执行次数'未翻译为英文的问题 2023-04-26 17:11:28 +08:00
ibuler
632627db11 perf: 去掉 debug model 2023-04-25 16:25:00 +08:00
fit2bot
a19586f8b8 perf: perm user asset add labels (#10339)
Co-authored-by: feng <1304903146@qq.com>
2023-04-25 14:48:09 +08:00
fit2bot
8fe5ab42e8 perf: 用户工作台资产显示更多字段 (#10338)
Co-authored-by: feng <1304903146@qq.com>
2023-04-25 14:36:01 +08:00
ibuler
f51af9736b perf: rdp 支持 console 模式 2023-04-25 14:35:07 +08:00
ibuler
20b7b794d8 perf: 修改 m2m field 2023-04-25 14:00:19 +08:00
fit2bot
2a196743f5 perf: 组织更新刷新缓存 (#10333)
Co-authored-by: feng <1304903146@qq.com>
2023-04-25 11:27:58 +08:00
fit2bot
917620736b feat: 修改模版账号密码 同步更新关联的账号 (#10328)
* feat: 修改模版账号密码 同步更新关联的账号

* feat: 同步多个账号

---------

Co-authored-by: feng <1304903146@qq.com>
2023-04-25 10:28:19 +08:00
ibuler
19d29d6637 perf: remove debug msg 2023-04-24 19:04:47 +08:00
ibuler
c824ae4478 perf: 修改 manager 2023-04-24 19:03:44 +08:00
ibuler
3cdb81cf4a perf: 搞定自定义 orm field 2023-04-24 19:00:31 +08:00
ibuler
378eee0402 pref: stash 2 2023-04-24 16:27:13 +08:00
Bai
9d2ae7d1ed fix: 修改 utils/disable_user_mfa.sh otp_level => mfa_level 2023-04-23 16:45:40 +08:00
ibuler
c991a73632 v1 2023-04-23 16:15:27 +08:00
feng
149ca1afce perf: 开源 acl去除 review 2023-04-21 18:41:47 +08:00
fit2bot
a1f65bccc5 feat: 只有系统管理员才能更新或删除系统管理员 (#10306)
Co-authored-by: feng <1304903146@qq.com>
2023-04-21 17:31:39 +08:00
ibuler
a105748a55 perf: 账号模版 protocols 过滤 2023-04-21 17:11:18 +08:00
fit2bot
f1ee454254 perf: user groups filter (#10300)
Co-authored-by: feng <1304903146@qq.com>
2023-04-21 15:35:56 +08:00
ibuler
a6ab886968 perf: 优化自定义类型的冲突 2023-04-21 15:21:11 +08:00
feng
f85daa088f perf: 创建资产 nodes 可为空 默认 default 2023-04-21 14:58:11 +08:00
fit2bot
ede53d3b6b perf: ssh key strategy translate (#10295)
Co-authored-by: feng <1304903146@qq.com>
2023-04-21 14:08:59 +08:00
ibuler
eb9ac213d5 perf: 去掉 debug msg 2023-04-21 11:32:49 +08:00
ibuler
06052b85a2 perf: 优化支持 自定义 applet
perf: 优化平台
2023-04-21 11:31:10 +08:00
老广
01827c7b3a Merge pull request #10292 from jumpserver/pr@dev@fix_util
fix: util add jobauditlog
2023-04-21 11:28:46 +08:00
Bai
14e572813f fix: util add jobauditlog 2023-04-21 11:20:51 +08:00
401 changed files with 8502 additions and 4169 deletions

View File

@@ -1,5 +1,4 @@
.git .git
logs/*
data/* data/*
.github .github
tmp/* tmp/*

View File

@@ -6,8 +6,7 @@ labels: 类型:需求
assignees: assignees:
- ibuler - ibuler
- baijiangjie - baijiangjie
- wojiushixiaobai
--- ---
**请描述您的需求或者改进建议.** **请描述您的需求或者改进建议.**

View File

@@ -21,17 +21,44 @@ jobs:
actions: 'remove-labels' actions: 'remove-labels'
labels: '状态:待反馈' labels: '状态:待反馈'
add-label-if-not-author: add-label-if-is-member:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: (github.event.issue.user.id != github.event.comment.user.id) && !github.event.issue.pull_request && (github.event.issue.state == 'open')
steps: steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Get Organization name
id: org_name
run: echo "data=$(echo '${{ github.repository }}' | cut -d '/' -f 1)" >> $GITHUB_OUTPUT
- name: Get Organization public members
uses: octokit/request-action@v2.x
id: members
with:
route: GET /orgs/${{ steps.org_name.outputs.data }}/public_members
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Process public members data
# 将 members 中的数据转化为 login 字段的拼接字符串
id: member_names
run: echo "data=$(echo '${{ steps.members.outputs.data }}' | jq '[.[].login] | join(",")')" >> $GITHUB_OUTPUT
- run: "echo members: '${{ steps.members.outputs.data }}'"
- run: "echo member names: '${{ steps.member_names.outputs.data }}'"
- run: "echo comment user: '${{ github.event.comment.user.login }}'"
- run: "echo contains? : '${{ contains(steps.member_names.outputs.data, github.event.comment.user.login) }}'"
- name: Add require replay label - name: Add require replay label
if: contains(steps.member_names.outputs.data, github.event.comment.user.login)
uses: actions-cool/issues-helper@v2 uses: actions-cool/issues-helper@v2
with: with:
actions: 'add-labels' actions: 'add-labels'
labels: '状态:待反馈' labels: '状态:待反馈'
- name: Remove require handle label - name: Remove require handle label
if: contains(steps.member_names.outputs.data, github.event.comment.user.login)
uses: actions-cool/issues-helper@v2 uses: actions-cool/issues-helper@v2
with: with:
actions: 'remove-labels' actions: 'remove-labels'

1
.gitignore vendored
View File

@@ -35,7 +35,6 @@ celerybeat-schedule.db
docs/_build/ docs/_build/
xpack xpack
xpack.bak xpack.bak
logs/*
### Vagrant ### ### Vagrant ###
.vagrant/ .vagrant/
release/* release/*

View File

@@ -1,4 +1,4 @@
FROM python:3.9-slim as stage-build FROM jumpserver/python:3.9-slim-buster as stage-build
ARG TARGETARCH ARG TARGETARCH
ARG VERSION ARG VERSION
@@ -8,7 +8,7 @@ WORKDIR /opt/jumpserver
ADD . . ADD . .
RUN cd utils && bash -ixeu build.sh RUN cd utils && bash -ixeu build.sh
FROM python:3.9-slim FROM jumpserver/python:3.9-slim-buster
ARG TARGETARCH ARG TARGETARCH
MAINTAINER JumpServer Team <ibuler@qq.com> MAINTAINER JumpServer Team <ibuler@qq.com>
@@ -22,11 +22,14 @@ ARG DEPENDENCIES=" \
libpq-dev \ libpq-dev \
libffi-dev \ libffi-dev \
libjpeg-dev \ libjpeg-dev \
libkrb5-dev \
libldap2-dev \ libldap2-dev \
libsasl2-dev \ libsasl2-dev \
libssl-dev \
libxml2-dev \ libxml2-dev \
libxmlsec1-dev \ libxmlsec1-dev \
libxmlsec1-openssl \ libxmlsec1-openssl \
freerdp2-dev \
libaio-dev" libaio-dev"
ARG TOOLS=" \ ARG TOOLS=" \
@@ -65,27 +68,35 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
ARG DOWNLOAD_URL=https://download.jumpserver.org ARG DOWNLOAD_URL=https://download.jumpserver.org
RUN mkdir -p /opt/oracle/ \ RUN set -ex \
&& cd /opt/oracle/ \ && \
&& wget ${DOWNLOAD_URL}/public/instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip \ if [ "${TARGETARCH}" == "amd64" ] || [ "${TARGETARCH}" == "arm64" ]; then \
&& unzip instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip \ mkdir -p /opt/oracle; \
&& sh -c "echo /opt/oracle/instantclient_19_10 > /etc/ld.so.conf.d/oracle-instantclient.conf" \ cd /opt/oracle; \
&& ldconfig \ wget ${DOWNLOAD_URL}/public/instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip; \
&& rm -f instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip unzip instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip; \
echo "/opt/oracle/instantclient_19_10" > /etc/ld.so.conf.d/oracle-instantclient.conf; \
ldconfig; \
rm -f instantclient-basiclite-linux.${TARGETARCH}-19.10.0.0.0.zip; \
fi
WORKDIR /tmp/build WORKDIR /tmp/build
COPY ./requirements ./requirements COPY ./requirements ./requirements
ARG PIP_MIRROR=https://pypi.douban.com/simple ARG PIP_MIRROR=https://pypi.douban.com/simple
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
RUN --mount=type=cache,target=/root/.cache/pip \ RUN --mount=type=cache,target=/root/.cache/pip \
set -ex \ set -ex \
&& pip config set global.index-url ${PIP_MIRROR} \ && pip config set global.index-url ${PIP_MIRROR} \
&& pip install --upgrade pip \ && pip install --upgrade pip \
&& pip install --upgrade setuptools wheel \ && pip install --upgrade setuptools wheel \
&& \
if [ "${TARGETARCH}" == "loong64" ]; then \
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; \
fi \
&& pip install $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \ && pip install $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install -r requirements/requirements.txt && pip install -r requirements/requirements.txt

View File

@@ -1,10 +1,21 @@
ARG VERSION ARG VERSION
FROM registry.fit2cloud.com/jumpserver/xpack:${VERSION} as build-xpack FROM registry.fit2cloud.com/jumpserver/xpack:${VERSION} as build-xpack
FROM jumpserver/core:${VERSION} FROM jumpserver/core:${VERSION}
ARG TARGETARCH
COPY --from=build-xpack /opt/xpack /opt/jumpserver/apps/xpack COPY --from=build-xpack /opt/xpack /opt/jumpserver/apps/xpack
WORKDIR /opt/jumpserver WORKDIR /opt/jumpserver
ARG ORACLE_VERSION=1.4.0b1
RUN --mount=type=cache,target=/root/.cache/pip \ RUN --mount=type=cache,target=/root/.cache/pip \
set -ex \ 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 && pip install -r requirements/requirements_xpack.txt

View File

@@ -1,96 +0,0 @@
FROM python:3.9-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.9-slim
ARG TARGETARCH
MAINTAINER JumpServer Team <ibuler@qq.com>
ARG BUILD_DEPENDENCIES=" \
g++ \
make \
pkg-config"
ARG DEPENDENCIES=" \
freetds-dev \
libpq-dev \
libffi-dev \
libjpeg-dev \
libldap2-dev \
libsasl2-dev \
libssl-dev \
libxml2-dev \
libxmlsec1-dev \
libxmlsec1-openssl \
libaio-dev"
ARG TOOLS=" \
ca-certificates \
curl \
default-libmysqlclient-dev \
default-mysql-client \
locales \
openssh-client \
procps \
sshpass \
telnet \
unzip \
vim \
git \
wget"
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
set -ex \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& apt-get update \
&& apt-get -y install --no-install-recommends ${BUILD_DEPENDENCIES} \
&& apt-get -y install --no-install-recommends ${DEPENDENCIES} \
&& apt-get -y install --no-install-recommends ${TOOLS} \
&& mkdir -p /root/.ssh/ \
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null\n\tCiphers +aes128-cbc\n\tKexAlgorithms +diffie-hellman-group1-sha1\n\tHostKeyAlgorithms +ssh-rsa" > /root/.ssh/config \
&& echo "set mouse-=a" > ~/.vimrc \
&& echo "no" | dpkg-reconfigure dash \
&& echo "zh_CN.UTF-8" | dpkg-reconfigure locales \
&& sed -i "s@# export @export @g" ~/.bashrc \
&& sed -i "s@# alias @alias @g" ~/.bashrc \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /tmp/build
COPY ./requirements ./requirements
ARG PIP_MIRROR=https://pypi.douban.com/simple
ENV PIP_MIRROR=$PIP_MIRROR
ARG PIP_JMS_MIRROR=https://pypi.douban.com/simple
ENV PIP_JMS_MIRROR=$PIP_JMS_MIRROR
RUN --mount=type=cache,target=/root/.cache/pip \
set -ex \
&& pip config set global.index-url ${PIP_MIRROR} \
&& pip install --upgrade pip \
&& pip install --upgrade setuptools wheel \
&& 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.0-cp39-cp39-linux_loongarch64.whl \
&& pip install $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install -r requirements/requirements.txt
COPY --from=stage-build /opt/jumpserver/release/jumpserver /opt/jumpserver
RUN echo > /opt/jumpserver/config.yml \
&& rm -rf /tmp/build
WORKDIR /opt/jumpserver
VOLUME /opt/jumpserver/data
VOLUME /opt/jumpserver/logs
ENV LANG=zh_CN.UTF-8
EXPOSE 8080
ENTRYPOINT ["./entrypoint.sh"]

View File

@@ -17,14 +17,19 @@
9 年时间,倾情投入,用心做好一款开源堡垒机。 9 年时间,倾情投入,用心做好一款开源堡垒机。
</p> </p>
| :warning: 注意 :warning: |
|:-------------------------------------------------------------------------------------------------------------------------:|
| 3.0 架构上和 2.0 变化较大,建议全新安装一套环境来体验。如需升级,请务必升级前进行备份,并[查阅文档](https://kb.fit2cloud.com/?p=06638d69-f109-4333-b5bf-65b17b297ed9) |
--------------------------
JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。 JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。
JumpServer 堡垒机帮助企业以更安全的方式管控和登录各种类型的资产,包括:
- **SSH**: Linux / Unix / 网络设备 等;
- **Windows**: Web 方式连接 / 原生 RDP 连接;
- **数据库**: MySQL / MariaDB / PostgreSQL / Oracle / SQLServer / ClickHouse 等;
- **NoSQL**: Redis / MongoDB 等;
- **GPT**: ChatGPT 等;
- **云服务**: Kubernetes / VMware vSphere 等;
- **Web 站点**: 各类系统的 Web 管理后台;
- **应用**: 通过 Remote App 连接各类应用。
## 产品特色 ## 产品特色
- **开源**: 零门槛,线上快速获取和安装; - **开源**: 零门槛,线上快速获取和安装;
@@ -33,8 +38,6 @@ JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运
- **多云支持**: 一套系统,同时管理不同云上面的资产; - **多云支持**: 一套系统,同时管理不同云上面的资产;
- **多租户**: 一套系统,多个子公司或部门同时使用; - **多租户**: 一套系统,多个子公司或部门同时使用;
- **云端存储**: 审计录像云端存储,永不丢失; - **云端存储**: 审计录像云端存储,永不丢失;
- **多应用支持**: 全面支持各类资产包括服务器、数据库、Windows RemoteApp、Kubernetes 等;
- **安全可靠**: 被广泛使用、验证和信赖,连续 9 年的持续研发投入和产品更新升级。
## UI 展示 ## UI 展示
@@ -72,14 +75,11 @@ JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运
- [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687) - [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687)
- [江苏农信JumpServer堡垒机助力行业云安全运维](https://blog.fit2cloud.com/?p=666) - [江苏农信JumpServer堡垒机助力行业云安全运维](https://blog.fit2cloud.com/?p=666)
## 社区 ## 社区交流
如果您在使用过程中有任何疑问或对建议,欢迎提交 [GitHub Issue](https://github.com/jumpserver/jumpserver/issues/new/choose) 如果您在使用过程中有任何疑问或对建议,欢迎提交 [GitHub Issue](https://github.com/jumpserver/jumpserver/issues/new/choose)
或加入到我们的社区当中进行进一步交流沟通。
### 微信交流群 您也可以到我们的 [社区论坛](https://bbs.fit2cloud.com/c/js/5) 当中进行交流沟通。
<img src="https://download.jumpserver.org/images/wecom-group.jpeg" alt="微信群二维码" width="200"/>
### 参与贡献 ### 参与贡献
@@ -89,15 +89,20 @@ JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运
## 组件项目 ## 组件项目
| 项目 | 状态 | 描述 | | 项目 | 状态 | 描述 |
|--------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| |--------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------|
| [Lina](https://github.com/jumpserver/lina) | <a href="https://github.com/jumpserver/lina/releases"><img alt="Lina release" src="https://img.shields.io/github/release/jumpserver/lina.svg" /></a> | JumpServer Web UI 项目 | | [Lina](https://github.com/jumpserver/lina) | <a href="https://github.com/jumpserver/lina/releases"><img alt="Lina release" src="https://img.shields.io/github/release/jumpserver/lina.svg" /></a> | JumpServer Web UI 项目 |
| [Luna](https://github.com/jumpserver/luna) | <a href="https://github.com/jumpserver/luna/releases"><img alt="Luna release" src="https://img.shields.io/github/release/jumpserver/luna.svg" /></a> | JumpServer Web Terminal 项目 | | [Luna](https://github.com/jumpserver/luna) | <a href="https://github.com/jumpserver/luna/releases"><img alt="Luna release" src="https://img.shields.io/github/release/jumpserver/luna.svg" /></a> | JumpServer Web Terminal 项目 |
| [KoKo](https://github.com/jumpserver/koko) | <a href="https://github.com/jumpserver/koko/releases"><img alt="Koko release" src="https://img.shields.io/github/release/jumpserver/koko.svg" /></a> | JumpServer 字符协议 Connector 项目,替代原来 Python 版本的 [Coco](https://github.com/jumpserver/coco) | | [KoKo](https://github.com/jumpserver/koko) | <a href="https://github.com/jumpserver/koko/releases"><img alt="Koko release" src="https://img.shields.io/github/release/jumpserver/koko.svg" /></a> | JumpServer 字符协议 Connector 项目 |
| [Lion](https://github.com/jumpserver/lion-release) | <a href="https://github.com/jumpserver/lion-release/releases"><img alt="Lion release" src="https://img.shields.io/github/release/jumpserver/lion-release.svg" /></a> | JumpServer 图形协议 Connector 项目,依赖 [Apache Guacamole](https://guacamole.apache.org/) | | [Lion](https://github.com/jumpserver/lion-release) | <a href="https://github.com/jumpserver/lion-release/releases"><img alt="Lion release" src="https://img.shields.io/github/release/jumpserver/lion-release.svg" /></a> | JumpServer 图形协议 Connector 项目,依赖 [Apache Guacamole](https://guacamole.apache.org/) |
| [Magnus](https://github.com/jumpserver/magnus-release) | <a href="https://github.com/jumpserver/magnus-release/releases"><img alt="Magnus release" src="https://img.shields.io/github/release/jumpserver/magnus-release.svg" /> | JumpServer 数据库代理 Connector 项目 | | [Razor](https://github.com/jumpserver/razor) | <img alt="Chen" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer RDP 代理 Connector 项目 |
| [Clients](https://github.com/jumpserver/clients) | <a href="https://github.com/jumpserver/clients/releases"><img alt="Clients release" src="https://img.shields.io/github/release/jumpserver/clients.svg" /> | JumpServer 客户端 项目 | | [Tinker](https://github.com/jumpserver/tinker) | <img alt="Tinker" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer 远程应用 Connector 项目 |
| [Installer](https://github.com/jumpserver/installer) | <a href="https://github.com/jumpserver/installer/releases"><img alt="Installer release" src="https://img.shields.io/github/release/jumpserver/installer.svg" /> | JumpServer 安装包 项目 | | [Magnus](https://github.com/jumpserver/magnus-release) | <a href="https://github.com/jumpserver/magnus-release/releases"><img alt="Magnus release" src="https://img.shields.io/github/release/jumpserver/magnus-release.svg" /> | JumpServer 数据库代理 Connector 项目 |
| [Chen](https://github.com/jumpserver/chen-release) | <a href="https://github.com/jumpserver/chen-release/releases"><img alt="Chen release" src="https://img.shields.io/github/release/jumpserver/chen-release.svg" /> | JumpServer Web DB 项目,替代原来的 OmniDB |
| [Kael](https://github.com/jumpserver/kael) | <a href="https://github.com/jumpserver/kael/releases"><img alt="Kael release" src="https://img.shields.io/github/release/jumpserver/kael.svg" /> | JumpServer 连接 GPT 资产的组件项目 |
| [Wisp](https://github.com/jumpserver/wisp) | <a href="https://github.com/jumpserver/wisp/releases"><img alt="Magnus release" src="https://img.shields.io/github/release/jumpserver/wisp.svg" /> | JumpServer 各系统终端组件和 Core Api 通信的组件项目 |
| [Clients](https://github.com/jumpserver/clients) | <a href="https://github.com/jumpserver/clients/releases"><img alt="Clients release" src="https://img.shields.io/github/release/jumpserver/clients.svg" /> | JumpServer 客户端 项目 |
| [Installer](https://github.com/jumpserver/installer) | <a href="https://github.com/jumpserver/installer/releases"><img alt="Installer release" src="https://img.shields.io/github/release/jumpserver/installer.svg" /> | JumpServer 安装包 项目 |
## 安全说明 ## 安全说明
@@ -107,11 +112,6 @@ JumpServer是一款安全产品请参考 [基本安全建议](https://docs.ju
- 邮箱support@fit2cloud.com - 邮箱support@fit2cloud.com
- 电话400-052-0755 - 电话400-052-0755
## 致谢
- [Apache Guacamole](https://guacamole.apache.org/) Web 页面连接 RDP、SSH、VNC 等协议资产JumpServer Lion 组件使用到该项目;
- [OmniDB](https://omnidb.org/) Web 页面连接使用数据库JumpServer Web 数据库组件使用到该项目。
## License & Copyright ## License & Copyright
Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved. Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved.

View File

@@ -22,7 +22,7 @@ __all__ = [
class AccountViewSet(OrgBulkModelViewSet): class AccountViewSet(OrgBulkModelViewSet):
model = Account model = Account
search_fields = ('username', 'asset__address', 'name') search_fields = ('username', 'name', 'asset__name', 'asset__address')
filterset_class = AccountFilterSet filterset_class = AccountFilterSet
serializer_classes = { serializer_classes = {
'default': serializers.AccountSerializer, 'default': serializers.AccountSerializer,
@@ -32,6 +32,7 @@ class AccountViewSet(OrgBulkModelViewSet):
'su_from_accounts': 'accounts.view_account', 'su_from_accounts': 'accounts.view_account',
'clear_secret': 'accounts.change_account', 'clear_secret': 'accounts.change_account',
} }
export_as_zip = True
@action(methods=['get'], detail=False, url_path='su-from-accounts') @action(methods=['get'], detail=False, url_path='su-from-accounts')
def su_from_accounts(self, request, *args, **kwargs): def su_from_accounts(self, request, *args, **kwargs):

View File

@@ -1,13 +1,15 @@
from django_filters import rest_framework as drf_filters from django_filters import rest_framework as drf_filters
from rest_framework.decorators import action
from rest_framework.response import Response
from assets.const import Protocol
from accounts import serializers from accounts import serializers
from accounts.models import AccountTemplate from accounts.models import AccountTemplate
from orgs.mixins.api import OrgBulkModelViewSet from assets.const import Protocol
from rbac.permissions import RBACPermission from common.drf.filters import BaseFilterSet
from common.permissions import UserConfirmation, ConfirmType from common.permissions import UserConfirmation, ConfirmType
from common.views.mixins import RecordViewLogMixin from common.views.mixins import RecordViewLogMixin
from common.drf.filters import BaseFilterSet from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission
class AccountTemplateFilterSet(BaseFilterSet): class AccountTemplateFilterSet(BaseFilterSet):
@@ -27,6 +29,8 @@ class AccountTemplateFilterSet(BaseFilterSet):
continue continue
_st = protocol_secret_type_map[p].get('secret_types', []) _st = protocol_secret_type_map[p].get('secret_types', [])
secret_types.update(_st) secret_types.update(_st)
if not secret_types:
secret_types = ['password']
queryset = queryset.filter(secret_type__in=secret_types) queryset = queryset.filter(secret_type__in=secret_types)
return queryset return queryset
@@ -36,8 +40,19 @@ class AccountTemplateViewSet(OrgBulkModelViewSet):
filterset_class = AccountTemplateFilterSet filterset_class = AccountTemplateFilterSet
search_fields = ('username', 'name') search_fields = ('username', 'name')
serializer_classes = { serializer_classes = {
'default': serializers.AccountTemplateSerializer 'default': serializers.AccountTemplateSerializer,
} }
rbac_perms = {
'su_from_account_templates': 'accounts.view_accounttemplate',
}
@action(methods=['get'], detail=False, url_path='su-from-account-templates')
def su_from_account_templates(self, request, *args, **kwargs):
pk = request.query_params.get('template_id')
templates = AccountTemplate.get_su_from_account_templates(pk)
templates = self.filter_queryset(templates)
serializer = self.get_serializer(templates, many=True)
return Response(data=serializer.data)
class AccountTemplateSecretsViewSet(RecordViewLogMixin, AccountTemplateViewSet): class AccountTemplateSecretsViewSet(RecordViewLogMixin, AccountTemplateViewSet):

View File

@@ -26,6 +26,7 @@
password: "{{ account.secret }}" password: "{{ account.secret }}"
commands: "{{ params.commands }}" commands: "{{ params.commands }}"
first_conn_delay_time: "{{ first_conn_delay_time | default(0.5) }}" first_conn_delay_time: "{{ first_conn_delay_time | default(0.5) }}"
ignore_errors: true
when: ping_info is succeeded when: ping_info is succeeded
register: change_info register: change_info
@@ -35,6 +36,3 @@
login_password: "{{ account.secret }}" login_password: "{{ account.secret }}"
login_host: "{{ jms_asset.address }}" login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
when:
- ping_info is succeeded
- change_info is succeeded

View File

@@ -15,5 +15,6 @@ params:
i18n: i18n:
SSH account change secret: SSH account change secret:
zh: SSH 账号改密 zh: 使用 SSH 命令行自定义改密
ja: SSH アカウントのパスワード変更 ja: SSH コマンドライン方式でカスタムパスワード変更
en: Custom password change by SSH command line

View File

@@ -38,8 +38,8 @@
db: "{{ jms_asset.spec_info.db_name }}" db: "{{ jms_asset.spec_info.db_name }}"
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret }}" password: "{{ account.secret }}"
ignore_errors: true
when: db_info is succeeded when: db_info is succeeded
register: change_info
- name: Verify password - name: Verify password
mongodb_ping: mongodb_ping:
@@ -53,6 +53,3 @@
ssl_certfile: "{{ jms_asset.secret_info.client_key }}" ssl_certfile: "{{ jms_asset.secret_info.client_key }}"
connection_options: connection_options:
- tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}" - tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}"
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -7,5 +7,6 @@ method: change_secret
i18n: i18n:
MongoDB account change secret: MongoDB account change secret:
zh: MongoDB 账号改密 zh: 使用 Ansible 模块 mongodb 执行 MongoDB 账号改密
ja: MongoDB アカウントのパスワード変更 ja: Ansible mongodb モジュールを使用して MongoDB アカウントのパスワード変更
en: Using Ansible module mongodb to change MongoDB account secret

View File

@@ -28,8 +28,8 @@
password: "{{ account.secret }}" password: "{{ account.secret }}"
host: "%" host: "%"
priv: "{{ account.username + '.*:USAGE' if db_name == '' else db_name + '.*:ALL' }}" priv: "{{ account.username + '.*:USAGE' if db_name == '' else db_name + '.*:ALL' }}"
ignore_errors: true
when: db_info is succeeded when: db_info is succeeded
register: change_info
- name: Verify password - name: Verify password
community.mysql.mysql_info: community.mysql.mysql_info:
@@ -38,6 +38,3 @@
login_host: "{{ jms_asset.address }}" login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
filter: version filter: version
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -8,5 +8,6 @@ method: change_secret
i18n: i18n:
MySQL account change secret: MySQL account change secret:
zh: MySQL 账号改密 zh: 使用 Ansible 模块 mysql 执行 MySQL 账号改密
ja: MySQL アカウントのパスワード変更 ja: Ansible mysql モジュールを使用して MySQL アカウントのパスワード変更
en: Using Ansible module mysql to change MySQL account secret

View File

@@ -29,8 +29,8 @@
mode: "{{ jms_account.mode }}" mode: "{{ jms_account.mode }}"
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret }}" password: "{{ account.secret }}"
ignore_errors: true
when: db_info is succeeded when: db_info is succeeded
register: change_info
- name: Verify password - name: Verify password
oracle_ping: oracle_ping:
@@ -39,6 +39,3 @@
login_host: "{{ jms_asset.address }}" login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}" login_database: "{{ jms_asset.spec_info.db_name }}"
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -29,8 +29,8 @@
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret }}" password: "{{ account.secret }}"
role_attr_flags: LOGIN role_attr_flags: LOGIN
ignore_errors: true
when: result is succeeded when: result is succeeded
register: change_info
- name: Verify password - name: Verify password
community.postgresql.postgresql_ping: community.postgresql.postgresql_ping:
@@ -39,8 +39,3 @@
login_host: "{{ jms_asset.address }}" login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
db: "{{ jms_asset.spec_info.db_name }}" db: "{{ jms_asset.spec_info.db_name }}"
when:
- result is succeeded
- change_info is succeeded
register: result
failed_when: not result.is_available

View File

@@ -41,8 +41,8 @@
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}' name: '{{ jms_asset.spec_info.db_name }}'
script: "ALTER LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" script: "ALTER LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version"
ignore_errors: true
when: user_exist.query_results[0] | length != 0 when: user_exist.query_results[0] | length != 0
register: change_info
- name: Add SQLServer user - name: Add SQLServer user
community.general.mssql_script: community.general.mssql_script:
@@ -52,8 +52,8 @@
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}' name: '{{ jms_asset.spec_info.db_name }}'
script: "CREATE LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" script: "CREATE LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version"
ignore_errors: true
when: user_exist.query_results[0] | length == 0 when: user_exist.query_results[0] | length == 0
register: change_info
- name: Verify password - name: Verify password
community.general.mssql_script: community.general.mssql_script:
@@ -64,6 +64,3 @@
name: '{{ jms_asset.spec_info.db_name }}' name: '{{ jms_asset.spec_info.db_name }}'
script: | script: |
SELECT @@version SELECT @@version
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -1,41 +1,79 @@
- hosts: demo - hosts: demo
gather_facts: no gather_facts: no
tasks: tasks:
- name: Test privileged account - name: "Test privileged {{ jms_account.username }} account"
ansible.builtin.ping: 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: ansible.builtin.user:
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret | password_hash('des') }}" password: "{{ account.secret | password_hash('des') }}"
update_password: always update_password: always
ignore_errors: true
when: account.secret_type == "password" 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 - name: remove jumpserver ssh key
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
dest: "{{ ssh_params.dest }}" dest: "{{ ssh_params.dest }}"
regexp: "{{ ssh_params.regexp }}" regexp: "{{ ssh_params.regexp }}"
state: absent state: absent
when: when:
- account.secret_type == "ssh_key" - account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms" - ssh_params.strategy == "set_jms"
- name: Change SSH key - name: "Change {{ account.username }} SSH key"
ansible.builtin.authorized_key: ansible.builtin.authorized_key:
user: "{{ account.username }}" user: "{{ account.username }}"
key: "{{ account.secret }}" key: "{{ account.secret }}"
exclusive: "{{ ssh_params.exclusive }}" exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key" 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 - name: Refresh connection
ansible.builtin.meta: reset_connection ansible.builtin.meta: reset_connection
- name: Verify password - name: "Verify {{ account.username }} password"
ansible.builtin.ping: ansible.builtin.ping:
become: no become: no
vars: vars:
@@ -44,7 +82,7 @@
ansible_become: no ansible_become: no
when: account.secret_type == "password" when: account.secret_type == "password"
- name: Verify SSH key - name: "Verify {{ account.username }} SSH key"
ansible.builtin.ping: ansible.builtin.ping:
become: no become: no
vars: vars:

View File

@@ -4,8 +4,58 @@ category: host
type: type:
- AIX - AIX
method: change_secret method: change_secret
params:
- name: sudo
type: str
label: 'Sudo'
default: '/bin/whoami'
help_text: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
- name: shell
type: str
label: 'Shell'
default: '/bin/bash'
- name: home
type: str
label: "{{ 'Params home label' | trans }}"
default: ''
help_text: "{{ 'Params home help text' | trans }}"
- name: groups
type: str
label: "{{ 'Params groups label' | trans }}"
default: ''
help_text: "{{ 'Params groups help text' | trans }}"
i18n: i18n:
AIX account change secret: AIX account change secret:
zh: AIX 账号改密 zh: '使用 Ansible 模块 user 执行账号改密 (DES)'
ja: AIX アカウントのパスワード変更 ja: 'Ansible user モジュールを使用してアカウントのパスワード変更 (DES)'
en: 'Using Ansible module user to change account secret (DES)'
Params sudo help text:
zh: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
ja: 'コンマで区切って複数のコマンドを入力してください。例: /bin/whoami,/sbin/ifconfig'
en: 'Use commas to separate multiple commands, such as: /bin/whoami,/sbin/ifconfig'
Params home help text:
zh: '默认家目录 /home/{账号用户名}'
ja: 'デフォルトのホームディレクトリ /home/{アカウントユーザ名}'
en: 'Default home directory /home/{account username}'
Params groups help text:
zh: '请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)'
ja: 'グループを入力してください。複数のグループはコンマで区切ってください(既存のグループを入力してください)'
en: 'Please enter the group. Multiple groups are separated by commas (please enter the existing group)'
Params home label:
zh: '家目录'
ja: 'ホームディレクトリ'
en: 'Home'
Params groups label:
zh: '用户组'
ja: 'グループ'
en: 'Groups'

View File

@@ -1,21 +1,48 @@
- hosts: demo - hosts: demo
gather_facts: no gather_facts: no
tasks: tasks:
- name: Test privileged account - name: "Test privileged {{ jms_account.username }} account"
ansible.builtin.ping: 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: ansible.builtin.user:
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}" password: "{{ account.secret | password_hash('sha512') }}"
update_password: always update_password: always
ignore_errors: true
when: account.secret_type == "password" 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 - name: remove jumpserver ssh key
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
dest: "{{ ssh_params.dest }}" dest: "{{ ssh_params.dest }}"
@@ -25,17 +52,28 @@
- account.secret_type == "ssh_key" - account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms" - ssh_params.strategy == "set_jms"
- name: Change SSH key - name: "Change {{ account.username }} SSH key"
ansible.builtin.authorized_key: ansible.builtin.authorized_key:
user: "{{ account.username }}" user: "{{ account.username }}"
key: "{{ account.secret }}" key: "{{ account.secret }}"
exclusive: "{{ ssh_params.exclusive }}" exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key" 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 - name: Refresh connection
ansible.builtin.meta: reset_connection ansible.builtin.meta: reset_connection
- name: Verify password - name: "Verify {{ account.username }} password"
ansible.builtin.ping: ansible.builtin.ping:
become: no become: no
vars: vars:
@@ -44,7 +82,7 @@
ansible_become: no ansible_become: no
when: account.secret_type == "password" when: account.secret_type == "password"
- name: Verify SSH key - name: "Verify {{ account.username }} SSH key"
ansible.builtin.ping: ansible.builtin.ping:
become: no become: no
vars: vars:

View File

@@ -5,8 +5,59 @@ type:
- unix - unix
- linux - linux
method: change_secret method: change_secret
params:
- name: sudo
type: str
label: 'Sudo'
default: '/bin/whoami'
help_text: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
- name: shell
type: str
label: 'Shell'
default: '/bin/bash'
help_text: ''
- name: home
type: str
label: "{{ 'Params home label' | trans }}"
default: ''
help_text: "{{ 'Params home help text' | trans }}"
- name: groups
type: str
label: "{{ 'Params groups label' | trans }}"
default: ''
help_text: "{{ 'Params groups help text' | trans }}"
i18n: i18n:
Posix account change secret: Posix account change secret:
zh: Posix 账号改密 zh: '使用 Ansible 模块 user 执行账号改密 (SHA512)'
ja: Posix アカウントのパスワード変更 ja: 'Ansible user モジュールを使用して アカウントのパスワード変更 (SHA512)'
en: 'Using Ansible module user to change account secret (SHA512)'
Params sudo help text:
zh: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
ja: 'コンマで区切って複数のコマンドを入力してください。例: /bin/whoami,/sbin/ifconfig'
en: 'Use commas to separate multiple commands, such as: /bin/whoami,/sbin/ifconfig'
Params home help text:
zh: '默认家目录 /home/{账号用户名}'
ja: 'デフォルトのホームディレクトリ /home/{アカウントユーザ名}'
en: 'Default home directory /home/{account username}'
Params groups help text:
zh: '请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)'
ja: 'グループを入力してください。複数のグループはコンマで区切ってください(既存のグループを入力してください)'
en: 'Please enter the group. Multiple groups are separated by commas (please enter the existing group)'
Params home label:
zh: '家目录'
ja: 'ホームディレクトリ'
en: 'Home'
Params groups label:
zh: '用户组'
ja: 'グループ'
en: 'Groups'

View File

@@ -8,19 +8,16 @@
# debug: # debug:
# msg: "Username: {{ account.username }}, Password: {{ account.secret }}" # msg: "Username: {{ account.username }}, Password: {{ account.secret }}"
- name: Get groups of a Windows user
ansible.windows.win_user:
name: "{{ jms_account.username }}"
register: user_info
- name: Change password - name: Change password
ansible.windows.win_user: ansible.windows.win_user:
fullname: "{{ account.username}}"
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret }}" password: "{{ account.secret }}"
groups: "{{ user_info.groups[0].name }}" password_never_expires: yes
groups: "{{ params.groups }}"
groups_action: add groups_action: add
update_password: always update_password: always
ignore_errors: true
when: account.secret_type == "password" when: account.secret_type == "password"
- name: Refresh connection - name: Refresh connection

View File

@@ -5,8 +5,22 @@ method: change_secret
category: host category: host
type: type:
- windows - windows
params:
- name: groups
type: str
label: '用户组'
default: 'Users,Remote Desktop Users'
help_text: "{{ 'Params groups help text' | trans }}"
i18n: i18n:
Windows account change secret: Windows account change secret:
zh: Windows 账号改密 zh: '使用 Ansible 模块 win_user 执行 Windows 账号改密'
ja: Windows アカウントのパスワード変更 ja: 'Ansible win_user モジュールを使用して Windows アカウントのパスワード変更'
en: 'Using Ansible module win_user to change Windows account secret'
Params groups help text:
zh: '请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)'
ja: 'グループを入力してください。複数のグループはコンマで区切ってください(既存のグループを入力してください)'
en: 'Please enter the group. Multiple groups are separated by commas (please enter the existing group)'

View File

@@ -72,14 +72,14 @@ class ChangeSecretManager(AccountBasePlaybookManager):
return [] return []
asset = privilege_account.asset asset = privilege_account.asset
accounts = asset.accounts.exclude(username=privilege_account.username) accounts = asset.accounts.all()
accounts = accounts.filter(id__in=self.account_ids) accounts = accounts.filter(id__in=self.account_ids)
if self.secret_type: if self.secret_type:
accounts = accounts.filter(secret_type=self.secret_type) accounts = accounts.filter(secret_type=self.secret_type)
if settings.CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED: if settings.CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED:
accounts = accounts.filter(privileged=False).exclude( accounts = accounts.filter(privileged=False).exclude(
username__in=['root', 'administrator'] username__in=['root', 'administrator', privilege_account.username]
) )
return accounts return accounts

View File

@@ -1,3 +1,5 @@
import re
from django.utils import timezone from django.utils import timezone
__all__ = ['GatherAccountsFilter'] __all__ = ['GatherAccountsFilter']
@@ -13,8 +15,8 @@ class GatherAccountsFilter:
def mysql_filter(info): def mysql_filter(info):
result = {} result = {}
for _, user_dict in info.items(): for _, user_dict in info.items():
for username, data in user_dict.items(): for username, _ in user_dict.items():
if data.get('account_locked') == 'N': if len(username.split('.')) == 1:
result[username] = {} result[username] = {}
return result return result
@@ -27,18 +29,25 @@ class GatherAccountsFilter:
@staticmethod @staticmethod
def posix_filter(info): def posix_filter(info):
username_pattern = re.compile(r'^(\S+)')
ip_pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
login_time_pattern = re.compile(r'\w{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}')
result = {} result = {}
for line in info: for line in info:
data = line.split('@') usernames = username_pattern.findall(line)
if len(data) == 1: username = ''.join(usernames)
result[line] = {} if username:
result[username] = {}
else:
continue continue
ip_addrs = ip_pattern.findall(line)
if len(data) != 3: ip_addr = ''.join(ip_addrs)
continue if ip_addr:
username, address, dt = data result[username].update({'address': ip_addr})
date = timezone.datetime.strptime(f'{dt} +0800', '%b %d %H:%M:%S %Y %z') login_times = login_time_pattern.findall(line)
result[username] = {'address': address, 'date': date} if login_times:
date = timezone.datetime.strptime(f'{login_times[0]} +0800', '%b %d %H:%M:%S %Y %z')
result[username].update({'date': date})
return result return result
@staticmethod @staticmethod

View File

@@ -5,7 +5,7 @@
ansible.builtin.shell: ansible.builtin.shell:
cmd: > cmd: >
users=$(getent passwd | grep -v nologin | grep -v shutdown | awk -F":" '{ print $1 }');for i in $users; users=$(getent passwd | grep -v nologin | grep -v shutdown | awk -F":" '{ print $1 }');for i in $users;
do k=$(last -w -F $i -1 | head -1 | grep -v ^$ | awk '{ print $1"@"$3"@"$5,$6,$7,$8 }') do k=$(last -w -F $i -1 | head -1 | grep -v ^$ | awk '{ print $0 }')
if [ -n "$k" ]; then if [ -n "$k" ]; then
echo $k echo $k
else else

View File

@@ -8,5 +8,6 @@ method: gather_accounts
i18n: i18n:
Posix account gather: Posix account gather:
zh: Posix 账号收集 zh: 使用命令 getent passwd 收集 Posix 资产账号
ja: Posix アカウント収集 ja: コマンド getent を使用してアセットアカウント収集する
en: Using command getent to gather accounts

View File

@@ -8,5 +8,6 @@ type:
i18n: i18n:
Windows account gather: Windows account gather:
zh: Windows 账号收集 zh: 使用命令 net user 收集 Windows 账号
ja: Windows アカウント収集 ja: コマンド net user を使用して Windows アカウント収集する
en: Using command net user to gather accounts

View File

@@ -38,8 +38,8 @@
db: "{{ jms_asset.spec_info.db_name }}" db: "{{ jms_asset.spec_info.db_name }}"
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret }}" password: "{{ account.secret }}"
ignore_errors: true
when: db_info is succeeded when: db_info is succeeded
register: change_info
- name: Verify password - name: Verify password
mongodb_ping: mongodb_ping:
@@ -53,6 +53,3 @@
ssl_certfile: "{{ jms_asset.secret_info.client_key }}" ssl_certfile: "{{ jms_asset.secret_info.client_key }}"
connection_options: connection_options:
- tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}" - tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}"
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -7,5 +7,6 @@ method: push_account
i18n: i18n:
MongoDB account push: MongoDB account push:
zh: MongoDB 账号推送 zh: 使用 Ansible 模块 mongodb 执行 MongoDB 账号推送
ja: MongoDB アカウントプッシュ ja: Ansible mongodb モジュールを使用してアカウントプッシュする
en: Using Ansible module mongodb to push account

View File

@@ -28,8 +28,8 @@
password: "{{ account.secret }}" password: "{{ account.secret }}"
host: "%" host: "%"
priv: "{{ account.username + '.*:USAGE' if db_name == '' else db_name + '.*:ALL' }}" priv: "{{ account.username + '.*:USAGE' if db_name == '' else db_name + '.*:ALL' }}"
ignore_errors: true
when: db_info is succeeded when: db_info is succeeded
register: change_info
- name: Verify password - name: Verify password
community.mysql.mysql_info: community.mysql.mysql_info:
@@ -38,6 +38,3 @@
login_host: "{{ jms_asset.address }}" login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
filter: version filter: version
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -8,5 +8,6 @@ method: push_account
i18n: i18n:
MySQL account push: MySQL account push:
zh: MySQL 账号推送 zh: 使用 Ansible 模块 mysql 执行 MySQL 账号推送
ja: MySQL アカウントプッシュ ja: Ansible mysql モジュールを使用してアカウントプッシュする
en: Using Ansible module mysql to push account

View File

@@ -29,8 +29,8 @@
mode: "{{ jms_account.mode }}" mode: "{{ jms_account.mode }}"
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret }}" password: "{{ account.secret }}"
ignore_errors: true
when: db_info is succeeded when: db_info is succeeded
register: change_info
- name: Verify password - name: Verify password
oracle_ping: oracle_ping:
@@ -39,6 +39,3 @@
login_host: "{{ jms_asset.address }}" login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}" login_database: "{{ jms_asset.spec_info.db_name }}"
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -7,5 +7,6 @@ method: push_account
i18n: i18n:
Oracle account push: Oracle account push:
zh: Oracle 账号推送 zh: 使用 Python 模块 oracledb 执行 Oracle 账号推送
ja: Oracle アカウントプッシュ ja: Python oracledb モジュールを使用してアカウントプッシュする
en: Using Python module oracledb to push account

View File

@@ -29,8 +29,8 @@
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret }}" password: "{{ account.secret }}"
role_attr_flags: LOGIN role_attr_flags: LOGIN
ignore_errors: true
when: result is succeeded when: result is succeeded
register: change_info
- name: Verify password - name: Verify password
community.postgresql.postgresql_ping: community.postgresql.postgresql_ping:
@@ -42,5 +42,3 @@
when: when:
- result is succeeded - result is succeeded
- change_info is succeeded - change_info is succeeded
register: result
failed_when: not result.is_available

View File

@@ -7,5 +7,6 @@ method: push_account
i18n: i18n:
PostgreSQL account push: PostgreSQL account push:
zh: PostgreSQL 账号推送 zh: 使用 Ansible 模块 postgresql 执行 PostgreSQL 账号推送
ja: PostgreSQL アカウントプッシュ ja: Ansible postgresql モジュールを使用してアカウントプッシュする
en: Using Ansible module postgresql to push account

View File

@@ -41,6 +41,7 @@
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}' name: '{{ jms_asset.spec_info.db_name }}'
script: "ALTER LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" script: "ALTER LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version"
ignore_errors: true
when: user_exist.query_results[0] | length != 0 when: user_exist.query_results[0] | length != 0
register: change_info register: change_info
@@ -52,6 +53,7 @@
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}' name: '{{ jms_asset.spec_info.db_name }}'
script: "CREATE LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" script: "CREATE LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version"
ignore_errors: true
when: user_exist.query_results[0] | length == 0 when: user_exist.query_results[0] | length == 0
register: change_info register: change_info
@@ -64,6 +66,3 @@
name: '{{ jms_asset.spec_info.db_name }}' name: '{{ jms_asset.spec_info.db_name }}'
script: | script: |
SELECT @@version SELECT @@version
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -7,5 +7,6 @@ method: push_account
i18n: i18n:
SQLServer account push: SQLServer account push:
zh: SQLServer 账号推送 zh: 使用 Ansible 模块 mssql 执行 SQLServer 账号推送
ja: SQLServer アカウントプッシュ ja: Ansible mssql モジュールを使用してアカウントプッシュする
en: Using Ansible module mssql to push account

View File

@@ -8,7 +8,7 @@
ansible.builtin.user: ansible.builtin.user:
name: "{{ account.username }}" name: "{{ account.username }}"
shell: "{{ params.shell }}" shell: "{{ params.shell }}"
home: "{{ '/home/' + account.username }}" home: "{{ params.home | default('/home/' + account.username, true) }}"
groups: "{{ params.groups }}" groups: "{{ params.groups }}"
expires: -1 expires: -1
state: present state: present
@@ -18,20 +18,6 @@
name: "{{ account.username }}" name: "{{ account.username }}"
state: present state: present
- name: Check home dir exists
ansible.builtin.stat:
path: "{{ '/home/' + account.username }}"
register: home_existed
- name: Set home dir permission
ansible.builtin.file:
path: "{{ '/home/' + account.username }}"
owner: "{{ account.username }}"
group: "{{ account.username }}"
mode: "0700"
when:
- home_existed.stat.exists == true
- name: Add user groups - name: Add user groups
ansible.builtin.user: ansible.builtin.user:
name: "{{ account.username }}" name: "{{ account.username }}"
@@ -43,6 +29,7 @@
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}" password: "{{ account.secret | password_hash('sha512') }}"
update_password: always update_password: always
ignore_errors: true
when: account.secret_type == "password" when: account.secret_type == "password"
- name: remove jumpserver ssh key - name: remove jumpserver ssh key

View File

@@ -16,6 +16,12 @@ params:
label: 'Shell' label: 'Shell'
default: '/bin/bash' default: '/bin/bash'
- name: home
type: str
label: '家目录'
default: ''
help_text: '默认家目录 /home/系统用户名: /home/username'
- name: groups - name: groups
type: str type: str
label: '用户组' label: '用户组'
@@ -24,6 +30,7 @@ params:
i18n: i18n:
Aix account push: Aix account push:
zh: Aix 账号推送 zh: 使用 Ansible 模块 user 执行 Aix 账号推送 (DES)
ja: Aix アカウントプッシュ ja: Ansible user モジュールを使用して Aix アカウントプッシュする (DES)
en: Using Ansible module user to push account (DES)

View File

@@ -8,7 +8,7 @@
ansible.builtin.user: ansible.builtin.user:
name: "{{ account.username }}" name: "{{ account.username }}"
shell: "{{ params.shell }}" shell: "{{ params.shell }}"
home: "{{ '/home/' + account.username }}" home: "{{ params.home | default('/home/' + account.username, true) }}"
groups: "{{ params.groups }}" groups: "{{ params.groups }}"
expires: -1 expires: -1
state: present state: present
@@ -18,20 +18,6 @@
name: "{{ account.username }}" name: "{{ account.username }}"
state: present state: present
- name: Check home dir exists
ansible.builtin.stat:
path: "{{ '/home/' + account.username }}"
register: home_existed
- name: Set home dir permission
ansible.builtin.file:
path: "{{ '/home/' + account.username }}"
owner: "{{ account.username }}"
group: "{{ account.username }}"
mode: "0700"
when:
- home_existed.stat.exists == true
- name: Add user groups - name: Add user groups
ansible.builtin.user: ansible.builtin.user:
name: "{{ account.username }}" name: "{{ account.username }}"
@@ -43,6 +29,7 @@
name: "{{ account.username }}" name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}" password: "{{ account.secret | password_hash('sha512') }}"
update_password: always update_password: always
ignore_errors: true
when: account.secret_type == "password" when: account.secret_type == "password"
- name: remove jumpserver ssh key - name: remove jumpserver ssh key

View File

@@ -18,6 +18,12 @@ params:
default: '/bin/bash' default: '/bin/bash'
help_text: '' help_text: ''
- name: home
type: str
label: '家目录'
default: ''
help_text: '默认家目录 /home/系统用户名: /home/username'
- name: groups - name: groups
type: str type: str
label: '用户组' label: '用户组'
@@ -26,5 +32,6 @@ params:
i18n: i18n:
Posix account push: Posix account push:
zh: Posix 账号推送 zh: 使用 Ansible 模块 user 执行账号推送 (sha512)
ja: Posix アカウントプッシュ ja: Ansible user モジュールを使用してアカウントプッシュする (sha512)
en: Using Ansible module user to push account (sha512)

View File

@@ -17,6 +17,7 @@
groups: "{{ params.groups }}" groups: "{{ params.groups }}"
groups_action: add groups_action: add
update_password: always update_password: always
ignore_errors: true
when: account.secret_type == "password" when: account.secret_type == "password"
- name: Refresh connection - name: Refresh connection

View File

@@ -14,5 +14,6 @@ params:
i18n: i18n:
Windows account push: Windows account push:
zh: Windows 账号推送 zh: 使用 Ansible 模块 win_user 执行 Windows 账号推送
ja: Windows アカウントプッシュ ja: Ansible win_user モジュールを使用して Windows アカウントプッシュする
en: Using Ansible module win_user to push account

View File

@@ -1,13 +0,0 @@
id: verify_account_by_ssh
name: "{{ 'SSH account verify' | trans }}"
category:
- device
- host
type:
- all
method: verify_account
i18n:
SSH account verify:
zh: SSH 账号验证
ja: SSH アカウントの検証

View File

@@ -0,0 +1,15 @@
- hosts: custom
gather_facts: no
vars:
ansible_shell_type: sh
ansible_connection: local
tasks:
- name: Verify account (pyfreerdp)
rdp_ping:
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_secret_type: "{{ account.secret_type }}"
login_private_key_path: "{{ account.private_key_path }}"

View File

@@ -0,0 +1,13 @@
id: verify_account_by_rdp
name: "{{ 'Windows rdp account verify' | trans }}"
category:
- host
type:
- windows
method: verify_account
i18n:
Windows rdp account verify:
zh: 使用 Python 模块 pyfreerdp 验证账号
ja: Python モジュール pyfreerdp を使用してアカウントを検証する
en: Using Python module pyfreerdp to verify account

View File

@@ -4,11 +4,11 @@
ansible_connection: local ansible_connection: local
tasks: tasks:
- name: Verify account - name: Verify account (paramiko)
ssh_ping: ssh_ping:
login_host: "{{ jms_asset.address }}" login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}" login_port: "{{ jms_asset.port }}"
login_user: "{{ account.username }}" login_user: "{{ account.username }}"
login_password: "{{ account.secret }}" login_password: "{{ account.secret }}"
login_secret_type: "{{ jms_account.secret_type }}" login_secret_type: "{{ account.secret_type }}"
login_private_key_path: "{{ jms_account.private_key_path }}" login_private_key_path: "{{ account.private_key_path }}"

View File

@@ -0,0 +1,14 @@
id: verify_account_by_ssh
name: "{{ 'SSH account verify' | trans }}"
category:
- device
- host
type:
- all
method: verify_account
i18n:
SSH account verify:
zh: 使用 Python 模块 paramiko 验证账号
ja: Python モジュール paramiko を使用してアカウントを検証する
en: Using Python module paramiko to verify account

View File

@@ -7,5 +7,6 @@ method: verify_account
i18n: i18n:
MongoDB account verify: MongoDB account verify:
zh: MongoDB 账号验证 zh: 使用 Ansible 模块 mongodb 验证账号
ja: MongoDB アカウント検証 ja: Ansible mongodb モジュールを使用してアカウント検証する
en: Using Ansible module mongodb to verify account

View File

@@ -8,5 +8,7 @@ method: verify_account
i18n: i18n:
MySQL account verify: MySQL account verify:
zh: MySQL 账号验证 zh: 使用 Ansible 模块 mysql 验证账号
ja: MySQL アカウント検証 ja: Ansible mysql モジュールを使用してアカウント検証する
en: Using Ansible module mysql to verify account

View File

@@ -7,5 +7,6 @@ method: verify_account
i18n: i18n:
Oracle account verify: Oracle account verify:
zh: Oracle 账号验证 zh: 使用 Python 模块 oracledb 验证账号
ja: Oracle アカウント検証 ja: Python モジュール oracledb を使用してアカウント検証する
en: Using Python module oracledb to verify account

View File

@@ -7,5 +7,6 @@ method: verify_account
i18n: i18n:
PostgreSQL account verify: PostgreSQL account verify:
zh: PostgreSQL 账号验证 zh: 使用 Ansible 模块 postgresql 验证账号
ja: PostgreSQL アカウント検証 ja: Ansible postgresql モジュールを使用してアカウント検証する
en: Using Ansible module postgresql to verify account

View File

@@ -7,5 +7,6 @@ method: verify_account
i18n: i18n:
SQLServer account verify: SQLServer account verify:
zh: SQLServer 账号验证 zh: 使用 Ansible 模块 mssql 验证账号
ja: SQLServer アカウント検証 ja: Ansible mssql モジュールを使用してアカウント検証する
en: Using Ansible module mssql to verify account

View File

@@ -8,5 +8,6 @@ method: verify_account
i18n: i18n:
Posix account verify: Posix account verify:
zh: Posix 账号验证 zh: 使用 Ansible 模块 ping 验证账号
ja: Posix アカウント検証 ja: Ansible ping モジュールを使用してアカウント検証する
en: Using Ansible module ping to verify account

View File

@@ -7,6 +7,7 @@ type:
- windows - windows
i18n: i18n:
Windows account verify: Windows account verify:
zh: Windows 账号验证 zh: 使用 Ansible 模块 win_ping 验证账号
ja: Windows アカウント検証 ja: Ansible win_ping モジュールを使用してアカウント検証する
en: Using Ansible module win_ping to verify account

View File

@@ -7,12 +7,14 @@ class SecretType(TextChoices):
SSH_KEY = 'ssh_key', _('SSH key') SSH_KEY = 'ssh_key', _('SSH key')
ACCESS_KEY = 'access_key', _('Access key') ACCESS_KEY = 'access_key', _('Access key')
TOKEN = 'token', _('Token') TOKEN = 'token', _('Token')
API_KEY = 'api_key', _("API key")
class AliasAccount(TextChoices): class AliasAccount(TextChoices):
ALL = '@ALL', _('All') ALL = '@ALL', _('All')
INPUT = '@INPUT', _('Manual input') INPUT = '@INPUT', _('Manual input')
USER = '@USER', _('Dynamic user') USER = '@USER', _('Dynamic user')
ANON = '@ANON', _('Anonymous account')
class Source(TextChoices): class Source(TextChoices):

View File

@@ -48,7 +48,7 @@ class SecretStrategy(models.TextChoices):
class SSHKeyStrategy(models.TextChoices): class SSHKeyStrategy(models.TextChoices):
add = 'add', _('Append SSH KEY') add = 'add', _('Append SSH KEY')
set = 'set', _('Empty and append SSH KEY') set = 'set', _('Empty and append SSH KEY')
set_jms = 'set_jms', _('Replace (The key generated by JumpServer) ') set_jms = 'set_jms', _('Replace (Replace only keys pushed by JumpServer) ')
class TriggerChoice(models.TextChoices, TreeChoices): class TriggerChoice(models.TextChoices, TreeChoices):

View File

@@ -5,7 +5,6 @@ from django_filters import rest_framework as drf_filters
from assets.models import Node from assets.models import Node
from common.drf.filters import BaseFilterSet from common.drf.filters import BaseFilterSet
from .models import Account, GatheredAccount from .models import Account, GatheredAccount
@@ -46,7 +45,7 @@ class AccountFilterSet(BaseFilterSet):
class Meta: class Meta:
model = Account model = Account
fields = ['id', 'asset_id'] fields = ['id', 'asset_id', 'source_id', 'secret_type']
class GatheredAccountFilterSet(BaseFilterSet): class GatheredAccountFilterSet(BaseFilterSet):

View File

@@ -1,12 +1,14 @@
# Generated by Django 3.2.14 on 2022-12-28 07:29 # Generated by Django 3.2.14 on 2022-12-28 07:29
import uuid
import django.db.models.deletion
import simple_history.models
from django.conf import settings
from django.db import migrations, models
import common.db.encoder import common.db.encoder
import common.db.fields import common.db.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
import uuid
class Migration(migrations.Migration): class Migration(migrations.Migration):
@@ -29,13 +31,16 @@ class Migration(migrations.Migration):
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id', ('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('connectivity', models.CharField(choices=[('-', 'Unknown'), ('ok', 'Ok'), ('err', 'Error')], default='-', max_length=16, verbose_name='Connectivity')), ('connectivity',
models.CharField(choices=[('-', 'Unknown'), ('ok', 'Ok'), ('err', 'Error')], default='-',
max_length=16, verbose_name='Connectivity')),
('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')), ('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')),
('name', models.CharField(max_length=128, verbose_name='Name')), ('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')), ('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
('secret_type', models.CharField( ('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')), ('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')), ('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('privileged', models.BooleanField(default=False, verbose_name='Privileged')), ('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')), ('is_active', models.BooleanField(default=True, verbose_name='Is active')),
@@ -61,7 +66,8 @@ class Migration(migrations.Migration):
('id', models.UUIDField(db_index=True, default=uuid.uuid4)), ('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
('secret_type', models.CharField( ('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')), ('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')), ('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('version', models.IntegerField(default=0, verbose_name='Version')), ('version', models.IntegerField(default=0, verbose_name='Version')),
('history_id', models.AutoField(primary_key=True, serialize=False)), ('history_id', models.AutoField(primary_key=True, serialize=False)),
@@ -96,7 +102,8 @@ class Migration(migrations.Migration):
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')), ('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
('secret_type', models.CharField( ('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')), ('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')), ('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('privileged', models.BooleanField(default=False, verbose_name='Privileged')), ('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')), ('is_active', models.BooleanField(default=True, verbose_name='Is active')),

View File

@@ -1,11 +1,13 @@
# Generated by Django 3.2.16 on 2022-12-30 08:08 # Generated by Django 3.2.16 on 2022-12-30 08:08
import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import common.db.encoder import common.db.encoder
import common.db.fields import common.db.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration): class Migration(migrations.Migration):
@@ -53,7 +55,8 @@ class Migration(migrations.Migration):
primary_key=True, serialize=False, to='assets.baseautomation')), primary_key=True, serialize=False, to='assets.baseautomation')),
('secret_type', models.CharField( ('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')), ('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret_strategy', models.CharField(choices=[('specific', 'Specific password'), ('secret_strategy', models.CharField(choices=[('specific', 'Specific password'),
('random_one', 'All assets use the same random password'), ('random_one', 'All assets use the same random password'),
('random_all', ('random_all',
@@ -156,7 +159,8 @@ class Migration(migrations.Migration):
primary_key=True, serialize=False, to='assets.baseautomation')), primary_key=True, serialize=False, to='assets.baseautomation')),
('secret_type', models.CharField( ('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')), ('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret_strategy', models.CharField(choices=[('specific', 'Specific password'), ('secret_strategy', models.CharField(choices=[('specific', 'Specific password'),
('random_one', 'All assets use the same random password'), ('random_one', 'All assets use the same random password'),
('random_all', ('random_all',

View File

@@ -0,0 +1,29 @@
# Generated by Django 3.2.17 on 2023-05-06 06:43
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('accounts', '0010_gatheraccountsautomation_is_sync_account'),
]
operations = [
migrations.AddField(
model_name='accounttemplate',
name='su_from',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='su_to', to='accounts.accounttemplate', verbose_name='Su from'),
),
migrations.AlterField(
model_name='changesecretautomation',
name='ssh_key_change_strategy',
field=models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy'),
),
migrations.AlterField(
model_name='pushaccountautomation',
name='ssh_key_change_strategy',
field=models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy'),
),
]

View File

@@ -1,3 +1,3 @@
from .base import *
from .account import * from .account import *
from .automations import * from .automations import *
from .base import *

View File

@@ -1,4 +1,6 @@
from django.db import models from django.db import models
from django.db.models import Count, Q
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
@@ -86,26 +88,44 @@ class Account(AbsConnectivity, BaseAccount):
def has_secret(self): def has_secret(self):
return bool(self.secret) return bool(self.secret)
@classmethod
def get_special_account(cls, name):
if name == AliasAccount.INPUT.value:
return cls.get_manual_account()
elif name == AliasAccount.ANON.value:
return cls.get_anonymous_account()
else:
return cls(name=name, username=name, secret=None)
@classmethod @classmethod
def get_manual_account(cls): def get_manual_account(cls):
""" @INPUT 手动登录的账号(any) """ """ @INPUT 手动登录的账号(any) """
return cls(name=AliasAccount.INPUT.label, username=AliasAccount.INPUT.value, secret=None) return cls(name=AliasAccount.INPUT.label, username=AliasAccount.INPUT.value, secret=None)
@lazyproperty @classmethod
def versions(self): def get_anonymous_account(cls):
return self.history.count() return cls(name=AliasAccount.ANON.label, username=AliasAccount.ANON.value, secret=None)
@classmethod @classmethod
def get_user_account(cls): def get_user_account(cls):
""" @USER 动态用户的账号(self) """ """ @USER 动态用户的账号(self) """
return cls(name=AliasAccount.USER.label, username=AliasAccount.USER.value, secret=None) return cls(name=AliasAccount.USER.label, username=AliasAccount.USER.value, secret=None)
@lazyproperty
def versions(self):
return self.history.count()
def get_su_from_accounts(self): def get_su_from_accounts(self):
""" 排除自己和以自己为 su-from 的账号 """ """ 排除自己和以自己为 su-from 的账号 """
return self.asset.accounts.exclude(id=self.id).exclude(su_from=self) return self.asset.accounts.exclude(id=self.id).exclude(su_from=self)
class AccountTemplate(BaseAccount): class AccountTemplate(BaseAccount):
su_from = models.ForeignKey(
'self', related_name='su_to', null=True,
on_delete=models.SET_NULL, verbose_name=_("Su from")
)
class Meta: class Meta:
verbose_name = _('Account template') verbose_name = _('Account template')
unique_together = ( unique_together = (
@@ -116,5 +136,65 @@ class AccountTemplate(BaseAccount):
('change_accounttemplatesecret', _('Can change asset account template secret')), ('change_accounttemplatesecret', _('Can change asset account template secret')),
] ]
@classmethod
def get_su_from_account_templates(cls, pk=None):
if pk is None:
return cls.objects.all()
return cls.objects.exclude(Q(id=pk) | Q(su_from_id=pk))
def __str__(self):
return f'{self.name}({self.username})'
def get_su_from_account(self, asset):
su_from = self.su_from
if su_from and asset.platform.su_enabled:
account = asset.accounts.filter(
username=su_from.username,
secret_type=su_from.secret_type
).first()
return account
def __str__(self): def __str__(self):
return self.username return self.username
@staticmethod
def bulk_update_accounts(accounts, data):
history_model = Account.history.model
account_ids = accounts.values_list('id', flat=True)
history_accounts = history_model.objects.filter(id__in=account_ids)
account_id_count_map = {
str(i['id']): i['count']
for i in history_accounts.values('id').order_by('id')
.annotate(count=Count(1)).values('id', 'count')
}
for account in accounts:
account_id = str(account.id)
account.version = account_id_count_map.get(account_id) + 1
for k, v in data.items():
setattr(account, k, v)
Account.objects.bulk_update(accounts, ['version', 'secret'])
@staticmethod
def bulk_create_history_accounts(accounts, user_id):
history_model = Account.history.model
history_account_objs = []
for account in accounts:
history_account_objs.append(
history_model(
id=account.id,
version=account.version,
secret=account.secret,
secret_type=account.secret_type,
history_user_id=user_id,
history_date=timezone.now()
)
)
history_model.objects.bulk_create(history_account_objs)
def bulk_sync_account_secret(self, accounts, user_id):
""" 批量同步账号密码 """
if not accounts:
return
self.bulk_update_accounts(accounts, {'secret': self.secret})
self.bulk_create_history_accounts(accounts, user_id)

View File

@@ -28,7 +28,6 @@ class ChangeSecretMixin(models.Model):
default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy') default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy')
) )
accounts: list[str] # account usernames
get_all_assets: callable # get all assets get_all_assets: callable # get all assets
class Meta: class Meta:

View File

@@ -1,9 +1,11 @@
import uuid import uuid
from copy import deepcopy
from django.db import IntegrityError from django.db import IntegrityError
from django.db.models import Q from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from rest_framework.generics import get_object_or_404
from rest_framework.validators import UniqueTogetherValidator from rest_framework.validators import UniqueTogetherValidator
from accounts.const import SecretType, Source, AccountInvalidPolicy from accounts.const import SecretType, Source, AccountInvalidPolicy
@@ -21,8 +23,8 @@ logger = get_logger(__name__)
class AccountCreateUpdateSerializerMixin(serializers.Serializer): class AccountCreateUpdateSerializerMixin(serializers.Serializer):
template = serializers.PrimaryKeyRelatedField( template = serializers.PrimaryKeyRelatedField(
queryset=AccountTemplate.objects, queryset=AccountTemplate.objects, required=False,
required=False, label=_("Template"), write_only=True label=_("Template"), write_only=True, allow_null=True
) )
push_now = serializers.BooleanField( push_now = serializers.BooleanField(
default=False, label=_("Push now"), write_only=True default=False, label=_("Push now"), write_only=True
@@ -32,9 +34,10 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
) )
on_invalid = LabeledChoiceField( on_invalid = LabeledChoiceField(
choices=AccountInvalidPolicy.choices, default=AccountInvalidPolicy.ERROR, choices=AccountInvalidPolicy.choices, default=AccountInvalidPolicy.ERROR,
write_only=True, label=_('Exist policy') write_only=True, allow_null=True, label=_('Exist policy'),
) )
_template = None _template = None
clean_auth_fields: callable
class Meta: class Meta:
fields = ['template', 'push_now', 'params', 'on_invalid'] fields = ['template', 'push_now', 'params', 'on_invalid']
@@ -58,10 +61,6 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
self.from_template_if_need(data) self.from_template_if_need(data)
self.set_uniq_name_if_need(data, asset) self.set_uniq_name_if_need(data, asset)
def to_internal_value(self, data):
self.from_template_if_need(data)
return super().to_internal_value(data)
def set_uniq_name_if_need(self, initial_data, asset): def set_uniq_name_if_need(self, initial_data, asset):
name = initial_data.get('name') name = initial_data.get('name')
if name is not None: if name is not None:
@@ -91,7 +90,7 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
self._template = template self._template = template
# Set initial data from template # Set initial data from template
ignore_fields = ['id', 'date_created', 'date_updated', 'org_id'] ignore_fields = ['id', 'date_created', 'date_updated', 'su_from', 'org_id']
field_names = [ field_names = [
field.name for field in template._meta.fields field.name for field in template._meta.fields
if field.name not in ignore_fields if field.name not in ignore_fields
@@ -103,6 +102,15 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
continue continue
attrs[name] = value attrs[name] = value
initial_data.update(attrs) initial_data.update(attrs)
initial_data.update({
'source': Source.TEMPLATE,
'source_id': str(template.id)
})
asset_id = initial_data.get('asset')
if isinstance(asset_id, list) or not asset_id:
return
asset = get_object_or_404(Asset, pk=asset_id)
initial_data['su_from'] = template.get_su_from_account(asset)
@staticmethod @staticmethod
def push_account_if_need(instance, push_now, params, stat): def push_account_if_need(instance, push_now, params, stat):
@@ -147,17 +155,10 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
else: else:
raise serializers.ValidationError('Account already exists') raise serializers.ValidationError('Account already exists')
def generate_source_data(self, validated_data):
template = self._template
if template is None:
return
validated_data['source'] = Source.TEMPLATE
validated_data['source_id'] = str(template.id)
def create(self, validated_data): def create(self, validated_data):
push_now = validated_data.pop('push_now', None) push_now = validated_data.pop('push_now', None)
params = validated_data.pop('params', None) params = validated_data.pop('params', None)
self.generate_source_data(validated_data) self.clean_auth_fields(validated_data)
instance, stat = self.do_create(validated_data) instance, stat = self.do_create(validated_data)
self.push_account_if_need(instance, push_now, params, stat) self.push_account_if_need(instance, push_now, params, stat)
return instance return instance
@@ -197,8 +198,11 @@ class AccountAssetSerializer(serializers.ModelSerializer):
class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerializer): class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerializer):
asset = AccountAssetSerializer(label=_('Asset')) asset = AccountAssetSerializer(label=_('Asset'))
source = LabeledChoiceField(choices=Source.choices, label=_("Source"), read_only=True)
has_secret = serializers.BooleanField(label=_("Has secret"), read_only=True) has_secret = serializers.BooleanField(label=_("Has secret"), read_only=True)
source = LabeledChoiceField(
choices=Source.choices, label=_("Source"), required=False,
allow_null=True, default=Source.LOCAL
)
su_from = ObjectRelatedField( su_from = ObjectRelatedField(
required=False, queryset=Account.objects, allow_null=True, allow_empty=True, required=False, queryset=Account.objects, allow_null=True, allow_empty=True,
label=_('Su from'), attrs=('id', 'name', 'username') label=_('Su from'), attrs=('id', 'name', 'username')
@@ -211,11 +215,12 @@ class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerialize
'source', 'source_id', 'connectivity', 'source', 'source_id', 'connectivity',
] + AccountCreateUpdateSerializerMixin.Meta.fields ] + AccountCreateUpdateSerializerMixin.Meta.fields
read_only_fields = BaseAccountSerializer.Meta.read_only_fields + [ read_only_fields = BaseAccountSerializer.Meta.read_only_fields + [
'source', 'source_id', 'connectivity' 'connectivity'
] ]
extra_kwargs = { extra_kwargs = {
**BaseAccountSerializer.Meta.extra_kwargs, **BaseAccountSerializer.Meta.extra_kwargs,
'name': {'required': False}, 'name': {'required': False},
'source_id': {'required': False, 'allow_null': True},
} }
@classmethod @classmethod
@@ -238,18 +243,25 @@ class AssetAccountBulkSerializerResultSerializer(serializers.Serializer):
class AssetAccountBulkSerializer( class AssetAccountBulkSerializer(
AccountCreateUpdateSerializerMixin, AuthValidateMixin, serializers.ModelSerializer AccountCreateUpdateSerializerMixin, AuthValidateMixin, serializers.ModelSerializer
): ):
su_from_username = serializers.CharField(
max_length=128, required=False, write_only=True, allow_null=True, label=_("Su from"),
allow_blank=True,
)
assets = serializers.PrimaryKeyRelatedField(queryset=Asset.objects, many=True, label=_('Assets')) assets = serializers.PrimaryKeyRelatedField(queryset=Asset.objects, many=True, label=_('Assets'))
class Meta: class Meta:
model = Account model = Account
fields = [ fields = [
'name', 'username', 'secret', 'secret_type', 'name', 'username', 'secret', 'secret_type', 'passphrase',
'privileged', 'is_active', 'comment', 'template', 'privileged', 'is_active', 'comment', 'template',
'on_invalid', 'push_now', 'assets', 'on_invalid', 'push_now', 'assets', 'su_from_username',
'source', 'source_id',
] ]
extra_kwargs = { extra_kwargs = {
'name': {'required': False}, 'name': {'required': False},
'secret_type': {'required': False}, 'secret_type': {'required': False},
'source': {'required': False, 'allow_null': True},
'source_id': {'required': False, 'allow_null': True},
} }
def set_initial_value(self): def set_initial_value(self):
@@ -293,8 +305,21 @@ class AssetAccountBulkSerializer(
raise serializers.ValidationError(_('Account already exists')) raise serializers.ValidationError(_('Account already exists'))
return instance, True, 'created' return instance, True, 'created'
def generate_su_from_data(self, validated_data):
template = self._template
asset = validated_data['asset']
su_from = validated_data.get('su_from')
su_from_username = validated_data.pop('su_from_username', None)
if template:
su_from = template.get_su_from_account(asset)
elif su_from_username:
su_from = asset.accounts.filter(username=su_from_username).first()
validated_data['su_from'] = su_from
def perform_create(self, vd, handler): def perform_create(self, vd, handler):
lookup = self.get_filter_lookup(vd) lookup = self.get_filter_lookup(vd)
vd = deepcopy(vd)
self.generate_su_from_data(vd)
try: try:
instance, changed, state = handler(vd, lookup) instance, changed, state = handler(vd, lookup)
except IntegrityError: except IntegrityError:
@@ -335,6 +360,7 @@ class AssetAccountBulkSerializer(
vd = vd.copy() vd = vd.copy()
vd['asset'] = asset vd['asset'] = asset
try: try:
self.clean_auth_fields(vd)
instance, changed, state = self.perform_create(vd, create_handler) instance, changed, state = self.perform_create(vd, create_handler)
_results[asset] = { _results[asset] = {
'changed': changed, 'instance': instance.id, 'state': state 'changed': changed, 'instance': instance.id, 'state': state
@@ -375,7 +401,6 @@ class AssetAccountBulkSerializer(
def create(self, validated_data): def create(self, validated_data):
push_now = validated_data.pop('push_now', False) push_now = validated_data.pop('push_now', False)
self.generate_source_data(validated_data)
results = self.perform_bulk_create(validated_data) results = self.perform_bulk_create(validated_data)
self.push_accounts_if_need(results, push_now) self.push_accounts_if_need(results, push_now)
for res in results: for res in results:

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from accounts.models import AccountBackupAutomation, AccountBackupExecution from accounts.models import AccountBackupAutomation, AccountBackupExecution

View File

@@ -78,4 +78,8 @@ class BaseAccountSerializer(AuthValidateMixin, BulkOrgResourceModelSerializer):
] ]
extra_kwargs = { extra_kwargs = {
'spec_info': {'label': _('Spec info')}, 'spec_info': {'label': _('Spec info')},
'username': {'help_text': _(
"Tip: If no username is required for authentication, fill in `null`, "
"If AD account, like `username@domain`"
)},
} }

View File

@@ -1,86 +1,51 @@
from django.db.transaction import atomic from django.utils.translation import ugettext_lazy as _
from django.db.utils import IntegrityError from rest_framework import serializers
from accounts.models import AccountTemplate, Account from accounts.models import AccountTemplate, Account
from assets.models import Asset
from common.serializers import SecretReadableMixin from common.serializers import SecretReadableMixin
from common.serializers.fields import ObjectRelatedField
from .base import BaseAccountSerializer from .base import BaseAccountSerializer
class AccountTemplateSerializer(BaseAccountSerializer): class AccountTemplateSerializer(BaseAccountSerializer):
is_sync_account = serializers.BooleanField(default=False, write_only=True)
_is_sync_account = False
su_from = ObjectRelatedField(
required=False, queryset=AccountTemplate.objects, allow_null=True,
allow_empty=True, label=_('Su from'), attrs=('id', 'name', 'username')
)
class Meta(BaseAccountSerializer.Meta): class Meta(BaseAccountSerializer.Meta):
model = AccountTemplate model = AccountTemplate
fields = BaseAccountSerializer.Meta.fields + ['is_sync_account', 'su_from']
@staticmethod def sync_accounts_secret(self, instance, diff):
def account_save(data, account): if not self._is_sync_account or 'secret' not in diff:
for field, value in data.items():
setattr(account, field, value)
try:
account.save(update_fields=list(data.keys()))
except IntegrityError:
pass
# TODO 数据库访问的太多了 后期优化
@atomic()
def bulk_update_accounts(self, instance, diff):
accounts = Account.objects.filter(source_id=instance.id)
if not accounts:
return return
query_data = {
'source_id': instance.id,
'username': instance.username,
'secret_type': instance.secret_type
}
accounts = Account.objects.filter(**query_data)
instance.bulk_sync_account_secret(accounts, self.context['request'].user.id)
diff.pop('secret', None) def validate(self, attrs):
name = diff.pop('name', None) self._is_sync_account = attrs.pop('is_sync_account', None)
username = diff.pop('username', None) attrs = super().validate(attrs)
secret_type = diff.pop('secret_type', None) return attrs
update_accounts = []
for account in accounts:
for field, value in diff.items():
setattr(account, field, value)
update_accounts.append(account)
if update_accounts:
Account.objects.bulk_update(update_accounts, diff.keys())
if name:
for account in accounts:
data = {'name': name}
self.account_save(data, account)
if secret_type and username:
asset_ids_supports = self.get_asset_ids_supports(accounts, secret_type)
for account in accounts:
asset_id = account.asset_id
if asset_id not in asset_ids_supports:
data = {'username': username}
self.account_save(data, account)
continue
data = {'username': username, 'secret_type': secret_type, 'secret': instance.secret}
self.account_save(data, account)
elif secret_type:
asset_ids_supports = self.get_asset_ids_supports(accounts, secret_type)
for account in accounts:
asset_id = account.asset_id
if asset_id not in asset_ids_supports:
continue
data = {'secret_type': secret_type, 'secret': instance.secret}
self.account_save(data, account)
elif username:
for account in accounts:
data = {'username': username}
self.account_save(data, account)
@staticmethod
def get_asset_ids_supports(accounts, secret_type):
asset_ids = accounts.values_list('asset_id', flat=True)
secret_type_supports = Asset.get_secret_type_assets(asset_ids, secret_type)
return [asset.id for asset in secret_type_supports]
def update(self, instance, validated_data): def update(self, instance, validated_data):
# diff = { diff = {
# k: v for k, v in validated_data.items() k: v for k, v in validated_data.items()
# if getattr(instance, k) != v if getattr(instance, k, None) != v
# } }
instance = super().update(instance, validated_data) instance = super().update(instance, validated_data)
# self.bulk_update_accounts(instance, diff) if {'username', 'secret_type'} & set(diff.keys()):
Account.objects.filter(source_id=instance.id).update(source_id=None)
else:
self.sync_accounts_secret(instance, diff)
return instance return instance

View File

@@ -1,4 +1,4 @@
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from accounts.models import AutomationExecution from accounts.models import AutomationExecution
@@ -63,15 +63,17 @@ class AutomationExecutionSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_snapshot(obj): def get_snapshot(obj):
tp = obj.snapshot['type'] tp = obj.snapshot.get('type', '')
type_display = tp if not hasattr(AutomationTypes, tp) \
else getattr(AutomationTypes, tp).label
snapshot = { snapshot = {
'type': tp, 'type': tp,
'name': obj.snapshot['name'], 'name': obj.snapshot.get('name'),
'comment': obj.snapshot['comment'], 'comment': obj.snapshot.get('comment'),
'accounts': obj.snapshot['accounts'], 'accounts': obj.snapshot.get('accounts'),
'node_amount': len(obj.snapshot['nodes']), 'node_amount': len(obj.snapshot.get('nodes', [])),
'asset_amount': len(obj.snapshot['assets']), 'asset_amount': len(obj.snapshot.get('assets', [])),
'type_display': getattr(AutomationTypes, tp).label, 'type_display': type_display,
} }
return snapshot return snapshot

View File

@@ -50,7 +50,7 @@ class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializ
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields read_only_fields = BaseAutomationSerializer.Meta.read_only_fields
fields = BaseAutomationSerializer.Meta.fields + read_only_fields + [ fields = BaseAutomationSerializer.Meta.fields + read_only_fields + [
'secret_type', 'secret_strategy', 'secret', 'password_rules', 'secret_type', 'secret_strategy', 'secret', 'password_rules',
'ssh_key_change_strategy', 'passphrase', 'recipients', 'ssh_key_change_strategy', 'passphrase', 'recipients', 'params'
] ]
extra_kwargs = {**BaseAutomationSerializer.Meta.extra_kwargs, **{ extra_kwargs = {**BaseAutomationSerializer.Meta.extra_kwargs, **{
'accounts': {'required': True}, 'accounts': {'required': True},

View File

@@ -10,7 +10,7 @@ class PushAccountAutomationSerializer(ChangeSecretAutomationSerializer):
class Meta(ChangeSecretAutomationSerializer.Meta): class Meta(ChangeSecretAutomationSerializer.Meta):
model = PushAccountAutomation model = PushAccountAutomation
fields = ['params'] + [ fields = [
n for n in ChangeSecretAutomationSerializer.Meta.fields n for n in ChangeSecretAutomationSerializer.Meta.fields
if n not in ['recipients'] if n not in ['recipients']
] ]

View File

@@ -39,7 +39,7 @@ urlpatterns = [
path('push-account/<uuid:pk>/asset/remove/', api.PushAccountRemoveAssetApi.as_view(), path('push-account/<uuid:pk>/asset/remove/', api.PushAccountRemoveAssetApi.as_view(),
name='push-account-remove-asset'), name='push-account-remove-asset'),
path('push-accountt/<uuid:pk>/asset/add/', api.PushAccountAddAssetApi.as_view(), name='push-account-add-asset'), path('push-account/<uuid:pk>/asset/add/', api.PushAccountAddAssetApi.as_view(), name='push-account-add-asset'),
path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(), path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(),
name='push-account-add-or-remove-node'), name='push-account-add-or-remove-node'),
path('push-account/<uuid:pk>/assets/', api.PushAccountAssetsListApi.as_view(), name='push-account-assets'), path('push-account/<uuid:pk>/assets/', api.PushAccountAssetsListApi.as_view(), name='push-account-assets'),

View File

@@ -4,7 +4,7 @@ from rest_framework import serializers
from accounts.const import ( from accounts.const import (
SecretType, DEFAULT_PASSWORD_RULES SecretType, DEFAULT_PASSWORD_RULES
) )
from common.utils import gen_key_pair, random_string from common.utils import ssh_key_gen, random_string
from common.utils import validate_ssh_private_key, parse_ssh_private_key_str from common.utils import validate_ssh_private_key, parse_ssh_private_key_str
@@ -16,7 +16,7 @@ class SecretGenerator:
@staticmethod @staticmethod
def generate_ssh_key(): def generate_ssh_key():
private_key, public_key = gen_key_pair() private_key, public_key = ssh_key_gen()
return private_key return private_key
def generate_password(self): def generate_password(self):

View File

@@ -1,4 +1,5 @@
from .command_acl import * from .command_acl import *
from .connect_method import *
from .login_acl import * from .login_acl import *
from .login_asset_acl import * from .login_asset_acl import *
from .login_asset_check import * from .login_asset_check import *

View File

@@ -1,6 +1,8 @@
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from .common import ACLUserAssetFilterMixin
from .. import models, serializers from .. import models, serializers
__all__ = ['CommandFilterACLViewSet', 'CommandGroupViewSet'] __all__ = ['CommandFilterACLViewSet', 'CommandGroupViewSet']
@@ -13,10 +15,16 @@ class CommandGroupViewSet(OrgBulkModelViewSet):
serializer_class = serializers.CommandGroupSerializer serializer_class = serializers.CommandGroupSerializer
class CommandACLFilter(ACLUserAssetFilterMixin):
class Meta:
model = models.CommandFilterACL
fields = ['name', ]
class CommandFilterACLViewSet(OrgBulkModelViewSet): class CommandFilterACLViewSet(OrgBulkModelViewSet):
model = models.CommandFilterACL model = models.CommandFilterACL
filterset_fields = ('name',) filterset_class = CommandACLFilter
search_fields = filterset_fields search_fields = ['name']
serializer_class = serializers.CommandFilterACLSerializer serializer_class = serializers.CommandFilterACLSerializer
rbac_perms = { rbac_perms = {
'command_review': 'tickets.add_superticket' 'command_review': 'tickets.add_superticket'

45
apps/acls/api/common.py Normal file
View File

@@ -0,0 +1,45 @@
from django.db.models import Q
from django_filters import rest_framework as drf_filters
from common.drf.filters import BaseFilterSet
from common.utils import is_uuid
class ACLUserFilterMixin(BaseFilterSet):
users = drf_filters.CharFilter(method='filter_user')
@staticmethod
def filter_user(queryset, name, value):
from users.models import User
if not value:
return queryset
if is_uuid(value):
user = User.objects.filter(id=value).first()
else:
q = Q(name=value) | Q(username=value)
user = User.objects.filter(q).first()
if not user:
return queryset.none()
q = queryset.model.users.get_filter_q(user)
return queryset.filter(q).distinct()
class ACLUserAssetFilterMixin(ACLUserFilterMixin):
assets = drf_filters.CharFilter(method='filter_asset')
@staticmethod
def filter_asset(queryset, name, value):
from assets.models import Asset
if not value:
return queryset
if is_uuid(value):
asset = Asset.objects.filter(id=value).first()
else:
q = Q(name=value) | Q(address=value)
asset = Asset.objects.filter(q).first()
if not asset:
return queryset.none()
q = queryset.model.assets.get_filter_q(asset)
return queryset.filter(q).distinct()

View File

@@ -0,0 +1,29 @@
from django_filters import rest_framework as drf_filters
from common.api import JMSBulkModelViewSet
from orgs.utils import tmp_to_root_org
from .common import ACLUserFilterMixin
from .. import serializers
from ..models import ConnectMethodACL
__all__ = ['ConnectMethodACLViewSet']
class ConnectMethodFilter(ACLUserFilterMixin):
methods = drf_filters.CharFilter(field_name="methods__contains", lookup_expr='exact')
class Meta:
model = ConnectMethodACL
fields = ['name', ]
class ConnectMethodACLViewSet(JMSBulkModelViewSet):
queryset = ConnectMethodACL.objects.all()
filterset_class = ConnectMethodFilter
search_fields = ('name',)
serializer_class = serializers.ConnectMethodACLSerializer
def filter_queryset(self, queryset):
with tmp_to_root_org():
return super().filter_queryset(queryset)

View File

@@ -1,14 +1,26 @@
from common.api import JMSBulkModelViewSet from common.api import JMSBulkModelViewSet
from ..models import LoginACL
from orgs.utils import tmp_to_root_org
from .common import ACLUserFilterMixin
from .. import serializers from .. import serializers
from ..filters import LoginAclFilter from ..models import LoginACL
__all__ = ['LoginACLViewSet'] __all__ = ['LoginACLViewSet']
class LoginACLFilter(ACLUserFilterMixin):
class Meta:
model = LoginACL
fields = ('name', 'action')
class LoginACLViewSet(JMSBulkModelViewSet): class LoginACLViewSet(JMSBulkModelViewSet):
queryset = LoginACL.objects.all() queryset = LoginACL.objects.all()
filterset_class = LoginAclFilter filterset_class = LoginACLFilter
search_fields = ('name',) search_fields = ('name',)
serializer_class = serializers.LoginACLSerializer serializer_class = serializers.LoginACLSerializer
def filter_queryset(self, queryset):
with tmp_to_root_org():
return super().filter_queryset(queryset)

View File

@@ -1,12 +1,18 @@
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from .common import ACLUserAssetFilterMixin
from .. import models, serializers from .. import models, serializers
__all__ = ['LoginAssetACLViewSet'] __all__ = ['LoginAssetACLViewSet']
class LoginAssetACLFilter(ACLUserAssetFilterMixin):
class Meta:
model = models.LoginAssetACL
fields = ['name', ]
class LoginAssetACLViewSet(OrgBulkModelViewSet): class LoginAssetACLViewSet(OrgBulkModelViewSet):
model = models.LoginAssetACL model = models.LoginAssetACL
filterset_fields = ('name', ) filterset_class = LoginAssetACLFilter
search_fields = filterset_fields search_fields = ['name']
serializer_class = serializers.LoginAssetACLSerializer serializer_class = serializers.LoginAssetACLSerializer

View File

@@ -30,14 +30,21 @@ class LoginAssetCheckAPI(CreateAPIView):
return serializer return serializer
def check_review(self): def check_review(self):
user = self.serializer.user
asset = self.serializer.asset
# 用户满足的 acls
queryset = LoginAssetACL.objects.all()
q = LoginAssetACL.users.get_filter_q(LoginAssetACL, 'users', user)
queryset = queryset.filter(q)
q = LoginAssetACL.assets.get_filter_q(LoginAssetACL, 'assets', asset)
queryset = queryset.filter(q)
account_username = self.serializer.validated_data.get('account_username')
queryset = queryset.filter(accounts__contains=account_username)
with tmp_to_org(self.serializer.asset.org): with tmp_to_org(self.serializer.asset.org):
kwargs = { acl = queryset.valid().first()
'user': self.serializer.user,
'asset': self.serializer.asset,
'account_username': self.serializer.validated_data.get('account_username'),
'action': LoginAssetACL.ActionChoices.review
}
acl = LoginAssetACL.filter_queryset(**kwargs).valid().first()
if acl: if acl:
need_review = True need_review = True
response_data = self._get_response_data_of_need_review(acl) response_data = self._get_response_data_of_need_review(acl)

9
apps/acls/const.py Normal file
View File

@@ -0,0 +1,9 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
class ActionChoices(models.TextChoices):
reject = 'reject', _('Reject')
accept = 'accept', _('Accept')
review = 'review', _('Review')
warning = 'warning', _('Warning')

View File

@@ -1,15 +0,0 @@
from django_filters import rest_framework as filters
from common.drf.filters import BaseFilterSet
from acls.models import LoginACL
class LoginAclFilter(BaseFilterSet):
user = filters.UUIDFilter(field_name='user_id')
user_display = filters.CharFilter(field_name='user__name')
class Meta:
model = LoginACL
fields = (
'name', 'user', 'user_display', 'action'
)

View File

@@ -1,14 +1,14 @@
# Generated by Django 3.1 on 2021-03-11 09:53 # Generated by Django 3.1 on 2021-03-11 09:53
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import uuid import uuid
import django.core.validators
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@@ -24,37 +24,51 @@ 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')),
('name', models.CharField(max_length=128, verbose_name='Name')), ('name', models.CharField(max_length=128, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')), ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first',
validators=[django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(100)],
verbose_name='Priority')),
('is_active', models.BooleanField(default=True, verbose_name='Active')), ('is_active', models.BooleanField(default=True, verbose_name='Active')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')), ('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('ip_group', models.JSONField(default=list, verbose_name='Login IP')), ('ip_group', models.JSONField(default=list, verbose_name='Login IP')),
('action', models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow')], default='reject', max_length=64, verbose_name='Action')), ('action',
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_acls', to=settings.AUTH_USER_MODEL, verbose_name='User')), models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow')], default='reject', max_length=64,
verbose_name='Action')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_acls',
to=settings.AUTH_USER_MODEL, verbose_name='User')),
], ],
options={ options={
'ordering': ('priority', '-date_updated', 'name'), 'ordering': ('priority', '-is_active', 'name'),
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='LoginAssetACL', name='LoginAssetACL',
fields=[ fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), ('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')), ('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('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')),
('name', models.CharField(max_length=128, verbose_name='Name')), ('name', models.CharField(max_length=128, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')), ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first',
validators=[django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(100)],
verbose_name='Priority')),
('is_active', models.BooleanField(default=True, verbose_name='Active')), ('is_active', models.BooleanField(default=True, verbose_name='Active')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')), ('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('users', models.JSONField(verbose_name='User')), ('users', models.JSONField(verbose_name='User')),
('system_users', models.JSONField(verbose_name='System User')), ('system_users', models.JSONField(verbose_name='System User')),
('assets', models.JSONField(verbose_name='Asset')), ('assets', models.JSONField(verbose_name='Asset')),
('action', models.CharField(choices=[('login_confirm', 'Login confirm')], default='login_confirm', max_length=64, verbose_name='Action')), ('action',
('reviewers', models.ManyToManyField(blank=True, related_name='review_login_asset_acls', to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')), models.CharField(choices=[('login_confirm', 'Login confirm')], default='login_confirm', max_length=64,
verbose_name='Action')),
('reviewers',
models.ManyToManyField(blank=True, related_name='review_login_asset_acls', to=settings.AUTH_USER_MODEL,
verbose_name='Reviewers')),
], ],
options={ options={
'ordering': ('priority', '-date_updated', 'name'), 'ordering': ('priority', '-is_active', 'name'),
'unique_together': {('name', 'org_id')}, 'unique_together': {('name', 'org_id')},
}, },
), ),

View File

@@ -2,7 +2,6 @@
import django import django
from django.conf import settings from django.conf import settings
from django.db import migrations, models, transaction from django.db import migrations, models, transaction
from acls.models import LoginACL
LOGIN_CONFIRM_ZH = '登录复核' LOGIN_CONFIRM_ZH = '登录复核'
LOGIN_CONFIRM_EN = 'Login confirm' LOGIN_CONFIRM_EN = 'Login confirm'
@@ -90,10 +89,10 @@ class Migration(migrations.Migration):
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='loginacl', name='loginacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login acl'}, options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='loginassetacl', name='loginassetacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login asset acl'}, options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'},
), ),
] ]

View File

@@ -4,7 +4,6 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('acls', '0002_auto_20210926_1047'), ('acls', '0002_auto_20210926_1047'),
] ]
@@ -12,10 +11,10 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='loginacl', name='loginacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login acl'}, options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='loginassetacl', name='loginassetacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login asset acl'}, options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'},
), ),
] ]

View File

@@ -63,7 +63,7 @@ class Migration(migrations.Migration):
], ],
options={ options={
'verbose_name': 'Command acl', 'verbose_name': 'Command acl',
'ordering': ('priority', '-date_updated', 'name'), 'ordering': ('priority', '-is_active', 'name'),
'unique_together': {('name', 'org_id')}, 'unique_together': {('name', 'org_id')},
}, },
), ),

View File

@@ -20,14 +20,14 @@ class Migration(migrations.Migration):
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='commandfilteracl', name='commandfilteracl',
options={'ordering': ('priority', 'date_updated', 'name'), 'verbose_name': 'Command acl'}, options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Command acl'},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='loginacl', name='loginacl',
options={'ordering': ('priority', 'date_updated', 'name'), 'verbose_name': 'Login acl'}, options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='loginassetacl', name='loginassetacl',
options={'ordering': ('priority', 'date_updated', 'name'), 'verbose_name': 'Login asset acl'}, options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'},
), ),
] ]

View File

@@ -0,0 +1,44 @@
# Generated by Django 3.2.17 on 2023-04-25 09:04
from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration):
dependencies = [
('acls', '0010_alter_commandfilteracl_command_groups'),
]
operations = [
migrations.AddField(
model_name='commandfilteracl',
name='new_accounts',
field=models.JSONField(default=list, verbose_name='Accounts'),
),
migrations.AddField(
model_name='commandfilteracl',
name='new_assets',
field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets'),
),
migrations.AddField(
model_name='commandfilteracl',
name='new_users',
field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'),
),
migrations.AddField(
model_name='loginassetacl',
name='new_accounts',
field=models.JSONField(default=list, verbose_name='Accounts')
),
migrations.AddField(
model_name='loginassetacl',
name='new_assets',
field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets'),
),
migrations.AddField(
model_name='loginassetacl',
name='new_users',
field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'),
),
]

View File

@@ -0,0 +1,41 @@
# Generated by Django 3.2.17 on 2023-04-26 03:11
from django.db import migrations
def migrate_base_acl_users_assets_accounts(apps, *args):
cmd_acl_model = apps.get_model('acls', 'CommandFilterACL')
login_asset_acl_model = apps.get_model('acls', 'LoginAssetACL')
for model in [cmd_acl_model, login_asset_acl_model]:
for obj in model.objects.all():
user_names = (obj.users or {}).get('username_group', [])
obj.new_users = {
"type": "attrs",
"attrs": [{"name": "username", "value": user_names, "match": "in"}]
}
asset_names = (obj.assets or {}).get('name_group', [])
asset_attrs = []
if asset_names:
asset_attrs.append({"name": "name", "value": asset_names, "match": "in"})
asset_address = (obj.assets or {}).get('address_group', [])
if asset_address:
asset_attrs.append({"name": "address", "value": asset_address, "match": "ip_in"})
obj.new_assets = {"type": "attrs", "attrs": asset_attrs}
account_usernames = (obj.accounts or {}).get('username_group', [])
if '*' in account_usernames:
account_usernames = ['@ALL']
obj.new_accounts = account_usernames
obj.save()
class Migration(migrations.Migration):
dependencies = [
('acls', '0011_auto_20230425_1704'),
]
operations = [
migrations.RunPython(migrate_base_acl_users_assets_accounts)
]

View File

@@ -0,0 +1,66 @@
# Generated by Django 3.2.17 on 2023-04-26 09:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('acls', '0012_auto_20230426_1111'),
]
operations = [
migrations.RemoveField(
model_name='commandfilteracl',
name='accounts',
),
migrations.RemoveField(
model_name='commandfilteracl',
name='assets',
),
migrations.RemoveField(
model_name='commandfilteracl',
name='users',
),
migrations.RemoveField(
model_name='loginassetacl',
name='accounts',
),
migrations.RemoveField(
model_name='loginassetacl',
name='assets',
),
migrations.RemoveField(
model_name='loginassetacl',
name='users',
),
migrations.RenameField(
model_name='commandfilteracl',
old_name='new_accounts',
new_name='accounts',
),
migrations.RenameField(
model_name='commandfilteracl',
old_name='new_assets',
new_name='assets',
),
migrations.RenameField(
model_name='commandfilteracl',
old_name='new_users',
new_name='users',
),
migrations.RenameField(
model_name='loginassetacl',
old_name='new_accounts',
new_name='accounts',
),
migrations.RenameField(
model_name='loginassetacl',
old_name='new_assets',
new_name='assets',
),
migrations.RenameField(
model_name='loginassetacl',
old_name='new_users',
new_name='users',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.17 on 2023-05-26 09:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acls', '0013_auto_20230426_1759'),
]
operations = [
migrations.AddField(
model_name='loginassetacl',
name='rules',
field=models.JSONField(default=dict, verbose_name='Rule'),
),
]

View File

@@ -0,0 +1,46 @@
# Generated by Django 3.2.17 on 2023-06-06 06:23
import uuid
import django.core.validators
from django.conf import settings
from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acls', '0014_loginassetacl_rules'),
]
operations = [
migrations.CreateModel(
name='ConnectMethodACL',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('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')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first',
validators=[django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(100)],
verbose_name='Priority')),
('action', models.CharField(default='reject', max_length=64, verbose_name='Action')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('users', common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users')),
('connect_methods', models.JSONField(default=list, verbose_name='Connect methods')),
(
'reviewers',
models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')),
],
options={
'ordering': ('priority', '-is_active', 'name'),
'abstract': False,
},
),
]

View File

@@ -0,0 +1,47 @@
# Generated by Django 3.2.17 on 2023-06-06 10:57
from django.db import migrations, models
import common.db.fields
def migrate_users_login_acls(apps, schema_editor):
login_acl_model = apps.get_model('acls', 'LoginACL')
name_used = []
login_acls = []
for login_acl in login_acl_model.objects.all().select_related('user'):
name = '{}_{}'.format(login_acl.name, login_acl.user.username)
if name.lower() in name_used:
name += '_{}'.format(str(login_acl.user_id)[:4])
name_used.append(name.lower())
login_acl.name = name
login_acl.users = {
"type": "ids", "ids": [str(login_acl.user_id)]
}
login_acls.append(login_acl)
login_acl_model.objects.bulk_update(login_acls, ['name', 'users'])
class Migration(migrations.Migration):
dependencies = [
('acls', '0015_connectmethodacl'),
]
operations = [
migrations.AddField(
model_name='loginacl',
name='users',
field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'),
),
migrations.RunPython(migrate_users_login_acls),
migrations.RemoveField(
model_name='loginacl',
name='user',
),
migrations.AlterField(
model_name='loginacl',
name='name',
field=models.CharField(max_length=128, unique=True, verbose_name='Name'),
),
]

View File

@@ -0,0 +1,16 @@
# Generated by Django 3.2.19 on 2023-06-13 07:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('acls', '0016_auto_20230606_1857'),
]
operations = [
migrations.AlterModelOptions(
name='connectmethodacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Connect method acl'},
),
]

View File

@@ -1,3 +1,4 @@
from .command_acl import *
from .connect_method import *
from .login_acl import * from .login_acl import *
from .login_asset_acl import * from .login_asset_acl import *
from .command_acl import *

View File

@@ -1,25 +1,20 @@
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from common.db.fields import JSONManyToManyField
from common.db.models import JMSBaseModel from common.db.models import JMSBaseModel
from common.utils import contains_ip from common.utils import contains_ip
from common.utils.time_period import contains_time_period
from orgs.mixins.models import OrgModelMixin, OrgManager from orgs.mixins.models import OrgModelMixin, OrgManager
from ..const import ActionChoices
__all__ = [ __all__ = [
'ACLManager', 'BaseACL', 'UserBaseACL', 'UserAssetAccountBaseACL',
'BaseACL',
'BaseACLQuerySet',
'UserAssetAccountBaseACL',
'UserAssetAccountACLQuerySet'
] ]
from orgs.utils import tmp_to_root_org
class ActionChoices(models.TextChoices): from orgs.utils import tmp_to_org
reject = 'reject', _('Reject')
accept = 'accept', _('Accept')
review = 'review', _('Review')
class BaseACLQuerySet(models.QuerySet): class BaseACLQuerySet(models.QuerySet):
@@ -36,43 +31,8 @@ class BaseACLQuerySet(models.QuerySet):
return self.inactive() return self.inactive()
class UserAssetAccountACLQuerySet(BaseACLQuerySet):
def filter_user(self, username):
q = Q(users__username_group__contains=username) | \
Q(users__username_group__contains='*')
return self.filter(q)
def filter_asset(self, name=None, address=None):
queryset = self.filter()
if name:
q = Q(assets__name_group__contains=name) | \
Q(assets__name_group__contains='*')
queryset = queryset.filter(q)
if address:
ids = [
q.id for q in queryset
if contains_ip(address, q.assets.get('address_group', []))
]
queryset = queryset.filter(id__in=ids)
return queryset
def filter_account(self, username):
q = Q(accounts__username_group__contains=username) | \
Q(accounts__username_group__contains='*')
return self.filter(q)
class ACLManager(models.Manager):
def valid(self):
return self.get_queryset().valid()
class OrgACLManager(OrgManager, ACLManager):
pass
class BaseACL(JMSBaseModel): class BaseACL(JMSBaseModel):
name = models.CharField(max_length=128, verbose_name=_('Name')) name = models.CharField(max_length=128, verbose_name=_('Name'), unique=True)
priority = models.IntegerField( priority = models.IntegerField(
default=50, verbose_name=_("Priority"), default=50, verbose_name=_("Priority"),
help_text=_("1-100, the lower the value will be match first"), help_text=_("1-100, the lower the value will be match first"),
@@ -83,46 +43,85 @@ class BaseACL(JMSBaseModel):
is_active = models.BooleanField(default=True, verbose_name=_("Active")) is_active = models.BooleanField(default=True, verbose_name=_("Active"))
ActionChoices = ActionChoices ActionChoices = ActionChoices
objects = ACLManager.from_queryset(BaseACLQuerySet)() objects = BaseACLQuerySet.as_manager()
class Meta: class Meta:
ordering = ('priority', 'date_updated', 'name') ordering = ('priority', '-is_active', 'name')
abstract = True abstract = True
def is_action(self, action): def is_action(self, action):
return self.action == action return self.action == action
@classmethod
def get_user_acls(cls, user):
return cls.objects.none()
class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): @classmethod
# username_group def get_match_rule_acls(cls, user, ip, acl_qs=None):
users = models.JSONField(verbose_name=_('User')) if acl_qs is None:
# name_group, address_group acl_qs = cls.get_user_acls(user)
assets = models.JSONField(verbose_name=_('Asset')) if not acl_qs:
# username_group return
accounts = models.JSONField(verbose_name=_('Account'))
objects = OrgACLManager.from_queryset(UserAssetAccountACLQuerySet)() for acl in acl_qs:
if acl.is_action(ActionChoices.review) and not acl.reviewers.exists():
continue
ip_group = acl.rules.get('ip_group')
time_periods = acl.rules.get('time_period')
is_contain_ip = contains_ip(ip, ip_group) if ip_group else True
is_contain_time_period = contains_time_period(time_periods) if time_periods else True
if is_contain_ip and is_contain_time_period:
# 满足条件,则返回
return acl
return None
class UserBaseACL(BaseACL):
users = JSONManyToManyField('users.User', default=dict, verbose_name=_('Users'))
class Meta(BaseACL.Meta): class Meta(BaseACL.Meta):
unique_together = ('name', 'org_id') abstract = True
@classmethod
def get_user_acls(cls, user):
queryset = cls.objects.all()
with tmp_to_root_org():
q = cls.users.get_filter_q(user)
queryset = queryset.filter(q)
return queryset.filter(is_active=True).distinct()
class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL):
name = models.CharField(max_length=128, verbose_name=_('Name'))
assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets'))
accounts = models.JSONField(default=list, verbose_name=_("Accounts"))
objects = OrgManager.from_queryset(BaseACLQuerySet)()
class Meta(UserBaseACL.Meta):
unique_together = [('name', 'org_id')]
abstract = True abstract = True
@classmethod @classmethod
def filter_queryset(cls, user=None, asset=None, account=None, account_username=None, **kwargs): def filter_queryset(cls, user=None, asset=None, account=None, account_username=None, **kwargs):
queryset = cls.objects.all() queryset = cls.objects.all()
org_id = None
if user: if user:
queryset = queryset.filter_user(user.username) q = cls.users.get_filter_q(user)
if account: queryset = queryset.filter(q)
org_id = account.org_id
queryset = queryset.filter_account(account.username)
if account_username:
queryset = queryset.filter_account(username=account_username)
if asset: if asset:
org_id = asset.org_id org_id = asset.org_id
queryset = queryset.filter_asset(asset.name, asset.address) with tmp_to_org(org_id):
if org_id: q = cls.assets.get_filter_q(asset)
kwargs['org_id'] = org_id queryset = queryset.filter(q)
if account and not account_username:
account_username = account.username
if account_username:
q = models.Q(accounts__contains=account_username) | \
models.Q(accounts__contains='*') | \
models.Q(accounts__contains='@ALL')
queryset = queryset.filter(q)
if kwargs: if kwargs:
queryset = queryset.filter(**kwargs) queryset = queryset.filter(**kwargs)
return queryset return queryset.valid().distinct()

View File

@@ -0,0 +1,14 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from .base import UserBaseACL
__all__ = ['ConnectMethodACL']
class ConnectMethodACL(UserBaseACL):
connect_methods = models.JSONField(default=list, verbose_name=_('Connect methods'))
class Meta(UserBaseACL.Meta):
verbose_name = _('Connect method acl')
abstract = False

Some files were not shown because too many files have changed in this diff Show More