Compare commits

...

507 Commits

Author SHA1 Message Date
fit2bot
5287475a57 feat: Update v3.3.0 2023-05-18 20:06:32 +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
吴小白
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
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
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
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
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
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
fit2bot
ea1c94c6db perf: 用户组织按照name 进行排序 (#10354)
Co-authored-by: feng <1304903146@qq.com>
2023-04-27 11:38:33 +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
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
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
Bai
9d2ae7d1ed fix: 修改 utils/disable_user_mfa.sh otp_level => mfa_level 2023-04-23 16:45:40 +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
Jiangjie.Bai
f2e7845d4b Merge pull request #10286 from jumpserver/dev
v3.2.0
2023-04-20 18:33:59 +08:00
fit2bot
d75b7c014e perf: 更新模版暂不同步修改账号 (#10285)
Co-authored-by: feng <1304903146@qq.com>
2023-04-20 18:29:31 +08:00
Jiangjie.Bai
b44e6c258f Merge pull request #10284 from jumpserver/dev
v3.2.0
2023-04-20 18:23:12 +08:00
Bai
2ae951e6e6 fix: 修改翻译 2023-04-20 17:53:42 +08:00
fit2bot
10b033ee97 perf: 批量更新资产消息 (#10280)
Co-authored-by: feng <1304903146@qq.com>
2023-04-20 16:22:02 +08:00
ibuler
177d634d85 fix: 修复登录 acl 显示不对 2023-04-20 15:48:56 +08:00
feng
ee122690ff perf: asset date_updated 2023-04-20 15:48:34 +08:00
ibuler
dac708f952 perf: 优化 api doc 报错 2023-04-20 15:47:50 +08:00
老广
75724cbddb Merge pull request #10272 from jumpserver/pr@dev@perf_asset_task_i18n
perf: 优化资产任务的 i18n
2023-04-20 14:45:24 +08:00
老广
4b5d9d3a76 Merge pull request #10273 from jumpserver/pr@dev@account_auto_i18n
perf: account auto i18n
2023-04-20 14:44:54 +08:00
fit2bot
0de6c41406 perf: update templat account (#10274)
Co-authored-by: feng <1304903146@qq.com>
2023-04-20 14:43:40 +08:00
ibuler
b52f18aea6 perf: 修改 i18n 2023-04-20 14:39:31 +08:00
ibuler
be58539df8 perf: 修改支持 i18n 2023-04-20 14:19:13 +08:00
feng
f030638ba4 perf: account auto i18n 2023-04-20 14:10:39 +08:00
ibuler
f496f7d635 perf: 优化资产任务的 i18n 2023-04-20 13:51:41 +08:00
老广
7887548174 Merge pull request #10269 from jumpserver/pr@dev@fix_loong64_build
fix: 修复 loong64 构建失败
2023-04-20 13:22:00 +08:00
老广
8e61dc8e02 Merge pull request #10267 from jumpserver/pr@dev@perf_yaml_support_i18n
perf: yaml 文件支持 i18n
2023-04-20 13:21:22 +08:00
吴小白
651c53a92c fix: 修复 loong64 构建失败 2023-04-20 11:38:50 +08:00
fit2bot
c9ee46c0fb perf: windows 账号可连接性 ansible 刷新 (#10268)
Co-authored-by: feng <1304903146@qq.com>
2023-04-20 11:32:33 +08:00
ibuler
f2d34de161 perf: 修改格式 2023-04-20 11:27:10 +08:00
fit2bot
dc5f7a5c05 fix: 资产 克隆有切换至的账号400 (#10266)
Co-authored-by: feng <1304903146@qq.com>
2023-04-20 11:14:23 +08:00
ibuler
6b3665e8d0 perf: yaml 文件支持 i18n 2023-04-20 11:13:28 +08:00
fit2bot
11ad6ab273 fix: 修复作业中心未开启的acl生效的问题 (#10265)
* fix: 修复作业中心未开启的acl生效的问题

* perf: 优化代码风格

---------

Co-authored-by: Aaron3S <chenyang@fit2cloud.com>
2023-04-20 10:33:53 +08:00
jiangweidong
2ba32f6971 perf: 优化自定义改密时需要在命令中包含ssh登录用户的密码问题 2023-04-20 09:52:13 +08:00
Bai
96eb87f935 feat: 服务启动时校验 migrations 文件是否有冲突(DEBUG_DEV) 2023-04-19 14:14:37 +08:00
fit2bot
3afab38c5f perf: 资产平台排序 (#10258)
Co-authored-by: feng <1304903146@qq.com>
2023-04-19 13:21:57 +08:00
fit2bot
9dedce6264 perf: 翻译 (#10257)
Co-authored-by: feng <1304903146@qq.com>
2023-04-19 13:02:24 +08:00
ibuler
4849b2627a perf: 优化一下迁移 2023-04-19 11:13:29 +08:00
ibuler
12adf66f41 perf: 优化账号历史过滤 2023-04-19 11:13:29 +08:00
fit2bot
fc4a77df1a fix: 账号导入500 (#10255)
Co-authored-by: feng <1304903146@qq.com>
2023-04-19 10:57:38 +08:00
fit2bot
3bc8eda66a perf: 更新模版关联更新账号 (#10250)
Co-authored-by: feng <1304903146@qq.com>
2023-04-19 10:18:13 +08:00
Bai
d402780d00 feat: 服务启动时校验 migrations 文件是否有冲突(DEBUG_DEV) 2023-04-18 20:23:56 +08:00
fit2bot
28f08251b3 perf: 修复创建资产时,account 的校验 (#10247)
* perf: 修复创建资产时,account 的校验

* perf: 优化一下提示

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-04-18 20:10:51 +08:00
Aaron3S
ca898ed7b5 perf: 优化代码 2023-04-18 19:54:14 +08:00
Aaron3S
50421a1f89 fix: 修复作业中心选择收藏资产取不到资产的问题 2023-04-18 19:54:14 +08:00
ibuler
a83d1c7c46 perf: 优化 applet host platform 2023-04-18 19:13:04 +08:00
ibuler
389f94d672 perf: 修改 assets serializer 支持 accounts template 2023-04-18 19:12:26 +08:00
fit2bot
f47d0b1a40 perf: 工单发消息失败 (#10242)
Co-authored-by: feng <1304903146@qq.com>
2023-04-18 18:56:17 +08:00
fit2bot
a28239f313 fix: 登录复核刷新后404 (#10240)
Co-authored-by: feng <1304903146@qq.com>
2023-04-18 18:07:54 +08:00
老广
996690fc02 Merge pull request #10235 from jumpserver/pr@dev@perf_asset_set_default_nodes
perf: custom fields 仅custom 类型资产支持
2023-04-18 17:18:53 +08:00
ibuler
8b98bbddaa perf: custom fields 仅custom 类型资产支持 2023-04-18 17:07:01 +08:00
fit2bot
cf197f7efc perf: 创建资产通过账号模版创建账号 (#10234)
Co-authored-by: feng <1304903146@qq.com>
2023-04-18 17:03:49 +08:00
ibuler
5921b2ee8f perf: 修改默认节点 2023-04-18 16:29:41 +08:00
老广
52891bfca3 Merge pull request #10232 from jumpserver/pr@dev@perf_platform_internal_create
perf: 修改 platforms
2023-04-18 16:06:36 +08:00
fit2bot
0856b0cbbe fix: k8s 无密码账号登录 (#10233)
Co-authored-by: feng <1304903146@qq.com>
2023-04-18 15:31:47 +08:00
ibuler
b30e9aedce perf: 优化内置平台创建 2023-04-18 15:06:22 +08:00
ibuler
bacda8248b perf: 修改内置 platform 创建 2023-04-18 14:25:35 +08:00
ibuler
ce38b2263c perf: 修改 platforms 2023-04-18 14:02:24 +08:00
fit2bot
810aff9597 perf: k8s 支持网关 (#10229)
Co-authored-by: feng <1304903146@qq.com>
2023-04-18 11:32:59 +08:00
jiangweidong
cad88560bb perf: 修改OAuth2的access_token前缀格式 2023-04-18 10:29:29 +08:00
ibuler
faff0cd20a perf: 优化创建内置 platform 2023-04-17 18:54:55 +08:00
fit2bot
5a34372ca5 perf: 批量创建账号 没解密 (#10226)
Co-authored-by: feng <1304903146@qq.com>
2023-04-17 17:46:10 +08:00
fit2bot
cff4309b03 fix: export assets (#10224)
Co-authored-by: feng <1304903146@qq.com>
2023-04-17 15:42:46 +08:00
ibuler
024d344f7e perf: 去掉 _autmoation_id 2023-04-17 15:41:35 +08:00
ibuler
20e7efcd70 perf: 优化 platform automation 结构 2023-04-17 15:41:35 +08:00
fit2bot
2b00e6e3a1 fix: 修复资产列表 mini 时报错 (#10220)
Co-authored-by: ibuler <ibuler@qq.com>
2023-04-17 15:10:34 +08:00
fit2bot
b3b7575b0c fix: 批量更新资产账号 错误 secret (#10221)
Co-authored-by: feng <1304903146@qq.com>
2023-04-17 15:07:34 +08:00
Jiangjie.Bai
9109a5e6a2 Merge pull request #10213 from jumpserver/dev
v3.2.0 rc2
2023-04-14 18:33:00 +08:00
jiangweidong
690e01cb78 feat: 支持部分资源的自定义自动化任务(Ping/VerifyAccount/ChangeSecret) (#9947)
* feat: 支持部分资源的自定义自动化任务(Ping/VerifyAccount/ChangeSecret)

* perf: 去掉无用的属性

* perf: 优化自定义改密逻辑

* feat: 支持ssh_key认证

* perf: 去掉无用注释

* perf: 优化

* perf: 优化逻辑

* perf: 优化标题

* perf: 去掉一些无用的函数

* perf: 优化helptext
2023-04-14 18:31:09 +08:00
fit2bot
f07e4e53ec perf: 推送成功后 设置账号可连接性 (#10211)
Co-authored-by: feng <1304903146@qq.com>
2023-04-14 17:53:21 +08:00
fit2bot
b1374c6aba fix: 更新平台 ansible_enabled 未设置 (#10210)
Co-authored-by: feng <1304903146@qq.com>
2023-04-14 17:10:33 +08:00
fit2bot
e0f077b054 fix: k8s api 500 (#10209)
Co-authored-by: feng <1304903146@qq.com>
2023-04-14 16:57:08 +08:00
feng
31653cab11 perf: 单独推送账号 2023-04-14 16:22:54 +08:00
feng
976daaa726 fix: 修复AllTypes to_tree_nodes 方法 2023-04-14 15:39:37 +08:00
feng
b359b1059c fix: 修复所有ansible任务执行失败问题 2023-04-14 14:25:01 +08:00
ibuler
490611c560 perf: 修改 applet 2023-04-14 11:30:04 +08:00
Jiangjie.Bai
8a3a9c87a8 Merge pull request #10201 from jumpserver/dev
v3.2.0 rc1
2023-04-13 21:29:05 +08:00
feng
00fd546776 fix: 修复迁移文件冲突bug 2023-04-13 21:28:12 +08:00
Jiangjie.Bai
68351b1c39 Merge pull request #10196 from jumpserver/dev
v3.2.0 rc1
2023-04-13 19:21:05 +08:00
Bai
21da805e78 fix: fix conflicts 2023-04-13 19:20:18 +08:00
fit2bot
928513edd0 fix: fix conflicts (#10197)
* perf: domain gateway 也添加

* fix: 不支持es8 提示

* perf: 授权过期通知

* fix: 过滤系统用户密码过滤ansible不支持的字符

* perf: 优化 apt (#8398)

* pref: 修改 oracle lib path

* perf: 优化 apt

Co-authored-by: ibuler <ibuler@qq.com>

* fix: 修复授权过期通知bug (#8404)

Co-authored-by: feng626 <1304903146@qq.com>

* fix: 修改推送系统用户提示文案

* feat: add client linux arm64 version

* perf: 优化签名认证

* pref: 优化没有获取到节点的问题

* fix: 修复openid用户登录时默认邮件后缀使用配置项

* fix: 修复华为短信配置错误,前端提示不对的问题

* fix: 修复账号备份失败问题 (#8852)

Co-authored-by: feng626 <1304903146@qq.com>

* perf: 优化加密,没有rsa则不加密

* feat: 支持对开启SSL/TLS的MongoDb数据库改密

* perf: 工单新增相关过滤

* fix: 修复配置mfa失效日期 失效问题 (#8856)

Co-authored-by: feng626 <1304903146@qq.com>

* fix: 修复日志记录到syslog时中文编码问题

* workflow: 修改 Gitee 同步的目的仓库

* fix: 修复导出账号历史翻译信息

---------

Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
Co-authored-by: 老广 <ibuler@qq.com>
Co-authored-by: feng626 <1304903146@qq.com>
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
Co-authored-by: jiangweidong <weidong.jiang@fit2cloud.com>
Co-authored-by: Bai <baijiangjie@gmail.com>
Co-authored-by: BugKing <wangzhen@fit2cloud.com>
2023-04-13 19:16:46 +08:00
fit2bot
1eb8e40d3e feat: 账号推送附加参数 (#10080)
* feat: 账号推送附加参数

* perf: 通过节点 资产 过滤平台api

* perf: push automation params

* perf: 修改playbook

* perf: params serializer

* perf: 账号推送playbook 调整

* perf: Automation serializer add params field

* perf: params 非必填

* perf: 添加is_params 给前端判断

* perf: is_params bool

* perf: 修改push account ansible逻辑

* perf: 修改获取push_kwargs方法

* perf: platform migrate

* perf: 修改api

* perf: 单个推送

* perf: push account

* perf: 修改asset auto_config

---------

Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2023-04-13 19:02:04 +08:00
jiangweidong
8e81aee1fd perf: luna连接时不显示 WinRM 协议选项 2023-04-13 18:29:21 +08:00
jiangweidong
e12b832992 perf: 关闭SFTP后,luna界面不显示相应选项 (#10186)
* perf: 关闭SFTP后,luna界面不显示相应选项

* perf: 修改默认值

* perf: 增加资产协议冗余字段,减少关联查询

* perf: 修改

* perf: 优化

* perf: 精简

* perf: 删掉空格

* perf: 修改继承类
2023-04-13 17:26:24 +08:00
fit2bot
1aadb760f4 perf: 优化命令长度限制到8m (#10193)
Co-authored-by: Aaron3S <chenyang@fit2cloud.com>
2023-04-13 15:47:16 +08:00
fit2bot
4654756966 fix: 修复账号克隆 500 (#10192)
Co-authored-by: feng <1304903146@qq.com>
2023-04-13 14:20:07 +08:00
Bai
4c7c8f482d fix: 修复执行批量命令时报错的问题 TypeError:set obiect is not subscriptable 2023-04-12 18:30:34 +08:00
fit2bot
30b89e5cc9 perf: 账号模版更新 (#10184)
Co-authored-by: feng <1304903146@qq.com>
2023-04-12 17:59:13 +08:00
老广
b0365838fb Merge pull request #10183 from O-Jiangweidong/pr@dev@perf_connect_gateway_no_gateway
perf: 当连接资产为网关时,connection_token不返回网域网关信息
2023-04-12 13:07:29 +08:00
jiangweidong
a59f1895a3 perf: 当连接资产为网关时,connection_token不返回网域网关信息 2023-04-12 11:43:06 +08:00
ibuler
59b27822be perf: 添加迁移文件 2023-04-11 19:32:29 +08:00
ibuler
36813f64db perf: 修改 device platform 支持 su 2023-04-11 19:32:29 +08:00
jiangweidong
111296ecd2 fix: 手机号码校验逻辑问题 2023-04-10 18:00:39 +08:00
jiangweidong
b7badc146a fix 2023-04-10 17:36:26 +08:00
jiangweidong
8ff1bae7e6 fix: 手机号可以为空及验证逻辑修改 2023-04-10 17:36:26 +08:00
Eric
b58488a7e9 perf: connection token api 兼容处理 2023-04-10 16:43:31 +08:00
老广
1f63a9675f Merge pull request #10169 from jumpserver/pr@dev@fix_migrate_error
perf: 优化 custom info
2023-04-10 15:19:38 +08:00
ibuler
907fcd7555 perf: 优化 custom info 2023-04-10 15:18:27 +08:00
Bai
616e636837 fix: 修复手机号字段问题 2023-04-10 14:36:22 +08:00
ibuler
34e846927b perf: 优化 connect token asset info 2023-04-10 13:47:38 +08:00
fit2bot
1248458451 perf: 优化支持 choices (#10151)
* perf: 支持自定义类型资产

* perf: 改名前

* perf: 优化支持 choices

* perf: 优化自定义资产

* perf: 优化资产的详情

* perf: 修改完成自定义平台和资产

---------

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2023-04-10 10:57:44 +08:00
wulabing
cec176cc33 fix notifications.py
fix ops.tasks.check_server_performance_period AttributeError: type object 'Status' has no attribute 'get_terminal_latest_stat'
2023-04-10 10:35:16 +08:00
jiangweidong
7833433d5f feat: 手机号支持选择区号 2023-04-10 10:33:31 +08:00
halo
ec2c8538d9 fix: 首次登录强制开启MFA页面bug 2023-04-07 10:19:49 +08:00
fit2bot
e34fbce082 perf: patch account 400 (#10153)
Co-authored-by: feng <1304903146@qq.com>
2023-04-06 19:53:01 +08:00
fit2bot
fb1978a40b fix: terminal status (#10142)
Co-authored-by: feng <1304903146@qq.com>
2023-04-06 10:31:41 +08:00
fit2bot
47d0882090 perf: 用户添加密码 设置是否已存在 (#10138)
Co-authored-by: feng <1304903146@qq.com>
2023-04-04 18:02:58 +08:00
fit2bot
7c1e92c787 fix: 更新账号 跳过name检查 (#10136)
Co-authored-by: feng <1304903146@qq.com>
2023-04-04 16:04:44 +08:00
老广
9af2974bad Merge pull request #10104 from O-Jiangweidong/pr@dev@feat_windows_winrm
feat: Windows类型资产增加winrm协议
2023-04-04 14:08:34 +08:00
Eric_Lee
ba5ca3532b Merge pull request #10133 from jumpserver/pr@dev@fix_deploy_applet
fix: 修正 applet 部署失败
2023-04-04 12:43:49 +08:00
吴小白
211963a098 fix: 修正 applet 部署失败 2023-04-04 12:32:54 +08:00
jiangweidong
187c1e3804 perf: 优化winrm协议网域连接支持ssh_key 2023-04-04 11:55:07 +08:00
Bai
55774dae02 fix: 修复Luna页面用户授权树搜索问题(同步加载方式) 2023-04-04 11:53:01 +08:00
Bai
00ec9b6d5a fix: 修复Luna页面用户授权树默认展开所有节点的问题(同步加载方式) 2023-04-04 11:31:38 +08:00
老广
98a2d9ffdb Merge pull request #10127 from jumpserver/pr@dev@fix_systemuser_without_username_migrate_error
fix: 优化系统用户迁移
2023-04-04 11:16:55 +08:00
ibuler
2b8d0a64fb fix: 优化系统用户迁移 2023-04-04 10:31:57 +08:00
fit2bot
3c07667689 perf: 修改 account migrate (#10125)
Co-authored-by: feng <1304903146@qq.com>
2023-04-03 18:53:37 +08:00
Eric
9686c66874 perf: 会话分享记录字段翻译 2023-04-03 18:37:01 +08:00
fit2bot
c5340b5adc perf: 修改 account (#10088)
* perf: 优化账号创建策略

* perf: 修改账号

* perf: 修改 account

* perf: 修改 account

* perf: 修改批量创建

* perf: 修改账号批量创建

* perf: 继续优化账号批量添加

* perf: 优化创建 accounts 的结果

* perf: 优化账号批量返回的格式

* perf: 优化账号

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-04-03 18:18:31 +08:00
fit2bot
4601bb9e58 perf: 优化mac客户端名字 (#10122)
Co-authored-by: feng <1304903146@qq.com>
2023-04-03 17:50:52 +08:00
老广
7d68148f7a Merge pull request #10110 from jumpserver/dependabot/pip/requirements/redis-4.5.4
build(deps): bump redis from 4.5.3 to 4.5.4 in /requirements
2023-04-03 17:13:46 +08:00
老广
e386e7f33a Merge pull request #10119 from jumpserver/pr@dev@fix_ldapuserimport
fix: 修复 LDAP 导入用户时指定其他组织,还会导入到 Default 组织的问题
2023-04-03 17:10:39 +08:00
Bai
34c9044d03 fix: 修复 LDAP 导入用户时指定其他组织,还会导入到 Default 组织的问题 2023-04-03 08:47:21 +00:00
fit2bot
90cbf653ac perf: 优化luna tree title (#10118)
Co-authored-by: feng <1304903146@qq.com>
2023-04-03 16:47:14 +08:00
Eric_Lee
1c93d7f0a3 Merge pull request #10107 from jumpserver/pr@dev@perf_dockerfile
perf: applet 使用 powershell 部署
2023-04-03 15:58:47 +08:00
Eric
d9ad5aee4a perf: 修改默认值和变量名 2023-04-03 15:39:15 +08:00
Eric
1fbaa85178 perf: 修改接口 2023-04-03 15:39:15 +08:00
Eric
789eb0cf36 feat: 协作分享增加读写控制 2023-04-03 15:39:15 +08:00
jiangweidong
cbe384161a perf: 优化一个函数名 2023-04-03 10:17:00 +08:00
jiangweidong
6aaa20ba17 Perf: 优化 2023-04-03 09:57:40 +08:00
dependabot[bot]
8b6a64d8ed build(deps): bump redis from 4.5.3 to 4.5.4 in /requirements
Bumps [redis](https://github.com/redis/redis-py) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v4.5.3...v4.5.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-31 14:31:35 +00:00
jiangweidong
4c5e47cb99 perf: 普通用户工单申请时,选择指定账号,提示无权限 2023-03-30 16:26:12 +08:00
jiangweidong
cfe0206179 feat: winrm协议支持网域自动化 2023-03-30 14:58:20 +08:00
吴小白
caef6a5052 perf: applet 使用 powershell 部署 2023-03-30 12:09:03 +08:00
老广
0cd6667ede Merge pull request #10079 from jumpserver/pr@dev@perf_super_switch
perf: 支持 super 方式的切换用户
2023-03-30 10:24:43 +08:00
老广
d3cc8e5efb Merge pull request #10082 from jumpserver/dependabot/pip/requirements/redis-4.5.3
build(deps): bump redis from 4.3.3 to 4.5.3 in /requirements
2023-03-30 10:23:35 +08:00
jiangweidong
bc186df8d5 Merge branch 'dev' of https://github.com/jumpserver/jumpserver into pr@dev@feat_windows_winrm 2023-03-29 17:11:07 +08:00
jiangweidong
cab72c6991 feat: Windows类型资产增加winrm协议 2023-03-29 17:10:58 +08:00
Bai
8acfcda956 perf: issues 模版 2023-03-29 15:19:17 +08:00
Eric
344451ba55 perf: navicat 移到企业版 2023-03-29 14:56:20 +08:00
feng
678df5bf3e perf: 补回get_terminal_latest_stat 方法 2023-03-29 14:03:35 +08:00
老广
f214b47306 Merge pull request #10094 from jumpserver/pr@dev@perf_dockerfile
perf: 使用 docker.io 仓库
2023-03-29 10:06:42 +08:00
吴小白
5b017daba1 perf: 使用 docker.io 仓库 2023-03-29 10:03:14 +08:00
fit2bot
8d3319717e perf: 开启安全模式后过滤root administrator (#10089)
Co-authored-by: feng <1304903146@qq.com>
2023-03-28 16:26:40 +08:00
fit2bot
23b13db9e2 perf: category order (#10087)
Co-authored-by: feng <1304903146@qq.com>
2023-03-28 15:04:24 +08:00
Bai
3fa1b46312 fix: 修复授权规则Util类 2023-03-28 11:39:19 +08:00
Eric_Lee
1cad4a7add Merge pull request #10084 from jumpserver/pr@dev@fix_ssh_config
fix: 修正错误的 ssh 参数配置
2023-03-28 11:12:41 +08:00
吴小白
d04a0ff5d7 fix: 修正错误的 ssh 参数配置 2023-03-28 11:11:15 +08:00
dependabot[bot]
616e1ded20 build(deps): bump redis from 4.3.3 to 4.5.3 in /requirements
Bumps [redis](https://github.com/redis/redis-py) from 4.3.3 to 4.5.3.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v4.3.3...v4.5.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-27 22:33:27 +00:00
jiangweidong
5b87470b5c perf: 优化账号活动日志界面的提示及操作日志的字段内容 2023-03-27 18:23:55 +08:00
Eric
118d33fa02 perf: 支持 super 方式的切换用户 2023-03-27 18:06:30 +08:00
Aaron3S
017682b383 perf: 增加我的资产通过 node_id 过滤我的资产 2023-03-27 14:53:39 +08:00
feng
1ac2fec13f feat: 收集账号 可选同步表 2023-03-27 14:13:44 +08:00
Bai
66d368f882 fix: 修改nodes_display required = False 2023-03-24 17:11:03 +08:00
Bai
30ab6836ab fix: 修改 login_button 2023-03-24 17:09:07 +08:00
fit2bot
55e1ef116b perf: clear secret (#10053)
Co-authored-by: feng <1304903146@qq.com>
2023-03-23 16:04:09 +08:00
Bai
5d022c7056 fix: 修复资产导入支持填写节点路径 2023-03-23 16:01:19 +08:00
fit2bot
f6c5c35a2c feat: 账号收集批量同步账号 (#10051)
Co-authored-by: feng <1304903146@qq.com>
2023-03-23 15:24:19 +08:00
老广
d3170e4815 Merge pull request #10050 from jumpserver/pr@dev@chore_readme
perf: 修改 readme
2023-03-23 14:34:42 +08:00
ibuler
3959f4615a perf: 修改 readme 2023-03-23 14:33:33 +08:00
ibuler
772ad7aff7 Merge branch 'dev' of github.com:jumpserver/jumpserver into dev 2023-03-23 14:18:21 +08:00
fit2bot
166d074adb perf: 修改 port (#10049)
Co-authored-by: ibuler <ibuler@qq.com>
2023-03-23 14:13:08 +08:00
ibuler
f12e6af86e perf: 修改 port 2023-03-23 14:11:26 +08:00
fit2bot
3b45ad0c61 feat: account remove secret (#10045)
Co-authored-by: feng <1304903146@qq.com>
2023-03-23 11:20:48 +08:00
老广
72b731629e Merge pull request #10043 from jumpserver/pr@dev@perf_ssh_negotiate
perf: 支持旧版本 SSH 服务端认证
2023-03-23 10:03:08 +08:00
吴小白
f9b83b11fb perf: 支持旧版本 SSH 服务端认证 2023-03-23 08:58:31 +08:00
老广
4b8fd64c5d Merge pull request #10041 from jumpserver/pr@dev@feat_k8s_support_gateway
feat: k8s 支持 gateway
2023-03-22 19:43:54 +08:00
ibuler
e3bd698baf feat: k8s 支持 gateway 2023-03-22 19:42:51 +08:00
fit2bot
0be3cb3c27 fix: account update (#10039)
Co-authored-by: feng <1304903146@qq.com>
2023-03-22 19:14:43 +08:00
fit2bot
f7ae23f7d9 perf: 导入资产账号模版api优化 (#10038)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2023-03-22 18:35:23 +08:00
老广
402c68edd0 Merge pull request #10036 from jumpserver/pr@dev@perf_device_add_sudo
perf: 优化一下
2023-03-22 17:21:27 +08:00
ibuler
4f703e2b31 merge: with dev 2023-03-22 17:20:56 +08:00
ibuler
1e0a6b5072 perf: 优化一下 2023-03-22 17:17:49 +08:00
ibuler
47c207ce13 perf: 硬件设备支持账号切换 2023-03-22 16:49:29 +08:00
ibuler
c6071740b1 perf: 硬件设备支持账号切换 2023-03-22 16:43:00 +08:00
老广
463d54a4d8 Merge pull request #10023 from jumpserver/pr@dev@asset_accounts_secret_type_default
perf: 设置资产账号的默认值,方便导入
2023-03-22 15:38:26 +08:00
老广
8289e4c2c8 Merge pull request #10032 from jumpserver/pr@dev@platform_set_protocols
perf: 修改 platform protocols
2023-03-22 15:38:01 +08:00
ibuler
aca0d62feb perf: 优化 protocols 2023-03-22 15:28:05 +08:00
ibuler
59d9572d07 perf: 优化 protocol 选择 2023-03-22 15:26:23 +08:00
ibuler
ba076f6612 perf: 优化提示 2023-03-22 14:56:20 +08:00
fit2bot
43d805d0ca perf: 配置CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED 对改密的特权账号过滤 (#10033)
Co-authored-by: feng <1304903146@qq.com>
2023-03-22 14:48:05 +08:00
ibuler
180ded1773 perf: 修改 platform protocols 2023-03-22 14:15:25 +08:00
fit2bot
81b04c449a fix: tanslate (#10031)
Co-authored-by: feng <1304903146@qq.com>
2023-03-22 13:47:12 +08:00
fit2bot
ed4a4ceca1 perf: 批量创建账号 定义创建账号策略 忽略或抛出错误 (#10028)
Co-authored-by: feng <1304903146@qq.com>
2023-03-22 11:09:48 +08:00
老广
8e61b53460 Merge pull request #10016 from jumpserver/pr@dev@use_ghcr_registry
perf: 使用 ghcr.io 托管镜像
2023-03-21 14:17:31 +08:00
ibuler
cac59db1ec perf: 设置资产账号的默认值,方便导入 2023-03-21 12:43:54 +08:00
fit2bot
9413fd4cd1 perf: 支持 iframe 标签选择 (#9908)
* perf: 支持 iframe 标签选择

* perf: 完善 iframe 的选择语法

---------

Co-authored-by: Eric <xplzv@126.com>
2023-03-20 17:26:47 +08:00
jiangweidong
bac296f82e Merge pull request #10015 from O-Jiangweidong/pr@dev@perf_dbeaver_no_upgrade_no_download
perf: DBeaver连接时不检查更新、不提示创建实例数据库、不弹出下载驱动框
2023-03-20 16:01:37 +08:00
fit2bot
69cd7bce17 perf: 批量创建账号时,跳过unique检查 不去创建 (#9966)
Co-authored-by: feng <1304903146@qq.com>
2023-03-20 15:45:21 +08:00
吴小白
664ab0797a perf: 使用 ghcr.io 托管镜像 2023-03-20 14:22:33 +08:00
老广
4a55c55022 Merge pull request #10003 from jumpserver/pr@dev@perf_import_export
perf: 优化导入导出
2023-03-20 10:07:48 +08:00
ibuler
44b6fd8771 fix: 去掉 warning 2023-03-20 10:05:29 +08:00
jiangweidong
b6ccc53a71 perf: DBeaver连接时不检查更新、不提示创建实例数据库、不弹出下载驱动框 2023-03-20 10:02:50 +08:00
ibuler
209f0d72b4 perf: 去掉 warning 2023-03-20 10:01:42 +08:00
ibuler
eac4b41783 perf: 优化 warning 2023-03-20 09:59:34 +08:00
老广
7a35309e88 Merge pull request #10009 from WeiZhixiong/dev
fix: SyntaxWarning, apps/common/drf/parsers/base.py:114, "is" should be "=="
2023-03-20 09:51:40 +08:00
fit2bot
39e618c127 perf: 资产批量更新平台 (#10013)
Co-authored-by: feng <1304903146@qq.com>
2023-03-19 23:55:16 +08:00
WeiZhixiong
8e33c6f422 fix: SyntaxWarning, apps/common/drf/parsers/base.py:114, "is" should be "==" 2023-03-18 23:19:51 +08:00
ibuler
f5523aaf7b perf: 优化导入导出 2023-03-17 10:45:45 +00:00
ibuler
12db64ea18 perf: 优化导入导出 2023-03-17 18:44:21 +08:00
fit2bot
1acfdf0398 perf: 批量推送账号 分批处理 (#10000)
Co-authored-by: feng <1304903146@qq.com>
2023-03-17 17:10:10 +08:00
老广
074c9c85b1 Merge pull request #9999 from jumpserver/pr@dev@perf_ansible_config
perf: 优化 ansible 写法
2023-03-17 17:03:46 +08:00
ibuler
c094bce71e perf: 优化 ansible 写法 2023-03-17 16:57:40 +08:00
ibuler
cad6fffd74 perf: 优化 Ansible 账号选择 2023-03-16 19:09:29 +08:00
Bai
0747cf7c5e fix: 修复导出账号历史翻译信息 2023-03-16 16:40:53 +08:00
BugKing
927251902c workflow: 修改 Gitee 同步的目的仓库 2023-03-16 16:40:53 +08:00
Bai
11675dc850 fix: 修复日志记录到syslog时中文编码问题 2023-03-16 16:40:53 +08:00
Bai
93a7cee4de fix: 修复导出账号历史翻译信息 2023-03-16 11:18:41 +08:00
老广
1cfdfacdf7 Merge pull request #9982 from wan92hen/patch-1
workflow: 修改 Gitee 同步的目的仓库
2023-03-16 10:45:21 +08:00
BugKing
8b6c2f4cc6 workflow: 修改 Gitee 同步的目的仓库 2023-03-16 09:56:25 +08:00
Bai
41edeb9027 fix: 修复日志记录到syslog时中文编码问题 2023-03-15 19:46:01 +08:00
Jiangjie.Bai
2bcd411164 Merge pull request #9976 from jumpserver/dev
v3.1.0 rc4
2023-03-15 19:29:22 +08:00
ibuler
891d9d36b0 fix: windows 平台默认不开启 console 2023-03-15 19:01:18 +08:00
fit2bot
ebdd67d0f4 perf: endpoint rules list (#9975)
Co-authored-by: feng <1304903146@qq.com>
2023-03-15 18:24:39 +08:00
老广
09eebd7486 Merge pull request #9970 from jumpserver/pr@dev@perf_platform_change
perf: 优化资产平台的获取
2023-03-15 17:37:12 +08:00
Bai
894955dd68 fix: 修复更新授权报错的问题 2023-03-15 16:33:38 +08:00
halo
0ade034391 fix: 修复celery api 报错 2023-03-15 15:37:15 +08:00
jiangweidong
07eebd93fb perf: 测试资产可连接性选择账号策略优化 (#9954) 2023-03-15 15:16:27 +08:00
Bai
ffe9dd1f95 fix: 优化账号模版可以根据 protocols 过滤 secret_type 字段 2023-03-15 14:48:14 +08:00
ibuler
2b7f90349c perf: 优化资产平台的获取 2023-03-15 14:14:48 +08:00
Bai
48b937d867 fix: 修复手动登录用户失败的问题 2023-03-15 11:36:51 +08:00
Aaron3S
df249a0355 perf: 优化 playbook 删除策略,正在被 job 使用时无法被删除 2023-03-14 20:02:23 +08:00
fit2bot
2ce293bd81 fix: push ssh key account bug (#9948)
Co-authored-by: feng <1304903146@qq.com>
2023-03-14 17:15:04 +08:00
老广
bff97929b5 Merge pull request #9942 from jumpserver/pr@dev@perf_csv_loads_error
perf: 优化 csv parse
2023-03-14 16:35:37 +08:00
Bai
0053d469f9 fix: 修复用户导入模版中没有 password_strategy 字段问题 2023-03-14 16:31:57 +08:00
ibuler
4c24e95b47 perf: 优化 csv parse 2023-03-14 14:12:42 +08:00
fit2bot
c4945b3563 perf: 优化ansible 选择账号 (#9940)
Co-authored-by: feng <1304903146@qq.com>
2023-03-14 11:40:25 +08:00
ibuler
082af029a7 perf: 优化资产迁移,避免冲突 2023-03-14 11:21:52 +08:00
Bai
44d7165674 perf: 优化一些翻译信息,label 中带单位 2023-03-14 11:19:41 +08:00
fit2bot
d4102ceb7a perf: push select account (#9932)
Co-authored-by: feng <1304903146@qq.com>
2023-03-13 19:35:12 +08:00
老广
4a3196e193 Merge pull request #9931 from jumpserver/pr@dev@fix_excel_import_export
perf: 优化 csv import export
2023-03-13 18:07:57 +08:00
ibuler
16a7ccc95e perf: 优化文案 2023-03-13 18:06:54 +08:00
ibuler
6bb42b8d59 perf: 优化 csv import export 2023-03-13 17:57:50 +08:00
fit2bot
ed70432016 fix: 账号模版创建带密码的密钥之后无法添加到主机 (#9927)
Co-authored-by: feng <1304903146@qq.com>
2023-03-13 15:46:17 +08:00
老广
6a9e013f2f Merge pull request #9921 from jumpserver/pr@dev@fix_remoteapp_privileged_account
fix: 远程应用特权用户不生效问题
2023-03-13 11:18:26 +08:00
halo
9f98e3f098 fix: 远程应用特权用户不生效问题 2023-03-12 21:27:30 +08:00
ibuler
2ffb9a5aa3 perf: 修改 Import export 2023-03-10 19:23:49 +08:00
ibuler
fa3bfceddc perf: 优化导入导出
perf: remove debug

perf: 修改账号导入导出

perf: 去掉一些 debug
2023-03-10 19:23:49 +08:00
fit2bot
3658ecce0c perf: 修改 ssh key with pass 报错 (#9917)
Co-authored-by: ibuler <ibuler@qq.com>
2023-03-10 16:04:48 +08:00
Bai
aeb2e47880 feat: 支持飞书国际版(lark) 2023-03-10 15:13:12 +08:00
Bai
9be01b4c67 feat: 支持飞书国际版(lark) 2023-03-10 15:13:12 +08:00
Bai
83296be11f fix: ignore 2023-03-09 18:12:56 +08:00
Bai
266f5e9350 fix: 修复存在无效 es 时获取终端配置失败的问题 2023-03-09 17:12:05 +08:00
fit2bot
dfbe8c0bc4 fix: 创建资产 可连接性为更新 (#9905)
Co-authored-by: feng <1304903146@qq.com>
2023-03-09 13:59:44 +08:00
jiangweidong
3de2992238 fix: 有可能保存明文密码 2023-03-09 13:02:34 +08:00
Eric
fde92a28bd fix: 修复存储故障造成的录像获取失败问题 2023-03-09 11:51:00 +08:00
吴小白
2662ead1c4 perf: 正确配置 Ansible 证书校验 2023-03-09 11:19:24 +08:00
Bai
3f5af27a4e perf: 优化设置 MFA 文案(禁用=>重置) 2023-03-08 19:13:17 +08:00
fit2bot
c90a2df28e perf: automation account username change id (#9867)
* perf: automation account username change id

* perf: 授权账号模版 自推送

---------

Co-authored-by: feng <1304903146@qq.com>
2023-03-08 18:52:00 +08:00
老广
8a0bd3379c Merge pull request #9889 from jumpserver/pr@dev@perf_ignore_ssl
perf: tinkerd 部署增加 ignore-verify-certs 配置
2023-03-08 16:34:34 +08:00
Eric
26ad12d448 perf: build action use pypi mirror 2023-03-08 16:28:17 +08:00
Eric
177150c5cc perf: tinkerd 部署增加 ignore-verify-certs 配置 2023-03-08 16:16:10 +08:00
Bai
bbddf6a342 fix: 修复组织管理员查看活动日志详情时没有对象的问题 2023-03-08 15:57:43 +08:00
Bai
6bbe602ebb fix: 修复组织管理员查看操作日志可以看到 system 组织下的操作问题, 只有系统管理员可以查看任务监控 2023-03-08 15:22:49 +08:00
老广
21352a2ab7 Merge pull request #9871 from jumpserver/pr@dev@fix_su_from_accounts
fix: 修复su-from-accounts API 500问题,Unsubscribe msg error 转成debug
2023-03-08 14:06:59 +08:00
老广
1cbfd48e11 Merge pull request #9874 from jumpserver/pr@dev@fix_operatelog_hide_sth
fix: 操作日志显示用户加密后的密文,及日期格式调整
2023-03-08 14:06:12 +08:00
老广
c8c33c02ef Merge pull request #9880 from jumpserver/pr@dev@perf_applet_certs
fix: 修复自签证书下发布机部署失败
2023-03-08 14:04:47 +08:00
老广
261ec60ab7 Merge pull request #9870 from jumpserver/pr@dev@fix_reconnecttoken
feat: connection-token 添加重联兑换 API
2023-03-08 14:04:01 +08:00
老广
c1d1863af4 Merge pull request #9881 from jumpserver/pr@dev@perf_email_test_error
perf: 邮箱测试时,不填写'主题前缀'会报错
2023-03-08 14:02:37 +08:00
jiangweidong
72ca55c293 perf: 邮箱测试时,不填写'主题前缀'会报错 2023-03-08 13:49:38 +08:00
吴小白
7d6295775f perf: 还原国际化文本格式 2023-03-08 13:42:37 +08:00
吴小白
17ec105f69 perf: 修正错误 2023-03-08 13:40:55 +08:00
吴小白
366e20b165 fix: 修复自签证书下发布机部署失败 2023-03-08 13:27:03 +08:00
jiangweidong
be669f7f05 fix: 操作日志显示用户加密后的密文,及日期格式调整 2023-03-08 11:21:15 +08:00
feng
8833b19d79 fix: 修复su-from-accounts API 500问题,Unsubscribe msg error 转成debug 2023-03-08 10:58:37 +08:00
Bai
4c7bc105d7 feat: connection-token 添加重联兑换 API 2023-03-08 10:25:53 +08:00
老广
bb30fcd7fd Merge pull request #9851 from jumpserver/pr@dev@fix_private_key
fix: 修复 ed25519 私钥测试可连接性失败问题
2023-03-07 11:29:10 +08:00
Eric
eedc1ae8b5 fix: 修复类型问题 2023-03-02 19:05:27 +08:00
Eric
b951ed9206 fix: 修复 account 私钥文件生成 2023-03-02 18:57:49 +08:00
Eric
03cc487fe6 fix: 修复 ed25519 私钥测试可连接性失败问题 2023-03-02 18:50:09 +08:00
feng
22f3caa954 fix: 修复i8n 500 2023-03-02 16:23:16 +08:00
Bai
891c478d13 fix: 修复 ldap 用户登录时邮箱存在 500 的问题 2023-03-02 16:22:55 +08:00
Bai
1901ef7252 fix: 修复 ldap 用户登录时邮箱存在 500 的问题 2023-03-02 15:58:32 +08:00
Aaron3S
6bc2f73f49 fix: 修复作业执行没有日志权限的问题 2023-03-01 18:37:27 +08:00
fit2bot
820971e2be perf: k8s tree run (#9834)
Co-authored-by: feng <1304903146@qq.com>
2023-03-01 18:26:54 +08:00
Bai
27e1c17b26 fix: 资产类型树返回类型节点时, 没有platfrom设置isParent为False, 解决展开节点重复的问题 2023-03-01 17:28:39 +08:00
fit2bot
d8d73700ea perf: k8s tree update api (#9827)
Co-authored-by: feng <1304903146@qq.com>
2023-03-01 17:04:17 +08:00
ibuler
ed967dcba9 perf: 优化翻译 2023-03-01 15:20:55 +08:00
Bai
c39acc9a93 fix: 修改翻译 Core API & HelpText 2023-03-01 15:20:27 +08:00
Bai
c37e2d3dc2 fix: 修改翻译 已有 RDS 许可证 2023-03-01 15:20:27 +08:00
fit2bot
797c7635a7 perf: asset hardwareinfo (#9813)
Co-authored-by: feng <1304903146@qq.com>
2023-02-28 18:45:38 +08:00
老广
410668c209 Merge pull request #9812 from jumpserver/pr@dev@perf_rd_license
perf: 优化 RD License 配置
2023-02-28 18:31:16 +08:00
吴小白
3cbd772c4e perf: 优化 RD License 配置 2023-02-28 18:00:08 +08:00
Bai
bc2d4735c1 fix: 修改翻译 2023-02-28 17:59:04 +08:00
fit2bot
dfa3f4b53b perf: 推送账号 社区版定时任务关闭 (#9804)
Co-authored-by: feng <1304903146@qq.com>
2023-02-28 13:35:17 +08:00
老广
442dbc836d Merge pull request #9799 from jumpserver/pr@dev@fix_protocol_init_error
perf: 修改协议创建时一些默认值
2023-02-28 09:44:31 +08:00
ibuler
8c81e60a1e perf: 修改协议创建时一些默认值 2023-02-27 19:48:07 +08:00
fit2bot
fccdb66530 perf: 今日活跃资产 (#9796)
Co-authored-by: feng <1304903146@qq.com>
2023-02-27 18:10:08 +08:00
Aaron3S
094ad85d39 fix: 默认增加普通用户作业中心权限 2023-02-27 17:27:45 +08:00
ibuler
32081ea6ec perf: 添加账号用户名的推荐
perf: 修改账号推荐
2023-02-27 15:19:59 +08:00
ibuler
8937447955 perf: 修改资产 address 长度,以支持 mb4
perf: 修改长度
2023-02-27 14:07:54 +08:00
ibuler
454a38f994 perf: 去掉没有 Name 的迁移 2023-02-27 14:02:30 +08:00
老广
972d6fb924 Merge pull request #9777 from jumpserver/pr@dev@perf_account_migrate2
perf: 优化迁移 accounts
2023-02-27 10:08:00 +08:00
ibuler
d2b6bb5013 perf: 优化迁移 accounts
perf: 优化账号迁移,同名的迁移到历史中
2023-02-26 09:47:40 +08:00
Bai
a6388fc482 perf: 优化 README 2023-02-25 22:47:46 +08:00
Bai
32c034fdec perf: 优化 README 2023-02-25 22:47:46 +08:00
Bai
e1724844b0 perf: 优化 README 2023-02-25 22:47:46 +08:00
Bai
912ee3de09 perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
78c6252318 perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
d07c3e2de5 perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
83d97111c6 perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
616b0d7e5d perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
6168608fa1 perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
9e8cf1926e perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
11ba29cb68 perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
e8e23c2566 perf: 优化 README 2023-02-25 13:01:49 +08:00
Bai
8db518d2cd perf: 优化 README 2023-02-25 13:01:49 +08:00
老广
ec31b4de73 Merge pull request #9759 from jumpserver/pr@dev@fix_activity_save_error
fix: 解决Activity保存因为参数出错问题
2023-02-24 18:18:18 +08:00
fit2bot
f1c568dfc0 perf: 修改host info 接口, 社区开放applet, 修改改密发邮件bug (#9757)
Co-authored-by: feng <1304903146@qq.com>
2023-02-24 18:08:22 +08:00
jiangweidong
824e4c9e81 fix: 解决Activity保存因为参数出错问题 2023-02-24 17:59:32 +08:00
老广
9895ae73bc Merge pull request #9756 from jumpserver/pr@dev@update_support_version
update: 更新问题支持版本说明
2023-02-24 15:43:51 +08:00
吴小白
7d3a702e7d update: 更新问题支持版本说明 2023-02-24 15:37:51 +08:00
Bai
6541cd9f5f fix: 修复 web gui 支持的数据库 2023-02-24 15:12:41 +08:00
ibuler
22a1d60e3f perf: 优化 msg 2023-02-24 14:46:43 +08:00
Bai
63ca4f8fab fix: 修复认证MFA失败次数清空问题 2023-02-24 14:44:13 +08:00
fit2bot
a4a871ff2b fix: 修复计算今日活跃资产过滤逻辑 (#9745)
Co-authored-by: Bai <baijiangjie@gmail.com>
2023-02-24 12:16:45 +08:00
Bai
1b2de703f4 fix: 修复获取授权资产详情时返回 spec_info 字段, 解决连接 Magnus 问题 2023-02-24 11:41:15 +08:00
maninhill
4650652faf perf:更新 README 中的产品 UI 展示截图 2023-02-24 00:32:15 +08:00
ibuler
0f338a3b58 perf: 修复社区版可能引起的问题 2023-02-24 00:31:38 +08:00
老广
6bb6e8eb9b Merge pull request #9735 from jumpserver/dev
fix: 修复 loong64 grpc 构建失败
2023-02-23 21:48:51 +08:00
Jiangjie.Bai
19276e6bd4 Merge pull request #9733 from jumpserver/dev
v3.0.0
2023-02-23 20:15:55 +08:00
Jiangjie.Bai
8757cc97ed Merge pull request #9703 from jumpserver/dev
v3.0.0-rc-latest
2023-02-22 22:22:47 +08:00
Jiangjie.Bai
aac805f5e4 Merge pull request #9383 from jumpserver/dev
v3.0.0-rc4
2023-01-31 18:34:24 +08:00
Jiangjie.Bai
6febc104de Merge pull request #9096 from jumpserver/dev
v2.28.0
2022-11-17 17:43:44 +08:00
Jiangjie.Bai
733b95ee99 Merge pull request #9089 from jumpserver/dev
v2.28.0-rc5
2022-11-17 14:14:18 +08:00
Jiangjie.Bai
b179264127 Merge pull request #9080 from jumpserver/dev
v2.28.0-rc4
2022-11-16 21:05:05 +08:00
Jiangjie.Bai
c18388e27a Merge pull request #9060 from jumpserver/dev
v2.28.0-rc3
2022-11-14 18:02:44 +08:00
Jiangjie.Bai
52830db500 Merge pull request #9052 from jumpserver/dev
v2.28.0-rc2
2022-11-14 09:54:50 +08:00
Jiangjie.Bai
2324cdc14e Merge pull request #9040 from jumpserver/dev
v2.28.0-rc1
2022-11-10 17:48:40 +08:00
Jiangjie.Bai
bab4562820 Merge pull request #8980 from jumpserver/dev
v2.27.0
2022-10-20 20:39:39 +08:00
Jiangjie.Bai
613a7d63b5 Merge pull request #8973 from jumpserver/dev
v2.27.0-rc5
2022-10-19 20:30:13 +08:00
Jiangjie.Bai
129c0e1bf4 Merge pull request #8968 from jumpserver/dev
v2.27.0-rc4
2022-10-18 20:48:37 +08:00
Jiangjie.Bai
384873b4cb Merge pull request #8964 from jumpserver/dev
v2.27.0-rc3
2022-10-18 11:19:59 +08:00
Jiangjie.Bai
9e410bb389 Merge pull request #8962 from jumpserver/dev
v2.27.0-rc2
2022-10-14 11:00:50 +08:00
Jiangjie.Bai
9337463471 Merge pull request #8957 from jumpserver/dev
v2.27.0-rc1
2022-10-13 19:03:33 +08:00
Jiangjie.Bai
e6d50cc8b4 Merge pull request #8951 from jumpserver/dev
v2.27.0-rc1
2022-10-13 15:05:53 +08:00
Jiangjie.Bai
fa08517bea Merge pull request #8868 from jumpserver/dev
v2.26.0-rc4
2022-09-15 16:16:51 +08:00
Jiangjie.Bai
d808256e6a Merge pull request #8864 from jumpserver/dev
v2.26.0-rc3
2022-09-14 20:44:13 +08:00
Jiangjie.Bai
061b60ef59 Merge pull request #8858 from jumpserver/dev
v2.26.0-rc2
2022-09-13 17:40:13 +08:00
fit2bot
c008115888 fix: 修复配置mfa失效日期 失效问题 (#8856)
Co-authored-by: feng626 <1304903146@qq.com>
2022-09-13 17:39:09 +08:00
feng626
8d1fb84aaf perf: 工单新增相关过滤 2022-09-13 17:39:09 +08:00
jiangweidong
43d61b5348 feat: 支持对开启SSL/TLS的MongoDb数据库改密 2022-09-13 17:39:09 +08:00
ibuler
c26a786287 perf: 优化加密,没有rsa则不加密 2022-09-13 17:39:09 +08:00
fit2bot
cb2bd0cf2c fix: 修复账号备份失败问题 (#8852)
Co-authored-by: feng626 <1304903146@qq.com>
2022-09-13 17:39:09 +08:00
jiangweidong
3048e6311b fix: 修复华为短信配置错误,前端提示不对的问题 2022-09-13 17:39:09 +08:00
Jiangjie.Bai
31de9375e7 Merge pull request #8846 from jumpserver/dev
v2.26.0-rc1
2022-09-08 15:43:18 +08:00
Jiangjie.Bai
188c04c9a6 Merge pull request #8776 from jumpserver/dev
v2.25.0
2022-08-18 16:12:16 +08:00
Jiangjie.Bai
a82ed3e924 Merge pull request #8768 from jumpserver/dev
v2.25.0-rc5
2022-08-17 18:57:22 +08:00
Jiangjie.Bai
831b67eae4 Merge pull request #8763 from jumpserver/dev
v2.25.0-rc4
2022-08-17 16:52:28 +08:00
Jiangjie.Bai
4642804077 Merge pull request #8756 from jumpserver/dev
v2.25.0-rc3
2022-08-16 19:07:42 +08:00
Jiangjie.Bai
09160fed5d Merge pull request #8740 from jumpserver/dev
v2.25.0-rc2
2022-08-12 18:05:13 +08:00
Jiangjie.Bai
8409523fee Merge pull request #8728 from jumpserver/dev
v2.25.0-rc1
2022-08-11 14:12:23 +08:00
Jiangjie.Bai
f52a0ce960 Merge pull request #8645 from jumpserver/dev
v2.24.0
2022-07-21 15:40:57 +08:00
Jiangjie.Bai
d34c4fb7ec Merge pull request #8640 from jumpserver/dev
v2.24.0-rc5
2022-07-20 19:07:18 +08:00
Jiangjie.Bai
c12efffcc9 Merge pull request #8622 from jumpserver/dev
v2.24.0-rc4
2022-07-19 16:25:32 +08:00
Jiangjie.Bai
6319be0ea3 Merge pull request #8620 from jumpserver/dev
v2.24.0-rc4
2022-07-19 16:12:08 +08:00
Jiangjie.Bai
4d7f8ffc71 Merge pull request #8610 from jumpserver/dev
v2.24.0-rc3
2022-07-18 12:02:23 +08:00
Jiangjie.Bai
c665b0dbae Merge pull request #8603 from jumpserver/dev
v2.24.0-rc2
2022-07-15 18:07:09 +08:00
Jiangjie.Bai
a770a19252 Merge pull request #8595 from jumpserver/dev
v2.24.0-rc1
2022-07-14 17:44:33 +08:00
Jiangjie.Bai
717f97cd88 Merge pull request #8592 from jumpserver/dev
v2.24.0-rc1
2022-07-14 14:40:03 +08:00
Jiangjie.Bai
d3355ab0ec Merge pull request #8427 from jumpserver/dev
v2.23.0 rc6
2022-06-16 18:12:44 +08:00
Jiangjie.Bai
7ac385d64c Merge pull request #8420 from jumpserver/dev
v2.23.0 rc5
2022-06-16 15:46:40 +08:00
Jiangjie.Bai
2898c35970 Merge pull request #8411 from jumpserver/dev
v2.23.0 rc4
2022-06-15 19:38:17 +08:00
Jiangjie.Bai
62f5662bd0 fix: 修复openid用户登录时默认邮件后缀使用配置项 2022-06-15 19:33:26 +08:00
ibuler
0fe221019a pref: 优化没有获取到节点的问题 2022-06-15 19:33:26 +08:00
ibuler
d745314aa1 perf: 优化签名认证 2022-06-15 19:33:26 +08:00
feng626
153fad9ac7 feat: add client linux arm64 version 2022-06-15 19:33:26 +08:00
Jiangjie.Bai
0792c7ec49 fix: 修改推送系统用户提示文案 2022-06-15 19:33:26 +08:00
fit2bot
e617697553 fix: 修复授权过期通知bug (#8404)
Co-authored-by: feng626 <1304903146@qq.com>
2022-06-15 19:33:26 +08:00
fit2bot
9dc7da3595 perf: 优化 apt (#8398)
* pref: 修改 oracle lib path

* perf: 优化 apt

Co-authored-by: ibuler <ibuler@qq.com>
2022-06-15 19:33:26 +08:00
Jiangjie.Bai
f7f4d3a42e fix: 过滤系统用户密码过滤ansible不支持的字符 2022-06-15 19:33:26 +08:00
feng626
70fcbfe883 perf: 授权过期通知 2022-06-15 19:33:26 +08:00
Jiangjie.Bai
68aad56bad Merge pull request #8379 from jumpserver/dev
v2.23.0-rc3
2022-06-13 17:42:31 +08:00
Jiangjie.Bai
85b2ec2e6a Merge pull request #8362 from jumpserver/dev
v2.23.0-rc2
2022-06-10 19:12:17 +08:00
Jiangjie.Bai
be75edcb41 Merge pull request #8353 from jumpserver/dev
v2.23.0-rc1
2022-06-09 17:40:10 +08:00
Jiangjie.Bai
c41fc54380 Merge pull request #8271 from jumpserver/dev
v2.22.0-rc4
2022-05-18 20:21:35 +08:00
feng626
c2fbe5c75a fix: 不支持es8 提示 2022-05-18 20:20:54 +08:00
Jiangjie.Bai
33090c4cdf Merge pull request #8268 from jumpserver/dev
v2.22.0-rc4
2022-05-18 19:49:11 +08:00
ibuler
b5ac5c5670 perf: domain gateway 也添加 2022-05-17 21:36:40 +08:00
Jiangjie.Bai
d672122c79 Merge pull request #8260 from jumpserver/dev
v2.22.0-rc3
2022-05-17 21:14:05 +08:00
Jiangjie.Bai
514fa9cf0a Merge pull request #8250 from jumpserver/dev
v2.22.0-rc2
2022-05-17 15:10:59 +08:00
Jiangjie.Bai
7f52675bd3 Merge pull request #8229 from jumpserver/dev
v2.22.0 rc1
2022-05-12 17:02:01 +08:00
Jiangjie.Bai
a4be0ff2f3 Merge pull request #8131 from jumpserver/dev
v2.21.0
2022-04-21 18:11:21 +08:00
Jiangjie.Bai
e83d676712 Merge pull request #8119 from jumpserver/dev
v2.21.0-rc6
2022-04-20 20:25:43 +08:00
Jiangjie.Bai
015ff4b119 Merge pull request #8105 from jumpserver/dev
v2.21.0-rc5
2022-04-20 10:46:27 +08:00
Jiangjie.Bai
c04ab1aab9 Merge pull request #8100 from jumpserver/dev
v2.21.0-rc5
2022-04-19 21:52:51 +08:00
老广
714b6b1233 Merge pull request #8085 from jumpserver/dev
v2.21.0-rc5
2022-04-19 13:15:16 +08:00
Jiangjie.Bai
6f49d240af Merge pull request #8079 from jumpserver/dev
v2.21.0-rc4
2022-04-18 15:31:02 +08:00
Jiangjie.Bai
afcbe60531 Merge pull request #8076 from jumpserver/dev
v2.21.0-rc3
2022-04-18 11:43:40 +08:00
Jiangjie.Bai
f98c170b8c Merge pull request #8061 from jumpserver/dev
v2.21.0-rc2
2022-04-14 19:51:29 +08:00
Jiangjie.Bai
21c41a6334 Merge pull request #8054 from jumpserver/dev
v2.21.0-rc1
2022-04-13 20:25:47 +08:00
Jiangjie.Bai
005dd27701 Merge pull request #7917 from jumpserver/dev
v2.20.0
2022-03-17 19:22:22 +08:00
Jiangjie.Bai
8080d36d90 Merge pull request #7911 from jumpserver/dev
v2.20.0-rc6
2022-03-17 17:07:22 +08:00
Jiangjie.Bai
91a34d1a88 Merge pull request #7888 from jumpserver/dev
v2.20.0-rc5
2022-03-16 20:49:53 +08:00
Jiangjie.Bai
166745baf6 Merge pull request #7866 from jumpserver/dev
v2.20.0 rc4
2022-03-15 20:54:40 +08:00
Jiangjie.Bai
c77f02b295 Merge pull request #7844 from jumpserver/dev
v2.20.0-rc3
2022-03-15 11:37:30 +08:00
Jiangjie.Bai
cfed849175 Merge pull request #7834 from jumpserver/dev
fix: 修复setting perm
2022-03-14 15:53:11 +08:00
Jiangjie.Bai
5996cedcd6 Merge pull request #7832 from jumpserver/dev
fix: 修复权限问题
2022-03-14 15:16:51 +08:00
Jiangjie.Bai
a64ec8a1d2 Merge pull request #7825 from jumpserver/dev
v2.20.0-rc2
2022-03-14 10:38:35 +08:00
老广
45331dc9e8 Merge pull request #7796 from jumpserver/dev
v2.20.0-rc1
2022-03-10 20:34:18 +08:00
Jiangjie.Bai
18c388f3a5 Merge pull request #7629 from jumpserver/dev
v2.19.0-rc3
2022-02-17 11:04:33 +08:00
Jiangjie.Bai
7be76feeb0 Merge pull request #7622 from jumpserver/dev
v2.19.0-rc3
2022-02-16 16:42:19 +08:00
Jiangjie.Bai
ff6dbe67a6 Merge pull request #7610 from jumpserver/dev
v2.19.0-rc2
2022-02-14 18:31:52 +08:00
Jiangjie.Bai
c10436de47 Merge pull request #7589 from jumpserver/dev
v2.19.0-rc1
2022-02-10 11:24:28 +08:00
Jiangjie.Bai
37a3566b0e Merge pull request #7540 from jumpserver/dev
v2.18
2022-01-20 13:47:13 +08:00
Jiangjie.Bai
2b364c1476 Merge pull request #7534 from jumpserver/dev
v2.18.0-rc4
2022-01-19 19:36:59 +08:00
Jiangjie.Bai
2036037675 Merge pull request #7527 from jumpserver/dev
v2.18.0-rc3
2022-01-18 19:35:37 +08:00
Jiangjie.Bai
6bd597eadd Merge pull request #7511 from jumpserver/dev
v2.18.0-rc2
2022-01-17 19:21:39 +08:00
Jiangjie.Bai
fbd0b44d4f Merge pull request #7490 from jumpserver/dev
v2.18.0-rc1
2022-01-12 20:58:04 +08:00
Jiangjie.Bai
35722a8466 Merge pull request #7487 from jumpserver/dev
v2.18.0-rc1
2022-01-12 20:56:33 +08:00
Jiangjie.Bai
d27947919b Merge pull request #7404 from jumpserver/dev
v2.17.0 rc4
2021-12-15 22:03:19 +08:00
Jiangjie.Bai
151d897746 Merge pull request #7391 from jumpserver/dev
v2.17.0 rc3
2021-12-14 21:58:27 +08:00
Jiangjie.Bai
d6aad41d05 Merge pull request #7373 from jumpserver/dev
v2.17.0 rc2
2021-12-13 19:47:33 +08:00
Jiangjie.Bai
5f7fa7e02f Merge pull request #7355 from jumpserver/dev
v2.17.0 rc1
2021-12-09 20:57:02 +08:00
331 changed files with 9032 additions and 3767 deletions

View File

@@ -8,4 +8,4 @@ celerybeat.pid
### Vagrant ###
.vagrant/
apps/xpack/.git
.history/

View File

@@ -3,7 +3,10 @@ name: 需求建议
about: 提出针对本项目的想法和建议
title: "[Feature] "
labels: 类型:需求
assignees: ibuler
assignees:
- ibuler
- baijiangjie
---

View File

@@ -3,11 +3,13 @@ name: Bug 提交
about: 提交产品缺陷帮助我们更好的改进
title: "[Bug] "
labels: 类型:bug
assignees: wojiushixiaobai
assignees:
- wojiushixiaobai
- baijiangjie
---
**JumpServer 版本(v1.5.9以下不再支持)**
**JumpServer 版本( v2.28 之前的版本不再支持 )**
**浏览器版本**
@@ -17,6 +19,6 @@ assignees: wojiushixiaobai
**Bug 重现步骤(有截图更好)**
1.
2.
3.
1.
2.
3.

View File

@@ -3,7 +3,9 @@ name: 问题咨询
about: 提出针对本项目安装部署、使用及其他方面的相关问题
title: "[Question] "
labels: 类型:提问
assignees: wojiushixiaobai
assignees:
- wojiushixiaobai
- baijiangjie
---

View File

@@ -24,6 +24,7 @@ jobs:
build-args: |
APT_MIRROR=http://deb.debian.org
PIP_MIRROR=https://pypi.org/simple
PIP_JMS_MIRROR=https://pypi.org/simple
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -20,4 +20,4 @@ jobs:
SSH_PRIVATE_KEY: ${{ secrets.GITEE_SSH_PRIVATE_KEY }}
with:
source-repo: 'git@github.com:jumpserver/jumpserver.git'
destination-repo: 'git@gitee.com:jumpserver/jumpserver.git'
destination-repo: 'git@gitee.com:fit2cloud-feizhiyun/JumpServer.git'

1
.gitignore vendored
View File

@@ -43,3 +43,4 @@ releashe
/apps/script.py
data/*
test.py
.history/

View File

@@ -55,7 +55,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
&& 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" > /root/.ssh/config \
&& 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 \

View File

@@ -53,7 +53,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
&& 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" > /root/.ssh/config \
&& 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 \
@@ -76,8 +76,8 @@ RUN --mount=type=cache,target=/root/.cache/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 $(grep 'PyNaCl' requirements/requirements.txt) \
&& GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=true pip install grpcio \
&& pip install https://download.jumpserver.org/pypi/simple/PyNaCl/PyNaCl-1.5.0-cp39-cp39-linux_loongarch64.whl \
&& pip install https://download.jumpserver.org/pypi/simple/grpcio/grpcio-1.54.2-cp39-cp39-linux_loongarch64.whl \
&& pip install $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install -r requirements/requirements.txt

1
GITSHA Normal file
View File

@@ -0,0 +1 @@
4a56875bdae55a28159c58c6708593fa744af08e

View File

@@ -10,9 +10,27 @@
<a href="https://github.com/jumpserver/jumpserver"><img src="https://img.shields.io/github/stars/jumpserver/jumpserver?color=%231890FF&style=flat-square" alt="Stars"></a>
</p>
<p align="center">
JumpServer <a href="https://github.com/jumpserver/jumpserver/releases/tag/v3.0.0">v3.0</a> 正式发布。
<br>
9 年时间,倾情投入,用心做好一款开源堡垒机。
</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 / Oracle / SQLServer / PostgreSQL 等;
- **Kubernetes**: 支持连接到 K8s 集群中的 Pods
- **Web 站点**: 各类系统的 Web 管理后台;
- **应用**: 通过 Remote App 连接各类应用。
## 产品特色
@@ -22,12 +40,10 @@ JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运
- **多云支持**: 一套系统,同时管理不同云上面的资产;
- **多租户**: 一套系统,多个子公司或部门同时使用;
- **云端存储**: 审计录像云端存储,永不丢失;
- **多应用支持**: 全面支持各类资产包括服务器、数据库、Windows RemoteApp、Kubernetes 等;
- **安全可靠**: 被广泛使用、验证和信赖,连续 9 年的持续研发投入和产品更新升级。
## UI 展示
![UI展示](https://www.jumpserver.org/images/screenshot/1.png)
![UI展示](https://docs.jumpserver.org/zh/v3/img/dashboard.png)
## 在线体验
@@ -41,9 +57,9 @@ JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运
## 快速开始
- [极速安装](https://docs.jumpserver.org/zh/master/install/setup_by_fast/)
- [手动安装](https://github.com/jumpserver/installer)
- [快速入门](https://docs.jumpserver.org/zh/v3/quick_start/)
- [产品文档](https://docs.jumpserver.org)
- [在线学习](https://edu.fit2cloud.com/page/2635362)
- [知识库](https://kb.fit2cloud.com/categories/jumpserver)
## 案例研究
@@ -61,12 +77,13 @@ JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运
- [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687)
- [江苏农信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"/>
@@ -96,7 +113,7 @@ JumpServer是一款安全产品请参考 [基本安全建议](https://docs.ju
- 邮箱support@fit2cloud.com
- 电话400-052-0755
## 致谢
## 致谢开源
- [Apache Guacamole](https://guacamole.apache.org/) Web 页面连接 RDP、SSH、VNC 等协议资产JumpServer Lion 组件使用到该项目;
- [OmniDB](https://omnidb.org/) Web 页面连接使用数据库JumpServer Web 数据库组件使用到该项目。

View File

@@ -1,20 +1,22 @@
from django.shortcuts import get_object_or_404
from rest_framework.decorators import action
from rest_framework.generics import ListAPIView
from rest_framework.generics import ListAPIView, CreateAPIView
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK
from accounts import serializers
from accounts.filters import AccountFilterSet
from accounts.models import Account
from assets.models import Asset
from common.permissions import UserConfirmation, ConfirmType
from assets.models import Asset, Node
from common.api import ExtraFilterFieldsMixin
from common.permissions import UserConfirmation, ConfirmType, IsValidUser
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission
__all__ = [
'AccountViewSet', 'AccountSecretsViewSet',
'AccountHistoriesSecretAPI'
'AccountHistoriesSecretAPI', 'AssetAccountBulkCreateApi',
]
@@ -28,7 +30,9 @@ class AccountViewSet(OrgBulkModelViewSet):
rbac_perms = {
'partial_update': ['accounts.change_account'],
'su_from_accounts': 'accounts.view_account',
'clear_secret': 'accounts.change_account',
}
export_as_zip = True
@action(methods=['get'], detail=False, url_path='su-from-accounts')
def su_from_accounts(self, request, *args, **kwargs):
@@ -42,11 +46,43 @@ class AccountViewSet(OrgBulkModelViewSet):
asset = get_object_or_404(Asset, pk=asset_id)
accounts = asset.accounts.all()
else:
accounts = []
accounts = Account.objects.none()
accounts = self.filter_queryset(accounts)
serializer = serializers.AccountSerializer(accounts, many=True)
return Response(data=serializer.data)
@action(
methods=['get'], detail=False, url_path='username-suggestions',
permission_classes=[IsValidUser]
)
def username_suggestions(self, request, *args, **kwargs):
asset_ids = request.query_params.get('assets')
node_keys = request.query_params.get('keys')
username = request.query_params.get('username')
assets = Asset.objects.all()
if asset_ids:
assets = assets.filter(id__in=asset_ids.split(','))
if node_keys:
patten = Node.get_node_all_children_key_pattern(node_keys.split(','))
assets = assets.filter(nodes__key__regex=patten)
accounts = Account.objects.filter(asset__in=assets)
if username:
accounts = accounts.filter(username__icontains=username)
usernames = list(accounts.values_list('username', flat=True).distinct()[:10])
usernames.sort()
common = [i for i in usernames if i in usernames if i.lower() in ['root', 'admin', 'administrator']]
others = [i for i in usernames if i not in common]
usernames = common + others
return Response(data=usernames)
@action(methods=['patch'], detail=False, url_path='clear-secret')
def clear_secret(self, request, *args, **kwargs):
account_ids = request.data.get('account_ids', [])
self.model.objects.filter(id__in=account_ids).update(secret=None)
return Response(status=HTTP_200_OK)
class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
"""
@@ -63,7 +99,21 @@ class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
}
class AccountHistoriesSecretAPI(RecordViewLogMixin, ListAPIView):
class AssetAccountBulkCreateApi(CreateAPIView):
serializer_class = serializers.AssetAccountBulkSerializer
rbac_perms = {
'POST': 'accounts.add_account',
}
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
data = serializer.create(serializer.validated_data)
serializer = serializers.AssetAccountBulkSerializerResultSerializer(data, many=True)
return Response(data=serializer.data, status=HTTP_200_OK)
class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, RecordViewLogMixin, ListAPIView):
model = Account.history.model
serializer_class = serializers.AccountHistorySerializer
http_method_names = ['get', 'options']
@@ -75,6 +125,10 @@ class AccountHistoriesSecretAPI(RecordViewLogMixin, ListAPIView):
def get_object(self):
return get_object_or_404(Account, pk=self.kwargs.get('pk'))
@staticmethod
def filter_spm_queryset(resource_ids, queryset):
return queryset.filter(history_id__in=resource_ids)
def get_queryset(self):
account = self.get_object()
histories = account.history.all()

View File

@@ -24,15 +24,16 @@ class AccountsTaskCreateAPI(CreateAPIView):
def perform_create(self, serializer):
data = serializer.validated_data
accounts = data.get('accounts', [])
params = data.get('params')
account_ids = [str(a.id) for a in accounts]
if data['action'] == 'push':
task = push_accounts_to_assets_task.delay(account_ids)
task = push_accounts_to_assets_task.delay(account_ids, params)
else:
account = accounts[0]
asset = account.asset
if not asset.auto_info['ansible_enabled'] or \
not asset.auto_info['ping_enabled']:
if not asset.auto_config['ansible_enabled'] or \
not asset.auto_config['ping_enabled']:
raise NotSupportedTemporarilyError()
task = verify_accounts_connectivity_task.delay(account_ids)

View File

@@ -1,19 +1,59 @@
from rbac.permissions import RBACPermission
from common.permissions import UserConfirmation, ConfirmType
from django_filters import rest_framework as drf_filters
from rest_framework.decorators import action
from rest_framework.response import Response
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet
from accounts import serializers
from accounts.models import AccountTemplate
from assets.const import Protocol
from common.drf.filters import BaseFilterSet
from common.permissions import UserConfirmation, ConfirmType
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission
class AccountTemplateFilterSet(BaseFilterSet):
protocols = drf_filters.CharFilter(method='filter_protocols')
class Meta:
model = AccountTemplate
fields = ('username', 'name')
@staticmethod
def filter_protocols(queryset, name, value):
secret_types = set()
protocols = value.split(',')
protocol_secret_type_map = Protocol.settings()
for p in protocols:
if p not in protocol_secret_type_map:
continue
_st = protocol_secret_type_map[p].get('secret_types', [])
secret_types.update(_st)
if not secret_types:
secret_types = ['password']
queryset = queryset.filter(secret_type__in=secret_types)
return queryset
class AccountTemplateViewSet(OrgBulkModelViewSet):
model = AccountTemplate
filterset_fields = ("username", 'name')
filterset_class = AccountTemplateFilterSet
search_fields = ('username', 'name')
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')
template = AccountTemplate.objects.filter(pk=pk).first()
templates = AccountTemplate.get_su_from_account_templates(template)
templates = self.filter_queryset(templates)
serializer = self.get_serializer(templates, many=True)
return Response(data=serializer.data)
class AccountTemplateSecretsViewSet(RecordViewLogMixin, AccountTemplateViewSet):

View File

@@ -1,13 +1,11 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from accounts import serializers
from accounts.const import AutomationTypes
from accounts.const import Source
from accounts.filters import GatheredAccountFilterSet
from accounts.models import GatherAccountsAutomation
from accounts.models import GatheredAccount
@@ -50,22 +48,12 @@ class GatheredAccountViewSet(OrgBulkModelViewSet):
'default': serializers.GatheredAccountSerializer,
}
rbac_perms = {
'sync_account': 'assets.add_gatheredaccount',
'sync_accounts': 'assets.add_gatheredaccount',
}
@action(methods=['post'], detail=True, url_path='sync')
def sync_account(self, request, *args, **kwargs):
gathered_account = super().get_object()
asset = gathered_account.asset
username = gathered_account.username
accounts = asset.accounts.filter(username=username)
if accounts.exists():
accounts.update(source=Source.COLLECTED)
else:
asset.accounts.model.objects.create(
asset=asset, username=username,
name=f'{username}-{_("Collected")}',
source=Source.COLLECTED
)
@action(methods=['post'], detail=False, url_path='sync-accounts')
def sync_accounts(self, request, *args, **kwargs):
gathered_account_ids = request.data.get('gathered_account_ids')
gathered_accounts = self.model.objects.filter(id__in=gathered_account_ids)
self.model.sync_accounts(gathered_accounts)
return Response(status=status.HTTP_201_CREATED)

View File

@@ -0,0 +1,40 @@
- hosts: custom
gather_facts: no
vars:
ansible_connection: local
tasks:
- name: Test privileged account
ssh_ping:
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_secret_type: "{{ jms_account.secret_type }}"
login_private_key_path: "{{ jms_account.private_key_path }}"
register: ping_info
- name: Change asset password
custom_command:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_secret_type: "{{ jms_account.secret_type }}"
login_private_key_path: "{{ jms_account.private_key_path }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
commands: "{{ params.commands }}"
first_conn_delay_time: "{{ first_conn_delay_time | default(0.5) }}"
when: ping_info is succeeded
register: change_info
- name: Verify password
ssh_ping:
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
when:
- ping_info is succeeded
- change_info is succeeded

View File

@@ -0,0 +1,19 @@
id: change_secret_by_ssh
name: "{{ 'SSH account change secret' | trans }}"
category:
- device
- host
type:
- all
method: change_secret
params:
- name: commands
type: list
label: '自定义命令'
default: [ '' ]
help_text: '自定义命令中如需包含账号的 账号、密码、SSH 连接的用户密码 字段,<br />请使用 &#123;username&#125;、&#123;password&#125;、&#123;login_password&#125;格式,执行任务时会进行替换 。<br />比如针对 Cisco 主机进行改密,一般需要配置五条命令:<br />1. enable<br />2. &#123;login_password&#125;<br />3. configure terminal<br />4. username &#123;username&#125; privilege 0 password &#123;password&#125; <br />5. end'
i18n:
SSH account change secret:
zh: SSH 账号改密
ja: SSH アカウントのパスワード変更

View File

@@ -1,6 +1,11 @@
id: change_secret_mongodb
name: Change secret for MongoDB
name: "{{ 'MongoDB account change secret' | trans }}"
category: database
type:
- mongodb
method: change_secret
i18n:
MongoDB account change secret:
zh: MongoDB 账号改密
ja: MongoDB アカウントのパスワード変更

View File

@@ -1,7 +1,12 @@
id: change_secret_mysql
name: Change secret for MySQL
name: "{{ 'MySQL account change secret' | trans }}"
category: database
type:
- mysql
- mariadb
method: change_secret
i18n:
MySQL account change secret:
zh: MySQL 账号改密
ja: MySQL アカウントのパスワード変更

View File

@@ -1,6 +1,11 @@
id: change_secret_oracle
name: Change secret for Oracle
name: "{{ 'Oracle account change secret' | trans }}"
category: database
type:
- oracle
method: change_secret
i18n:
Oracle account change secret:
zh: Oracle 账号改密
ja: Oracle アカウントのパスワード変更

View File

@@ -1,6 +1,11 @@
id: change_secret_postgresql
name: Change secret for PostgreSQL
name: "{{ 'PostgreSQL account change secret' | trans }}"
category: database
type:
- postgresql
method: change_secret
i18n:
PostgreSQL account change secret:
zh: PostgreSQL 账号改密
ja: PostgreSQL アカウントのパスワード変更

View File

@@ -1,6 +1,11 @@
id: change_secret_sqlserver
name: Change secret for SQLServer
name: "{{ 'SQLServer account change secret' | trans }}"
category: database
type:
- sqlserver
method: change_secret
i18n:
SQLServer account change secret:
zh: SQLServer 账号改密
ja: SQLServer アカウントのパスワード変更

View File

@@ -9,28 +9,28 @@
name: "{{ account.username }}"
password: "{{ account.secret | password_hash('des') }}"
update_password: always
when: 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: secret_type == "ssh_key"
when: account.secret_type == "ssh_key"
- name: remove jumpserver ssh key
ansible.builtin.lineinfile:
dest: "{{ kwargs.dest }}"
regexp: "{{ kwargs.regexp }}"
dest: "{{ ssh_params.dest }}"
regexp: "{{ ssh_params.regexp }}"
state: absent
when:
- secret_type == "ssh_key"
- kwargs.strategy == "set_jms"
- account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms"
- name: Change SSH key
ansible.builtin.authorized_key:
user: "{{ account.username }}"
key: "{{ account.secret }}"
exclusive: "{{ kwargs.exclusive }}"
when: secret_type == "ssh_key"
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: Refresh connection
ansible.builtin.meta: reset_connection
@@ -42,7 +42,7 @@
ansible_user: "{{ account.username }}"
ansible_password: "{{ account.secret }}"
ansible_become: no
when: secret_type == "password"
when: account.secret_type == "password"
- name: Verify SSH key
ansible.builtin.ping:
@@ -51,4 +51,4 @@
ansible_user: "{{ account.username }}"
ansible_ssh_private_key_file: "{{ account.private_key_path }}"
ansible_become: no
when: secret_type == "ssh_key"
when: account.secret_type == "ssh_key"

View File

@@ -1,6 +1,11 @@
id: change_secret_aix
name: Change secret for aix
name: "{{ 'AIX account change secret' | trans }}"
category: host
type:
- AIX
method: change_secret
i18n:
AIX account change secret:
zh: AIX 账号改密
ja: AIX アカウントのパスワード変更

View File

@@ -9,28 +9,28 @@
name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}"
update_password: always
when: 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: secret_type == "ssh_key"
when: account.secret_type == "ssh_key"
- name: remove jumpserver ssh key
ansible.builtin.lineinfile:
dest: "{{ kwargs.dest }}"
regexp: "{{ kwargs.regexp }}"
dest: "{{ ssh_params.dest }}"
regexp: "{{ ssh_params.regexp }}"
state: absent
when:
- secret_type == "ssh_key"
- kwargs.strategy == "set_jms"
- account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms"
- name: Change SSH key
ansible.builtin.authorized_key:
user: "{{ account.username }}"
key: "{{ account.secret }}"
exclusive: "{{ kwargs.exclusive }}"
when: secret_type == "ssh_key"
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: Refresh connection
ansible.builtin.meta: reset_connection
@@ -42,7 +42,7 @@
ansible_user: "{{ account.username }}"
ansible_password: "{{ account.secret }}"
ansible_become: no
when: secret_type == "password"
when: account.secret_type == "password"
- name: Verify SSH key
ansible.builtin.ping:
@@ -51,4 +51,4 @@
ansible_user: "{{ account.username }}"
ansible_ssh_private_key_file: "{{ account.private_key_path }}"
ansible_become: no
when: secret_type == "ssh_key"
when: account.secret_type == "ssh_key"

View File

@@ -1,7 +1,12 @@
id: change_secret_posix
name: Change secret for posix
name: "{{ 'Posix account change secret' | trans }}"
category: host
type:
- unix
- linux
method: change_secret
i18n:
Posix account change secret:
zh: Posix 账号改密
ja: Posix アカウントのパスワード変更

View File

@@ -1,7 +1,12 @@
id: change_secret_local_windows
name: Change secret local account for Windows
name: "{{ 'Windows account change secret' | trans }}"
version: 1
method: change_secret
category: host
type:
- windows
i18n:
Windows account change secret:
zh: Windows 账号改密
ja: Windows アカウントのパスワード変更

View File

@@ -12,7 +12,7 @@ from accounts.models import ChangeSecretRecord
from accounts.notifications import ChangeSecretExecutionTaskMsg
from accounts.serializers import ChangeSecretRecordBackUpSerializer
from assets.const import HostTypes
from common.utils import get_logger, lazyproperty
from common.utils import get_logger
from common.utils.file import encrypt_and_compress_zip_file
from common.utils.timezone import local_now_display
from users.models import User
@@ -28,23 +28,23 @@ class ChangeSecretManager(AccountBasePlaybookManager):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.method_hosts_mapper = defaultdict(list)
self.secret_type = self.execution.snapshot['secret_type']
self.secret_type = self.execution.snapshot.get('secret_type')
self.secret_strategy = self.execution.snapshot.get(
'secret_strategy', SecretStrategy.custom
)
self.ssh_key_change_strategy = self.execution.snapshot.get(
'ssh_key_change_strategy', SSHKeyStrategy.add
)
self.snapshot_account_usernames = self.execution.snapshot['accounts']
self.account_ids = self.execution.snapshot['accounts']
self.name_recorder_mapper = {} # 做个映射,方便后面处理
@classmethod
def method_type(cls):
return AutomationTypes.change_secret
def get_kwargs(self, account, secret):
def get_ssh_params(self, account, secret, secret_type):
kwargs = {}
if self.secret_type != SecretType.SSH_KEY:
if secret_type != SecretType.SSH_KEY:
return kwargs
kwargs['strategy'] = self.ssh_key_change_strategy
kwargs['exclusive'] = 'yes' if kwargs['strategy'] == SSHKeyStrategy.set else 'no'
@@ -54,18 +54,34 @@ class ChangeSecretManager(AccountBasePlaybookManager):
kwargs['regexp'] = '.*{}$'.format(secret.split()[2].strip())
return kwargs
@lazyproperty
def secret_generator(self):
def secret_generator(self, secret_type):
return SecretGenerator(
self.secret_strategy, self.secret_type,
self.secret_strategy, secret_type,
self.execution.snapshot.get('password_rules')
)
def get_secret(self):
def get_secret(self, secret_type):
if self.secret_strategy == SecretStrategy.custom:
return self.execution.snapshot['secret']
else:
return self.secret_generator.get_secret()
return self.secret_generator(secret_type).get_secret()
def get_accounts(self, privilege_account):
if not privilege_account:
print(f'not privilege account')
return []
asset = privilege_account.asset
accounts = asset.accounts.all()
accounts = accounts.filter(id__in=self.account_ids)
if self.secret_type:
accounts = accounts.filter(secret_type=self.secret_type)
if settings.CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED:
accounts = accounts.filter(privileged=False).exclude(
username__in=['root', 'administrator', privilege_account.username]
)
return accounts
def host_callback(
self, host, asset=None, account=None,
@@ -78,17 +94,10 @@ class ChangeSecretManager(AccountBasePlaybookManager):
if host.get('error'):
return host
accounts = asset.accounts.all()
if account:
accounts = accounts.exclude(username=account.username)
if '*' not in self.snapshot_account_usernames:
accounts = accounts.filter(username__in=self.snapshot_account_usernames)
accounts = accounts.filter(secret_type=self.secret_type)
accounts = self.get_accounts(account)
if not accounts:
print('没有发现待改密账号: %s 用户: %s 类型: %s' % (
asset.name, self.snapshot_account_usernames, self.secret_type
print('没有发现待改密账号: %s 用户ID: %s 类型: %s' % (
asset.name, self.account_ids, self.secret_type
))
return []
@@ -97,16 +106,17 @@ class ChangeSecretManager(AccountBasePlaybookManager):
method_hosts = [h for h in method_hosts if h != host['name']]
inventory_hosts = []
records = []
host['secret_type'] = self.secret_type
if asset.type == HostTypes.WINDOWS and self.secret_type == SecretType.SSH_KEY:
print(f'Windows {asset} does not support ssh key push \n')
print(f'Windows {asset} does not support ssh key push')
return inventory_hosts
host['ssh_params'] = {}
for account in accounts:
h = deepcopy(host)
secret_type = account.secret_type
h['name'] += '(' + account.username + ')'
new_secret = self.get_secret()
new_secret = self.get_secret(secret_type)
recorder = ChangeSecretRecord(
asset=asset, account=account, execution=self.execution,
@@ -116,15 +126,15 @@ class ChangeSecretManager(AccountBasePlaybookManager):
self.name_recorder_mapper[h['name']] = recorder
private_key_path = None
if self.secret_type == SecretType.SSH_KEY:
if secret_type == SecretType.SSH_KEY:
private_key_path = self.generate_private_key_path(new_secret, path_dir)
new_secret = self.generate_public_key(new_secret)
h['kwargs'] = self.get_kwargs(account, new_secret)
h['ssh_params'].update(self.get_ssh_params(account, new_secret, secret_type))
h['account'] = {
'name': account.name,
'username': account.username,
'secret_type': account.secret_type,
'secret_type': secret_type,
'secret': new_secret,
'private_key_path': private_key_path
}
@@ -206,7 +216,7 @@ class ChangeSecretManager(AccountBasePlaybookManager):
serializer = serializer_cls(recorders, many=True)
header = [str(v.label) for v in serializer.child.fields.values()]
rows = [list(row.values()) for row in serializer.data]
rows = [[str(i) for i in row.values()] for row in serializer.data]
if not rows:
return False

View File

@@ -1,6 +1,11 @@
id: gather_accounts_mongodb
name: Gather account from MongoDB
name: "{{ 'MongoDB account gather' | trans }}"
category: database
type:
- mongodb
method: gather_accounts
i18n:
MongoDB account gather:
zh: MongoDB 账号收集
ja: MongoDB アカウントの収集

View File

@@ -1,7 +1,12 @@
id: gather_accounts_mysql
name: Gather account from MySQL
name: "{{ 'MySQL account gather' | trans }}"
category: database
type:
- mysql
- mariadb
method: gather_accounts
i18n:
MySQL account gather:
zh: MySQL 账号收集
ja: MySQL アカウントの収集

View File

@@ -1,6 +1,11 @@
id: gather_accounts_oracle
name: Gather account from Oracle
name: "{{ 'Oracle account gather' | trans }}"
category: database
type:
- oracle
method: gather_accounts
i18n:
Oracle account gather:
zh: Oracle 账号收集
ja: Oracle アカウントの収集

View File

@@ -1,6 +1,11 @@
id: gather_accounts_postgresql
name: Gather account for PostgreSQL
name: "{{ 'PostgreSQL account gather' | trans }}"
category: database
type:
- postgresql
method: gather_accounts
i18n:
PostgreSQL account gather:
zh: PostgreSQL 账号收集
ja: PostgreSQL アカウントの収集

View File

@@ -13,8 +13,8 @@ class GatherAccountsFilter:
def mysql_filter(info):
result = {}
for _, user_dict in info.items():
for username, data in user_dict.items():
if data.get('account_locked') == 'N':
for username, _ in user_dict.items():
if len(username.split('.')) == 1:
result[username] = {}
return result
@@ -60,4 +60,6 @@ class GatherAccountsFilter:
if not run_method_name:
return info
return getattr(self, f'{run_method_name}_filter')(info)
if hasattr(self, f'{run_method_name}_filter'):
return getattr(self, f'{run_method_name}_filter')(info)
return info

View File

@@ -1,7 +1,12 @@
id: gather_accounts_posix
name: Gather posix account
name: "{{ 'Posix account gather' | trans }}"
category: host
type:
- linux
- unix
method: gather_accounts
i18n:
Posix account gather:
zh: Posix 账号收集
ja: Posix アカウントの収集

View File

@@ -1,7 +1,12 @@
id: gather_accounts_windows
name: Gather account windows
name: "{{ 'Windows account gather' | trans }}"
version: 1
method: gather_accounts
category: host
type:
- windows
i18n:
Windows account gather:
zh: Windows 账号收集
ja: Windows アカウントの収集

View File

@@ -12,6 +12,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.host_asset_mapper = {}
self.is_sync_account = self.execution.snapshot.get('is_sync_account')
@classmethod
def method_type(cls):
@@ -22,29 +23,41 @@ class GatherAccountsManager(AccountBasePlaybookManager):
self.host_asset_mapper[host['name']] = asset
return host
def filter_success_result(self, host, result):
result = GatherAccountsFilter(host).run(self.method_id_meta_mapper, result)
def filter_success_result(self, tp, result):
result = GatherAccountsFilter(tp).run(self.method_id_meta_mapper, result)
return result
@staticmethod
def update_or_create_gathered_accounts(asset, result):
def generate_data(asset, result):
data = []
for username, info in result.items():
d = {'asset': asset, 'username': username, 'present': True}
if info.get('date'):
d['date_last_login'] = info['date']
if info.get('address'):
d['address_last_login'] = info['address'][:32]
data.append(d)
return data
def update_or_create_accounts(self, asset, result):
data = self.generate_data(asset, result)
with tmp_to_org(asset.org_id):
gathered_accounts = []
GatheredAccount.objects.filter(asset=asset, present=True).update(present=False)
for username, data in result.items():
d = {'asset': asset, 'username': username, 'present': True}
if data.get('date'):
d['date_last_login'] = data['date']
if data.get('address'):
d['address_last_login'] = data['address'][:32]
GatheredAccount.objects.update_or_create(
for d in data:
username = d['username']
gathered_account, __ = GatheredAccount.objects.update_or_create(
defaults=d, asset=asset, username=username,
)
gathered_accounts.append(gathered_account)
if not self.is_sync_account:
return
GatheredAccount.sync_accounts(gathered_accounts)
def on_host_success(self, host, result):
info = result.get('debug', {}).get('res', {}).get('info', {})
asset = self.host_asset_mapper.get(host)
if asset and info:
result = self.filter_success_result(asset.type, info)
self.update_or_create_gathered_accounts(asset, result)
self.update_or_create_accounts(asset, result)
else:
logger.error("Not found info".format(host))

View File

@@ -1,30 +1,6 @@
import os
import copy
from accounts.const import AutomationTypes
from assets.automations.methods import get_platform_automation_methods
def copy_change_secret_to_push_account(methods):
push_account = AutomationTypes.push_account
change_secret = AutomationTypes.change_secret
copy_methods = copy.deepcopy(methods)
for method in copy_methods:
if not method['id'].startswith(change_secret):
continue
copy_method = copy.deepcopy(method)
copy_method['method'] = push_account.value
copy_method['id'] = copy_method['id'].replace(
change_secret, push_account
)
copy_method['name'] = copy_method['name'].replace(
'Change secret', 'Push account'
)
methods.append(copy_method)
return methods
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
automation_methods = get_platform_automation_methods(BASE_DIR)
platform_automation_methods = copy_change_secret_to_push_account(automation_methods)
platform_automation_methods = get_platform_automation_methods(BASE_DIR)

View File

@@ -0,0 +1,58 @@
- hosts: mongodb
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Test MongoDB connection
mongodb_ping:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}"
ssl: "{{ jms_asset.spec_info.use_ssl }}"
ssl_ca_certs: "{{ jms_asset.secret_info.ca_cert }}"
ssl_certfile: "{{ jms_asset.secret_info.client_key }}"
connection_options:
- tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}"
register: db_info
- name: Display MongoDB version
debug:
var: db_info.server_version
when: db_info is succeeded
- name: Change MongoDB password
mongodb_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}"
ssl: "{{ jms_asset.spec_info.use_ssl }}"
ssl_ca_certs: "{{ jms_asset.secret_info.ca_cert }}"
ssl_certfile: "{{ jms_asset.secret_info.client_key }}"
connection_options:
- tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}"
db: "{{ jms_asset.spec_info.db_name }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
when: db_info is succeeded
register: change_info
- name: Verify password
mongodb_ping:
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}"
ssl: "{{ jms_asset.spec_info.use_ssl }}"
ssl_ca_certs: "{{ jms_asset.secret_info.ca_cert }}"
ssl_certfile: "{{ jms_asset.secret_info.client_key }}"
connection_options:
- tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}"
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -0,0 +1,11 @@
id: push_account_mongodb
name: "{{ 'MongoDB account push' | trans }}"
category: database
type:
- mongodb
method: push_account
i18n:
MongoDB account push:
zh: MongoDB 账号推送
ja: MongoDB アカウントのプッシュ

View File

@@ -0,0 +1,43 @@
- hosts: mysql
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
db_name: "{{ jms_asset.spec_info.db_name }}"
tasks:
- name: Test MySQL connection
community.mysql.mysql_info:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
filter: version
register: db_info
- name: MySQL version
debug:
var: db_info.version.full
- name: Change MySQL password
community.mysql.mysql_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
host: "%"
priv: "{{ account.username + '.*:USAGE' if db_name == '' else db_name + '.*:ALL' }}"
when: db_info is succeeded
register: change_info
- name: Verify password
community.mysql.mysql_info:
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
filter: version
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -0,0 +1,12 @@
id: push_account_mysql
name: "{{ 'MySQL account push' | trans }}"
category: database
type:
- mysql
- mariadb
method: push_account
i18n:
MySQL account push:
zh: MySQL 账号推送
ja: MySQL アカウントのプッシュ

View File

@@ -0,0 +1,44 @@
- hosts: oracle
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Test Oracle connection
oracle_ping:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}"
mode: "{{ jms_account.mode }}"
register: db_info
- name: Display Oracle version
debug:
var: db_info.server_version
when: db_info is succeeded
- name: Change Oracle password
oracle_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}"
mode: "{{ jms_account.mode }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
when: db_info is succeeded
register: change_info
- name: Verify password
oracle_ping:
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.spec_info.db_name }}"
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -0,0 +1,11 @@
id: push_account_oracle
name: "{{ 'Oracle account push' | trans }}"
category: database
type:
- oracle
method: push_account
i18n:
Oracle account push:
zh: Oracle 账号推送
ja: Oracle アカウントのプッシュ

View File

@@ -0,0 +1,46 @@
- hosts: postgre
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Test PostgreSQL connection
community.postgresql.postgresql_ping:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_db: "{{ jms_asset.spec_info.db_name }}"
register: result
failed_when: not result.is_available
- name: Display PostgreSQL version
debug:
var: result.server_version.full
when: result is succeeded
- name: Change PostgreSQL password
community.postgresql.postgresql_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
db: "{{ jms_asset.spec_info.db_name }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
role_attr_flags: LOGIN
when: result is succeeded
register: change_info
- name: Verify password
community.postgresql.postgresql_ping:
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
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

@@ -0,0 +1,11 @@
id: push_account_postgresql
name: "{{ 'PostgreSQL account push' | trans }}"
category: database
type:
- postgresql
method: push_account
i18n:
PostgreSQL account push:
zh: PostgreSQL 账号推送
ja: PostgreSQL アカウントのプッシュ

View File

@@ -0,0 +1,69 @@
- hosts: sqlserver
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Test SQLServer connection
community.general.mssql_script:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}'
script: |
SELECT @@version
register: db_info
- name: SQLServer version
set_fact:
info:
version: "{{ db_info.query_results[0][0][0][0].splitlines()[0] }}"
- debug:
var: info
- name: Check whether SQLServer User exist
community.general.mssql_script:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}'
script: "SELECT 1 from sys.sql_logins WHERE name='{{ account.username }}';"
when: db_info is succeeded
register: user_exist
- name: Change SQLServer password
community.general.mssql_script:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}'
script: "ALTER LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version"
when: user_exist.query_results[0] | length != 0
register: change_info
- name: Add SQLServer user
community.general.mssql_script:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}'
script: "CREATE LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version"
when: user_exist.query_results[0] | length == 0
register: change_info
- name: Verify password
community.general.mssql_script:
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}'
script: |
SELECT @@version
when:
- db_info is succeeded
- change_info is succeeded

View File

@@ -0,0 +1,11 @@
id: push_account_sqlserver
name: "{{ 'SQLServer account push' | trans }}"
category: database
type:
- sqlserver
method: push_account
i18n:
SQLServer account push:
zh: SQLServer 账号推送
ja: SQLServer アカウントのプッシュ

View File

@@ -0,0 +1,93 @@
- hosts: demo
gather_facts: no
tasks:
- name: Test privileged account
ansible.builtin.ping:
- name: Push user
ansible.builtin.user:
name: "{{ account.username }}"
shell: "{{ params.shell }}"
home: "{{ '/home/' + account.username }}"
groups: "{{ params.groups }}"
expires: -1
state: present
- name: "Add {{ account.username }} group"
ansible.builtin.group:
name: "{{ account.username }}"
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
ansible.builtin.user:
name: "{{ account.username }}"
groups: "{{ params.groups }}"
when: params.groups
- name: Push user password
ansible.builtin.user:
name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}"
update_password: always
when: account.secret_type == "password"
- name: remove jumpserver ssh key
ansible.builtin.lineinfile:
dest: "{{ ssh_params.dest }}"
regexp: "{{ ssh_params.regexp }}"
state: absent
when:
- account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms"
- name: Push SSH key
ansible.builtin.authorized_key:
user: "{{ account.username }}"
key: "{{ account.secret }}"
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: Set sudo setting
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:
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection
- name: Verify password
ansible.builtin.ping:
become: no
vars:
ansible_user: "{{ account.username }}"
ansible_password: "{{ account.secret }}"
ansible_become: no
when: account.secret_type == "password"
- name: Verify SSH key
ansible.builtin.ping:
become: no
vars:
ansible_user: "{{ account.username }}"
ansible_ssh_private_key_file: "{{ account.private_key_path }}"
ansible_become: no
when: account.secret_type == "ssh_key"

View File

@@ -0,0 +1,29 @@
id: push_account_aix
name: "{{ 'Aix account push' | trans }}"
category: host
type:
- AIX
method: push_account
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: groups
type: str
label: '用户组'
default: ''
help_text: '请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)'
i18n:
Aix account push:
zh: Aix 账号推送
ja: Aix アカウントのプッシュ

View File

@@ -0,0 +1,93 @@
- hosts: demo
gather_facts: no
tasks:
- name: Test privileged account
ansible.builtin.ping:
- name: Push user
ansible.builtin.user:
name: "{{ account.username }}"
shell: "{{ params.shell }}"
home: "{{ '/home/' + account.username }}"
groups: "{{ params.groups }}"
expires: -1
state: present
- name: "Add {{ account.username }} group"
ansible.builtin.group:
name: "{{ account.username }}"
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
ansible.builtin.user:
name: "{{ account.username }}"
groups: "{{ params.groups }}"
when: params.groups
- name: Push user password
ansible.builtin.user:
name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}"
update_password: always
when: account.secret_type == "password"
- name: remove jumpserver ssh key
ansible.builtin.lineinfile:
dest: "{{ ssh_params.dest }}"
regexp: "{{ ssh_params.regexp }}"
state: absent
when:
- account.secret_type == "ssh_key"
- ssh_params.strategy == "set_jms"
- name: Push SSH key
ansible.builtin.authorized_key:
user: "{{ account.username }}"
key: "{{ account.secret }}"
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: Set sudo setting
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:
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection
- name: Verify password
ansible.builtin.ping:
become: no
vars:
ansible_user: "{{ account.username }}"
ansible_password: "{{ account.secret }}"
ansible_become: no
when: account.secret_type == "password"
- name: Verify SSH key
ansible.builtin.ping:
become: no
vars:
ansible_user: "{{ account.username }}"
ansible_ssh_private_key_file: "{{ account.private_key_path }}"
ansible_become: no
when: account.secret_type == "ssh_key"

View File

@@ -0,0 +1,30 @@
id: push_account_posix
name: "{{ 'Posix account push' | trans }}"
category: host
type:
- unix
- linux
method: push_account
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: groups
type: str
label: '用户组'
default: ''
help_text: '请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)'
i18n:
Posix account push:
zh: Posix 账号推送
ja: Posix アカウントのプッシュ

View File

@@ -0,0 +1,30 @@
- hosts: demo
gather_facts: no
tasks:
- name: Test privileged account
ansible.windows.win_ping:
# - name: Print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.secret }}"
- name: Push user password
ansible.windows.win_user:
fullname: "{{ account.username}}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
password_never_expires: yes
groups: "{{ params.groups }}"
groups_action: add
update_password: always
when: account.secret_type == "password"
- name: Refresh connection
ansible.builtin.meta: reset_connection
- name: Verify password
ansible.windows.win_ping:
vars:
ansible_user: "{{ account.username }}"
ansible_password: "{{ account.secret }}"
when: account.secret_type == "password"

View File

@@ -0,0 +1,18 @@
id: push_account_local_windows
name: "{{ 'Windows account push' | trans }}"
version: 1
method: push_account
category: host
type:
- windows
params:
- name: groups
type: str
label: '用户组'
default: 'Users,Remote Desktop Users'
help_text: '请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)'
i18n:
Windows account push:
zh: Windows 账号推送
ja: Windows アカウントのプッシュ

View File

@@ -1,9 +1,6 @@
from copy import deepcopy
from django.db.models import QuerySet
from accounts.const import AutomationTypes, SecretType
from accounts.models import Account
from accounts.const import AutomationTypes, SecretType, Connectivity
from assets.const import HostTypes
from common.utils import get_logger
from ..base.manager import AccountBasePlaybookManager
@@ -19,36 +16,6 @@ class PushAccountManager(ChangeSecretManager, AccountBasePlaybookManager):
def method_type(cls):
return AutomationTypes.push_account
def create_nonlocal_accounts(self, accounts, snapshot_account_usernames, asset):
secret_type = self.secret_type
usernames = accounts.filter(secret_type=secret_type).values_list(
'username', flat=True
)
create_usernames = set(snapshot_account_usernames) - set(usernames)
create_account_objs = [
Account(
name=f'{username}-{secret_type}', username=username,
secret_type=secret_type, asset=asset,
)
for username in create_usernames
]
Account.objects.bulk_create(create_account_objs)
def get_accounts(self, privilege_account, accounts: QuerySet):
if not privilege_account:
print(f'not privilege account')
return []
snapshot_account_usernames = self.execution.snapshot['accounts']
if '*' in snapshot_account_usernames:
return accounts.exclude(username=privilege_account.username)
asset = privilege_account.asset
self.create_nonlocal_accounts(accounts, snapshot_account_usernames, asset)
accounts = asset.accounts.exclude(username=privilege_account.username).filter(
username__in=snapshot_account_usernames, secret_type=self.secret_type
)
return accounts
def host_callback(self, host, asset=None, account=None, automation=None, path_dir=None, **kwargs):
host = super(ChangeSecretManager, self).host_callback(
host, asset=asset, account=account, automation=automation,
@@ -57,34 +24,37 @@ class PushAccountManager(ChangeSecretManager, AccountBasePlaybookManager):
if host.get('error'):
return host
accounts = asset.accounts.all()
accounts = self.get_accounts(account, accounts)
accounts = self.get_accounts(account)
inventory_hosts = []
host['secret_type'] = self.secret_type
if asset.type == HostTypes.WINDOWS and self.secret_type == SecretType.SSH_KEY:
msg = f'Windows {asset} does not support ssh key push \n'
msg = f'Windows {asset} does not support ssh key push'
print(msg)
return inventory_hosts
host['ssh_params'] = {}
for account in accounts:
h = deepcopy(host)
secret_type = account.secret_type
h['name'] += '(' + account.username + ')'
new_secret = self.get_secret()
if self.secret_type is None:
new_secret = account.secret
else:
new_secret = self.get_secret(secret_type)
self.name_recorder_mapper[h['name']] = {
'account': account, 'new_secret': new_secret,
}
private_key_path = None
if self.secret_type == SecretType.SSH_KEY:
if secret_type == SecretType.SSH_KEY:
private_key_path = self.generate_private_key_path(new_secret, path_dir)
new_secret = self.generate_public_key(new_secret)
h['kwargs'] = self.get_kwargs(account, new_secret)
h['ssh_params'].update(self.get_ssh_params(account, new_secret, secret_type))
h['account'] = {
'name': account.name,
'username': account.username,
'secret_type': account.secret_type,
'secret_type': secret_type,
'secret': new_secret,
'private_key_path': private_key_path
}
@@ -104,6 +74,7 @@ class PushAccountManager(ChangeSecretManager, AccountBasePlaybookManager):
return
account.secret = new_secret
account.save(update_fields=['secret'])
account.set_connectivity(Connectivity.OK)
def on_host_error(self, host, error, result):
pass
@@ -112,9 +83,9 @@ class PushAccountManager(ChangeSecretManager, AccountBasePlaybookManager):
logger.error("Pust account error: ", e)
def run(self, *args, **kwargs):
if not self.check_secret():
if self.secret_type and not self.check_secret():
return
super().run(*args, **kwargs)
super(ChangeSecretManager, self).run(*args, **kwargs)
# @classmethod
# def trigger_by_asset_create(cls, asset):

View File

@@ -0,0 +1,14 @@
- hosts: custom
gather_facts: no
vars:
ansible_connection: local
tasks:
- name: Verify account
ssh_ping:
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_user: "{{ account.username }}"
login_password: "{{ account.secret }}"
login_secret_type: "{{ jms_account.secret_type }}"
login_private_key_path: "{{ jms_account.private_key_path }}"

View File

@@ -0,0 +1,13 @@
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

@@ -1,6 +1,11 @@
id: verify_account_mongodb
name: Verify account from MongoDB
name: "{{ 'MongoDB account verify' | trans }}"
category: database
type:
- mongodb
method: verify_account
i18n:
MongoDB account verify:
zh: MongoDB 账号验证
ja: MongoDB アカウントの検証

View File

@@ -1,7 +1,12 @@
id: verify_account_mysql
name: Verify account from MySQL
name: "{{ 'MySQL account verify' | trans }}"
category: database
type:
- mysql
- mariadb
method: verify_account
i18n:
MySQL account verify:
zh: MySQL 账号验证
ja: MySQL アカウントの検証

View File

@@ -1,6 +1,11 @@
id: verify_account_oracle
name: Verify account from Oracle
name: "{{ 'Oracle account verify' | trans }}"
category: database
type:
- oracle
method: verify_account
i18n:
Oracle account verify:
zh: Oracle 账号验证
ja: Oracle アカウントの検証

View File

@@ -1,6 +1,11 @@
id: verify_account_postgresql
name: Verify account for PostgreSQL
name: "{{ 'PostgreSQL account verify' | trans }}"
category: database
type:
- postgresql
method: verify_account
i18n:
PostgreSQL account verify:
zh: PostgreSQL 账号验证
ja: PostgreSQL アカウントの検証

View File

@@ -1,6 +1,11 @@
id: verify_account_sqlserver
name: Verify account from SQLServer
name: "{{ 'SQLServer account verify' | trans }}"
category: database
type:
- sqlserver
method: verify_account
i18n:
SQLServer account verify:
zh: SQLServer 账号验证
ja: SQLServer アカウントの検証

View File

@@ -1,7 +1,12 @@
id: verify_account_posix
name: Verify posix account
name: "{{ 'Posix account verify' | trans }}"
category: host
type:
- linux
- unix
method: verify_account
i18n:
Posix account verify:
zh: Posix 账号验证
ja: Posix アカウントの検証

View File

@@ -1,6 +1,9 @@
- hosts: windows
gather_facts: no
tasks:
- name: Refresh connection
ansible.builtin.meta: reset_connection
- name: Verify account
ansible.windows.win_ping:
vars:

View File

@@ -1,7 +1,12 @@
id: verify_account_windows
name: Verify account windows
name: "{{ 'Windows account verify' | trans }}"
version: 1
method: verify_account
category: host
type:
- windows
i18n:
Windows account verify:
zh: Windows 账号验证
ja: Windows アカウントの検証

View File

@@ -25,6 +25,15 @@ class VerifyAccountManager(AccountBasePlaybookManager):
f.write('ssh_args = -o ControlMaster=no -o ControlPersist=no\n')
return path
@classmethod
def method_type(cls):
return AutomationTypes.verify_account
def get_accounts(self, privilege_account, accounts: QuerySet):
account_ids = self.execution.snapshot['accounts']
accounts = accounts.filter(id__in=account_ids)
return accounts
def host_callback(self, host, asset=None, account=None, automation=None, path_dir=None, **kwargs):
host = super().host_callback(
host, asset=asset, account=account,
@@ -62,16 +71,6 @@ class VerifyAccountManager(AccountBasePlaybookManager):
inventory_hosts.append(h)
return inventory_hosts
@classmethod
def method_type(cls):
return AutomationTypes.verify_account
def get_accounts(self, privilege_account, accounts: QuerySet):
snapshot_account_usernames = self.execution.snapshot['accounts']
if '*' not in snapshot_account_usernames:
accounts = accounts.filter(username__in=snapshot_account_usernames)
return accounts
def on_host_success(self, host, result):
account = self.host_account_mapper.get(host)
account.set_connectivity(Connectivity.OK)

View File

@@ -1,6 +1,6 @@
from common.utils import get_logger
from accounts.const import AutomationTypes
from assets.automations.ping_gateway.manager import PingGatewayManager
from common.utils import get_logger
logger = get_logger(__name__)
@@ -16,6 +16,6 @@ class VerifyGatewayAccountManager(PingGatewayManager):
logger.info(">>> 开始执行测试网关账号可连接性任务")
def get_accounts(self, gateway):
usernames = self.execution.snapshot['accounts']
accounts = gateway.accounts.filter(username__in=usernames)
account_ids = self.execution.snapshot['accounts']
accounts = gateway.accounts.filter(id__in=account_ids)
return accounts

View File

@@ -18,3 +18,10 @@ class AliasAccount(TextChoices):
class Source(TextChoices):
LOCAL = 'local', _('Local')
COLLECTED = 'collected', _('Collected')
TEMPLATE = 'template', _('Template')
class AccountInvalidPolicy(TextChoices):
SKIP = 'skip', _('Skip')
UPDATE = 'update', _('Update')
ERROR = 'error', _('Failed')

View File

@@ -48,7 +48,7 @@ class SecretStrategy(models.TextChoices):
class SSHKeyStrategy(models.TextChoices):
add = 'add', _('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):

View File

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

View File

@@ -0,0 +1,69 @@
# Generated by Django 3.2.16 on 2023-03-07 07:36
from django.db import migrations
from django.db.models import Q
def get_nodes_all_assets(apps, *nodes):
node_model = apps.get_model('assets', 'Node')
asset_model = apps.get_model('assets', 'Asset')
node_ids = set()
descendant_node_query = Q()
for n in nodes:
node_ids.add(n.id)
descendant_node_query |= Q(key__istartswith=f'{n.key}:')
if descendant_node_query:
_ids = node_model.objects.order_by().filter(descendant_node_query).values_list('id', flat=True)
node_ids.update(_ids)
return asset_model.objects.order_by().filter(nodes__id__in=node_ids).distinct()
def get_all_assets(apps, snapshot):
node_model = apps.get_model('assets', 'Node')
asset_model = apps.get_model('assets', 'Asset')
asset_ids = snapshot.get('assets', [])
node_ids = snapshot.get('nodes', [])
nodes = node_model.objects.filter(id__in=node_ids)
node_asset_ids = get_nodes_all_assets(apps, *nodes).values_list('id', flat=True)
asset_ids = set(list(asset_ids) + list(node_asset_ids))
return asset_model.objects.filter(id__in=asset_ids)
def migrate_account_usernames_to_ids(apps, schema_editor):
db_alias = schema_editor.connection.alias
execution_model = apps.get_model('accounts', 'AutomationExecution')
account_model = apps.get_model('accounts', 'Account')
executions = execution_model.objects.using(db_alias).all()
executions_update = []
for execution in executions:
snapshot = execution.snapshot
accounts = account_model.objects.none()
account_usernames = snapshot.get('accounts', [])
for asset in get_all_assets(apps, snapshot):
accounts = accounts | asset.accounts.all()
secret_type = snapshot.get('secret_type')
if secret_type:
ids = accounts.filter(
username__in=account_usernames,
secret_type=secret_type
).values_list('id', flat=True)
else:
ids = accounts.filter(
username__in=account_usernames
).values_list('id', flat=True)
snapshot['accounts'] = [str(_id) for _id in ids]
execution.snapshot = snapshot
executions_update.append(execution)
execution_model.objects.bulk_update(executions_update, ['snapshot'])
class Migration(migrations.Migration):
dependencies = [
('accounts', '0008_alter_gatheredaccount_options'),
]
operations = [
migrations.RunPython(migrate_account_usernames_to_ids),
]

View File

@@ -0,0 +1,22 @@
# Generated by Django 3.2.16 on 2023-03-23 08:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0009_account_usernames_to_ids'),
]
operations = [
migrations.AddField(
model_name='gatheraccountsautomation',
name='is_sync_account',
field=models.BooleanField(blank=True, default=False, verbose_name='Is sync account'),
),
migrations.AddField(
model_name='account',
name='source_id',
field=models.CharField(max_length=128, null=True, blank=True, verbose_name='Source ID'),
),
]

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,4 +1,6 @@
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 simple_history.models import HistoricalRecords
@@ -53,6 +55,7 @@ class Account(AbsConnectivity, BaseAccount):
version = models.IntegerField(default=0, verbose_name=_('Version'))
history = AccountHistoricalRecords(included_fields=['id', 'secret', 'secret_type', 'version'])
source = models.CharField(max_length=30, default=Source.LOCAL, verbose_name=_('Source'))
source_id = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Source ID'))
class Meta:
verbose_name = _('Account')
@@ -105,6 +108,11 @@ class Account(AbsConnectivity, 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:
verbose_name = _('Account template')
unique_together = (
@@ -115,5 +123,62 @@ class AccountTemplate(BaseAccount):
('change_accounttemplatesecret', _('Can change asset account template secret')),
]
@classmethod
def get_su_from_account_templates(cls, instance=None):
if not instance:
return cls.objects.all()
return cls.objects.exclude(Q(id=instance.id) | Q(su_from=instance))
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):
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

@@ -1,11 +1,12 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from common.db import fields
from common.db.models import JMSBaseModel
from accounts.const import (
AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy
)
from accounts.models import Account
from common.db import fields
from common.db.models import JMSBaseModel
from .base import AccountBaseAutomation
__all__ = ['ChangeSecretAutomation', 'ChangeSecretRecord', 'ChangeSecretMixin']
@@ -27,18 +28,34 @@ class ChangeSecretMixin(models.Model):
default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy')
)
get_all_assets: callable # get all assets
class Meta:
abstract = True
def create_nonlocal_accounts(self, usernames, asset):
pass
def get_account_ids(self):
usernames = self.accounts
accounts = Account.objects.none()
for asset in self.get_all_assets():
self.create_nonlocal_accounts(usernames, asset)
accounts = accounts | asset.accounts.all()
account_ids = accounts.filter(
username__in=usernames, secret_type=self.secret_type
).values_list('id', flat=True)
return [str(_id) for _id in account_ids]
def to_attr_json(self):
attr_json = super().to_attr_json()
attr_json.update({
'secret': self.secret,
'secret_type': self.secret_type,
'secret_strategy': self.secret_strategy,
'accounts': self.get_account_ids(),
'password_rules': self.password_rules,
'secret_strategy': self.secret_strategy,
'ssh_key_change_strategy': self.ssh_key_change_strategy,
})
return attr_json

View File

@@ -1,7 +1,9 @@
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from accounts.const import AutomationTypes
from accounts.const import AutomationTypes, Source
from accounts.models import Account
from orgs.mixins.models import JMSOrgBaseModel
from .base import AccountBaseAutomation
@@ -19,6 +21,25 @@ class GatheredAccount(JMSOrgBaseModel):
def address(self):
return self.asset.address
@staticmethod
def sync_accounts(gathered_accounts):
account_objs = []
for gathered_account in gathered_accounts:
asset_id = gathered_account.asset_id
username = gathered_account.username
accounts = Account.objects.filter(
Q(asset_id=asset_id, username=username) |
Q(asset_id=asset_id, name=username)
)
if accounts.exists():
continue
account = Account(
asset_id=asset_id, username=username,
name=username, source=Source.COLLECTED
)
account_objs.append(account)
Account.objects.bulk_create(account_objs)
class Meta:
verbose_name = _('Gather account automation')
unique_together = [
@@ -31,6 +52,17 @@ class GatheredAccount(JMSOrgBaseModel):
class GatherAccountsAutomation(AccountBaseAutomation):
is_sync_account = models.BooleanField(
default=False, blank=True, verbose_name=_("Is sync account")
)
def to_attr_json(self):
attr_json = super().to_attr_json()
attr_json.update({
'is_sync_account': self.is_sync_account,
})
return attr_json
def save(self, *args, **kwargs):
self.type = AutomationTypes.gather_accounts
super().save(*args, **kwargs)

View File

@@ -2,6 +2,8 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from accounts.const import AutomationTypes
from accounts.models import Account
from jumpserver.utils import has_valid_xpack_license
from .base import AccountBaseAutomation
from .change_secret import ChangeSecretMixin
@@ -13,6 +15,21 @@ class PushAccountAutomation(ChangeSecretMixin, AccountBaseAutomation):
username = models.CharField(max_length=128, verbose_name=_('Username'))
action = models.CharField(max_length=16, verbose_name=_('Action'))
def create_nonlocal_accounts(self, usernames, asset):
secret_type = self.secret_type
account_usernames = asset.accounts.filter(secret_type=self.secret_type).values_list(
'username', flat=True
)
create_usernames = set(usernames) - set(account_usernames)
create_account_objs = [
Account(
name=f'{username}-{secret_type}', username=username,
secret_type=secret_type, asset=asset,
)
for username in create_usernames
]
Account.objects.bulk_create(create_account_objs)
def set_period_schedule(self):
pass
@@ -27,12 +44,15 @@ class PushAccountAutomation(ChangeSecretMixin, AccountBaseAutomation):
def save(self, *args, **kwargs):
self.type = AutomationTypes.push_account
if not has_valid_xpack_license():
self.is_periodic = False
super().save(*args, **kwargs)
def to_attr_json(self):
attr_json = super().to_attr_json()
attr_json.update({
'username': self.username
'username': self.username,
'params': self.params,
})
return attr_json

View File

@@ -12,7 +12,7 @@ from accounts.const import SecretType
from common.db import fields
from common.utils import (
ssh_key_string_to_obj, ssh_key_gen, get_logger,
random_string, lazyproperty, parse_ssh_public_key_str
random_string, lazyproperty, parse_ssh_public_key_str, is_openssh_format_key
)
from orgs.mixins.models import JMSOrgBaseModel, OrgManager
@@ -118,7 +118,13 @@ class BaseAccount(JMSOrgBaseModel):
key_name = '.' + md5(self.private_key.encode('utf-8')).hexdigest()
key_path = os.path.join(tmp_dir, key_name)
if not os.path.exists(key_path):
self.private_key_obj.write_private_key_file(key_path)
# https://github.com/ansible/ansible-runner/issues/544
# ssh requires OpenSSH format keys to have a full ending newline.
# It does not require this for old-style PEM keys.
with open(key_path, 'w') as f:
f.write(self.secret)
if is_openssh_format_key(self.secret.encode('utf-8')):
f.write("\n")
os.chmod(key_path, 0o400)
return key_path

View File

@@ -1,75 +1,183 @@
import uuid
from copy import deepcopy
from django.db import IntegrityError
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from accounts.const import SecretType, Source
from accounts.const import SecretType, Source, AccountInvalidPolicy
from accounts.models import Account, AccountTemplate
from accounts.tasks import push_accounts_to_assets_task
from assets.const import Category, AllTypes
from assets.models import Asset
from common.serializers import SecretReadableMixin, BulkModelSerializer
from common.serializers import SecretReadableMixin
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
from .base import BaseAccountSerializer
from common.utils import get_logger
from .base import BaseAccountSerializer, AuthValidateMixin
logger = get_logger(__name__)
class AccountSerializerCreateValidateMixin:
from_id: str
template: bool
push_now: bool
replace_attrs: callable
class AccountCreateUpdateSerializerMixin(serializers.Serializer):
template = serializers.PrimaryKeyRelatedField(
queryset=AccountTemplate.objects,
required=False, label=_("Template"), write_only=True
)
push_now = serializers.BooleanField(
default=False, label=_("Push now"), write_only=True
)
params = serializers.JSONField(
decoder=None, encoder=None, required=False, style={'base_template': 'textarea.html'}
)
on_invalid = LabeledChoiceField(
choices=AccountInvalidPolicy.choices, default=AccountInvalidPolicy.ERROR,
write_only=True, label=_('Exist policy')
)
_template = None
clean_auth_fields: callable
class Meta:
fields = ['template', 'push_now', 'params', 'on_invalid']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_initial_value()
def set_initial_value(self):
if not getattr(self, 'initial_data', None):
return
if isinstance(self.initial_data, dict):
initial_data = [self.initial_data]
else:
initial_data = self.initial_data
for data in initial_data:
if not data.get('asset') and not self.instance:
raise serializers.ValidationError({'asset': UniqueTogetherValidator.missing_message})
asset = data.get('asset') or self.instance.asset
self.from_template_if_need(data)
self.set_uniq_name_if_need(data, asset)
def to_internal_value(self, data):
from_id = data.pop('id', None)
ret = super().to_internal_value(data)
self.from_id = from_id
return ret
self.from_template_if_need(data)
return super().to_internal_value(data)
def set_secret(self, attrs):
_id = self.from_id
template = attrs.pop('template', None)
def set_uniq_name_if_need(self, initial_data, asset):
name = initial_data.get('name')
if name is not None:
return
if not name:
name = initial_data.get('username')
if self.instance and self.instance.name == name:
return
if Account.objects.filter(name=name, asset=asset).exists():
name = name + '_' + uuid.uuid4().hex[:4]
initial_data['name'] = name
if _id and template:
account_template = AccountTemplate.objects.get(id=_id)
attrs['secret'] = account_template.secret
elif _id and not template:
account = Account.objects.get(id=_id)
attrs['secret'] = account.secret
return attrs
def from_template_if_need(self, initial_data):
if isinstance(initial_data, str):
return
def validate(self, attrs):
attrs = super().validate(attrs)
return self.set_secret(attrs)
template_id = initial_data.pop('template', None)
if not template_id:
return
if isinstance(template_id, (str, uuid.UUID)):
template = AccountTemplate.objects.filter(id=template_id).first()
else:
template = template_id
if not template:
raise serializers.ValidationError({'template': 'Template not found'})
self._template = template
# Set initial data from template
ignore_fields = ['id', 'date_created', 'date_updated', 'su_from', 'org_id']
field_names = [
field.name for field in template._meta.fields
if field.name not in ignore_fields
]
attrs = {}
for name in field_names:
value = getattr(template, name, None)
if value is None:
continue
attrs[name] = value
initial_data.update(attrs)
@staticmethod
def push_account(instance, push_now):
if not push_now:
def push_account_if_need(instance, push_now, params, stat):
if not push_now or stat not in ['created', 'updated']:
return
push_accounts_to_assets_task.delay([str(instance.id)])
push_accounts_to_assets_task.delay([str(instance.id)], params)
def get_validators(self):
_validators = super().get_validators()
if getattr(self, 'initial_data', None) is None:
return _validators
on_invalid = self.initial_data.get('on_invalid')
if on_invalid == AccountInvalidPolicy.ERROR and not self.parent:
return _validators
_validators = [v for v in _validators if not isinstance(v, UniqueTogetherValidator)]
return _validators
@staticmethod
def do_create(vd):
on_invalid = vd.pop('on_invalid', None)
q = Q()
if vd.get('name'):
q |= Q(name=vd['name'])
if vd.get('username'):
q |= Q(username=vd['username'], secret_type=vd.get('secret_type'))
instance = Account.objects.filter(asset=vd['asset']).filter(q).first()
# 不存在这个资产,不用关系策略
if not instance:
instance = Account.objects.create(**vd)
return instance, 'created'
if on_invalid == AccountInvalidPolicy.SKIP:
return instance, 'skipped'
elif on_invalid == AccountInvalidPolicy.UPDATE:
for k, v in vd.items():
setattr(instance, k, v)
instance.save()
return instance, 'updated'
else:
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):
push_now = validated_data.pop('push_now', None)
instance = super().create(validated_data)
self.push_account(instance, push_now)
params = validated_data.pop('params', None)
self.clean_auth_fields(validated_data)
self.generate_source_data(validated_data)
instance, stat = self.do_create(validated_data)
self.push_account_if_need(instance, push_now, params, stat)
return instance
def update(self, instance, validated_data):
# account cannot be modified
validated_data.pop('username', None)
validated_data.pop('on_invalid', None)
push_now = validated_data.pop('push_now', None)
params = validated_data.pop('params', None)
validated_data['source_id'] = None
instance = super().update(instance, validated_data)
self.push_account(instance, push_now)
self.push_account_if_need(instance, push_now, params, 'updated')
return instance
class AccountSerializerCreateMixin(AccountSerializerCreateValidateMixin, BulkModelSerializer):
template = serializers.BooleanField(
default=False, label=_("Template"), write_only=True
)
push_now = serializers.BooleanField(
default=False, label=_("Push now"), write_only=True
)
has_secret = serializers.BooleanField(label=_("Has secret"), read_only=True)
class AccountAssetSerializer(serializers.ModelSerializer):
platform = ObjectRelatedField(read_only=True)
category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category'))
@@ -77,11 +185,11 @@ class AccountAssetSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = ['id', 'name', 'address', 'type', 'category', 'platform', 'auto_info']
fields = ['id', 'name', 'address', 'type', 'category', 'platform', 'auto_config']
def to_internal_value(self, data):
if isinstance(data, dict):
i = data.get('id')
i = data.get('id') or data.get('pk')
else:
i = data
@@ -91,9 +199,10 @@ class AccountAssetSerializer(serializers.ModelSerializer):
raise serializers.ValidationError(_('Asset not found'))
class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer):
class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerializer):
asset = AccountAssetSerializer(label=_('Asset'))
source = LabeledChoiceField(choices=Source.choices, label=_("Source"), read_only=True)
has_secret = serializers.BooleanField(label=_("Has secret"), read_only=True)
su_from = ObjectRelatedField(
required=False, queryset=Account.objects, allow_null=True, allow_empty=True,
label=_('Su from'), attrs=('id', 'name', 'username')
@@ -102,27 +211,200 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer):
class Meta(BaseAccountSerializer.Meta):
model = Account
fields = BaseAccountSerializer.Meta.fields + [
'su_from', 'asset', 'template', 'version',
'push_now', 'source', 'connectivity',
'su_from', 'asset', 'version',
'source', 'source_id', 'connectivity',
] + AccountCreateUpdateSerializerMixin.Meta.fields
read_only_fields = BaseAccountSerializer.Meta.read_only_fields + [
'source', 'source_id', 'connectivity'
]
extra_kwargs = {
**BaseAccountSerializer.Meta.extra_kwargs,
'name': {'required': False, 'allow_null': True},
'name': {'required': False},
}
def validate_name(self, value):
if not value:
value = self.initial_data.get('username')
return value
@classmethod
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset \
.prefetch_related('asset', 'asset__platform', 'asset__platform__automation')
queryset = queryset.prefetch_related(
'asset', 'asset__platform',
'asset__platform__automation'
)
return queryset
class AssetAccountBulkSerializerResultSerializer(serializers.Serializer):
asset = serializers.CharField(read_only=True, label=_('Asset'))
state = serializers.CharField(read_only=True, label=_('State'))
error = serializers.CharField(read_only=True, label=_('Error'))
changed = serializers.BooleanField(read_only=True, label=_('Changed'))
class AssetAccountBulkSerializer(
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'))
class Meta:
model = Account
fields = [
'name', 'username', 'secret', 'secret_type', 'passphrase',
'privileged', 'is_active', 'comment', 'template',
'on_invalid', 'push_now', 'assets', 'su_from_username'
]
extra_kwargs = {
'name': {'required': False},
'secret_type': {'required': False},
}
def set_initial_value(self):
if not getattr(self, 'initial_data', None):
return
initial_data = self.initial_data
self.from_template_if_need(initial_data)
@staticmethod
def get_filter_lookup(vd):
return {
'username': vd['username'],
'secret_type': vd['secret_type'],
'asset': vd['asset'],
}
@staticmethod
def get_uniq_name(vd):
return vd['name'] + '-' + uuid.uuid4().hex[:4]
@staticmethod
def _handle_update_create(vd, lookup):
ori = Account.objects.filter(**lookup).first()
if ori and ori.secret == vd.get('secret'):
return ori, False, 'skipped'
instance, value = Account.objects.update_or_create(defaults=vd, **lookup)
state = 'created' if value else 'updated'
return instance, True, state
@staticmethod
def _handle_skip_create(vd, lookup):
instance, value = Account.objects.get_or_create(defaults=vd, **lookup)
state = 'created' if value else 'skipped'
return instance, value, state
@staticmethod
def _handle_err_create(vd, lookup):
instance, value = Account.objects.get_or_create(defaults=vd, **lookup)
if not value:
raise serializers.ValidationError(_('Account already exists'))
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):
lookup = self.get_filter_lookup(vd)
vd = deepcopy(vd)
self.generate_su_from_data(vd)
try:
instance, changed, state = handler(vd, lookup)
except IntegrityError:
vd['name'] = self.get_uniq_name(vd)
instance, changed, state = handler(vd, lookup)
return instance, changed, state
def get_create_handler(self, on_invalid):
if on_invalid == 'update':
handler = self._handle_update_create
elif on_invalid == 'skip':
handler = self._handle_skip_create
else:
handler = self._handle_err_create
return handler
def perform_bulk_create(self, vd):
assets = vd.pop('assets')
on_invalid = vd.pop('on_invalid', 'skip')
secret_type = vd.get('secret_type', 'password')
if not vd.get('name'):
vd['name'] = vd.get('username')
create_handler = self.get_create_handler(on_invalid)
asset_ids = [asset.id for asset in assets]
secret_type_supports = Asset.get_secret_type_assets(asset_ids, secret_type)
_results = {}
for asset in assets:
if asset not in secret_type_supports:
_results[asset] = {
'error': _('Asset does not support this secret type: %s') % secret_type,
'state': 'error',
}
continue
vd = vd.copy()
vd['asset'] = asset
try:
self.clean_auth_fields(vd)
instance, changed, state = self.perform_create(vd, create_handler)
_results[asset] = {
'changed': changed, 'instance': instance.id, 'state': state
}
except serializers.ValidationError as e:
_results[asset] = {'error': e.detail[0], 'state': 'error'}
except Exception as e:
logger.exception(e)
_results[asset] = {'error': str(e), 'state': 'error'}
results = [{'asset': asset, **result} for asset, result in _results.items()]
state_score = {'created': 3, 'updated': 2, 'skipped': 1, 'error': 0}
results = sorted(results, key=lambda x: state_score.get(x['state'], 4))
if on_invalid != 'error':
return results
errors = []
errors.extend([result for result in results if result['state'] == 'error'])
for result in results:
if result['state'] != 'skipped':
continue
errors.append({
'error': _('Account has exist'),
'state': 'error',
'asset': str(result['asset'])
})
if errors:
raise serializers.ValidationError(errors)
return results
@staticmethod
def push_accounts_if_need(results, push_now):
if not push_now:
return
accounts = [str(v['instance']) for v in results if v.get('instance')]
push_accounts_to_assets_task.delay(accounts)
def create(self, validated_data):
push_now = validated_data.pop('push_now', False)
self.generate_source_data(validated_data)
results = self.perform_bulk_create(validated_data)
self.push_accounts_if_need(results, push_now)
for res in results:
res['asset'] = str(res['asset'])
return results
class AccountSecretSerializer(SecretReadableMixin, AccountSerializer):
class Meta(AccountSerializer.Meta):
extra_kwargs = {
@@ -132,11 +414,19 @@ class AccountSecretSerializer(SecretReadableMixin, AccountSerializer):
class AccountHistorySerializer(serializers.ModelSerializer):
secret_type = LabeledChoiceField(choices=SecretType.choices, label=_('Secret type'))
id = serializers.IntegerField(label=_('ID'), source='history_id', read_only=True)
class Meta:
model = Account.history.model
fields = ['id', 'secret', 'secret_type', 'version', 'history_date', 'history_user']
fields = [
'id', 'secret', 'secret_type', 'version', 'history_date',
'history_user'
]
read_only_fields = fields
extra_kwargs = {
'history_user': {'label': _('User')},
'history_date': {'label': _('Date')},
}
class AccountTaskSerializer(serializers.Serializer):
@@ -150,3 +440,7 @@ class AccountTaskSerializer(serializers.Serializer):
queryset=Account.objects, required=False, allow_empty=True, many=True
)
task = serializers.CharField(read_only=True)
params = serializers.JSONField(
decoder=None, encoder=None, required=False,
style={'base_template': 'textarea.html'}
)

View File

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

View File

@@ -13,10 +13,10 @@ __all__ = ['AuthValidateMixin', 'BaseAccountSerializer']
class AuthValidateMixin(serializers.Serializer):
secret_type = LabeledChoiceField(
choices=SecretType.choices, required=True, label=_('Secret type')
choices=SecretType.choices, label=_('Secret type'), default='password'
)
secret = EncryptedField(
label=_('Secret/Password'), required=False, max_length=40960, allow_blank=True,
label=_('Secret'), required=False, max_length=40960, allow_blank=True,
allow_null=True, write_only=True,
)
passphrase = serializers.CharField(
@@ -33,7 +33,8 @@ class AuthValidateMixin(serializers.Serializer):
return secret
elif secret_type == SecretType.SSH_KEY:
passphrase = passphrase if passphrase else None
return validate_ssh_key(secret, passphrase)
secret = validate_ssh_key(secret, passphrase)
return secret
else:
return secret
@@ -41,8 +42,9 @@ class AuthValidateMixin(serializers.Serializer):
secret_type = validated_data.get('secret_type')
passphrase = validated_data.get('passphrase')
secret = validated_data.pop('secret', None)
self.handle_secret(secret, secret_type, passphrase)
validated_data['secret'] = secret
validated_data['secret'] = self.handle_secret(
secret, secret_type, passphrase
)
for field in ('secret',):
value = validated_data.get(field)
if not value:
@@ -75,6 +77,6 @@ class BaseAccountSerializer(AuthValidateMixin, BulkOrgResourceModelSerializer):
'date_verified', 'created_by', 'date_created',
]
extra_kwargs = {
'name': {'required': True},
'spec_info': {'label': _('Spec info')},
'username': {'help_text': _("Tip: If no username is required for authentication, fill in `null`")}
}

View File

@@ -1,23 +1,45 @@
from accounts.models import AccountTemplate
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from accounts.models import AccountTemplate, Account
from common.serializers import SecretReadableMixin
from common.serializers.fields import ObjectRelatedField
from .base import 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):
model = AccountTemplate
fields = BaseAccountSerializer.Meta.fields + ['is_sync_account', 'su_from']
# @classmethod
# def validate_required(cls, attrs):
# # TODO 选择模版后检查一些必填项
# required_field_dict = {}
# error = _('This field is required.')
# for k, v in cls().fields.items():
# if v.required and k not in attrs:
# required_field_dict[k] = error
# if not required_field_dict:
# return
# raise serializers.ValidationError(required_field_dict)
def sync_accounts_secret(self, instance, diff):
if not self._is_sync_account or 'secret' not in diff:
return
accounts = Account.objects.filter(source_id=instance.id)
instance.bulk_sync_account_secret(accounts, self.context['request'].user.id)
def validate(self, attrs):
self._is_sync_account = attrs.pop('is_sync_account', None)
attrs = super().validate(attrs)
return attrs
def update(self, instance, validated_data):
diff = {
k: v for k, v in validated_data.items()
if getattr(instance, k, None) != v
}
instance = super().update(instance, validated_data)
self.sync_accounts_secret(instance, diff)
return instance
class AccountTemplateSecretSerializer(SecretReadableMixin, AccountTemplateSerializer):

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 accounts.models import AutomationExecution

View File

@@ -58,6 +58,7 @@ class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializ
"Currently only mail sending is supported"
)},
}}
@property
def model_type(self):
return AutomationTypes.change_secret

View File

@@ -17,7 +17,8 @@ class GatherAccountAutomationSerializer(BaseAutomationSerializer):
class Meta:
model = GatherAccountsAutomation
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields
fields = BaseAutomationSerializer.Meta.fields + read_only_fields
fields = BaseAutomationSerializer.Meta.fields \
+ ['is_sync_account'] + read_only_fields
extra_kwargs = BaseAutomationSerializer.Meta.extra_kwargs

View File

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

View File

@@ -8,8 +8,8 @@ logger = get_logger(__name__)
@receiver(pre_save, sender=Account)
def on_account_pre_save(sender, instance, created=False, **kwargs):
if created:
def on_account_pre_save(sender, instance, **kwargs):
if instance.version == 0:
instance.version = 1
else:
instance.version = instance.history.count()

View File

@@ -8,7 +8,7 @@ from orgs.utils import tmp_to_org, tmp_to_root_org
logger = get_logger(__file__)
def task_activity_callback(self, pid, trigger, tp):
def task_activity_callback(self, pid, trigger, tp, *args, **kwargs):
model = AutomationTypes.get_type_model(tp)
with tmp_to_root_org():
instance = get_object_or_none(model, pk=pid)

View File

@@ -9,7 +9,7 @@ from orgs.utils import tmp_to_org, tmp_to_root_org
logger = get_logger(__file__)
def task_activity_callback(self, pid, trigger):
def task_activity_callback(self, pid, trigger, *args, **kwargs):
from accounts.models import AccountBackupAutomation
with tmp_to_root_org():
plan = get_object_or_none(AccountBackupAutomation, pk=pid)

View File

@@ -27,7 +27,7 @@ def gather_asset_accounts_util(nodes, task_name):
@shared_task(
queue="ansible", verbose_name=_('Gather asset accounts'),
activity_callback=lambda self, node_ids, task_name=None: (node_ids, None)
activity_callback=lambda self, node_ids, task_name=None, *args, **kwargs: (node_ids, None)
)
def gather_asset_accounts_task(node_ids, task_name=None):
if task_name is None:

View File

@@ -13,9 +13,9 @@ __all__ = [
@shared_task(
queue="ansible", verbose_name=_('Push accounts to assets'),
activity_callback=lambda self, account_ids, asset_ids: (account_ids, None)
activity_callback=lambda self, account_ids, *args, **kwargs: (account_ids, None)
)
def push_accounts_to_assets_task(account_ids):
def push_accounts_to_assets_task(account_ids, params=None):
from accounts.models import PushAccountAutomation
from accounts.models import Account
@@ -23,12 +23,11 @@ def push_accounts_to_assets_task(account_ids):
task_name = gettext_noop("Push accounts to assets")
task_name = PushAccountAutomation.generate_unique_name(task_name)
for account in accounts:
task_snapshot = {
'secret': account.secret,
'secret_type': account.secret_type,
'accounts': [account.username],
'assets': [str(account.asset_id)],
}
tp = AutomationTypes.push_account
quickstart_automation_by_snapshot(task_name, tp, task_snapshot)
task_snapshot = {
'accounts': [str(account.id) for account in accounts],
'assets': [str(account.asset_id) for account in accounts],
'params': params or {},
}
tp = AutomationTypes.push_account
quickstart_automation_by_snapshot(task_name, tp, task_snapshot)

View File

@@ -17,9 +17,9 @@ __all__ = [
def verify_connectivity_util(assets, tp, accounts, task_name):
if not assets or not accounts:
return
account_usernames = list(accounts.values_list('username', flat=True))
account_ids = [str(account.id) for account in accounts]
task_snapshot = {
'accounts': account_usernames,
'accounts': account_ids,
'assets': [str(asset.id) for asset in assets],
}
quickstart_automation_by_snapshot(task_name, tp, task_snapshot)

View File

@@ -25,6 +25,7 @@ router.register(r'push-account-executions', api.PushAccountExecutionViewSet, 'pu
router.register(r'push-account-records', api.PushAccountRecordViewSet, 'push-account-record')
urlpatterns = [
path('accounts/bulk/', api.AssetAccountBulkCreateApi.as_view(), name='account-bulk-create'),
path('accounts/tasks/', api.AccountsTaskCreateAPI.as_view(), name='account-task-create'),
path('account-secrets/<uuid:pk>/histories/', api.AccountHistoriesSecretAPI.as_view(),
name='account-secret-history'),

View File

@@ -1,7 +1,7 @@
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from common.db.models import JMSBaseModel
from common.utils import contains_ip

View File

@@ -3,11 +3,12 @@ from rest_framework import serializers
from acls.models.base import ActionChoices
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
from jumpserver.utils import has_valid_xpack_license
from orgs.models import Organization
from users.models import User
common_help_text = _(
"Format for comma-delimited string, with * indicating a match all. "
"With * indicating a match all. "
)
@@ -22,7 +23,7 @@ class ACLUsersSerializer(serializers.Serializer):
class ACLAssestsSerializer(serializers.Serializer):
address_group_help_text = _(
"Format for comma-delimited string, with * indicating a match all. "
"With * indicating a match all. "
"Such as: "
"192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64"
" (Domain name support)"
@@ -51,7 +52,26 @@ class ACLAccountsSerializer(serializers.Serializer):
)
class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer):
class ActionAclSerializer(serializers.Serializer):
action = LabeledChoiceField(
choices=ActionChoices.choices, default=ActionChoices.reject, label=_("Action")
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_action_choices()
def set_action_choices(self):
action = self.fields.get("action")
if not action:
return
choices = action.choices
if not has_valid_xpack_license():
choices.pop(ActionChoices.review, None)
action._choices = choices
class BaseUserAssetAccountACLSerializerMixin(ActionAclSerializer, serializers.Serializer):
users = ACLUsersSerializer(label=_('User'))
assets = ACLAssestsSerializer(label=_('Asset'))
accounts = ACLAccountsSerializer(label=_('Account'))
@@ -77,9 +97,6 @@ class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer):
reviewers_amount = serializers.IntegerField(
read_only=True, source="reviewers.count", label=_('Reviewers amount')
)
action = LabeledChoiceField(
choices=ActionChoices.choices, default=ActionChoices.reject, label=_("Action")
)
class Meta:
fields_mini = ["id", "name"]

View File

@@ -1,10 +1,10 @@
from django.utils.translation import ugettext as _
from rest_framework import serializers
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
from common.serializers import BulkModelSerializer, MethodSerializer
from jumpserver.utils import has_valid_xpack_license
from common.serializers.fields import ObjectRelatedField
from users.models import User
from .base import ActionAclSerializer
from .rules import RuleSerializer
from ..models import LoginACL
@@ -13,16 +13,15 @@ __all__ = [
]
common_help_text = _(
"Format for comma-delimited string, with * indicating a match all. "
"With * indicating a match all. "
)
class LoginACLSerializer(BulkModelSerializer):
class LoginACLSerializer(ActionAclSerializer, BulkModelSerializer):
user = ObjectRelatedField(queryset=User.objects, label=_("User"))
reviewers = ObjectRelatedField(
queryset=User.objects, label=_("Reviewers"), many=True, required=False
)
action = LabeledChoiceField(choices=LoginACL.ActionChoices.choices, label=_('Action'))
reviewers_amount = serializers.IntegerField(
read_only=True, source="reviewers.count", label=_("Reviewers amount")
)
@@ -44,18 +43,5 @@ class LoginACLSerializer(BulkModelSerializer):
"is_active": {"default": True},
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_action_choices()
def set_action_choices(self):
action = self.fields.get("action")
if not action:
return
choices = action.choices
if not has_valid_xpack_license():
choices.pop(LoginACL.ActionChoices.review, None)
action.choices = choices
def get_rules_serializer(self):
return RuleSerializer()

View File

@@ -22,7 +22,7 @@ def ip_group_child_validator(ip_group_child):
ip_group_help_text = _(
'Format for comma-delimited string, with * indicating a match all. '
'With * indicating a match all. '
'Such as: '
'192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64 '
)

View File

@@ -1,7 +1,8 @@
from .asset import *
from .host import *
from .database import *
from .web import *
from .cloud import *
from .custom import *
from .database import *
from .device import *
from .host import *
from .permission import *
from .web import *

View File

@@ -2,15 +2,17 @@
#
import django_filters
from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK
from accounts.tasks import push_accounts_to_assets_task, verify_accounts_connectivity_task
from assets import serializers
from assets.exceptions import NotSupportedTemporarilyError
from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend
from assets.models import Asset, Gateway
from assets.models import Asset, Gateway, Platform
from assets.tasks import test_assets_connectivity_manual, update_assets_hardware_info_manual
from common.api import SuggestionMixin
from common.drf.filters import BaseFilterSet
@@ -18,11 +20,12 @@ from common.utils import get_logger, is_uuid
from orgs.mixins import generics
from orgs.mixins.api import OrgBulkModelViewSet
from ..mixin import NodeFilterMixin
from ...notifications import BulkUpdatePlatformSkipAssetUserMsg
logger = get_logger(__file__)
__all__ = [
"AssetViewSet", "AssetTaskCreateApi",
"AssetsTaskCreateApi", 'AssetFilterSet'
"AssetsTaskCreateApi", 'AssetFilterSet',
]
@@ -93,19 +96,19 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
model = Asset
filterset_class = AssetFilterSet
search_fields = ("name", "address")
ordering = ("name", "connectivity")
ordering_fields = ('name', 'connectivity', 'platform', 'date_updated')
serializer_classes = (
("default", serializers.AssetSerializer),
("platform", serializers.PlatformSerializer),
("suggestion", serializers.MiniAssetSerializer),
("gateways", serializers.GatewaySerializer),
("spec_info", serializers.SpecSerializer)
)
rbac_perms = (
("match", "assets.match_asset"),
("platform", "assets.view_platform"),
("gateways", "assets.view_gateway"),
("spec_info", "assets.view_asset"),
("gathered_info", "assets.view_asset"),
)
extra_filter_backends = [LabelFilterBackend, IpInFilterBackend, NodeFilterBackend]
@@ -123,11 +126,6 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
serializer = super().get_serializer(instance=asset.platform)
return Response(serializer.data)
@action(methods=["GET"], detail=True, url_path="spec-info")
def spec_info(self, *args, **kwargs):
asset = super().get_object()
return Response(asset.spec_info)
@action(methods=["GET"], detail=True, url_path="gateways")
def gateways(self, *args, **kwargs):
asset = self.get_object()
@@ -143,6 +141,32 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
return Response({'error': error}, status=400)
return super().create(request, *args, **kwargs)
def filter_bulk_update_data(self):
bulk_data = []
skip_assets = []
for data in self.request.data:
pk = data.get('id')
platform = data.get('platform')
if not platform:
bulk_data.append(data)
continue
asset = get_object_or_404(Asset, pk=pk)
platform = get_object_or_404(Platform, **platform)
if platform.type == asset.type:
bulk_data.append(data)
continue
skip_assets.append(asset)
return bulk_data, skip_assets
def bulk_update(self, request, *args, **kwargs):
bulk_data, skip_assets = self.filter_bulk_update_data()
request._full_data = bulk_data
response = super().bulk_update(request, *args, **kwargs)
if response.status_code == HTTP_200_OK and skip_assets:
user = request.user
BulkUpdatePlatformSkipAssetUserMsg(user, skip_assets).publish()
return response
class AssetsTaskMixin:
def perform_assets_task(self, serializer):
@@ -153,8 +177,8 @@ class AssetsTaskMixin:
task = update_assets_hardware_info_manual(assets)
else:
asset = assets[0]
if not asset.auto_info['ansible_enabled'] or \
not asset.auto_info['ping_enabled']:
if not asset.auto_config['ansible_enabled'] or \
not asset.auto_config['ping_enabled']:
raise NotSupportedTemporarilyError()
task = test_assets_connectivity_manual(assets)
return task

View File

@@ -0,0 +1,16 @@
from assets.models import Custom, Asset
from assets.serializers import CustomSerializer
from .asset import AssetViewSet
__all__ = ['CustomViewSet']
class CustomViewSet(AssetViewSet):
model = Custom
perm_model = Asset
def get_serializer_classes(self):
serializer_classes = super().get_serializer_classes()
serializer_classes['default'] = CustomSerializer
return serializer_classes

View File

@@ -1,8 +1,5 @@
from rest_framework.decorators import action
from rest_framework.response import Response
from assets.models import Host, Asset
from assets.serializers import HostSerializer, HostInfoSerializer
from assets.serializers import HostSerializer
from .asset import AssetViewSet
__all__ = ['HostViewSet']
@@ -15,10 +12,4 @@ class HostViewSet(AssetViewSet):
def get_serializer_classes(self):
serializer_classes = super().get_serializer_classes()
serializer_classes['default'] = HostSerializer
serializer_classes['info'] = HostInfoSerializer
return serializer_classes
@action(methods=["GET"], detail=True, url_path="info")
def info(self, *args, **kwargs):
asset = super().get_object()
return Response(asset.info)

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