Compare commits

...

1128 Commits
v2.4 ... v2.15

Author SHA1 Message Date
ibuler
79600e25f1 fix: 修复数据库连接没有关闭的问题 2021-11-18 16:34:11 +08:00
feng626
2604f35bb8 perf: 异地登陆去掉本地判断 2021-11-02 21:10:56 +08:00
feng626
6e42a9704c fix: 修复xpack引入包问题 2021-10-29 15:40:21 +08:00
Jiangjie.Bai
15cdd44c6c Merge pull request #7107 from jumpserver/dev
v2.15.0
2021-10-28 17:45:42 +08:00
feng626
d44f90ea3d fix: acl xpack 2021-10-28 17:38:55 +08:00
Jiangjie.Bai
42e9fbf37a Merge pull request #7103 from jumpserver/dev
v2.15.0
2021-10-28 15:31:44 +08:00
ibuler
d44656aa10 fix: 修复修改用户信息后,绑定丢失
perf: 还原提示文案
2021-10-28 15:29:55 +08:00
feng626
09d4228182 Merge pull request #7102 from jumpserver/pr@dev@ticket_tips
perf: 工单错误提示优化
2021-10-28 15:25:42 +08:00
feng626
3ae8da231a perf: 工单错误提示优化 2021-10-28 15:16:52 +08:00
feng626
2e4b6d150a fix: 登录复合浏览器不兼容 2021-10-28 15:02:54 +08:00
Michael Bai
8542d53aff fix: 修复ldap用户导入时字段进行strip 2021-10-28 15:02:33 +08:00
Michael Bai
141dafc8bf fix: 创建授权/添加资产到节点;不再自动更新资产的管理用户 2021-10-28 13:39:27 +08:00
Michael Bai
28a6024b49 fix: 修改工单列表默认按照创建日志倒叙排序,修改翻译 2021-10-28 13:38:10 +08:00
ibuler
6cf2bc4baf pref: 优化工单验证 2021-10-28 13:37:24 +08:00
xinwen
631f802961 fix: 钉钉报错的时取得字段不对 2021-10-28 13:31:27 +08:00
feng626
0eedda748a perf: acl username unified 2021-10-28 13:31:05 +08:00
Jiangjie.Bai
7183f0d274 Merge pull request #7089 from jumpserver/dev
v2.15.0-rc3
2021-10-27 19:24:42 +08:00
feng626
c93ab15351 fix: acl migrate bug 2021-10-27 11:31:16 +08:00
Michael Bai
3fffd667dc fix: 修改系统用户、工单列表排序字段 2021-10-27 11:16:01 +08:00
fit2bot
11fd2afa3a perf: 优化下载页面 (#7082)
Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
2021-10-26 17:27:01 +08:00
Michael Bai
1eb59b11da fix: 添加Model的verbose_name属性 2021-10-26 17:22:05 +08:00
feng626
a1e2d4ca57 Merge pull request #7081 from jumpserver/pr@dev@command_record_filter
fix: 命令记录-导出选择项命令:却导出了所有命令
2021-10-26 16:54:27 +08:00
feng626
8a413563be fix: 命令记录-导出选择项命令:却导出了所有命令 2021-10-26 16:50:14 +08:00
ibuler
203a01240b perf: 优化dockerfile 2021-10-26 15:48:17 +08:00
Michael Bai
37fef6153a fix: 修改依赖包版本: jumpserver-django-oidc-rp==0.3.7.8 2021-10-26 15:16:24 +08:00
feng626
ba6c49e62b Merge pull request #7077 from jumpserver/pr@dev@app_account_translate
fix: 【【账号管理】应用账号导出字段存在英文】
2021-10-26 13:42:31 +08:00
feng626
da79f8beab fix: 【【账号管理】应用账号导出字段存在英文】 2021-10-26 13:34:59 +08:00
ibuler
3f72c02049 perf: 添加命令org 2021-10-26 11:49:56 +08:00
feng626
380226a7d2 fix: 用户登陆mfa code为空限制 2021-10-26 11:01:12 +08:00
fit2bot
f88e5de3c1 perf: 优化用户创建邮件 (#7072)
* perf: 优化通知中的连接点击

* perf: 优化用户创建邮件

* perf: 优化时间日期

Co-authored-by: ibuler <ibuler@qq.com>
2021-10-26 10:52:23 +08:00
Michael Bai
7c149fe91b fix: 修复系统用户applications_amount字段只读 2021-10-25 16:25:12 +08:00
Jiangjie.Bai
f673fed706 Merge pull request #7068 from jumpserver/dev
v2.15.0-rc2
2021-10-25 15:07:25 +08:00
Michael Bai
84326cc999 fix: 系统用户列表添加 应用数量 字段 2021-10-25 15:01:29 +08:00
xinwen
7d56678a8e fix: 修复登录次数出现 0 2021-10-25 14:30:48 +08:00
feng626
25d1b71448 fix: 修复分时登陆bug 2021-10-25 14:26:47 +08:00
feng626
d3920a0cc9 Merge pull request #7065 from jumpserver/pr@dev@ticket_bug
fix: 修复工单发邮件及授权资产备注信息修改
2021-10-25 11:32:01 +08:00
feng626
52889cb67a fix: 修复工单发邮件及授权资产备注信息修改 2021-10-25 11:30:37 +08:00
feng626
0b67c7a953 fix: 修复登陆复合acl时 未添加规则bug 2021-10-25 10:49:00 +08:00
ibuler
1f50a2fe33 perf: 优化签名 2021-10-25 10:48:27 +08:00
ibuler
cd5094f10d perf: 优化通知中的连接点击 2021-10-25 10:48:03 +08:00
fit2bot
c244cf5f43 pref: 修改使用的消息内容 (#7061)
* perf:  再次优化通知

* pref: 修改使用的消息内容

* perf: 修复url地址

Co-authored-by: ibuler <ibuler@qq.com>
2021-10-22 20:06:16 +08:00
feng626
a0db2f6ef8 Merge pull request #7059 from jumpserver/pr@dev@ticket_send_message_multiple_times
fix: 修复工单结束重复发送受理人消息bug
2021-10-22 16:40:51 +08:00
feng626
ea485c3070 fix: 修复工单结束重复发送受理人消息bug 2021-10-22 16:38:14 +08:00
feng626
705f352cb9 Merge pull request #7057 from jumpserver/pr@dev@acl_bug
fix: 修复acl 选择时间段为空bug
2021-10-22 16:12:40 +08:00
feng626
dc13134b7b fix: 修复acl 选择时间段为空bug 2021-10-22 16:09:22 +08:00
Michael Bai
06de6c3575 fix: 修复资产系统用户auth-info获取流程及创建时手动登录方式的校验 2021-10-22 15:19:58 +08:00
ibuler
c341d01e5a perf: 修改工单信息 2021-10-21 20:04:27 +08:00
feng626
d1a3d31d3f feat: 客户端协议内容添加rdp文件名 2021-10-21 19:16:04 +08:00
ibuler
10f4ff4eec fix: 修复工单通知内容bug 2021-10-21 18:36:29 +08:00
ibuler
25ea3ba01d perf: 修改sdk位置 2021-10-21 17:39:28 +08:00
ibuler
072865f3e5 perf: 优化修改 sdk 位置 2021-10-21 17:39:28 +08:00
ibuler
d5c9ec1c3d perf: 优化位置 2021-10-21 17:39:28 +08:00
ibuler
487c945d1d perf: 修改代码位置,用户sugestion增加到6个 2021-10-21 17:39:28 +08:00
feng626
a78b2f4b62 fix: 修复工单发消息报错 2021-10-21 17:31:59 +08:00
ibuler
a1f1dce56b perf: 修改格式错误 2021-10-21 16:22:08 +08:00
xinwen
a1221a39fd fix: 会话管理翻译 2021-10-21 16:21:49 +08:00
xinwen
8c118b6f47 fix: 组织删除报错未翻译 2021-10-21 16:21:11 +08:00
feng626
68fd8012d8 Merge pull request #7042 from jumpserver/pr@dev@acl_perf
perf: acl filter
2021-10-21 15:11:50 +08:00
feng626
526928518d perf: acl filter 2021-10-21 15:00:29 +08:00
feng626
c5f6c564a7 fix: 系统启动bug 2021-10-21 13:05:07 +08:00
Jiangjie.Bai
076adec218 Merge pull request #7033 from jumpserver/dev
v2.15.0 rc1
2021-10-20 20:24:29 +08:00
fit2bot
00d434ceea perf: 优化消息通知 (#7024)
* perf: 优化系统用户列表

* stash

* perf: 优化消息通知

* perf: 修改钉钉

* perf: 修改优化消息通知

* perf: 修改requirements

* perf: 优化datetime

Co-authored-by: ibuler <ibuler@qq.com>
2021-10-20 19:45:37 +08:00
fit2bot
9acfd461b4 feat: user login acl (#6963)
* feat: user login acl

* 添加分时登陆

* acl 部分还原

* 简化acl判断逻辑

Co-authored-by: feng626 <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2021-10-20 17:56:59 +08:00
feng626
9424929dde fix: sms bug 2021-10-19 20:23:06 +08:00
Michael Bai
b95d3ac9be fix: 修改终端status翻译 2021-10-19 16:16:48 +08:00
Michael Bai
af2a9bb1e6 fix: 修复用户登录失败未记录日志的问题 2021-10-19 15:28:39 +08:00
fit2bot
63638ed1ce feat: 首页的 chanlege 和 MFA 统一 (#6989)
* feat: 首页的 chanlege 和 MFA 统一

* 登陆样式调整

* mfa bug

* q

* m

* mfa封装组件 前端可修改配置

* perf: 添加翻译

* login css bug

* perf: 修改一些风格

* perf: 修改命名

* perf: 修改 mfa code 不是必填

* mfa 前端统一组件

* stash

* perf: 统一验证码

Co-authored-by: feng626 <1304903146@qq.com>
Co-authored-by: ibuler <ibuler@qq.com>
2021-10-18 18:41:41 +08:00
fit2bot
fa68389028 perf: 去掉单独的flash msg (#7013)
* perf: 去掉单独的flash msg

perf: 修改使用库

* fix: guangbug

* pref: 修改 context

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: xinwen <coderWen@126.com>
2021-10-18 11:25:39 +08:00
halo
63b338085a feat: 修改username校验,telnet协议支持输入中文 2021-10-15 15:36:29 +08:00
fit2bot
5d8818e69e feat: 添加资产授权用户API、资产授权用户的授权规则API (#7008)
* feat: 添加资产授权用户API、资产授权用户的授权规则API

* feat: 添加资产授权用户组API、资产授权用户组的授权规则API

* feat: 抽象API类

Co-authored-by: Michael Bai <baijiangjie@gmail.com>
2021-10-15 14:02:32 +08:00
xinwen
77521119b9 fix: 修改 oauth 认证提示信息 2021-10-15 11:32:20 +08:00
ibuler
baee71e4b8 perf: 添加requirements 2021-10-15 11:31:06 +08:00
ibuler
6459c20516 perf: Django语言文件推送到lfs
perf: 修改mac依赖,添加安装 git lfs

perf: 修改添加 mac 开发环境依赖
2021-10-14 16:30:18 +08:00
ibuler
0207fe60c5 perf: 修改ip城市获取算法
perf: 优化使用lfs
2021-10-14 10:35:18 +08:00
Eric
b8c43f5944 fix: 修复获取系统用户密码问题 2021-10-13 14:34:57 +08:00
xinwen
63ca2ab182 fix: 修复 traceback 问题 2021-10-13 11:42:54 +08:00
ibuler
f9ea119928 perf: 不再需要 tls 类型,any 方式都可以 2021-10-12 17:45:38 +08:00
xinwen.xu
d4bdc74bd8 feat: 授权过期通知 2021-10-11 15:41:13 +08:00
ibuler
42e7ca6a18 perf: 资产编号允许api更改 2021-10-11 15:26:31 +08:00
xinwen
6e0341b7b1 feat: xrdp挂载受授权的上传下载控制 2021-10-11 15:24:34 +08:00
jiangweidong
2f25e2b24c fix: 系统用户认证方式从托管密码更新到手动输入模式后,不填写用户名报错 2021-10-11 10:02:48 +08:00
halo
87dcd2dcb7 feat: 增加关闭第三方登录跳转配置参数 2021-09-29 16:04:59 +08:00
ibuler
e96aac058f fix: 修复跳转msg页面,取消button太小的问题 2021-09-29 15:30:17 +08:00
Jiangjie.Bai
d76bad125b Merge pull request #6973 from jumpserver/pr@dev@feat_announcement
feat: 支持公告
2021-09-29 14:58:15 +08:00
ibuler
913b1a1426 perf: 修改翻译 2021-09-29 14:55:14 +08:00
ibuler
0213154a19 merge: with dev 2021-09-29 14:53:42 +08:00
ibuler
8f63b488b2 perf: 修改翻译 2021-09-29 14:43:00 +08:00
ibuler
f8921004c2 perf: 修改依赖版本 2021-09-29 14:42:11 +08:00
feng626
5588eab57e feat: 用户异地登陆 2021-09-29 14:33:52 +08:00
ibuler
e0a8f91741 perf: 修改翻译 2021-09-28 18:57:21 +08:00
ibuler
467ebfa650 perf: 添加公告id 2021-09-28 18:17:10 +08:00
ibuler
0533b77b1b perf: 支持公告 2021-09-28 17:01:47 +08:00
ibuler
a558ee2ac0 perf: 修改dockerfile 2021-09-28 10:10:20 +08:00
ibuler
46a39701d4 fix: 修复docker无法构建 2021-09-27 19:27:33 +08:00
ibuler
8c3ab31e4e fix: 修复由于修改filter引起的问题 2021-09-27 18:50:29 +08:00
Jiangjie.Bai
476e6cdc2f Merge pull request #6932 from jumpserver/pr@dev@perf_remove_djangopo
perf: 去掉django.po
2021-09-27 14:12:26 +08:00
ibuler
0b593f4555 perf: 优化drf filter, 修改terminal filter
perf: 去掉debug

perf: 去掉debug
2021-09-27 14:09:22 +08:00
ibuler
456116938d perf: 优化数据迁移,性能提升50倍 2021-09-27 14:05:21 +08:00
ibuler
76b24f62d4 perf: merge with dev 2021-09-27 14:03:19 +08:00
Michael Bai
e1eef0a3f3 fix: 修复authbook systemuser字段问题 2021-09-24 20:24:25 +08:00
Michael Bai
2c74727b65 fix: 修复邮件测试序列类及API 2021-09-24 14:13:55 +08:00
ibuler
08cd91c426 perf: 修改应用授权树,没有的时候不显示 2021-09-24 14:12:31 +08:00
wojiushixiaobai
90d269d2a2 fix: 添加包 2021-09-24 12:56:35 +08:00
Michael Bai
a9ddbcc0cd fix: 修复系统用户和资产/节点关联时资产特权用户更新的问题 2021-09-24 12:48:35 +08:00
Michael Bai
aec31128cf perf: 修改翻译 2021-09-23 11:14:53 +08:00
ibuler
b415ee051d perf: 去掉django.po 2021-09-23 10:26:39 +08:00
ibuler
082a5ae84c perf: 修改不再添加编译后的翻译文件 2021-09-22 18:53:04 +08:00
老广
6b7554d69a Merge pull request #6929 from jumpserver/pr@dev@ticket_comment
perf: 工单优化
2021-09-22 15:51:10 +08:00
feng626
5923562440 perf: 工单优化 2021-09-22 15:17:57 +08:00
老广
d144e7e572 Merge pull request #6922 from jumpserver/pr@dev@fix_tokensmsoptions
fix: 修复KoKo登录时,未开启SMS服务出现了SMS选项的问题
2021-09-22 11:24:03 +08:00
ibuler
cafbd08986 perf: 修改啊 2021-09-22 11:18:38 +08:00
ibuler
b436fc9b44 perf: 优化登录 2021-09-22 11:18:38 +08:00
ibuler
26fc56b4be perf: 优化登录html 2021-09-22 11:18:38 +08:00
Michael Bai
3b1d199669 fix: 修复KoKo登录时,未开启SMS服务出现了SMS选项的问题 2021-09-22 03:17:14 +00:00
ibuler
e7edbc9d84 perf: 修改啊 2021-09-18 15:46:41 +08:00
ibuler
41f81bc0bf merge: with dev 2021-09-18 15:29:29 +08:00
ibuler
75d2c81d33 perf: 优化登录 2021-09-18 15:24:04 +08:00
ibuler
da2dea5003 perf: 登录错误提示颜色 2021-09-18 15:07:05 +08:00
老广
fc60156c23 Merge pull request #6913 from jumpserver/pr@dev@perf_dockerfile
perf: 优化依赖包
2021-09-17 18:03:31 +08:00
wojiushixiaobai
76fb547551 perf: 优化依赖包 2021-09-17 16:14:15 +08:00
ibuler
e686f51703 perf: 优化登录html 2021-09-17 16:00:23 +08:00
feng626
7578bda588 Merge pull request #6911 from jumpserver/pr@dev@ticket_perf
perf: 工单优化
2021-09-17 15:50:48 +08:00
feng626
f2d743ec2b perf: 工单优化 2021-09-17 15:46:33 +08:00
ibuler
7099aef360 perf: 登录错误提示颜色 2021-09-17 14:35:05 +08:00
wojiushixiaobai
246f5d8a11 fix: 添加依赖 2021-09-16 23:24:02 +08:00
wojiushixiaobai
6c98bd3b48 fix: 添加 pg 依赖包 2021-09-16 23:24:02 +08:00
老广
6def113cbd Merge pull request #6902 from jumpserver/dev
v2.14.0
2021-09-16 21:17:25 +08:00
ibuler
2dc0af2553 perf: 优化 dockerfile 2021-09-16 21:08:04 +08:00
Jiangjie.Bai
a291592e59 Merge pull request #6900 from jumpserver/dev
修改依赖包版本 jumpserver-django-oidc-rp==0.3.7.7
2021-09-16 20:15:32 +08:00
Michael Bai
6fb4c1e181 修改依赖包版本 jumpserver-django-oidc-rp==0.3.7.7 2021-09-16 19:49:42 +08:00
老广
eee093742c Merge pull request #6898 from jumpserver/dev
merge: dev to master
2021-09-16 19:35:39 +08:00
feng626
743c9bc3f1 fix: 过滤其它类型app 2021-09-16 19:30:32 +08:00
ibuler
f963c5ef9d perf: 修改翻译 2021-09-16 19:29:05 +08:00
ibuler
2c46072db2 fix: 修复serializer问题 2021-09-16 19:08:21 +08:00
xinwen
b375cd3e75 fix: otp 绑定问题 2021-09-16 19:04:19 +08:00
fit2bot
c26ca20ad8 fix: 更新OIDC配置时,将keycloak配置转换为openid (#6893)
* fix: 修改磁盘使用等key值

* fix: 更新OIDC配置时,将keycloak配置转换为openid

Co-authored-by: Michael Bai <baijiangjie@gmail.com>
2021-09-16 18:57:09 +08:00
Jiangjie.Bai
982a510213 Merge pull request #6892 from jumpserver/ibuler-patch-1
Update README.md
2021-09-16 17:46:06 +08:00
老广
5d6880f6e9 Update README.md 2021-09-16 17:45:10 +08:00
xinwen
a784a33203 fix: 去掉手动系统用户提示输入密码 2021-09-16 16:47:15 +08:00
xinwen
a452f3307f fix: 组件监控的消息 2021-09-16 16:29:56 +08:00
Michael Bai
b7a6287925 fix: 修改磁盘使用等key值 2021-09-16 16:29:19 +08:00
feng626
3cba8648cb fix: 工单日期bug 2021-09-16 16:12:42 +08:00
ibuler
ef7b2b7980 perf: 优化登录错误提示 2021-09-16 14:07:51 +08:00
xinwen
1ab247ac22 fix: 用户密码过期提醒 2021-09-16 13:43:09 +08:00
Michael Bai
ef8a027849 fix: 修改翻译,链接过期 2021-09-16 11:16:21 +08:00
Michael Bai
7890e43f5a fix: 修改网关测试可连接性报错提示信息 2021-09-16 11:00:10 +08:00
fit2bot
2030cbd19d fix: 修复authbook信号监听;添加翻译文件.mo (#6882)
Co-authored-by: Michael Bai <baijiangjie@gmail.com>
Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
2021-09-16 10:36:24 +08:00
feng626
0f7c8c2570 fix: 工单复核bug 2021-09-16 10:35:19 +08:00
Jiangjie.Bai
9b60d86ddd Merge pull request #6880 from jumpserver/dev
v2.14.0 rc3
2021-09-15 21:05:26 +08:00
ibuler
f129f99faa perf: 优化修改获取Hostname 2021-09-15 21:04:56 +08:00
fit2bot
43f30b37da fix: 用户手机号没有校验 (#6875)
Co-authored-by: xinwen <coderWen@126.com>
Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
2021-09-15 21:00:54 +08:00
xinwen
45aefa6b75 fix: 修改一些翻译 2021-09-15 20:59:50 +08:00
xinwen
b30123054b fix: xrdp 手动登录系统用户仍然不需要输入密码 2021-09-15 20:58:56 +08:00
wojiushixiaobai
b456e71ec4 perf: 更新 client 链接 2021-09-15 20:57:04 +08:00
xinwen
7560b70c4d feat: 用户详情页面显示 手机号,钉钉,企业微信,飞书 2021-09-15 19:42:24 +08:00
Michael Bai
0c96df5283 fix: 系统用户序列类返回nodes 2021-09-15 19:41:45 +08:00
fit2bot
9dda19b8d7 fix: 修改LDAP同步提示信息 (#6872)
* fix: 修改资产和特权用户发生变化时,更新资产的admin_user

* fix: 修改资产和特权用户发生变化时,更新资产的admin_user

* fix: 修改资产和特权用户发生变化时,更新资产的admin_user

* fix: 修改LDAP同步提示信息

Co-authored-by: Michael Bai <baijiangjie@gmail.com>
2021-09-15 19:16:44 +08:00
fit2bot
fbe5f9a63a fix: 修改资产和特权用户发生变化时,更新资产的admin_user (#6871)
* fix: 修改资产和特权用户发生变化时,更新资产的admin_user

* fix: 修改资产和特权用户发生变化时,更新资产的admin_user

* fix: 修改资产和特权用户发生变化时,更新资产的admin_user

Co-authored-by: Michael Bai <baijiangjie@gmail.com>
2021-09-15 19:11:19 +08:00
xinwen
1c4b4951dc fix: 一些提示 2021-09-15 18:06:57 +08:00
ibuler
8e12399058 perf: 资产序列类优化,改为只读 2021-09-15 18:05:55 +08:00
ibuler
741b96ddee perf: 优化设置中的数字大小 2021-09-15 17:22:23 +08:00
xinwen
8c3f89ee51 fix: 高危命令告警偶发 session 不存在 2021-09-15 17:21:36 +08:00
xinwen
dee45ce2e0 fix: 用户离开组织命令复核没有删除 2021-09-15 17:19:37 +08:00
ibuler
cfab30f7f7 perf: 修改 i18n 2021-09-15 17:18:17 +08:00
Michael Bai
02e9a96792 fix: 修改翻译 2021-09-15 17:09:48 +08:00
feng626
aa6dcdc65d Merge pull request #6862 from jumpserver/pr@dev@ticket_time_validation
fix: 工单失效日期小于开始日期
2021-09-15 16:44:23 +08:00
feng626
5a6b64eebd fix: 工单失效日期小于开始日期 2021-09-15 16:25:43 +08:00
feng626
2dd7867b32 Merge pull request #6860 from jumpserver/pr@dev@login_confirm
fix: 登陆复核返回后 删除工单
2021-09-15 15:42:18 +08:00
feng626
6507f0982c fix: 登陆复核返回后 删除工单 2021-09-15 15:39:34 +08:00
ibuler
c115ef7b47 perf: 优化ttl 2021-09-15 15:27:04 +08:00
xinwen
bf68ddf09e fix: 腾讯短信检测是否发送成功 2021-09-15 15:26:35 +08:00
xinwen
f3906ff998 fix: 用户导出 can_public_key_auth 没翻译 2021-09-15 15:25:52 +08:00
Michael Bai
e47ee43631 fix: 修改默认es doc_type 为 _doc 2021-09-15 15:25:09 +08:00
xinwen
d22bb2c92f fix: 重置密码连接生成多个token 2021-09-15 11:58:26 +08:00
xinwen
870dac37b9 fix: 重置密码成功的消息里有 br 标签 2021-09-15 11:10:57 +08:00
feng626
d14c5c58ff Merge pull request #6855 from jumpserver/pr@dev@ticket_notice_bug
fix: ticket_notice_bug
2021-09-14 22:33:42 +08:00
feng626
a6b40510d0 fix: ticket_notice_bug 2021-09-14 22:32:13 +08:00
feng626
f762fe73ff fix: 工单拒绝清除mfa 2021-09-14 19:36:03 +08:00
xinwen
d49d1ba055 perf: oauth2 登录不再限制只能本地用户 2021-09-14 17:40:51 +08:00
ibuler
6e3d950e23 perf: 优化迁移账号,性能提高50倍 2021-09-14 17:39:27 +08:00
Michael Bai
7939ef34b0 fix: 修复服务告警主题替换<br> 2021-09-14 17:39:06 +08:00
Michael Bai
07cd930c0e fix: 删除配置 PERIOD_TASK_ENABLED 2021-09-14 17:38:47 +08:00
Michael Bai
c14c89a758 fix: 修改CAS配置项和CAS登录失败问题 2021-09-14 16:43:57 +08:00
feng626
245367ec29 Merge pull request #6844 from jumpserver/pr@dev@ticket_bug
fix: 修复工单消息推送bug
2021-09-14 15:56:35 +08:00
feng626
c5f4ecc8cc fix: 修复工单消息推送bug 2021-09-14 15:48:22 +08:00
ibuler
eb8bdf8623 perf: 添加安全说明 2021-09-14 14:47:40 +08:00
Michael Bai
a26c5a5e32 fix: 修复设置未分组节点显示单独授权资产的配置时,用户授权树没有变化的问题 2021-09-14 14:46:51 +08:00
Michael Bai
068db6d1ca fix: 修复设置未分组节点显示单独授权资产的配置时,用户授权树没有变化的问题 2021-09-14 14:46:51 +08:00
Michael Bai
e6e2a35745 fix: 修复设置未分组节点显示单独授权资产的配置时,用户授权树没有变化的问题 2021-09-14 14:46:51 +08:00
feng626
fafc2791ab Merge pull request #6841 from jumpserver/pr@dev@ticket_bug
fix: 工单不同组织取相应资产的名字
2021-09-14 14:10:09 +08:00
feng626
39507ef152 fix: 工单不同组织取相应资产的名字 2021-09-14 14:03:28 +08:00
Jiangjie.Bai
683fb9f596 Merge pull request #6838 from jumpserver/dev
v2.14.0 rc2
2021-09-14 00:05:35 +08:00
Bai
ced9e53d62 fix: 修复 debug 日志信息 2021-09-14 00:04:17 +08:00
Jiangjie.Bai
93846234f8 Merge pull request #6834 from jumpserver/dev
v2.14.0 rc2
2021-09-13 21:27:15 +08:00
ibuler
8ac7d4b682 perf: 优化登录backends 2021-09-13 21:26:45 +08:00
Michael Bai
c4890f66e1 fix: i18n 2021-09-13 20:45:34 +08:00
Michael Bai
4618989813 fix: i18n 2021-09-13 20:39:18 +08:00
xinwen
29645768a0 fix: 登录复核没有日志 2021-09-13 20:39:18 +08:00
Michael Bai
8f1c934f73 fix: 授权规则支持通过 from_ticket 工单过滤 2021-09-13 20:24:27 +08:00
fit2bot
7a45f4d129 perf: 优化短信 (#6826)
* perf: 优化短信

* refactor: 适配新的短信模板配置

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: xinwen <coderWen@126.com>
2021-09-13 20:15:59 +08:00
feng626
55a5dd1e34 fix: ticket bug 2021-09-13 20:12:34 +08:00
xinwen
6695d0a8a2 fix: 用户不能禁用或启用自己 2021-09-13 19:52:30 +08:00
Michael Bai
84d6b3de26 fix: 修改测试网关端口错误时提示信息 2021-09-13 19:06:25 +08:00
feng626
17a5e919d5 fix: ticket bug 2021-09-13 19:05:41 +08:00
feng626
3ba07867c8 Merge pull request #6824 from jumpserver/pr@dev@fix_system_msg
feat: 工单多种审批
2021-09-13 18:59:03 +08:00
feng626
75b76170f9 feat: 工单多种审批 2021-09-13 18:54:02 +08:00
xinwen
d34c7edb00 refactor: 重构消息 2021-09-13 18:52:02 +08:00
feng626
f64740c2db fix: 修改翻译及建议接口 2021-09-13 18:04:01 +08:00
Michael Bai
3a09845c29 fix: 修复终端启动时更新remote_addr字段 2021-09-13 18:03:06 +08:00
xinwen
09d51fd5be fix: OTP_IN_RADIUS 与 mfa 冲突 2021-09-13 17:43:19 +08:00
Michael Bai
fc8181b5ed fix: 修复删除关联了资产的特权用户失败的问题 2021-09-13 17:33:27 +08:00
feng626
5a993c255d Merge pull request #6818 from jumpserver/pr@dev@fix_ticket_bug
fix: 修复工单与koko相关接口bug
2021-09-13 16:26:45 +08:00
feng626
ad592fa504 fix: 修复工单与koko相关接口bug 2021-09-13 16:23:58 +08:00
feng626
1dcc8ff0a3 Merge pull request #6816 from jumpserver/pr@dev@perm_user_node_tree_bug
fix: 修复用户详情获取子节点bug
2021-09-13 15:30:49 +08:00
feng626
11a9a49bf8 fix: 修复用户详情获取子节点bug 2021-09-13 15:23:12 +08:00
Michael Bai
b9ffc23066 fix: 修复应用账号不能通过用户名过滤的问题 2021-09-13 15:09:13 +08:00
feng626
ea4dccbab8 fix: 修复工单bug 2021-09-13 14:12:33 +08:00
Michael Bai
683461a49b 修改 FORGOT_PASSWORD_URL 允许为空 2021-09-13 14:02:46 +08:00
Michael Bai
1a1ad0f1a2 perf: 取消API Token的配置 2021-09-13 14:02:46 +08:00
xinwen
773f7048be fix: 通知暂不支持短信 2021-09-13 13:30:54 +08:00
xinwen
f8f783745c fix: 修改密码没有发通知 2021-09-13 13:30:54 +08:00
xinwen
4fe715d953 fix: 首次登录不能提交 2021-09-13 13:29:07 +08:00
Michael Bai
36dfc4bcb8 fix: i18n 2021-09-10 19:02:38 +08:00
xinwen
8925314dc7 refactor: 修改多对多关系日志样式 2021-09-10 19:02:38 +08:00
ibuler
817c02c667 fix: 修复is_app bug 2021-09-10 18:02:07 +08:00
xinwen
58a10778cd fix: 修复短信问题 2021-09-10 18:01:36 +08:00
Michael Bai
fa81652de5 perf: 修改授权中(资产/应用)系统用户字段不必填 2021-09-10 17:55:08 +08:00
fit2bot
7e6fa27719 perf: 优化通知 (#6798)
* perf: 优化通知

* perf: 优化危险命令提示

* fix: i18n

* fix: i18n

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Michael Bai <baijiangjie@gmail.com>
2021-09-10 17:54:34 +08:00
xinwen
3e737c8cb8 fix: 修复短信问题 2021-09-10 16:43:52 +08:00
feng626
345c0fcf4f fix: 修复工单流bug 添加登陆审核配置 2021-09-10 16:22:30 +08:00
Michael Bai
bf6b685e8c fix: api/health/健康检测添加localhost 2021-09-10 15:11:25 +08:00
xinwen
654ec4970e 更改设置接口 2021-09-10 13:52:51 +08:00
feng626
4a436856b4 feat: sms setting 2021-09-10 13:52:51 +08:00
Jiangjie.Bai
e993e7257c Merge pull request #6795 from jumpserver/dev
v2.14.0 rc1
2021-09-09 21:18:32 +08:00
Michael Bai
f12a59da2f fix: 修改翻译 2021-09-09 21:14:44 +08:00
Michael Bai
42c3c85863 fix: 修改翻译 2021-09-09 21:14:44 +08:00
xinwen
7e638ff8de fix: 翻译 2021-09-09 20:49:56 +08:00
Michael Bai
932a65b840 perf: 修复批量更新组织失败的问题 2021-09-09 20:49:30 +08:00
fit2bot
81000953e2 fix: 修改消息订阅 (#6789)
Co-authored-by: xinwen <coderWen@126.com>
2021-09-09 20:12:52 +08:00
fit2bot
dc742d1281 perf: 提交禁用xrdp的开关 (#6788)
* perf: 提交禁用xrdp的开关

* perf: 修复换行

Co-authored-by: ibuler <ibuler@qq.com>
2021-09-09 19:18:37 +08:00
xinwen
b1fceca8a6 feat: 添加短信服务和用户消息通知 2021-09-09 16:47:24 +08:00
ibuler
d49d1e1414 perf: 修改添加downlaod 2021-09-09 16:31:32 +08:00
xinwen
dac3f7fc71 refactor: 修改 xrdp 挂载磁盘参数名称 2021-09-09 16:31:03 +08:00
Jiangjie.Bai
47989c41a3 perf: Update README 2021-09-09 16:17:46 +08:00
Michael Bai
ca34216141 perf: 优化Core/Celery注册终端名称 2021-09-09 16:17:23 +08:00
fit2cloud-jiangweidong
905014d441 feat: 改密计划支持数据库改密 (#6709)
* feat: 改密计划支持数据库改密

* fix: 将数据库账户信息不保存在资产信息里,保存到自己的存储中

* perf: 早餐村

* perf: 修改account

* perf: 修改app和系统用户

* perf: 优化系统用户和应用关系

* fix: 修复oracle不可连接问题

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: feng626 <1304903146@qq.com>
Co-authored-by: Michael Bai <baijiangjie@gmail.com>
2021-09-09 16:04:54 +08:00
feng626
3e51f4d616 fix: 修复授权500 2021-09-09 14:43:03 +08:00
fit2bot
07179a4d22 feat: 页面配置serializer版 (#6750)
* feat: 页面配置serializer版

* perf: 优化配置

* perf: 优化设置

* perf: 优化设置

* perf: 优化配置页面

* perf: 基本完成设置优化

Co-authored-by: feng626 <1304903146@qq.com>
Co-authored-by: ibuler <ibuler@qq.com>
2021-09-09 14:00:50 +08:00
Michael Bai
7a2e93c087 perf: 优化终端注册时名称长度处理逻辑 2021-09-09 13:27:27 +08:00
xinwen
3fb368c741 fix: 修复 xrdp domain 不生效 2021-09-08 17:54:03 +08:00
fit2bot
fca3a8fbca perf: 绑定MFA认证密码时对密码进行加密传输 (#6776)
* perf: 绑定MFA认证密码时对密码进行加密传输

* perf: 绑定MFA认证密码时对密码进行加密传输

Co-authored-by: Michael Bai <baijiangjie@gmail.com>
2021-09-08 16:40:09 +08:00
xinwen
c1375ed7cb feat: xrdp 支持挂载本地磁盘(仅适用于 win) 2021-09-07 19:10:27 +08:00
Michael Bai
8b483b8c36 fix: 终端获取配置API返回SECURITY_SESSION_SHARE 2021-09-07 19:07:50 +08:00
Jiangjie.Bai
c465fccc33 feat: 支持 Session 会话共享 (#6768)
* feat: 添加 SECURITY_SESSION_SHARE 配置

* feat: 添加 SessionShare / ShareJoinRecord Model

* feat: 添加 SessionShare / ShareJoinRecord Model

* feat: 添加 SessionSharing / SessionJoinRecord Model

* feat: 添加 SessionSharing API

* feat: 添加 SessionJoinRecord API

* feat: 修改迁移文件

* feat: 修改迁移文件

* feat: 修改迁移文件

* feat: 修改API权限
2021-09-07 18:16:27 +08:00
ibuler
3d934dc7c0 perf: 优化迁移 2021-09-06 19:57:37 +08:00
feng626
b69ed8cbe9 Merge pull request #6767 from jumpserver/pr@dev@keep_only_flow_app_asset
perf: 只保留app asset flow
2021-09-06 18:45:50 +08:00
feng626
c27230762b perf: 只保留app asset flow 2021-09-06 18:44:58 +08:00
Bai
7ea8205672 feat: 云管中心添加GCP 2021-09-06 18:21:15 +08:00
wojiushixiaobai
b9b55e3d67 perf: 添加常用工具 2021-09-06 18:20:30 +08:00
feng626
900fc4420c perf: 只保留app asset flow 2021-09-06 18:19:47 +08:00
feng626
0a3e5aed56 perf: 授权分类采用from_ticket字段 2021-09-06 11:03:16 +08:00
feng626
9fb6fd44d1 Merge pull request #6745 from jumpserver/pr@dev@add_authorization_rule
feat: 授权规则分类管理
2021-09-01 16:48:56 +08:00
feng626
4214b220e1 feat: 授权规则分类管理 2021-08-31 14:13:05 +08:00
feng626
ae80797ce4 fix: 修复工单迁移bug 2021-08-27 18:05:14 +08:00
feng626
d1be4a136e Merge pull request #6735 from jumpserver/pr@dev@asset_app_suggestion
feat: add app asset suggestion
2021-08-27 16:52:56 +08:00
feng626
e8e211f47c feat: add app asset suggestion 2021-08-27 16:47:36 +08:00
feng626
44044a7d99 Merge pull request #6730 from jumpserver/pr@dev@ticket_fix
perf: 优化变量名
2021-08-27 10:14:46 +08:00
feng626
5854ad1975 perf: 优化变量名 2021-08-26 18:29:02 +08:00
健健
0b1a1591f8 从 __all__ 中删除 RDPFileSerializer (#6727)
* 从 __all__ 中删除 RDPFileSerializer

RDPFileSerializer 已经被删除

Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
Co-authored-by: 老广 <ibuler@qq.com>
Co-authored-by: xinwen <coderWen@126.com>
Co-authored-by: Eric_Lee <xplzv@126.com>
2021-08-26 15:12:19 +08:00
ibuler
6241238b45 feat: sso支持验证mfa 2021-08-26 15:07:55 +08:00
fit2bot
0f87f05b3f feat: 工单多级审批 + 模版创建 (#6640)
* feat: 工单多级审批 + 模版创建

* feat: 工单权限处理

* fix: 工单关闭后 再审批bug

* perf: 修改一点

Co-authored-by: feng626 <1304903146@qq.com>
Co-authored-by: ibuler <ibuler@qq.com>
2021-08-25 19:02:50 +08:00
Jiangjie.Bai
19c63a0b19 Merge pull request #6708 from jumpserver/dev
feat:README
2021-08-20 16:52:02 +08:00
fit2bot
1fdc558ef7 feat: 修改readme (#6707)
* feat: 修改readme

* feat: 修改readme

* feat: 修改readme

* feat: 修改readme

Co-authored-by: Bai <bugatti_it@163.com>
2021-08-20 16:47:49 +08:00
ibuler
9f6e26c4db fix: 修复ws引起的redis连接增加 2021-08-20 15:23:23 +08:00
ibuler
628012a7ee perf: 修改健康监测 2021-08-20 14:33:51 +08:00
ibuler
c1579f5fe4 perf: 修改readme 2021-08-20 14:13:40 +08:00
Bai
cbe0483b46 fix: 资产mini接口返回platform、protocols 2021-08-20 14:12:59 +08:00
xinwen
10c2935df4 fix: 用户创建 500 2021-08-20 10:07:17 +08:00
Jiangjie.Bai
10e06a4533 Merge pull request #6692 from jumpserver/dev
v2.13.0
2021-08-19 18:52:25 +08:00
ibuler
98e38ebfd8 perf: 修复系统用户翻译 2021-08-19 17:26:38 +08:00
Bai
9660e20176 fix: 修复远程应用资产必填项 2021-08-19 16:28:51 +08:00
xinwen
21a7ec9fec fix: 升级时清空缓存 2021-08-19 15:45:59 +08:00
xinwen
7d123ff8c5 fix: 登录时验证码卡住 2021-08-19 15:19:01 +08:00
ibuler
2af6ac504d perf: 优化版本号 2021-08-19 11:15:10 +08:00
Jiangjie.Bai
6c8d1c4e77 Merge pull request #6680 from jumpserver/dev
v2.13.0 rc4
2021-08-18 19:50:17 +08:00
Bai
52d3e1b34b fix: 修改协议错误信息翻译 2021-08-18 19:33:50 +08:00
Bai
bf6fcc9020 fix: 修改翻译信息;添加水印配置项到页面 2021-08-18 19:14:49 +08:00
Bai
a0b756ebaa feat: 添加同步任务执行历史保留天数配置项 2021-08-18 18:30:10 +08:00
xinwen
5e8a55f949 fix: AuthBook 变动审计 2021-08-18 16:47:28 +08:00
xinwen
f9218584f4 fix: 组织统计里系统用户与特权用户数量不对 2021-08-18 16:46:01 +08:00
Bai
228446979f fix: 修改过期节点资产映射缓存清除 2021-08-18 15:37:40 +08:00
Bai
aa37d86959 fix: 将flower放到web服务中;修复账号列表过滤节点的逻辑,获取所有子节点。 2021-08-18 15:36:13 +08:00
feng626
0e9079fa2e Merge pull request #6673 from jumpserver/pr@dev@user_role_search
fix: 用户角色搜索
2021-08-18 15:26:56 +08:00
feng626
58c058c1a5 fix: 修复user筛选用户bug 2021-08-18 15:25:35 +08:00
ibuler
f390556a87 perf: 优化spm请求的问题 2021-08-18 14:39:55 +08:00
Bai
b7378da46e fix: 修复创建/更新远程应用资产可以为空的问题 2021-08-18 11:28:28 +08:00
Bai
0c8c926aac fix: 修复校验用户登录规则的API权限 2021-08-18 10:31:42 +08:00
xinwen
81d8592ee1 fix: 系统用户的账号列表里修改密码后不能登录 2021-08-18 10:22:02 +08:00
Jiangjie.Bai
af827f3626 Merge pull request #6664 from jumpserver/dev
v2.13.0 rc3
2021-08-17 20:37:03 +08:00
ibuler
91b269fc36 fix: 修复应用账号 2021-08-17 20:31:19 +08:00
ibuler
1605a57df6 perf: 修复应用账号选择部分导出问题 2021-08-17 17:33:55 +08:00
ibuler
5cd23b843a fix: 修复授权树api数据结构 2021-08-17 17:31:45 +08:00
Bai
d46f1080f8 fix: 修复校验用户密码规则 2021-08-17 16:37:38 +08:00
feng626
9a541ebf05 fix: 资产批量推送和测试连接性 bug 2021-08-17 14:05:03 +08:00
ibuler
dba416f5eb fix: 修复remote app没有返回asset的bug 2021-08-17 11:29:02 +08:00
xinwen
7d7da9bf98 fix: 添加新的 es 时创建索引 2021-08-17 11:27:57 +08:00
老广
4425efd3c2 Merge pull request #6649 from jumpserver/dev
Dev
2021-08-17 10:17:49 +08:00
feng626
c6bb9e97fb fix: 工单已关闭 再审批bug 2021-08-16 19:24:42 +08:00
xinwen
9c7adb7a14 fix: 用户列表导出部分字段没翻译 2021-08-16 17:41:56 +08:00
xinwen
7b4faccf05 fix: 飞书没有翻译 2021-08-16 16:46:20 +08:00
xinwen
0cd3419e09 fix: 修复应用授权列表报错 2021-08-16 16:45:45 +08:00
Eric_Lee
e49dedf6b1 Merge pull request #6645 from jumpserver/dev
Dev
2021-08-16 11:25:24 +08:00
ibuler
bee4e05b5f fix: 修复应用账号中没有应用却有账号的问题 2021-08-16 11:23:15 +08:00
ibuler
a5419b49ee perf: 添加监测 celery 2021-08-16 09:51:48 +08:00
ibuler
84e60283b8 fix(account): 修复应用账号前端不对的问题 2021-08-16 09:51:22 +08:00
Jiangjie.Bai
96206384c0 Merge pull request #6634 from jumpserver/dev
v2.13.0 rc1
2021-08-12 19:51:48 +08:00
Bai
78c61d5afa feat: 升级依赖 jms-storage==0.0.39 2021-08-12 18:38:10 +08:00
Bai
ee712d9a9d feat: 升级依赖 s3transfer==0.5.0 2021-08-12 18:38:10 +08:00
ibuler
a1e8c2849a perf: 修改entrypoint 2021-08-12 17:55:03 +08:00
fit2bot
54751a715c feat: 添加 飞书 (#6602)
* feat: 添加 飞书

Co-authored-by: xinwen <coderWen@126.com>
Co-authored-by: wenyann <64353056+wenyann@users.noreply.github.com>
2021-08-12 16:44:06 +08:00
fit2bot
a2907a6e6d fix: 将 es 的 doc_type 默认值改为 _doc (#6627)
* fix: 无效的 es 报 500

* fix: 修复索引不存在时报错

* fix: 将 es 的 doc_type 默认值改为 _doc

Co-authored-by: xinwen <coderWen@126.com>
2021-08-12 15:37:22 +08:00
Bai
33236aaa47 fix: 修复启动脚本beat进程偶尔不会结束的问题 2021-08-12 15:35:22 +08:00
Bai
cd6c7ce7fa perf: jms脚本添加collectstatic命令 2021-08-11 14:28:39 +08:00
Bai
363baece4f fix: 修复删除远程应用关联资产后,更新页面显示资产ID的问题 2021-08-11 14:23:47 +08:00
feng626
1db0e28346 feat: 用户管理增加角色搜素 2021-08-11 10:36:43 +08:00
xinwen
7366bbb197 fix: 修复 es 命令存储过滤不准确 2021-08-10 17:25:41 +08:00
Bai
7959f84bba fix: 修改启动脚本 2021-08-10 14:45:58 +08:00
ibuler
0c96bf61ef chore: 添加注释 2021-08-09 10:22:16 +08:00
fit2bot
39ce60c93a feat: 系统监控添加 Core/Celery Terminal; 修改检测终端状态逻辑; (#6570)
* feat: 系统监控添加 Core Terminal; 修改检测终端状态逻辑;

* feat: 添加management包

* feat: 添加management包

* feat: 添加 start 模块

* feat: 修改 start 模块

* feat: 修改启动命令目录结构

* feat: 修改启动命令目录结构

* feat: 修改启动命令目录结构

* feat: 修改启动命令目录结构

* feat: 修改启动命令目录结构

* feat: 修改启动命令目录结构

* feat: 修改启动命令目录结构

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

* feat: 修改启动脚本

Co-authored-by: Bai <bugatti_it@163.com>
2021-08-06 19:16:18 +08:00
Bai
8ad78ffef8 fix: 修改SECURITY_PASSWORD_MIN_LENGTH 2021-08-05 10:38:22 +08:00
xinwen
66b499b8e3 fix: 修复多对多审计内容太长报错&全局组织没有审计 2021-08-04 17:13:25 +08:00
xinwen
22406f47f7 fix: Luna 页面搜索资产,结果按资产名称排序 2021-08-04 10:32:20 +08:00
feng626
72f782b589 Merge pull request #6576 from jumpserver/pr@dev@edit_xpack_internationalization
feat: 修改xpack 国际化
2021-08-03 14:31:20 +08:00
xinwen
cf3df951a9 fix: xrdp 连接可以指定是否全屏 2021-08-03 11:28:49 +08:00
xinwen
4085df913b feat: 记录网关可连接性 2021-08-02 18:42:43 +08:00
ibuler
d93f3aca51 perf: 修改支持客户端拉起
perf: remove print
2021-08-02 18:15:11 +08:00
老广
b180a162cd Merge pull request #6580 from jumpserver/pr@dev@update_pip_version
perf: 修改依赖包版本
2021-08-02 17:59:15 +08:00
ibuler
1bf3ff5e1b perf: 修改依赖包版本 2021-08-02 17:55:22 +08:00
Bai
0def477b63 fix: 修复收集windows资产用户时未收集到全部用户的问题 2021-08-02 16:34:54 +08:00
feng626
337e1ba206 feat: 修改xpack 国际化 2021-08-02 14:19:54 +08:00
Bai
fe2d80046c fix: 修改用户密码更新API取消Retrieve权限 2021-08-02 12:00:14 +08:00
Bai
f16a9ddb86 fix: 修改 settings.SECURITY_MFA_AUTH 开启判断条件 2021-08-02 10:52:41 +08:00
老广
5f6c207721 Merge pull request #6572 from jumpserver/pr@dev@perf_account_filter
perf: 修改账号搜索
2021-07-30 19:52:08 +08:00
ibuler
988d686418 perf: 修改账号搜索 2021-07-30 19:48:23 +08:00
老广
89e654af80 Merge pull request #6571 from jumpserver/pr@dev@perf_i18n
perf: 优化i18n
2021-07-30 19:21:31 +08:00
ibuler
2ab1bbaa2c chore: merge with dev 2021-07-30 19:18:36 +08:00
ibuler
b43626b5a2 perf: 优化i18n 2021-07-30 19:13:47 +08:00
ibuler
5e4b3e924f perf: 优化树 2021-07-30 17:29:50 +08:00
fit2bot
66b0173e20 feat: 服务性能告警指标包含:Core服务和各组件状态;指标包括:cpu/disk/memory/is_alive (#6564)
* feat: 服务性能告警指标包含:Core服务和各组件状态;指标包括:cpu/disk/memory/is_alive

* feat: 服务性能告警指标包含:Core服务和各组件状态;指标包括:cpu/disk/memory/is_alive 2

Co-authored-by: Bai <bugatti_it@163.com>
2021-07-30 15:42:06 +08:00
fit2bot
67f6b1080e feat: 管理员和普通用户支持单独设置MFA和密码长度 (#6562)
* feat: 支持配置系统管理员强制MFA和独立密码长度限制

* feat: 支持配置系统管理员强制MFA和独立密码长度限制

* feat: 支持配置系统管理员强制MFA和独立密码长度限制, 翻译文件

* fix: 设置界面可设置管理员用户开启MFA,当在设置开启全局的时候,不改变用户的mfa字段状态

* fix: 修改管理员最小密码长度变量名称

* perf: 优化不同的配置

* perf: 修改check password rule

* perf: 添加配置文件

* perf: 修改profile

* perf: 优化代码

* fix: 修复bug

Co-authored-by: fit2cloud-jiangweidong <weidong.jiang@fit2cloud.com>
Co-authored-by: ibuler <ibuler@qq.com>
2021-07-30 15:19:00 +08:00
ibuler
b56b897260 perf: 优化计算数量 2021-07-30 11:08:12 +08:00
ibuler
f031f4d560 perf: 修复授权应用树的问题 2021-07-29 19:45:36 +08:00
Bai
d0e119fb50 feat: session.Task model add kwargs field (记录kill_session的用户名称) 2021-07-29 15:06:54 +08:00
Bai
7892e50aa2 feat: session.Task model add kwargs field (记录kill_session的用户名称) 2021-07-29 15:06:54 +08:00
ibuler
bff3582136 perf: 修改时间日志格式,兼容firefox 2021-07-28 17:56:23 +08:00
Bai
bdf95903ce feat: 支持终断DB会话 2021-07-28 17:48:53 +08:00
feng626
c1e6bc5d60 Merge pull request #6555 from jumpserver/pr@dev@user_collection_node_fix
fix: 用户管理-用户-授权的资产-收藏夹下拉菜单报404bug修复
2021-07-28 14:39:53 +08:00
feng626
da588ce0ae perf: 代码优化 2021-07-28 14:33:02 +08:00
feng626
d0680c3753 fix: 用户管理-用户-授权的资产-收藏夹下拉菜单报404bug修复 2021-07-28 14:21:53 +08:00
fit2bot
905d0d5131 perf: 统一应用树 (#6535)
* perf: 添加应用树api

* perf: perms tree

* perf: 统一应用树

* perf: 修改icon

* perf: stash it

* perf: 优化应用账号

* perf: 基本完成应用账号重构

* perf: 修改翻译

Co-authored-by: ibuler <ibuler@qq.com>
2021-07-27 16:06:00 +08:00
feng626
d347ed9862 perf: 优化代码 2021-07-27 15:54:44 +08:00
feng626
8611f765a3 feat: 增加rdp 云端唤醒 api 2021-07-27 15:54:44 +08:00
ibuler
962f1c0310 perf: 资产账号支持,几点过滤 2021-07-27 15:54:08 +08:00
feng626
473a66719b 终端 批量更新 数据必填 2021-07-27 15:52:59 +08:00
Bai
aeb43a04f6 feat: 添加翻译: trigger 触发模式、手动触发、自动触发 2021-07-27 10:45:28 +08:00
xinwen
49a35985a1 feat: 多对多关系添加审计 2021-07-26 18:10:41 +08:00
Bai
21b789e08c perf: 优化测试网域可连接性的错误提示信息 2021-07-26 15:53:08 +08:00
Bai
51387ad97e fix: 解决访问api-docs失败的问题 2021-07-26 14:32:53 +08:00
Bai
290d584ac9 perf: 校验系统用户/账号密码不能包含 {{ 字符;升级依赖包ansible==2.9.24 2021-07-23 19:00:43 +08:00
Bai
160b238058 fix: 修复ssh-private-key错误导致系统用户列表加载出现500的问题 2021-07-23 18:57:53 +08:00
Bai
938255df6f perf: 添加LDAPServerURL ldaps:// ldap:// 协议检测 2021-07-23 14:50:44 +08:00
Bai
4230da0fd9 perf: 添加LDAPServerURL ldaps:// ldap:// 协议检测 2021-07-23 11:24:05 +08:00
xinwen
fee3715d30 fix: 应用授权按type 过滤报错 2021-07-22 11:06:14 +08:00
Bai
689bd093be 云管中心同步任务支持设置同步IP网段和协议组(修改特权用户文案) 2021-07-21 16:50:04 +08:00
feng626
77461d7834 网域网管取消密码不为空校验 2021-07-21 16:33:09 +08:00
ibuler
ee5894c296 perf: 优化工单推荐资产的数量 2021-07-21 14:39:29 +08:00
Bai
07898004b0 feat: 丰富资产任务API创建;支持针对多个系统用户一个资产的推送和测试 2021-07-20 16:59:51 +08:00
Eric_Lee
630164cd51 Merge pull request #6494 from jumpserver/pr@dev@add_watermark
perf: 添加配置文件,控制luna水印
2021-07-19 18:28:24 +08:00
feng626
981319e553 关闭 网域网关 密码特殊字符校验 2021-07-19 18:27:11 +08:00
ibuler
fedd32ea7a merge: 合并dev 2021-07-19 18:26:04 +08:00
ibuler
e57574f10a perf: 添加配置文件,控制luna水印
perf: 添加配置文件样例
2021-07-19 18:20:51 +08:00
xinwen
3f0a0b33b5 feat: 应用按类型筛选可以指定多个类型 2021-07-19 10:11:07 +08:00
Bai
c21217d50c perf: 添加配置项 LOGIN_REDIRECT_TO_BACKEND 2021-07-16 14:34:23 +08:00
Bai
e44c8ae940 perf: 优化登录跳转flash时间间隔可配置;0表示直接跳转 2021-07-16 14:34:23 +08:00
wojiushixiaobai
1da187c373 perf: 优化 MFA 绑定提示 2021-07-16 14:33:08 +08:00
xinwen
36ad42beb2 fix: xrdp 设置分辨率不生效 2021-07-16 14:32:18 +08:00
Jiangjie.Bai
c0560ad3cc Merge pull request #6464 from jumpserver/dev
v2.12.0 rc5
2021-07-15 19:19:18 +08:00
ibuler
c318762f82 perf: 修改account密码加载 2021-07-15 19:12:58 +08:00
ibuler
5d373c0137 fix: 修复错误格式 2021-07-15 19:12:58 +08:00
Jiangjie.Bai
3aea998bd2 Merge pull request #6462 from jumpserver/dev
v2.12.0 rc5
2021-07-15 18:23:38 +08:00
ibuler
c1ca48a32a perf: 修改i18n 2021-07-15 18:22:53 +08:00
Jiangjie.Bai
2f0fcddc29 Merge pull request #6458 from jumpserver/dev
v2.12.0 rc5
2021-07-15 18:00:27 +08:00
ibuler
329565251a perf: 修改prefetch 2021-07-15 17:58:45 +08:00
ibuler
06a223376c perf: 基本完成 2021-07-15 17:58:45 +08:00
Bai
47e8ad3aac fix: 修复创建资产关联所在节点的系统用户时没有设置组织ID的问题 2021-07-15 17:12:56 +08:00
Jiangjie.Bai
c4fb3a8c04 Merge pull request #6455 from jumpserver/dev
v2.12.0 rc5
2021-07-15 17:04:22 +08:00
ibuler
9d4121c3b7 perf: 优化代码 2021-07-15 11:02:45 +08:00
xinwen
2eb1fe8547 fix: 系统用户与资产关系变化时 AuthBook 表的 org_id 可能是 root 组织 2021-07-15 11:02:45 +08:00
ibuler
e933774e6c fix: 修复创建 authbook 可能没有组织id的问题 2021-07-15 11:01:14 +08:00
Jiangjie.Bai
0b994d1c46 Merge pull request #6450 from jumpserver/dev
v2.12.0 rc4
2021-07-14 21:38:38 +08:00
xinwen
381b150c2b fix: 探测 authbook 在 root 组织下保存的情况 2021-07-14 21:37:48 +08:00
xinwen
53ebac9363 fix: 探测 authbook 在 root 组织下保存的情况 2021-07-14 21:36:53 +08:00
Jiangjie.Bai
a0638dd5c4 Merge pull request #6447 from jumpserver/dev
v2.12.0 rc4
2021-07-14 19:02:45 +08:00
Bai
5b741de896 fix: 修复系统用户资产导出包含组织名称 2021-07-14 18:56:40 +08:00
Bai
d7f587216d fix: 修复测试系统用户可连接性问题 2021-07-14 17:07:55 +08:00
ibuler
019f00a34a perf: 优化特权账号创建和导出
perf: 优化搜索

perf: Huany

perf: 还原

perf: 又改

xxx
2021-07-14 16:56:34 +08:00
Bai
9684b2d4ac fix: 修复测试资产可连接性获取admin_user总是新加载的authbook对象 2021-07-14 15:31:39 +08:00
xinwen
2e190c9ea9 fix: 授权过期自动刷新授权树 2021-07-14 15:00:41 +08:00
xinwen
601a48071f fix: 组织统计中系统用户数量不对 2021-07-14 13:56:44 +08:00
Bai
bf885f94e4 fix: 修复系统用户资产导出文案 2021-07-14 12:27:58 +08:00
Bai
7d4be819b8 fix: 修复系统用户资产导出文案 2021-07-14 12:25:07 +08:00
xinwen
26a7fa836c fix: 网关测试连接 500 2021-07-14 12:24:43 +08:00
Jiangjie.Bai
187329b006 Merge pull request #6429 from jumpserver/dev
v2.12.0 rc3
2021-07-13 20:45:03 +08:00
xinwen
8375008cfa fix: 用户无效时,企业微信&钉钉扫码 500 2021-07-13 20:43:37 +08:00
ibuler
16333fa1aa fix: 修复管理用户批量删除失败的bug 2021-07-13 18:12:19 +08:00
Bai
72deb005a6 fix: 修复改密日志支持模糊搜索 2021-07-13 18:07:48 +08:00
Bai
18509a0ca4 fix: 修复导出系统用户资产列表时包含org_id字段 2021-07-13 17:46:21 +08:00
ibuler
e63d0dcd9e perf: 添加ssh 指纹 2021-07-13 17:45:59 +08:00
Bai
62ba3984bd fix: 修复用户列表角色字段不显示的问题 2021-07-13 16:22:49 +08:00
ibuler
db170aac9e perf: 添加测试多个账号的任务 2021-07-13 13:16:27 +08:00
ibuler
5c7e73e2e0 fix: 修复系统用户详情,测试资产可连接性问题
fix; bug

perf: 还原migrations
2021-07-13 11:31:39 +08:00
ibuler
f772296dff fix(assets): 修复patch system user的问题
perf: 去掉debug
2021-07-13 11:30:38 +08:00
xinwen
f6a26ac165 fix: 全局组织命令记录无数据 2021-07-13 10:58:48 +08:00
ibuler
4e3b3442d2 perf: 修改添加翻译
perf: 优化翻译

perf: 修改i18n

perf: 编译
2021-07-13 10:35:42 +08:00
Jiangjie.Bai
2752770ce2 Merge pull request #6416 from jumpserver/dev
v2.12.0 rc2
2021-07-12 18:26:56 +08:00
ibuler
1840609d53 fix: 修复动态系统用户无法提交的问题
fix: 修复动态系统用户
2021-07-12 18:21:04 +08:00
fit2bot
4f23090a5c fix: 修复账号搜索 5xx (#6413)
Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
2021-07-12 18:20:32 +08:00
ibuler
898b51c593 fix: 修复账号搜索问题 2021-07-12 18:17:21 +08:00
xinwen
2494418208 fix: 用户组删除时,授权树不会自动更新 2021-07-12 18:16:53 +08:00
Bai
0fec70fe69 feat: 添加移除AssetUser Model的migrations 2021-07-12 13:10:40 +08:00
Jiangjie.Bai
bcf90d71a2 Merge pull request #6405 from jumpserver/dev
v2.12.0 rc1
2021-07-08 16:55:46 +08:00
ibuler
f8f7ac0af5 fix(assets): 修复创建资产报错 2021-07-08 16:52:31 +08:00
Jiangjie.Bai
d6c2705bd6 Merge pull request #6402 from jumpserver/dev
v2.12 rc1
2021-07-08 15:19:21 +08:00
ibuler
10f8b9f130 perf: 优化ansible执行命令 2021-07-08 14:54:05 +08:00
Bai
1e601288fa fix: 修改CAS配置默认值 2021-07-08 14:47:03 +08:00
Tommy.chen
b1032761c8 add cas CAS_USERNAME_ATTRIBUTE CAS_RENAME_ATTRIBUTES CAS_CREATE_USER read 2021-07-08 14:34:30 +08:00
Z000000
c532c361c0 批量命令支持更广泛的设备如思科等网络设备,docker等 (#6356)
* feat: Update README (#6182)

* feat: Update README

* feat: Update README

* Update README.md

* feat: update README

* Update README.md

* docs: 修改英文版本

* Update README.md

* 批量命令支持更广泛的设备如思科等网络设备,docker等

Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
Co-authored-by: 老广 <ibuler@qq.com>
2021-07-08 14:32:03 +08:00
fit2bot
ec8dca90d6 refactor: 整合系统用户和管理用户 (#6236)
* perf: 整合系统用户和管理用户

* stash

stash

perf: 优化系统用户和资产的表结构

* perf: 添加信号

* perf: 添加算法

* perf: 去掉 asset user backends

* perf: 整理系统用户api

* perfF: 暂存一下

* stash

* perf: 暂存一下

* perf: 暂存

* xxx

* perf: ...

* stash it

* xxx

* xxx

* xxx

* xxx

* xxx

* stash it

* 修改Protocols

* perf: 修改创建authbook信号

* perf: 添加auth info

* .stash

* perf: 基本完成

* perf: 修复完成

* perf: 修复更改的id

* perf: 修复迁移过去数量不对的问题

* perf: 修改systemuser

* fix: 修复批量编辑近期的问题

* fix: 修复authbook加载的问题

* xxx

Co-authored-by: ibuler <ibuler@qq.com>
2021-07-08 14:23:18 +08:00
xinwen
a9f814a515 fix: 过期用户登录提示不明确 2021-07-08 10:27:15 +08:00
xinwen
c4bbeaaccc feat: rdp 添加授权过期自动断开 2021-07-07 11:09:17 +08:00
xinwen
0fd5ab02e9 fix: 修复 interval 周期任务不执行问题 2021-07-01 16:42:22 +08:00
老广
745979074a Update README.md 2021-06-29 15:12:10 +08:00
Bai
8ae6863266 fix: 修复终端更新存储失败的问题 2021-06-29 13:33:16 +08:00
Bai
4fd7f0e949 fix: 修复自动生成系统用户密码中包含 {{ 双字符时测试可连接性失败的问题 2021-06-29 13:22:59 +08:00
xinwen
732f0b55dc refactor: 更改系统消息初始化策略 2021-06-28 15:57:49 +08:00
Jiangjie.Bai
c0ec0f1343 feat: 支持设置默认存储(命令、录像) (#6336)
* fix: 修改LDAP用户导入的组织为当前组织

* fix: 修改翻译信息

* feat: 支持设置默认存储

* feat: 支持设置默认存储(2)

* feat: 支持设置默认存储(3)
2021-06-28 10:32:59 +08:00
xinwen
aa6e550ba2 fix: 系统消息通知升级错误 2021-06-25 23:47:13 +08:00
Jiangjie.Bai
2ffaf59238 Merge pull request #6328 from jumpserver/ibuler-patch-1
Update README.md
2021-06-25 14:47:36 +08:00
ibuler
6c13fdbc46 perf: 优化图片大小
perf: ...
2021-06-25 10:16:26 +08:00
fghbng@qq.com
35941ddf7f feat: 优化缓存,将会话的缓存拿出来 2021-06-25 10:13:51 +08:00
fghbng@qq.com
3ae976c183 优化缓存,将会话的缓存拿出来 2021-06-25 10:13:51 +08:00
ibuler
999666f0eb docs: 修改英文版本 2021-06-23 17:16:01 +08:00
老广
1812074231 Update README.md 2021-06-23 11:31:51 +08:00
Bai
53eb32e620 fix: 修改翻译信息 2021-06-22 19:17:44 +08:00
Bai
50bd0b796d fix: 修改LDAP用户导入的组织为当前组织 2021-06-22 19:17:44 +08:00
wojiushixiaobai
a02d80a2ae feat: arm64 支持 2021-06-22 14:44:47 +08:00
ibuler
71a7eea8ad perf: 修复next为空可能会导致的bug 2021-06-22 11:13:44 +08:00
ibuler
2b927caa60 fix: 修复oidc登录的问题
..
2021-06-22 11:04:12 +08:00
ibuler
053d958f9a fix: 修复app无法下载xrdp文件 2021-06-22 10:20:37 +08:00
ibuler
8d25d0a653 fix: 修复登录页面的 i18n 问题 2021-06-22 10:18:48 +08:00
Bai
62eb131f59 fix: 修改创建用户时如果没有在任何组织内默认添加到default组织 2021-06-21 18:59:07 +08:00
jiangweidong
40eb7c79bb feat: 添加青云SDK 2021-06-21 15:57:21 +08:00
Bai
dabc9eb09b fix: 修改获取系统用户认证信息时username的选择逻辑;(单独设置过的系统用户认证信息登录资产失败) 2021-06-18 18:15:58 +08:00
Jiangjie.Bai
502657bad4 Merge pull request #6294 from jumpserver/dev
v2.11.0 rc5
2021-06-17 12:23:20 +08:00
ibuler
b5120e72c8 perf(notification): 发送html msg 2021-06-17 12:20:51 +08:00
Bai
2ca659414e fix: 修改应用账号序列类添加token字段 2021-06-17 12:13:06 +08:00
Jiangjie.Bai
64f772e747 Merge pull request #6291 from jumpserver/dev
v2.11.0. rc5
2021-06-17 11:49:04 +08:00
Bai
67a897f9c3 fix: 修改ldap导入 2021-06-17 11:48:00 +08:00
Jiangjie.Bai
d0a9ccbdfe Merge pull request #6286 from jumpserver/dev
v2.11.0 rc5 (2)
2021-06-16 19:47:51 +08:00
xinwen
1a30675a86 fix: 去掉命令告警开关 2021-06-16 18:03:17 +08:00
ibuler
f6273450bb perf: 优化批量危险命令告警 2021-06-16 18:02:17 +08:00
ibuler
8f35fcd6f9 perf: 优化通知迁移 2021-06-16 16:58:07 +08:00
xinwen
1999cfdfeb perf: 优化钉钉命令告警 2021-06-16 16:57:28 +08:00
Bai
c4af78c9f0 fix: 修改AuthBook删除raise异常类 2021-06-16 14:42:03 +08:00
Bai
a3d02decd6 fix: 修改翻译 2021-06-16 14:28:28 +08:00
ibuler
e623f63fcf perf: 修改i18n
perf: 优化命令告警,优化翻译
2021-06-16 14:24:57 +08:00
Jiangjie.Bai
4f1b2aceda Merge pull request #6277 from jumpserver/dev
v2.11.0 rc5
2021-06-16 13:03:17 +08:00
健健
94fc1fb53b fix: 导入数据解析 title 时,没有过滤 read only 字段 (#6269)
* feat: Update README (#6182)

* feat: Update README

* feat: Update README

* Update README.md

* feat: update README

* fix: 导入数据解析 title 时,没有过滤 read only 字段

type,type_display 翻译都是一样的,导出时使用的是 type,导入时识别成 type_display

Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
2021-06-16 13:00:55 +08:00
xinwen
937acbd0b5 fix: 资产授权不能打开或关闭 2021-06-16 12:54:03 +08:00
xinwen
067a70463e fix: 高危命令邮件收不到 2021-06-16 12:41:14 +08:00
Bai
b115ed3b79 fix: 修改LDAP用户导入默认添加到Default组织 2021-06-16 11:13:21 +08:00
Jiangjie.Bai
057fbdf0b1 Merge pull request #6268 from jumpserver/dev
v2.11.0 rc3
2021-06-15 14:50:02 +08:00
xinwen
5263a146e2 fix: 修复站内信迁移脚本问题 2021-06-15 14:47:16 +08:00
Jiangjie.Bai
84070a558e Merge pull request #6265 from jumpserver/dev
v2.11.0 rc2
2021-06-15 10:49:46 +08:00
Bai
e0604a3211 feat: 修改翻译 2021-06-15 10:42:06 +08:00
Bai
00e4c3cd07 feat: 添加应用用户API 2021-06-15 10:42:06 +08:00
ibuler
97a0e27307 perf: 优化消息中心未读数量 2021-06-11 18:02:53 +08:00
ibuler
8d3c1bd783 perf: 优化获取token secret, 重新校验权限 2021-06-10 19:51:11 +08:00
ibuler
db99ab80db perf(auth): 授权token形式登录,支持记录登录日志 2021-06-10 18:07:24 +08:00
Jiangjie.Bai
1e8d9ba2ec Merge pull request #6256 from jumpserver/dev
v2.11.0 rc1
2021-06-10 14:03:45 +08:00
xinwen
7dddf0c3c2 fix: 站内信未读信息计数不准 2021-06-10 10:24:54 +08:00
fit2bot
891a5157a7 perf: 优化token时间 (#6252)
* perf: 修复上次引起的小bug

* perf: 优化token时间

Co-authored-by: ibuler <ibuler@qq.com>
2021-06-09 20:10:34 +08:00
ibuler
34b2a5fe0b perf: 修复上次引起的小bug 2021-06-09 15:47:26 +08:00
ibuler
de6908e5a6 perf: rdp file添加domain
fix: 禁用的用户不返回信息

perf: 优化token,禁用的资产无法链接
2021-06-09 14:18:15 +08:00
fit2bot
d6527e3b02 perf: 优化支持记录密码 (#6247)
* perf: 优化 xrdp setting

* perf: 优化支持记录密码

Co-authored-by: ibuler <ibuler@qq.com>
2021-06-08 20:50:15 +08:00
ibuler
33a29ae788 perf: 优化 xrdp setting 2021-06-08 15:25:32 +08:00
ibuler
a2eb431015 perf: 优化自动分辨率 2021-06-08 12:48:48 +08:00
Bai
8fbea2f702 fix: 修改资产账号name为非必填 2021-06-08 11:38:37 +08:00
fit2bot
af92271a52 feat: 调整站内信接口 (#6228)
* feat: 调整站内信接口

* 添加 websockt

* 添加信息类型字段

* 添加 has_read 过滤参数

* feat: 调整站内信接口

* 添加 websockt

* 添加信息类型字段

* 添加 has_read 过滤参数

* 去掉type websocket

* perf: 去掉type

Co-authored-by: xinwen <coderWen@126.com>
Co-authored-by: ibuler <ibuler@qq.com>
2021-06-08 11:11:27 +08:00
ibuler
391a5cb7d0 perf: 修复手动设置密码的问题 2021-06-07 10:46:58 +08:00
xinwen
daf7d98f0e fix: 其他组织中创建的用户不要添加到默认组织了 2021-06-04 04:30:40 -05:00
Jiangjie.Bai
ed297fd1bd Merge pull request #6226 from jumpserver/pr@dev@add_missing_migrations
chore: 添加删除的文件
2021-06-04 14:40:32 +08:00
Bai
f91bef4105 feat: 修改依赖包版本号: jms-storage-sdk==0.0.37 2021-06-04 14:37:02 +08:00
Bai
a8d84fc6e1 feat: 修改迁移文件 2021-06-04 11:39:17 +08:00
Bai
0c7838d0e3 feat: 修改迁移文件 2021-06-04 11:39:17 +08:00
Jiangjie.Bai
f26483c9cd Merge pull request #6224 from jumpserver/feat_account_manager
feat: 添加账号管理相关API
2021-06-04 11:15:53 +08:00
Bai
5daca6592b feat: 修改文案 后端 -> 来源 2021-06-04 11:14:53 +08:00
Bai
0bced39f08 fix: 修复redis服务异常时(如: 主从切换), 用户session立即过期的问题 2021-06-03 22:04:10 -05:00
ibuler
6d83dd0e3a chore: 添加删除的文件 2021-06-03 14:54:41 +08:00
ibuler
46e99d10cb Merge branch 'dev' of github.com:jumpserver/jumpserver into dev 2021-06-03 14:28:39 +08:00
liubo
95eb11422a feat: 支持添加 OBS 存储 2021-06-03 01:28:23 -05:00
ibuler
e8b3ee4565 perf: 优化系统用户,支持用户设置临时密码
perf: 优化rdp file下载

perf: 修改密码途观选项

perf: 优化api获取
2021-06-03 01:24:28 -05:00
Bai
1e99be1775 feat: 修改获取应用用户API 2021-06-03 13:59:44 +08:00
Bai
adae509bc0 fix: 修复组织批量删除的问题 2021-06-03 11:36:24 +08:00
ibuler
7868e91844 Merge branch 'dev' of github.com:jumpserver/jumpserver into dev 2021-06-03 11:19:02 +08:00
xinwen
a9bdbcf7c6 fix: metadata api view 报错 2021-06-02 22:02:14 -05:00
xinwen
a809eac2b8 fix: 修复获取 Metadata 时,获取的总是 action 为 metadata 2021-06-02 04:41:01 -05:00
Bai
bdab93260f feat: 资产用户API返回 BackendDisplay 和 Name 字段 2021-06-02 17:00:31 +08:00
fit2bot
4ef3b2630a feat: 站内信 (#6183)
* 添加站内信

* s

* s

* 添加接口

* fix

* fix

* 重构了一些

* 完成

* 完善

* s

* s

* s

* s

* s

* s

* 测试ok

* 替换业务中发送消息的方式

* 修改

* s

* 去掉 update 兼容 create

* 添加 unread total 接口

* 调整json字段

Co-authored-by: xinwen <coderWen@126.com>
2021-05-31 17:20:38 +08:00
Bai
4eef25982d feat: 更新 ApplicationUserList API 2021-05-27 18:42:43 +08:00
xinwen
b82e9f860b fix: users 遗漏一个 migration 2021-05-26 15:26:56 +08:00
Bai
6b46f5b48e feat: 添加ApplicationUserList API 2021-05-24 19:11:47 +08:00
Jiangjie.Bai
fe717f0244 feat: Update README (#6182)
* feat: Update README

* feat: Update README

* Update README.md

* feat: update README
2021-05-24 16:04:40 +08:00
ibuler
33fb063f78 perf: 暂时禁用xrdp实时监控 2021-05-24 15:37:21 +08:00
老广
7edc9c37f8 Update README.md 2021-05-24 11:02:18 +08:00
Michael Bai
f8b4259a8c fix: 修复创建/更新用户时密码策略相关的问题 2021-05-23 21:56:37 -05:00
Michael Bai
572d0e3f27 fix: 修复parser没有处理int类型数据的问题 2021-05-23 21:54:14 -05:00
ibuler
b334f3c2d9 Merge branch 'dev' of github.com:jumpserver/jumpserver into dev 2021-05-24 10:46:43 +08:00
Jiangjie.Bai
6b4b9f4b02 Merge pull request #6169 from jumpserver/dev
v2.10.1
2021-05-21 15:20:25 +08:00
ibuler
d765e61991 fix(assets): 修复网关信息没有密码的bug 2021-05-21 15:17:29 +08:00
Bai
9ccde03656 fix: 修改cloud翻译 2021-05-20 22:27:29 -05:00
xinwen
c66f366446 fix: 修复 default 组织用户数量统计错误 2021-05-21 10:36:27 +08:00
ibuler
34d46897f8 fix: 修复周期监测任务配置的bug 2021-05-21 10:35:39 +08:00
ibuler
2d9ce16601 Merge branch 'dev' of github.com:jumpserver/jumpserver into dev 2021-05-20 15:53:16 +08:00
Jiangjie.Bai
0380be51dd Merge pull request #6155 from jumpserver/dev
Merge dev to master
2021-05-20 15:02:28 +08:00
Bai
47df0cfaab fix: 修改翻译 2021-05-20 15:00:10 +08:00
Bai
a2fb4a701e fix: 修复命令过滤器规则Action Choices显示 2021-05-20 01:07:33 -05:00
fit2bot
6e4381ac04 perf: 修改readme (#6152)
* perf: 修改readme

* perf: 修改readme

Co-authored-by: ibuler <ibuler@qq.com>
2021-05-20 13:14:34 +08:00
fghbng@qq.com
8ae03e4374 修复资产导出字段名显示 2021-05-20 00:11:44 -05:00
fghbng@qq.com
73f2022ff6 修复全局组织仪表盘用户总数统计 2021-05-20 00:07:49 -05:00
ibuler
bc4258256a perf: 修改readme 2021-05-20 13:06:37 +08:00
Jiangjie.Bai
58dfe58ae0 Merge pull request #6147 from jumpserver/dev
v2.10.0 rc4
2021-05-19 19:28:10 +08:00
fghbng@qq.com
53e3fa2590 修复全局组织仪表盘用户总数统计 2021-05-19 19:27:30 +08:00
xinwen
23dbdaf6c0 fix: 系统用户里测试资产可连接性不能指定资产 2021-05-19 18:07:29 +08:00
xinwen
3eba92548b fix: 修改企业微信&钉钉一些小问题和翻译 2021-05-19 18:02:34 +08:00
fghbng@qq.com
ac5f2c560d 修复网关更新获取到了明文密码 2021-05-19 17:58:26 +08:00
Bai
f7f9331c48 fix: 修复Dashboard活跃用户数据不准确问题 2021-05-19 17:49:03 +08:00
xinwen
77b4847bd9 fix: 有在线会话的终端不能删除 2021-05-19 16:17:47 +08:00
Jiangjie.Bai
0de9b29fa9 Merge pull request #6136 from jumpserver/dev
v2.10.0 rc3
2021-05-18 19:16:25 +08:00
xinwen
f9ca46dd67 fix: 修复用户历史密码在创建时不起作用 2021-05-18 19:15:58 +08:00
xinwen
ba28f3263d fix: 企业微信&钉钉解绑报错 2021-05-18 14:03:16 +08:00
xinwen
2e118665f5 fix: 过期用户退出登录 2021-05-17 21:08:01 -05:00
fit2bot
bf53df46dc fix: 修复包含组织管理员时可以删除组织的问题 (#6130)
Co-authored-by: Bai <bugatti_it@163.com>
2021-05-17 19:11:55 +08:00
fit2bot
6449f36c7e perf: 修改文案 (#6129)
* perf: 修改i18n

* perf: 修改文案

Co-authored-by: ibuler <ibuler@qq.com>
2021-05-17 19:11:28 +08:00
Bai
ba35f5906b fix: 修复收集用户interval等字段的校验 2021-05-17 18:31:30 +08:00
fghbng@qq.com
c8d7d42f66 仪表盘全局组织统计 2021-05-17 17:35:13 +08:00
fghbng@qq.com
20dacea260 仪表盘全局组织报500错误 2021-05-17 17:35:13 +08:00
ibuler
d2dc2ab02c perf: 修改i18n 2021-05-17 17:30:56 +08:00
xinwen
ba3b5a4027 fix: 创建 Es 时失败的提示翻译 2021-05-17 17:29:53 +08:00
xinwen
3743761024 fix: 修复绑定企业微信&钉钉的一些问题 2021-05-17 17:20:48 +08:00
Bai
70055b8af2 fix: 修复remoteapp获取asset_info失败的问题 2021-05-17 16:15:28 +08:00
ibuler
726fd94f65 fix: 修复 xslx 提交数字类型报错 2021-05-17 01:54:52 -05:00
Bai
8b951ce12c perf: 添加迁移文件(lion) 2021-05-17 14:50:35 +08:00
Bai
189bc9d74a perf: 添加lion终端类型; 修改加入会话校验逻辑(vnc/rdp) 2021-05-17 14:50:35 +08:00
Jiangjie.Bai
dd6c063478 Merge pull request #6119 from jumpserver/dev
v2.10.0 rc2 fix-dashboard
2021-05-17 10:11:06 +08:00
fghbng@qq.com
5e9006d0c2 修复仪表盘数据统计错误 2021-05-17 10:09:38 +08:00
Jiangjie.Bai
c42f69d1ba Merge pull request #6117 from jumpserver/dev
v2.10.0 rc2
2021-05-14 19:20:40 +08:00
fghbng@qq.com
c7dfd0edce 修复授权导入系统用户为空报错 2021-05-14 19:20:24 +08:00
fghbng@qq.com
4382921c57 修复授权导入优化资产、用户、用户组、节点、系统用户id为空报错的情况 2021-05-14 19:20:24 +08:00
Bai
45feb468be perf: 优化工单邮件信息 2021-05-14 16:19:25 +08:00
xinwen
c9b6b9a37a fix: 修复企业微信,钉钉登录 BACKEND 没有注册 2021-05-14 15:55:28 +08:00
Michael Bai
8010bdecea fix: 修复创建动态系统用户时设置了home目录,使得所有推送的用户共用同一个home目录,导致目录权限只限制在第一个推送的用户,其他用户进行可连接性测试时失败的问题 2021-05-14 15:43:50 +08:00
Bai
fc1c9c564a fix: 修改翻译文件 2021-05-14 11:01:36 +08:00
Jiangjie.Bai
7c13b72739 Merge pull request #6107 from jumpserver/dev
v2.10.0 rc1
2021-05-13 19:51:43 +08:00
Bai
6a4bc1f8b3 perf: 修改翻译 2021-05-13 19:50:52 +08:00
Jiangjie.Bai
7d51d8c570 Merge pull request #6105 from jumpserver/dev
v2.10 rc1
2021-05-13 19:19:42 +08:00
Bai
0ecd9fa32a fix: 修复自动生成公钥优先使用dss格式的问题(默认优先使用rsa) 2021-05-13 19:12:03 +08:00
xinwen
b37c8b09bf refactor: 添加一些翻译&修正字段WECOM_SECRET 2021-05-13 16:29:41 +08:00
fghbng@qq.com
23f22e92b8 首页的统计数据,可以从 org resource cache 中获取
首页的统计数据,可以从 org resource cache 中获取
2021-05-13 16:05:53 +08:00
xinwen
c16319ec48 feat: 添加企业微信,钉钉扫码登录 2021-05-13 14:15:07 +08:00
jym503558564
340547c889 perf(README): 白皮书下载 2021-05-12 02:12:34 -05:00
xinwen
54f5e65d36 feat: 检查资产授权过期接口添加过期时间 2021-05-11 10:40:33 +08:00
ibuler
4d6d4cbc22 perf: 优化登录,cas, openid 自动登录 2021-05-07 05:58:56 -05:00
xinwen
7294f6e5e0 refactor: command es storage IGNORE_VERIFY_CERTS 2021-05-07 03:48:59 -05:00
ibuler
8ca2522c71 fix: 修改tokent中信息中没有返回 Protocols 的问题
fix: 优化protocols

fix: session bpp

token 时间加长
2021-04-30 01:29:52 -05:00
fghbng@qq.com
72f9d0d371 serializer优化&&资产授权导入优化 2021-04-30 14:05:46 +08:00
fghbng@qq.com
9a92e24e50 serializer优化&&授权导入优化 2021-04-30 14:05:46 +08:00
Bai
fea0170c5e perf: 可以删除包含子孙节点但不包含子孙资产的节点 2021-04-29 00:42:58 -05:00
ibuler
5e5cd80bc2 perf: 优化登录前修改密码 2021-04-29 00:42:07 -05:00
fit2cloud-jiangweidong
e3511df4f8 feat: 管理员可以设置用户是否下次登录需修改密码 (#6006)
* feat: 管理员可以设置用户是否下次登录需修改密码

* feat: 管理员可以设置用户下次是否需要更改密码,本次修改:字段命名规范化

* feat: 管理员可以设置用户下次是否需要更改密码,本次修改:字段命名规范化

* fix: 用户下次登录是否需要改密,函数名及变量名规范化

* fix: 管理员设置用户下次是否改密功能的国际化翻译文件

* fixs: 管理员设置用户下次登录是否需改密功能,逻辑修改

* fix: 管理员可设置用户下次登录是否需要改密,字段名称更改
2021-04-28 19:25:30 +08:00
fit2cloud-jiangweidong
11e5a97f14 feat: 用户更改密码不可使用前n次历史密码,管理员可设置历史密码重复次数 (#6010)
* feat: 用户更改密码不可使用前n次历史密码,管理员可设置历史密码重复次数

* feat: 用户更改密码不可使用前n次历史密码,管理员可设置历史密码重复次数, 判断是否为历史密码逻辑修改

* feat: 用户更改密码不可使用前n次历史密码,管理员可设置历史密码重复次数, 提示内容更人性化

* fixs: 用户更改密码不可使用前n次历史密码,管理员可设置历史密码重复次数, 最新国际化翻译文件
2021-04-28 17:03:20 +08:00
fit2bot
4519ccfe1a 授权导入优化 (#6057)
* 授权导入优化,支持使用 用户名,资产名,ip,节点路径,系统用户名称导入

* Update permission.py

* 授权导入优化

* 授权导入优化

* 授权导入优化

* 授权导入优化

Co-authored-by: fghbng@qq.com <fghbng@qq.com>
2021-04-28 16:42:54 +08:00
xinwen
657a2ac7e7 fix: 命令记录导出选择项 2021-04-28 03:35:36 -05:00
Bai
f5d8e125cb fix: 修复创建资产不传nodes时报错的问题 & 修复Option资产API时报JSON序列化失败的问题 2021-04-28 03:19:00 -05:00
xinwen
fd203c67c3 fix: 添加无效的 es 命令记录存储时,抛出错误提示 2021-04-27 05:39:50 -05:00
jing guo
9fe5496ce9 通过 api 添加资产,不写 protocols 时,默认值应该是列表 2021-04-27 05:36:46 -05:00
老广
c0875f6a87 Merge pull request #6037 from jumpserver/pr@dev@perf_public_key_setting
perf: 优化公钥设置,并删掉一部分不用的 html
2021-04-27 05:07:53 -05:00
ibuler
d1a005f750 perf: 优化MFA verify requierd 2021-04-27 05:05:22 -05:00
ibuler
c52431b5ce chore(merge): 合并ddev 2021-04-27 18:01:15 +08:00
Bai
4a9e83ba15 feat: 添加命令复核逻辑; 添加命令复核工单; 5 2021-04-27 17:53:06 +08:00
Bai
7712c1659e feat: 添加命令复核逻辑; 添加命令复核工单; 4 2021-04-27 16:36:42 +08:00
Bai
74c7b18dc4 feat: 添加命令复核逻辑; 添加命令复核工单; 3 2021-04-27 16:36:42 +08:00
Bai
5a3c67989b feat: 添加命令复核逻辑; 添加命令复核工单; 2 2021-04-27 16:36:42 +08:00
Bai
50918a3dd2 feat: 添加命令复核逻辑; 添加命令复核工单; 2021-04-27 16:36:42 +08:00
Bai
e9b174f342 feat: 修改命令过滤规则Model: 添加Action-reconfirm; 添加field-reviewers 2021-04-27 16:36:42 +08:00
老广
63efbfe62e Merge pull request #6049 from jumpserver/pr@dev@fix_expire_caches
fix: 添加启动失效缓存
2021-04-27 03:12:53 -05:00
xinwen
99cce185dd fix: 添加启动失效缓存 2021-04-27 16:09:07 +08:00
ibuler
ab0fda93f6 perf: 优化公钥设置,并删掉一部分不用的 html 2021-04-26 10:21:22 +08:00
ibuler
d9552c0038 perf: 优化公钥设置,让用户可以选择是否开启 2021-04-25 18:13:41 +08:00
老广
f0f493081a Merge pull request #6032 from jumpserver/pr@dev@fix_panelboard
【仪表盘】在线用户数不对,(连上windows资产之后,在线用户数就不对了)
2021-04-25 02:06:34 -05:00
fghbng@qq.com
c4727e1eba 【仪表盘】在线用户数不对,(连上windows资产之后,在线用户数就不对了) 2021-04-25 14:58:06 +08:00
Bai
ce8143c2ec fix: 修改ACL提示支持的协议为: ssh、telnet 2021-04-23 16:35:50 +08:00
Bai
65ad63272c fix: 修复操作应用/应用授权/acl等未记录日志的问题2 2021-04-20 16:47:31 +08:00
老广
4a4d5f3243 Merge pull request #5999 from jumpserver/pr@dev@fix_rdp_file_addr
fix: 修复下载rdp文件失败的问题
2021-04-20 03:28:34 -05:00
ibuler
4563743f00 fix: 修复下载rdp文件失败的问题 2021-04-20 16:17:18 +08:00
ibuler
7b679f3e82 fix(task): 修复推送过期的问题
fix(rdp): 修复下载rdp文件失败的问题
2021-04-20 15:20:49 +08:00
Bai
3d6aa15ece fix: 修复操作应用/应用授权/acl等未记录日志的问题 2021-04-20 00:08:23 -05:00
ibuler
94a798eb01 fix(task): 修复推送过期的问题 2021-04-20 12:58:48 +08:00
ibuler
ec393c1440 fix(task): 修复推送过期的问题 2021-04-20 11:27:02 +08:00
ibuler
6571209864 fix: 修复创建的系统用户很快过期的问题 2021-04-19 17:01:48 +08:00
Jiangjie.Bai
d042de7b09 Merge pull request #5972 from jumpserver/dev
v2.9.0 发版
2021-04-15 21:02:28 +08:00
ibuler
5e6e97c822 perf: 优化推送系统用户,设置有效期 2021-04-15 19:25:58 +08:00
xinwen
f146873501 fix: key=0 修改到 key=1 时 parent_key 没有更新 2021-04-15 01:33:00 -05:00
Jiangjie.Bai
35dfdf831a Merge pull request #5965 from jumpserver/dev
v2.9.0 rc3
2021-04-14 18:43:45 +08:00
xinwen
2b31cb2806 fix: 命令记录导出适配 ES 2021-04-14 05:02:50 -05:00
xinwen
e43ffa7994 fix: 远程应用显示名称 2021-04-14 04:56:59 -05:00
ibuler
b0a9a83231 fix(terminal): 修复终端列表看到的在线会话数量不对的bug 2021-04-14 16:41:57 +08:00
xinwen
7da14571ac fix: 请求 token 接口,登录类型没内容 2021-04-14 03:14:10 -05:00
xinwen
73b67da4c0 fix: 修复 acl 一些翻译 2021-04-14 03:13:18 -05:00
Jiangjie.Bai
4bf2371cf0 Merge pull request #5952 from jumpserver/dev
v2.9.0 rc2
2021-04-13 19:19:43 +08:00
Jiangjie.Bai
075cbc497b Merge pull request #5953 from jumpserver/pr@dev@dev_merge
chore(merge): 合并
2021-04-13 19:16:54 +08:00
ibuler
1a0d9a20f9 chore(merge): 合并 2021-04-13 18:54:08 +08:00
ibuler
fdb8416cac fix: 修复组件在线会话数量不对的问题 2021-04-13 05:49:03 -05:00
ibuler
e2d5b69510 perf: 优化健康监测,并添加 health check 的 key 2021-04-13 05:48:35 -05:00
xinwen
9944474ba0 fix: settings 订阅不稳定 2021-04-13 05:40:04 -05:00
xinwen
ce6b9de07c fix: ES 自动创建索引 2021-04-13 04:44:44 -05:00
xinwen
b97759687d fix: 邀请用没有触发信号 2021-04-13 04:23:29 -05:00
xinwen
68b6236de2 fix: SSO 登录日志 2021-04-12 04:48:17 -05:00
xinwen
6616374c30 fix: subscribe_settings_change 2021-04-12 04:45:30 -05:00
xinwen
682f6b2fb9 fix: 资产节点关系变化时也要清空 root 组织的 node_assets_mapping 2021-04-12 04:44:13 -05:00
xinwen
a2e3979916 fix: org_mapping 保护订阅线程 2021-04-12 04:42:48 -05:00
xinwen
f11d3c1cf2 fix: 过期用户登录提示无效 2021-04-09 02:03:35 -05:00
xinwen
f0bad5f107 fix: 登录页面测试 cookie 失败 2021-04-09 01:46:21 -05:00
ibuler
ad3bc72dfb fix(terminal): 修复session id 长度误写为 35 的bug 2021-04-08 19:23:36 +08:00
xinwen
de9c69843d fix: 登录日志 user_agent 过长 2021-04-08 19:23:36 +08:00
xinwen
d2678e2a43 refactor: 移动 PermissionsMixin 位置 2021-04-08 19:23:36 +08:00
xinwen
632ea87f07 feat: MFA 登录次数限制 2021-04-08 19:23:36 +08:00
fit2bot
4e7e1d5e15 style: 优化全局组织设置相关代码 (#5921)
* feat:支持配置全局组织的显示名称

* style: 优化全局组织设置相关代码

Co-authored-by: liubo <liubo@fit2cloud.com>
2021-04-08 19:23:36 +08:00
liuboF2c
1ac8537a34 feat:支持配置全局组织的显示名称 (#5919)
Co-authored-by: liubo <liubo@fit2cloud.com>
2021-04-08 19:23:36 +08:00
fit2bot
dcaa798c2e perf: csv upload (#5894)
perf: 修改翻译

Co-authored-by: ibuler <ibuler@qq.com>
2021-04-08 19:23:36 +08:00
xinwen
8da4027e32 fix: 授权资产列表 platform 应该显示名称 2021-04-08 19:23:36 +08:00
xinwen
32e2d19553 fix: 改密计划关掉周期执行再打开,任务不再执行 2021-04-08 19:23:36 +08:00
xinwen
48d1eecc08 fix: 修正 key 为 0 的节点 2021-04-08 19:23:36 +08:00
xinwen
0ab88ce754 fix: 访问 tokens 接口更新用户最后登录时间 2021-04-08 19:23:36 +08:00
xinwen
bee5500425 fix: 创建节点的时候加锁,可以并发调用 2021-04-08 19:23:36 +08:00
xinwen
7c03af7668 feat: 资产授权支持按名称模糊搜索 2021-04-08 19:23:36 +08:00
xinwen
7a61a671a2 fix: 管理用户输入带密码的秘钥报错 2021-04-08 19:23:36 +08:00
Bai
4a1fc0e2ac fix: 修复NodeChildrenAddAPI不支持patch方法的问题 2021-04-08 19:23:36 +08:00
ibuler
1e5e87e62a perf: 优化acl提示 2021-04-08 19:23:36 +08:00
ibuler
96c3b81383 perf: upgrade requirements version 2021-04-08 19:23:36 +08:00
xinwen
297fedeffa fix: Default 组织下出现 app user 2021-04-08 19:23:36 +08:00
ibuler
9cd5675209 perf: 修改terminal statuts
perf: 优化status api

perf: 优化 status api

perf: 修改sesion参数

perf: 修改migrations

perf: 优化数据结构

perf: 修改保留日志

perf: 优化之前的一个写法
2021-04-08 19:23:36 +08:00
xinwen
a5179d1596 feat: 增加 es 忽略 https 证书验证 2021-04-08 19:23:36 +08:00
Bai
c2463fe573 perf: Session Login from 添加 RDP Terminal 类型 2021-04-08 19:23:36 +08:00
xinwen
2f8042141c fix: 授权树节点排序 2021-04-08 19:23:36 +08:00
ibuler
06a4e0d395 perf: 修改表结构迁移,增加rdp terminal 2021-04-08 19:23:36 +08:00
xinwen
bb9d92fd7e perf: delete_test_cookie 2021-04-08 19:23:36 +08:00
ibuler
749f9d3f81 fix(terminal): 修复session id 长度误写为 35 的bug 2021-04-08 17:39:29 +08:00
xinwen
03ad7777d0 fix: 登录日志 user_agent 过长 2021-04-08 04:39:12 -05:00
xinwen
7e4f20f443 refactor: 移动 PermissionsMixin 位置 2021-04-08 02:15:02 -05:00
xinwen
607b7fd29f feat: MFA 登录次数限制 2021-04-08 01:46:36 -05:00
fit2bot
8895763ab4 style: 优化全局组织设置相关代码 (#5921)
* feat:支持配置全局组织的显示名称

* style: 优化全局组织设置相关代码

Co-authored-by: liubo <liubo@fit2cloud.com>
2021-04-08 14:18:53 +08:00
liuboF2c
8b1e202e68 feat:支持配置全局组织的显示名称 (#5919)
Co-authored-by: liubo <liubo@fit2cloud.com>
2021-04-08 13:55:58 +08:00
fit2bot
32fe8f674c perf: csv upload (#5894)
perf: 修改翻译

Co-authored-by: ibuler <ibuler@qq.com>
2021-04-08 10:11:46 +08:00
xinwen
b4ef7bef55 fix: 授权资产列表 platform 应该显示名称 2021-04-08 10:10:32 +08:00
xinwen
31982c6547 fix: 改密计划关掉周期执行再打开,任务不再执行 2021-04-07 18:38:45 +08:00
xinwen
67d3b63c6d fix: 修正 key 为 0 的节点 2021-04-07 11:11:23 +08:00
xinwen
f34fb5d9d5 fix: 访问 tokens 接口更新用户最后登录时间 2021-04-07 10:45:34 +08:00
xinwen
3ec78ff9be fix: 创建节点的时候加锁,可以并发调用 2021-04-07 10:29:19 +08:00
xinwen
f361621ab5 feat: 资产授权支持按名称模糊搜索 2021-04-07 10:28:14 +08:00
xinwen
cd9587f68e fix: 管理用户输入带密码的秘钥报错 2021-04-06 19:46:16 +08:00
Bai
2ff01a4bb3 fix: 修复NodeChildrenAddAPI不支持patch方法的问题 2021-04-01 10:55:21 +08:00
ibuler
06ed358fbc perf: 优化acl提示 2021-03-30 10:36:41 +08:00
ibuler
3e11249e8c perf: upgrade requirements version 2021-03-30 10:25:30 +08:00
xinwen
6b5435b768 fix: Default 组织下出现 app user 2021-03-30 10:24:25 +08:00
ibuler
7d5a13de38 perf: 修改terminal statuts
perf: 优化status api

perf: 优化 status api

perf: 修改sesion参数

perf: 修改migrations

perf: 优化数据结构

perf: 修改保留日志

perf: 优化之前的一个写法
2021-03-29 19:21:32 +08:00
xinwen
07bd44990b feat: 增加 es 忽略 https 证书验证 2021-03-29 15:23:33 +08:00
noon
e4938ffc85 Update README_EN.md (#5856)
* Update README_EN.md

Translate parts of the README.md

* Update README_EN.md

* Update README_EN.md

change the word PAM to Bastion host

* Update README_EN.md

* Update README_EN.md

Clip the bug part to JumpServer 远程执行漏洞 2021-01-15
2021-03-27 20:14:45 +08:00
Bai
85d226eb07 perf: Session Login from 添加 RDP Terminal 类型 2021-03-26 10:38:48 +08:00
xinwen
c9a9ca7923 fix: 授权树节点排序 2021-03-24 10:23:45 +08:00
ibuler
306f7a08d1 perf: 修改表结构迁移,增加rdp terminal 2021-03-24 10:14:59 +08:00
老广
b86f9ac871 Update README.md 2021-03-23 15:47:19 +08:00
xinwen
2562386fe0 perf: delete_test_cookie 2021-03-23 15:27:06 +08:00
老广
61d4311e24 Merge pull request #5808 from jumpserver/dev
Dev
2021-03-19 20:01:03 +08:00
xinwen
370e1628be fix: 禁用的资产限制访问 2021-03-19 20:00:25 +08:00
xinwen
adf5c4a7b9 fix: LDAP 自动创建的用户有多余的空格 2021-03-19 17:39:06 +08:00
Bai
9fc1ae7b6d perf: 修改翻译 2021-03-19 14:45:05 +08:00
xinwen
313757dbe9 fix: 修复用户与用户组关系变化时 500 2021-03-19 14:33:39 +08:00
Jiangjie.Bai
b32e352b24 Merge pull request #5799 from jumpserver/dev
v2.8 发版
2021-03-18 21:04:37 +08:00
Bai
b950b48112 fix: 隐藏azure-sdk的日志 2021-03-18 21:03:35 +08:00
Jiangjie.Bai
519eb3bef2 Merge pull request #5797 from jumpserver/dev
v2.8 发版
2021-03-18 20:41:28 +08:00
Bai
4e55d0f1e4 添加依赖: (azure-identity==1.5.0)(azure-mgmt-subscription==1.0.0) 2021-03-18 20:30:59 +08:00
Jiangjie.Bai
2b3bb65114 Merge pull request #5794 from jumpserver/dev
v2.8 发版 (rc6)
2021-03-18 17:39:02 +08:00
xinwen
b597cfcd19 fix: 修复一些 Root 组织没数据的问题 2021-03-18 17:25:11 +08:00
xinwen
33952b2333 fix: 有无效的 ES 时,创建 Session 失败 2021-03-18 14:34:00 +08:00
xinwen
a47a9c0345 fix: Root 组织用户从用户组移除报错 2021-03-18 10:53:31 +08:00
xinwen
4e0c056867 fix: 日志审计-> 批量命令 全局组织无数据 2021-03-18 10:42:52 +08:00
ibuler
a9b5599db5 perf: 更换登录页图片 2021-03-18 10:30:23 +08:00
ibuler
8a2eb70ad2 revert: 还原api限制 2021-03-18 10:25:40 +08:00
老广
776234e8cc Merge pull request #5785 from jumpserver/dev
v2.8 发版 (rc4)
2021-03-17 20:15:31 +08:00
ibuler
e2406955bc perf: 优化license判断
perf: 优化license 过期
2021-03-17 18:47:38 +08:00
Bai
dba9550bc0 perf: 修改翻译 2021-03-17 18:25:39 +08:00
xinwen
6ad1362a3f perf: 批量命令日志导出增加 hosts_display 字段 2021-03-17 18:16:19 +08:00
Bai
dfa2f7d6c9 fix: 修复用户登录复核工单org_id为ROOT 2021-03-17 17:23:39 +08:00
ibuler
c55e2db75e perf: 优化license判断 2021-03-17 17:18:39 +08:00
xinwen
fd3a4d887e fix: Root 组织查不到命令记录 2021-03-17 17:17:15 +08:00
ibuler
42afc1e0bf fix(perms): 修复删除 资产或授权引起的bug 2021-03-17 17:15:38 +08:00
ibuler
50c89431df perf: 修复ansible summary显示两遍的问题 2021-03-17 17:13:07 +08:00
xinwen
f1f5017be3 fix: 无效的 ES 会卡住 2021-03-17 17:09:52 +08:00
ibuler
9b85aafa52 perf: 全局组织仅支持删除和查看 2021-03-17 17:09:11 +08:00
xinwen
817268d7cd perf: 资产与节点变化的时候,优化发送推送系统用户信号 2021-03-17 17:04:53 +08:00
ibuler
d3bbfdc458 perf: 不修改原来的默认配置 2021-03-17 17:02:44 +08:00
Bai
18a390d66a perf: 修改迁移文件(default_org_name: DEFAULT => Default) 2021-03-17 15:22:21 +08:00
老广
73b57a662e Merge pull request #5766 from jumpserver/dev
v2.8 发版 (rc4)
2021-03-16 20:49:04 +08:00
ibuler
ea325f6e52 perf(users): 优化用户认证来源 2021-03-16 20:48:00 +08:00
Bai
1216f15e45 fix: 修复新旧版本对于default_node节点变更冲突的问题(旧版本会将新版本迁移后的default_node节点的key修改为非1) 2021-03-16 20:45:50 +08:00
ibuler
cc3911d2f1 fix: 修复 user profile all orgs 的bug 2021-03-16 20:30:46 +08:00
xinwen
36c083f674 fix: 会话里查不到命令记录 2021-03-16 20:29:05 +08:00
xinwen
98c6a93658 fix: 任务应该分组织 2021-03-16 19:26:13 +08:00
Bai
adc607dafe fix: 修复用户角色由组织用户->组织管理员时从组织清除用户 2021-03-16 19:21:01 +08:00
xinwen
1e85805ea3 fix: 用户授权资产过滤失效 2021-03-16 19:19:36 +08:00
老广
957d3660ce Merge pull request #5754 from jumpserver/dev
v2.8 发版 (rc3)
2021-03-15 19:59:31 +08:00
xinwen
049f6dca67 fix: 删除组织时,确保没有跟节点之外的其他节点。以及组织删除后,将跟节点删除 2021-03-15 19:58:46 +08:00
ibuler
7f4377b0e8 fix(auditor): 修复审计员无法访问命令列表的bug 2021-03-15 19:29:47 +08:00
ibuler
7dfd0ee8fe fix(orgs): 修复访问 current org api 错误
perf(users): 优化用户删除和移除行为

perf: 优化组织权限判断
2021-03-15 19:29:21 +08:00
xinwen
41f375a4f7 fix: 修正多个 DEFAULT 节点 2021-03-15 19:09:29 +08:00
Bai
a50dfe9c18 perf: 管理用户创建/更新username字段设置为required 2021-03-15 19:05:47 +08:00
Bai
bd8a1a7d0e fix: 修复MFA绑定失败的问题(通过修改session中auth_backend的key实现;django.auth.get_user时校验backends路径失败返回AnonymousUser) 2021-03-15 19:05:10 +08:00
Bai
5546719712 fix: 修改get_instance逻辑;二次构建org_mapping;订阅失效速度慢于读取速度; 2021-03-15 11:40:54 +08:00
xinwen
068b39d922 perf: 优化 jms 脚本 2021-03-15 10:19:29 +08:00
Jiangjie.Bai
2e1763cce7 Merge pull request #5739 from jumpserver/dev
v2.8 发版 (2)
2021-03-12 20:56:23 +08:00
xinwen
ff9e470ce2 fix: 命令执行 500 2021-03-12 19:17:06 +08:00
xinwen
3080bf3647 fix: 修复获取整个授权树缺少节点 bug 2021-03-12 19:12:18 +08:00
Jiangjie.Bai
0b04821794 Merge pull request #5736 from jumpserver/dev
v2.8 发版 (2)
2021-03-12 18:11:25 +08:00
Bai
296bb88834 fix: 修改celery健康检测worker数量 2021-03-12 18:09:47 +08:00
Bai
c57cce8881 perf: 修改system_user.priority默认值为81 2021-03-12 18:07:52 +08:00
Jiangjie.Bai
174cc16980 Merge pull request #5728 from jumpserver/dev
v2.8 发版
2021-03-11 21:17:39 +08:00
fit2bot
5b2649f775 fix: 修改用户序列类read_only字段 (#5729)
* fix: 修改用户序列类read_only字段

Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
Co-authored-by: Bai <bugatti_it@163.com>
2021-03-11 21:15:45 +08:00
xinwen
83829df70c fix: 干掉 dockerfile 行内注释 2021-03-11 20:31:38 +08:00
Jiangjie.Bai
64641a18e6 feat: ACL (#5696)
* feature: acl (v0.1)

* feature: acl (v0.2)

* feature: acl (v0.3)

* feature: acl (v0.4)

* feature: acl (v0.5)

* feature: acl (v0.6)

* feature: acl (v0.7)

* feature: acl (v0.8)

* feature: acl (v0.9)

* feature: acl (v1.0)

* feature: acl (v1.1)

* feature: acl (v1.2)

* feature: acl (v1.3)

* feature: acl (v1.4)

* feature: acl (v1.5)

* feature: acl (v1.6)

* feature: acl (v1.7)

* feature: acl (v1.8)

* feature: acl (v1.9)

* feature: acl (v2.0)

* feature: acl (v2.1)

* feature: acl (v2.2)

* feature: acl (v2.3)

* feature: acl (v2.4)

* feature: acl (v2.5)

* feature: acl (v2.6)

* feature: acl (v2.7)

* feature: acl (v2.8)

* feature: acl (v2.9)

* feature: acl (v3.0)

* feature: acl (v3.1)

* feature: acl (v3.2)

* feature: acl (v3.3)

* feature: acl (v3.4)

* feature: acl (v3.5)

* feature: acl (v3.6)

* feature: acl (v3.7)

* feature: acl (v3.8)

* feature: acl (v3.9)

* feature: acl (v4.0)

* feature: acl (v4.1)

* feature: acl (v4.2)

* feature: acl (v4.3)

* feature: acl (v4.4)
2021-03-11 20:17:44 +08:00
ibuler
09303ecc56 perf: 优化各serializer字段翻译 2021-03-11 20:15:27 +08:00
xinwen
5f48e7aeb2 perf: Dockerfile 安装软件包时添加 rm -rf /var/lib/apt/lists/* 清理 2021-03-11 20:13:41 +08:00
ibuler
25dfce621b perf: 优化,添加登录页面图片链接到 github 2021-03-11 18:45:50 +08:00
xinwen
102d3b590b perf: luna 页面获取资产系统用户按 name 排序 2021-03-11 15:07:06 +08:00
fit2bot
a45f581b0e fix: 将 user 添加到 default 组织时进度数量显示不准确 (#5720)
Co-authored-by: xinwen <coderWen@126.com>
2021-03-11 11:09:47 +08:00
ibuler
b3991d0388 fix: 修复Migrate的问题
fix: 修复 org migrations 依赖
2021-03-11 10:59:13 +08:00
xinwen
184e8b31e6 perf: 优化下 orgid_nodekey_assetsid_mapping 2021-03-10 18:15:49 +08:00
xinwen
615bcadf62 fix: 资产授权规则过滤添加 distinct 2021-03-10 17:51:31 +08:00
fit2bot
7b2f813e7f feat: 支持修改忘记密码重置密码的连接 (#5700)
perf: 优化代码暗示

Co-authored-by: ibuler <ibuler@qq.com>
2021-03-10 11:21:12 +08:00
ibuler
81170b4b7b perf: 优化登录页面,非常给力
perf: 优化报错

perf: 优化忘记密码

perf: 添加注释
2021-03-10 10:49:11 +08:00
xinwen
c4eacbabc6 refactor: 重构缓存框架 2021-03-10 10:33:45 +08:00
xinwen
ccb0509d85 feat: 批量导入解析为Json的接口添加 title 字段 2021-03-10 10:14:06 +08:00
xinwen
886393c539 feat: 添加批量导入时将其他格式(csv, excel)解析为Json的接口 2021-03-09 14:24:13 +08:00
xinwen
15b0ad9c12 refactor: 清理代码 orgs.mixins.api.OrgMembershipModelViewSetMixin 2021-03-09 12:44:28 +08:00
wojiushixiaobai
19e2a5b9f9 fix(terminal): 修正录像接口返回状态码 2021-03-08 10:14:01 +08:00
fit2bot
0aa2c2016f perf(project): 优化命名的风格 (#5693)
perf: 修改错误的地

perf: 优化写错的几个

Co-authored-by: ibuler <ibuler@qq.com>
2021-03-08 10:08:51 +08:00
xinwen
935947c97a fix: 用户详情页的资产授权列表慢 2021-03-08 07:56:58 +08:00
xinwen
3e7e01418d perf: 优化命令记录慢的问题 2021-03-08 07:56:28 +08:00
xinwen
7f42e59714 fix: 修复生成假数据脚本错误 2021-03-05 15:59:38 +08:00
xinwen
840e5e8863 fix: 修复 default 组织迁移脚本问题 2021-03-05 15:56:08 +08:00
xinwen
24fb8b2a89 feat: 管理用户详情页添加认证方式与秘钥指纹 2021-03-05 15:26:14 +08:00
Bai
c1bf854824 perf: 添加依赖包(pyvmomi==7.0.1)(termcolor==1.1.0) 2021-03-04 17:12:51 +08:00
xinwen
ab23a357f7 feat: 推送动态系统用户,系统上用户的 comment 字段是 userdisplayname 2021-03-04 11:28:24 +08:00
xinwen
78bf6f5817 refactor: 获取授权树或者资产列表时避免读时锁 2021-03-04 11:26:54 +08:00
ibuler
91a26abf9e perf: 优化default节点 2021-03-04 11:26:37 +08:00
ibuler
d7e7c62c7a perf: 优化表结构迁移 2021-03-04 10:42:57 +08:00
xinwen
09bdff4a67 fix: 缓存框架 expire_fields 可能报错 2021-03-04 10:40:29 +08:00
Bai
56328e112a perf: 移除资源创建时对于Auditor用户的限制 2021-03-03 15:57:13 +08:00
Bai
1d15f7125e perf: 优化org获取逻辑 - 采用redis订阅机制实现orgs_mapping数据的维护;删除get_org_by_id等方法;
perf: 优化get_instance接口
2021-03-03 13:19:37 +08:00
ibuler
e6b17da57d perf: 去掉pycrypto库
perf: 显示添加pycryptodome
2021-03-03 11:48:45 +08:00
xinwen
1870fc97d5 refactor: 适配新的 default 组织 2021-03-03 10:52:09 +08:00
fit2bot
f548b4bd2b feat: serializer 添加默认值,前端可以调用 (#5666)
perf: 优化默认值

Co-authored-by: ibuler <ibuler@qq.com>
2021-03-02 19:18:25 +08:00
fit2bot
a56ac7b34e perf(orgs): 默认组织改为实体组织,并支持全局组织 (#5617)
* perf(orgs): 默认组织改为实体组织

* perf: 添加获取当前组织信息的api

* perf: 资产列表在 root 组织下的表现

* fix: 修复 root 组织引起的问题

* perf: 优化OrgModelMixin save; org_root获取; org_roles获取; UserCanUseCurrentOrg权限类

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Bai <bugatti_it@163.com>
2021-03-02 14:57:48 +08:00
fit2bot
51c9a89b1f fix: 用户页面授权资产列表获取系统用户慢 (#5663)
Co-authored-by: xinwen <coderWen@126.com>
2021-03-02 14:48:47 +08:00
fit2bot
6f3ead3c42 perf: 优化系统用户生成密码的复杂度 (#5648)
* perf: 优化系统用户生成密码的复杂度

* perf: 修改 common.random_string

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Bai <bugatti_it@163.com>
2021-03-01 18:40:07 +08:00
xinwen
1036d1c132 fix: 修复授权树一些问题 2021-03-01 18:09:41 +08:00
ibuler
5de5fa2e96 fix: 修复获取不到 org 的问题 2021-03-01 14:35:44 +08:00
ibuler
19043d0a66 perf: 添加 xrdp type 2021-03-01 14:34:08 +08:00
ibuler
bc3e50a529 fix: 修复代码更改引起的bug 2021-03-01 14:32:30 +08:00
fit2bot
a7ab7da61c feat: 添加限制用户只能从source登录的功能 (#5592)
* stash it

* feat: 添加限制用户只能从source登录的功能

* fix: 修复小错误

Co-authored-by: ibuler <ibuler@qq.com>
2021-02-26 17:33:11 +08:00
fit2bot
b483f78d52 fix(assets): 系统用户支持 OPENSSH 格式的私钥 (#5604)
* fix(assets): 系统用户支持 OPENSSH 格式的私钥

* fix: 升级paramiko

Co-authored-by: ibuler <ibuler@qq.com>
2021-02-26 16:34:15 +08:00
ibuler
88d8a3326f perf(ops): 优化定期检查磁盘,添加开关控制 2021-02-26 16:33:39 +08:00
ibuler
8f7dcd512a perf(ops): ansible 增加 summary 汇总 2021-02-26 16:33:27 +08:00
xinwen
d795867916 perf: 优化批量更新会查询全部数据的问题 2021-02-26 16:32:46 +08:00
xinwen
4c4f544f0d fix: 修复禁用 MFA 后还可以用 MFA 查看密码匣子 2021-02-26 16:28:45 +08:00
xinwen
8ec26dea43 feat: 重置 MFA 发个邮件 #754 2021-02-26 16:25:55 +08:00
xinwen
799d1e4043 feat: 资产授权规则添加是否有效的过滤条件 2021-02-25 14:48:47 +08:00
ibuler
b03642847e perf: 去掉 data_tree 2021-02-24 16:22:26 +08:00
fit2bot
a4e635bff0 feat: 添加下载rdp文件的api (#5637)
* feat: 添加下载rdp文件的api

* perf: 优化一些权限

* perf: 优化一波token

Co-authored-by: ibuler <ibuler@qq.com>
2021-02-24 15:31:22 +08:00
xinwen
83cc339d4b refactor: 调整组织统计数据缓存的更新策略为懒更新模式 2021-02-23 17:48:14 +08:00
ibuler
bb9790a50f feat: 为rdp 添加一个api 2021-02-23 16:22:37 +08:00
xinwen
9be3cbb936 perf: 优化用户详情页授权列表加载速度&添加可重入锁 2021-02-20 10:25:35 +08:00
xinwen
e599bca951 fix: 命令存储 es 类型主机带用户名密码报错 2021-02-18 16:41:27 +08:00
fit2bot
501ad698b7 添加 UnionQuertSet (#5578)
* 添加 UnionQuertSet

* 跑通了

* 改变了 count 这类方法的代理模式

* 使用了老广的

Co-authored-by: xinwen <coderWen@126.com>
2021-02-07 10:15:39 +08:00
Bai
50e6c96358 fix: 修复 component status 获取key error 问题 2021-02-05 17:07:21 +08:00
Jiangjie.Bai
7cf6e54f01 refactor tree (重构&优化资产树/用户授权树加载速度) (#5548) (#5549)
* Bai reactor tree ( 重构获取完整资产树中节点下资产总数的逻辑) (#5548)

* tree: v0.1

* tree: v0.2

* tree: v0.3

* tree: v0.4

* tree: 添加并发锁未请求到时的debug日志

* 以空间换时间的方式优化资产树

* Reactor tree togther v2 (#5576)

* Bai reactor tree ( 重构获取完整资产树中节点下资产总数的逻辑) (#5548)

* tree: v0.1

* tree: v0.2

* tree: v0.3

* tree: v0.4

* tree: 添加并发锁未请求到时的debug日志

* 以空间换时间的方式优化资产树

* 修改授权适配新方案

* 添加树处理工具

* 完成新的用户授权树计算以及修改一些信号

* 重构了获取资产的一些 api

* 重构了一些节点的api

* 整理了一些代码

* 完成了api 的重构

* 重构检查节点数量功能

* 完成重构授权树工具类

* api 添加强制刷新参数

* 整理一些信号

* 处理一些信号的问题

* 完成了信号的处理

* 重构了资产树相关的锁机制

* RebuildUserTreeTask 还得添加回来

* 优化下不能在root组织的检查函数

* 优化资产树变化时锁的使用

* 修改一些算法的小工具

* 资产树锁不再校验是否在具体组织里

* 整理了一些信号的位置

* 修复资产与节点关系维护的bug

* 去掉一些调试代码

* 修复资产授权过期检查刷新授权树的 bug

* 添加了可重入锁

* 添加一些计时,优化一些sql

* 增加 union 查询的支持

* 尝试用 sql 解决节点资产数量问题

* 开始优化计算授权树节点资产数量不用冗余表

* 新代码能跑起来了,修复一下bug

* 去掉 UserGrantedMappingNode 换成 UserAssetGrantedTreeNodeRelation

* 修了些bug,做了些优化

* 优化QuerySetStage 执行逻辑

* 与小白的内存结合了

* 删掉老的表,迁移新的 assets_amount 字段

* 优化用户授权页面资产列表 count 慢

* 修复批量命令数量不对

* 修改获取非直接授权节点的 children 的逻辑

* 获取整棵树的节点

* 回退锁

* 整理迁移脚本

* 改变更新树策略

* perf: 修改一波缩进

* fix: 修改handler名称

* 修复授权树获取资产sql 泛滥

* 修复授权规则有效bug

* 修复一些bug

* 修复一些bug

* 又修了一些小bug

* 去掉了老的 get_nodes_all_assets

* 修改一些写法

* Reactor tree togther b2 (#5570)

* fix: 修改handler名称

* perf: 优化生成树

* perf: 去掉注释

* 优化了一些

* 重新生成迁移脚本

* 去掉周期检查节点资产数量的任务

* Pr@reactor tree togther guang@perf mapping (#5573)

* fix: 修改handler名称

* perf: mapping 拆分出来

* 修改名称

* perf: 修改锁名

* perf: 去掉检查节点任务

* perf: 修改一下名称

* perf: 优化一波

Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
Co-authored-by: Bai <bugatti_it@163.com>
Co-authored-by: xinwen <coderWen@126.com>

Co-authored-by: xinwen <coderWen@126.com>
Co-authored-by: 老广 <ibuler@qq.com>
2021-02-05 13:29:29 +08:00
Bai
709e7af953 perf: 修改依赖版本jumpserver-django-oidc-rp=0.3.7.6 2021-02-03 14:38:38 +08:00
ibuler
93474766f6 perf(permission): 优化权限控制,显式的声明权限 2021-02-03 14:28:47 +08:00
fit2bot
542eb25e7b fix(perms): 修复权限校验时的组织切换问题 (#5546)
* fix(perms): 修复权限校验时的组织切换问题

* fix(perms): 修复获取actions的切换组织问题

* perf: 继续添加 application 的验证组织

Co-authored-by: ibuler <ibuler@qq.com>
2021-02-03 12:01:18 +08:00
Bai
609d2710fa perf: 会话列表添加search_fields字段 2021-02-03 11:55:19 +08:00
ibuler
d852d2f670 perf: 还原回原来的用户来源字段 2021-02-02 16:54:51 +08:00
Bai
087a3f2914 fix: 注释fake数据生成模块的导入(system) 2021-02-02 02:11:30 -06:00
fit2bot
36f113e307 chore: 添加贡献者图片 (#5532)
* chore: 添加贡献者图片

* chore: 优化通知样式
Co-authored-by: ibuler <ibuler@qq.com>
2021-01-27 13:03:20 +08:00
ibuler
23afe81ff5 perf(authentication): 优化connection token的使用 2021-01-26 18:07:11 +08:00
ibuler
dd5b2b9101 perf: 去掉 v2 的api 2021-01-26 18:04:47 +08:00
fit2bot
d363118911 perf(settings): 优化settings配置 (#5515)
* stash

* perf: 优化 动态seting

* perf(settings): 优化settings配置

* perf: 完成终端和安全setting

* perf: 修改翻译

* perf: 去掉其他位置的DYNAMIC

* perf: 还原回来原来的一些代码

* perf: 优化ldap

* perf: 移除dynmic config

* perf: 去掉debug消息

* perf: 优化 refresh 命名

Co-authored-by: ibuler <ibuler@qq.com>
2021-01-26 17:54:12 +08:00
fit2bot
351d4d8123 refactor(celery): 重构celery,使用 threads 模型,避免 占用太多内存 (#5525)
* refactor(celery): 重构celery,使用 threads 模型,避免 占用太多内存

* fix: 修复无法关闭fd的bug

Co-authored-by: ibuler <ibuler@qq.com>
2021-01-25 05:34:41 -06:00
Bai
efb9f48c6f perf: 删除pycryptodome依赖包安装(因为pycryptodomepycrypto安装包目录冲突);只安装 pycryptodomex依赖包; 修改 from cryptofrom cryptodome 2021-01-25 11:59:20 +08:00
Bai
d04b90b8e8 feat: 修改copyright 2014-2021 2021-01-22 10:29:33 +08:00
Jiangjie.Bai
66f57fdb27 Merge pull request #5504 from jumpserver/dev
Dev
2021-01-21 15:56:09 +08:00
Bai
c949589564 perf: 修改翻译信息; 添加Domain迁移文件 2021-01-21 15:54:45 +08:00
ibuler
992708abe8 chore: 添加ping等工具 2021-01-21 15:43:17 +08:00
xinwen
f63f8d085d fix: Web页面-> 命令执行 高危命令没有告警 2021-01-21 15:39:24 +08:00
Jiangjie.Bai
3e55447327 Merge pull request #5497 from jumpserver/dev
Dev
2021-01-20 19:31:33 +08:00
xinwen
3ac20d80d1 fix: 登录日志的登录方式不准确 2021-01-20 19:21:29 +08:00
fit2bot
3e38e4fc59 i18n: 优化翻译 (#5492)
* i18n: 优化翻译

* i18n: 优化翻译(2)

* i18n: 优化翻译(3)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-20 19:08:39 +08:00
xinwen
1090887b2b fix: 管理用户-> 资产用户列表 更新密码报错 2021-01-20 00:58:20 -06:00
Bai
7c55d462cd fix: 修复工单翻译和登录确认工单开启问题 2021-01-20 13:57:05 +08:00
fit2bot
ea16088c08 fix: 修改翻译内容 (#5489)
* fix: 修改翻译内容

* fix: 修改翻译内容(2)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-20 11:38:09 +08:00
Bai
4de9e608b1 fix: 修改命令存储配置DOC_TYPE字段类型为ReadableHiddenField 2021-01-20 11:24:08 +08:00
xinwen
dd9a55bd5f fix: 用户名超过64字符,命令无法记录问题 2021-01-19 20:13:20 -06:00
Jiangjie.Bai
ee22006683 Merge pull request #5485 from jumpserver/dev
Dev
2021-01-19 20:10:24 +08:00
xinwen
09d91d8bf3 fix: 修复系统平台创建名称报错信息 2021-01-19 20:08:33 +08:00
Bai
46fbc19697 i18n: 修改翻译 2021-01-19 20:05:44 +08:00
Bai
44a42e4739 fix: 修改用户相关tickets为自己申请的或者待受理的 2021-01-19 19:43:17 +08:00
xinwen
4de2ae607d perf: 优化 日志审计-> 批量命令-> 用户显示格式 2021-01-19 05:06:43 -06:00
Bai
9fee82cd14 fix: 添加录像存储endpoint校验逻辑 2021-01-19 19:05:16 +08:00
fit2bot
9126c7780d perf: 工单优化(审批人可以填写工单对应的授权规则名称) (#5468)
* perf: 工单优化(审批人可以填写工单对应的授权规则名称)

* perf: 工单优化(优化推荐的资产、应用、系统用户等逻辑)

* perf: 工单优化(优化工单邮件内容)

* perf: MethodSerializer优化(优化当Serializer不需要时, 默认可以不传递对应字段)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-19 15:44:19 +08:00
fit2bot
0842553f8a fix: 修复 celery 等日志文件的访问漏洞 (#5469)
Co-authored-by: xinwen <coderWen@126.com>
2021-01-19 14:36:41 +08:00
xinwen
5fae919499 fix: 跳板机危险命令告警发送邮件失败 2021-01-18 06:57:57 -06:00
noon
1243546627 Update README_EN.md
style: change some sentences in the critical bug warning
2021-01-18 04:13:11 -06:00
Bai
a0cb16e5c4 perf: 修改关闭工单API权限, 申请人有权限关闭工单 2021-01-18 18:06:30 +08:00
ibuler
7b8f932dcd perf: 去掉几个不用的api 2021-01-18 17:18:05 +08:00
Bai
243eedc4f9 perf: 优化工单body html显示格式及翻译信息 2021-01-18 17:14:15 +08:00
xinwen
230ef2f662 fix: 修复用户离开组织信号被覆盖问题 2021-01-18 01:20:47 -06:00
xinwen
42019c9e8a fix: 修复 AssetUserFilterBackend 2021-01-18 01:19:01 -06:00
Bai
f6622f5e01 fix: 修改翻译 2021-01-18 15:06:36 +08:00
Bai
31f098449f perf: 修改 OPTION 获取 choices 字段选项; 修改display字段翻译 (显示名称) 2021-01-18 15:01:09 +08:00
ibuler
0d4e346210 chore: 修改readme 2021-01-18 00:26:51 -06:00
fit2bot
df193162f7 chore: 修改readme 英文版本 (#5448)
* chore: 修改readme 英文版本

Co-authored-by: ibuler <ibuler@qq.com>
2021-01-18 13:46:55 +08:00
ibuler
646f0a568b chore: 修改readme 2021-01-17 21:21:33 -06:00
Jiangjie.Bai
be5b4a5f71 Merge pull request #5440 from jumpserver/dev
Dev
2021-01-17 19:29:37 +08:00
xinwen
e61511372c fix: 修复缓存框架组织切换问题&组织的 resource_statistics 字段是只读 2021-01-17 19:28:00 +08:00
Jiangjie.Bai
d4f3280427 Merge pull request #5437 from jumpserver/dev
Dev
2021-01-17 17:58:30 +08:00
fit2bot
083f061665 perf: 更新翻译 (#5438)
* perf: 更新翻译

* perf: 更新翻译

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-17 16:22:06 +08:00
fit2bot
be7a93d81a feat: 在登录页面添加CAS/OpenID等第三方登录链接;不再自动跳转登录地址;统一开源/企业版登录页面; (#5389)
* feat: 在登录页面添加CAS/OpenID等第三方登录链接;不再自动跳转登录地址;统一开源/企业版登录页面;

* feat: 登录页面<忘记密码>链接,不限制第三方用户; 在忘记密码页面进行判断与限制

* feat: 登录页面<忘记密码>链接,不限制第三方用户; 在忘记密码页面进行判断与限制 (2)

* fix: 调整样式

Co-authored-by: Bai <bugatti_it@163.com>
Co-authored-by: Orange <orangemtony@gmail.com>
2021-01-17 15:28:22 +08:00
xinwen
156be0a64e fix: 网域列表添加默认 name 排序 2021-01-17 13:06:00 +08:00
fit2bot
a7fa2331bd feat: 添加缓存模块,添加组织资源统计 (#5407)
* feat: 添加缓存模块,添加组织资源统计

* refactor

* recover .gitkeep

* refactor

* 合并信号处理

* 修复组织添加用户没有发信号

* 修改了一个log级别

Co-authored-by: xinwen <coderWen@126.com>
2021-01-17 12:08:21 +08:00
老广
9e0d731a0c Update README.md (#5432)
* Update README.md

* Update README.md
2021-01-16 16:23:30 +08:00
Orange
1b184db956 Merge pull request #5427 from jumpserver/ibuler-patch-1
Update README.md
2021-01-15 18:06:09 +08:00
老广
4b9ed47cda Update README.md 2021-01-15 18:05:09 +08:00
ibuler
f04e2fa090 fix: bug 2021-01-14 10:27:49 +08:00
Bai
83d12d02fb perf: 重构工单处理流程 (7) 2021-01-13 18:48:38 +08:00
ibuler
64257823c5 pref(common): 优化drf options的filterset 可能引起的问题 2021-01-13 18:06:15 +08:00
fit2bot
a7468a243d perf: 重构工单处理流程 (#5408)
* perf: 重构工单处理流程

* perf: 重构工单处理流程 (1)

* perf: 重构工单处理流程 (2)

* perf: 重构工单处理流程 (3)

* perf: 重构工单处理流程 (4)

* perf: 重构工单处理流程 (5)

* perf: 重构工单处理流程 (6)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-13 17:49:03 +08:00
fit2bot
528e251f31 perf: 日志增加请求耗时 (#5406)
Co-authored-by: Eric <xplzv@126.com>
2021-01-12 18:15:59 +08:00
fit2bot
86a055638c reactor: 重构命令&录像存储模块的Serializer及相关模块 (#5392)
* reactor: 重构命令&录像存储模块的Serializer及相关模块


Co-authored-by: Bai <bugatti_it@163.com>
2021-01-12 18:06:42 +08:00
fit2bot
b3f359d47b perf(assets): 优化节点生成子节点key生成逻辑 (#5405)
* perf(assets): 优化节点生成子节点key生成逻辑

* perf(assets): 优化写法

* perf(assets): 优化获取子节点的mark

* perf(assets): 再优化一波

* perf(asset): 继续优化这里的写法

Co-authored-by: ibuler <ibuler@qq.com>
2021-01-12 12:59:05 +08:00
Bai
dbe969b064 perf: 解决MethodSerializer被swagger调用时parent.Serializer会互相影响所需字段显示的问题 2021-01-11 15:37:29 +08:00
Bai
b9258878fe fix: 修复celery日志清除问题 2021-01-11 10:30:10 +08:00
Bai
19c2973501 perf: 可以获取多种协议类型的系统用户列表 2021-01-07 19:09:31 +08:00
ibuler
e7a3c5a822 perf(api): filter_fields被filterset_fields取代
https://django-filter.readthedocs.io/en/stable/guide/migration.html
2021-01-07 18:36:17 +08:00
老广
ff4748f9f4 Merge pull request #5385 from jumpserver/pr@dev@feat_asset_task
feat: 添加批量执行资产任务的接口
2021-01-06 16:54:21 +08:00
xinwen
60c19148dc feat: 添加批量执行资产任务的接口 2021-01-06 16:51:25 +08:00
老广
7eedc0635e Merge pull request #5362 from jumpserver/pr@dev@fix_adhoc_excution
fix: 修复多个 AdHocExecution 在一个 celery task 执行时日志错误
2021-01-06 15:57:09 +08:00
xinwen
f5fd40978e fix: 修复多个 AdHocExecution 在一个 celery task 执行时日志错误 2021-01-06 15:53:38 +08:00
Bai
72dd23dcce perf: ticket 申请添加 comment 2021-01-06 15:19:43 +08:00
老广
5b5c33116a Merge pull request #5350 from hctech/dev
fix:资产自动推送UUIDD数组格式化字符串失败
2021-01-06 14:41:24 +08:00
fit2bot
7167515a53 feat: 实现MethodSerializer, 满足serializer中SerializerField动态更改的需求 (#5382)
* feat: 实现MethodSerializer, 满足serializer中SerializerField动态更改的需求

* feat: 实现MethodSerializer, 满足serializer中SerializerField动态更改的需求 (2)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-06 12:44:12 +08:00
fit2bot
17a01a12db reactor: 增加DynamicMappingSerializer类,实现Serializer中的字段可以动态改变的功能 (#5379)
* reactor: 增加DynamicMappingSerializer类,实现Serializer中的字段可以动态改变的功能

* reactor: 增加DynamicMappingSerializer类,实现Serializer中的字段可以动态改变的功能 (2)

* reactor: 增加DynamicMappingSerializer类,实现Serializer中的字段可以动态改变的功能 (3)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-05 23:39:38 +08:00
Bai
3188692691 perf: 修改swagger问题 2021-01-04 16:25:16 +08:00
Bai
aab59403e1 perf: 修改工单创建授权规则的字段(created_by) 2021-01-04 14:36:54 +08:00
fit2bot
7e7e24f51f reactor&remove: 重构applications模块 & 移除applications、perms中已不再使用的模块 (#5374)
* reactor: 重构applications模块 & 删除applications、perms中已不再使用的模块

 * reactor: 1. 针对application.attrs字段的view-serializer映射逻辑,采用DynamicMapping的方案重写;
 * reactor: 2. 删除applications和perms模块中已不再使用的database-app/k8s-app/remote-app模块;

* reactor: 添加迁移文件(删除perms/databaseperrmission/remoteapppermission/k8sapppermission)

* reactor: 修改细节

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-04 05:27:03 +08:00
fit2bot
428e8bf2a0 perf: 修改 View dynamic mapping include dynamic mapping fields Serializer Class 方案的说明 (#5373)
* perf: 修改 View dynamic mapping `include dynamic mapping fields Serializer Class` 方案的说明

* perf: 修改 View dynamic mapping `include dynamic mapping fields Serializer Class` 方案的说明 (2)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-03 14:17:02 +08:00
Bai
24b1c87121 perf: 修改细节 2021-01-02 08:00:05 +08:00
fit2bot
cef93abb2f feat: 抽象View Mapping Serializer架构设计; 重构工单View、Serializer模块 (#5371)
* perf: 优化工单模块(修改迁移文件->Model assignees_display 字段类型为list)

* ignore: try `view` `serializer jsonfields` Map design (1)

* ignore: try `view` `serializer jsonfields` Map design (2)

* ignore: try `view` `serializer jsonfields` Map design (3)

* ignore: try `view` `serializer jsonfields` Map design (4)

* ignore: try `view` `serializer jsonfields` Map design (5)

* ignore: try `view` `serializer.DynamicMappingField` Mapping design (6)

* feat: 抽象view_mapping_serializer逻辑架构; 重构工单View、Serializer模块

* feat: 抽象view_mapping_serializer逻辑架构; 重构工单View、Serializer模块(2)

* feat: 抽象view_mapping_serializer逻辑架构; 重构工单View、Serializer模块(3)

* feat: 抽象view_mapping_serializer逻辑架构; 重构工单View、Serializer模块(4)

Co-authored-by: Bai <bugatti_it@163.com>
2021-01-02 07:25:23 +08:00
Bai
5c483084b7 feat: 优化工单模块 2020-12-31 18:39:40 +08:00
fit2bot
167734ca5d feat: 优化工单模块 (#5365)
* feat: 优化工单模块

* feat: 优化工单模块2

Co-authored-by: Bai <bugatti_it@163.com>
2020-12-31 05:47:27 +08:00
Bai
1a9a5c28f5 feat: 优化工单模块1 2020-12-31 05:09:46 +08:00
fit2bot
430e20a49c feat: 优化工单模块 (#5361)
* feat: 优化工单模块1

* feat: 优化工单模块2

* feat: 优化工单模块3

Co-authored-by: Bai <bugatti_it@163.com>
2020-12-30 18:14:06 +08:00
Jiangjie.Bai
3b056ff953 reactor&feat: 重构工单模块 & 支持申请应用工单 (#5352)
* reactor: 修改工单Model,添加工单迁移文件

* reactor: 修改工单Model,添加工单迁移文件

* reactor: 重构工单模块

* reactor: 重构工单模块2

* reactor: 重构工单模块3

* reactor: 重构工单模块4

* reactor: 重构工单模块5

* reactor: 重构工单模块6

* reactor: 重构工单模块7

* reactor: 重构工单模块8

* reactor: 重构工单模块9

* reactor: 重构工单模块10

* reactor: 重构工单模块11

* reactor: 重构工单模块12

* reactor: 重构工单模块13

* reactor: 重构工单模块14

* reactor: 重构工单模块15

* reactor: 重构工单模块16

* reactor: 重构工单模块17

* reactor: 重构工单模块18

* reactor: 重构工单模块19

* reactor: 重构工单模块20

* reactor: 重构工单模块21

* reactor: 重构工单模块22

* reactor: 重构工单模块23

* reactor: 重构工单模块24

* reactor: 重构工单模块25

* reactor: 重构工单模块26

* reactor: 重构工单模块27

* reactor: 重构工单模块28

* reactor: 重构工单模块29

* reactor: 重构工单模块30

* reactor: 重构工单模块31

* reactor: 重构工单模块32

* reactor: 重构工单模块33

* reactor: 重构工单模块34

* reactor: 重构工单模块35

* reactor: 重构工单模块36

* reactor: 重构工单模块37

* reactor: 重构工单模块38

* reactor: 重构工单模块39
2020-12-30 00:19:59 +08:00
huangchao
795d1b59e0 fix:资产自动推送UUIDD数组格式化字符串失败 2020-12-27 23:00:45 +08:00
Bai
9d4f1a01fd perf: 升级依赖 python-ldap==3.3.1 2020-12-22 17:18:42 +08:00
xinwen
332f65cf2f fix: 将节点的资产添加到系统用户时固定组织 2020-12-22 15:14:01 +08:00
Bai
b79e6799c4 fix: 修复资产导入携带disk_info信息时失败的问题 2020-12-21 17:10:44 +08:00
Bai
4eef425e2a fix: 修复提交系统设置失败的问题 2020-12-21 14:30:12 +08:00
Jiangjie.Bai
3f4877f26b Merge pull request #5295 from jumpserver/dev
fix: 修复命令列表过滤字段文案`会话ID`
2020-12-17 18:26:54 +08:00
Bai
0e4d778335 fix: 修复命令列表过滤字段文案会话ID 2020-12-17 18:25:48 +08:00
Jiangjie.Bai
52d20080ff Merge pull request #5293 from jumpserver/dev
fix: 修改系统监控问题
2020-12-17 17:36:06 +08:00
Bai
ed8d72c06b fix: 修改系统监控问题 2020-12-17 17:34:37 +08:00
Jiangjie.Bai
5e9e3ec6f6 Merge pull request #5288 from jumpserver/dev
chore: Merge master from dev
2020-12-17 14:56:25 +08:00
xinwen
4f5f92deb8 fix: 批量删除管理用户报错信息太丑 2020-12-17 14:47:37 +08:00
xinwen
d2a15ee702 fix: 申请资产工单如果系统用户没填内容不推荐系统用户 2020-12-17 14:35:08 +08:00
Bai
a3a591da4b fix: 修复命令导出excel格式报错 2020-12-17 14:31:34 +08:00
Bai
3f2925116e fix: 修复metrics获取terminal过滤is_deleted字段 2020-12-17 11:30:29 +08:00
xinwen
c3e2e536e0 fix: 【用户管理】-创建用户组-可将系统审计员加入到用户组 #579 2020-12-17 10:33:45 +08:00
Jiangjie.Bai
8c133d5fdb Merge pull request #5278 from jumpserver/dev
chore: Merge master from dev
2020-12-16 18:50:49 +08:00
xinwen
89d8efe0f1 fix: perms.signals_handler.on_application_permission_applications_changed 修改名字 2020-12-16 18:49:20 +08:00
Bai
54303ea33f fix: 修复节点创建时更新孩子full_value日志输出问题 2020-12-16 18:37:54 +08:00
Bai
4dcd8dd8dd fix: 修复节点创建时更新孩子full_value日志输出问题 2020-12-16 18:37:54 +08:00
老广
4f04a7d258 Merge pull request #5280 from jumpserver/pr@dev@fix_auto_push
fix: 推送系统用户时 AdHocExecution id 重复
2020-12-16 17:36:45 +08:00
xinwen
bf308e24b6 fix: 推送系统用户时 AdHocExecution id 重复 2020-12-16 17:31:37 +08:00
Bai
b3642f3ff4 fix: 修复LDAP用户登录(未找到)时循环调用问题 2020-12-16 12:01:57 +08:00
xinwen
3aed4955c8 fix: 远程应用授权的一些问题 2020-12-16 12:00:53 +08:00
fit2bot
9a5f9a9c92 fix: 应用授权不会自动推送的bug (#5271)
Co-authored-by: xinwen <coderWen@126.com>
2020-12-16 10:23:37 +08:00
Orange
6d5bec1ef2 Merge pull request #5269 from jumpserver/dev
chore: Merge master from dev
2020-12-15 20:35:51 +08:00
Bai
e93fd1fd44 fix: 删除终端列表state的默认值0 2020-12-15 20:34:47 +08:00
xinwen
7bf37611bd fix: 系统审计员不应该能添加到组 2020-12-15 19:24:25 +08:00
xinwen
b8ec4bfaa5 fix: 日志审计-操作日志中搜索-按动作搜索:需修改文字 删除文件-->删除 #524 2020-12-15 18:38:23 +08:00
Bai
58b6293b76 fix: 组件监控添加offline数量 2020-12-15 18:37:16 +08:00
xinwen
8e12eebceb fix: 获得 oidc acs 等认证方式失败 2020-12-15 18:36:37 +08:00
Bai
72d6ea43fa fix: 修改命令列表过滤参数session 2020-12-15 18:34:05 +08:00
Bai
deedd49dc5 fix: 修复命令记录导出excel文件格式未定义的问题 2020-12-15 18:07:11 +08:00
fit2bot
a36e6fbf84 fix: 修改判断会话活跃逻辑;不必要判断协议 (#5262)
* fix: 修改判断会话活跃逻辑;不必要判断协议

* fix: 修改导入task问题

Co-authored-by: Bai <bugatti_it@163.com>
2020-12-15 18:06:35 +08:00
Bai
b57453cc3c fix: 修复命令列表过滤使用session_id字段 2020-12-15 18:05:42 +08:00
Jiangjie.Bai
62f2909d59 Merge pull request #5256 from jumpserver/dev
chore: Merge master from dev
2020-12-15 14:20:23 +08:00
xinwen
0d469ff95b fix(orgs): 用户离开组织后授权的资产没主动刷新 2020-12-15 14:00:51 +08:00
xinwen
ca883f1fb4 fix: 工单申请资产审批时系统用户没有推荐 2020-12-15 13:06:55 +08:00
fit2bot
6e0fbd78e7 fix: 修复prometheus_metricsAPI数据获取bug;修复组件注册type为空bug (#5253)
* fix: 修复prometheus_metricsAPI数据获取bug;修复组件注册type为空bug

* fix: 修改审计migrations/userloginlog/backend的verbose_name字段

Co-authored-by: Bai <bugatti_it@163.com>
2020-12-15 13:00:59 +08:00
ibuler
0813cff74f perf: 优化 docs swagger,不再要求debug 2020-12-14 11:39:02 +08:00
ibuler
ff428b84f9 fix(assets): 修复asset更新子节点时的日志错误 2020-12-14 11:33:34 +08:00
ibuler
d0c9aa2c55 fix(assets): 修复更新孩子节点时的log error 2020-12-14 11:33:34 +08:00
老广
1d5e603c0d Merge pull request #5231 from jumpserver/dev
chore(merge): 合并 dev 到 master
2020-12-11 19:29:45 +08:00
ibuler
ddbbc8df17 fix(docker): 修复Dockerfile中 echo引起的sh和bash换行兼容问题 2020-12-11 19:26:46 +08:00
Bai
90df404931 fix: 修复swagger问题 2020-12-11 19:02:33 +08:00
Bai
b9cbff1a5f del: 删除测试prometheus相关代码 2020-12-11 19:02:33 +08:00
ibuler
b9717eece3 fix: 修改访问swagger会产生的错误 2020-12-11 18:30:20 +08:00
Bai
f9cf2a243b fix: 修复settings中搜索LDAP用户重复问题 2020-12-11 18:26:10 +08:00
Bai
e056430fce fix: 修复只配置DC域时,LDAP用户认证失败的问题 2020-12-11 18:26:10 +08:00
Jiangjie.Bai
2b2821c0a1 Merge pull request #5223 from jumpserver/dev
chore(merge): 合并 dev 到 master
2020-12-11 16:53:36 +08:00
Bai
213221beae perf: 修改BasePermissionViewSet的custom_filter_fields 2020-12-11 16:19:18 +08:00
Bai
2db9c90a74 feat: 修改翻译:认证方式 2020-12-11 15:49:39 +08:00
Bai
8ced6f1168 fix: 用户ProfileAPI设置is_first_login不是可读写 2020-12-11 15:44:17 +08:00
Bai
6703ab9a77 perf: 添加BasePermissionsViewSet,支持搜索过滤 2020-12-11 15:44:17 +08:00
老广
2fc6e6cd54 Merge pull request #5213 from jumpserver/dev
chore(merge): 合并dev到master
2020-12-10 23:03:35 +08:00
Bai
2176fd8fac feat: 更新翻译 2020-12-10 21:30:56 +08:00
fit2bot
856e7c16e5 feat: 添加组件监控;TerminalModel添加type字段; (#5206)
* feat: 添加组件监控;TerminalModel添加type字段;

* feat: Terminal序列类添加type字段

* feat: Terminal序列类添加type字段为只读

* feat: 修改组件status文案

* feat: 取消上传组件状态序列类count字段

* reactor: 修改termina/models目录结构

* feat: 修改ComponentTypeChoices

* feat: 取消考虑CoreComponent类型

* feat: 修改Terminal status判断逻辑

* feat: 终端列表添加status过滤; 组件状态序列类添加default值

* feat: 添加PrometheusMetricsAPI

* feat: 修改PrometheusMetricsAPI

Co-authored-by: Bai <bugatti_it@163.com>
2020-12-10 20:50:22 +08:00
fit2bot
d4feaf1e08 fix: 修复由于更新django captch版本引起的css丢失问题 (#5204)
* fix: 修复由于更新django captch版本引起的css丢失问题

* perf: 优化验证码的高度

Co-authored-by: ibuler <ibuler@qq.com>
2020-12-10 20:48:10 +08:00
fit2bot
5aee2ce3db chore: 升级依赖库版本 (#5205)
* chore: 升级依赖库版本

* fix: 几个库回退几个版本

Co-authored-by: ibuler <ibuler@qq.com>
2020-12-10 20:46:45 +08:00
xinwen
4424c4bde2 perf(asset): 手动启动节点资产数量自检程序时区分组织 2020-12-10 18:17:01 +08:00
fit2bot
5863e3e008 perf(asset): 资产树,右击增加计算节点数量的菜单,可以让后台去计算 #527 (#5207)
Co-authored-by: xinwen <coderWen@126.com>
2020-12-10 17:12:39 +08:00
xinwen
79a371eb6c perf(auth): 密码过期后,走重置密码流程 #530 2020-12-10 16:06:26 +08:00
fit2bot
7c7de96158 feat(login): 登录日志要体现用哪个backend登录的 #4472 (#5199)
Co-authored-by: xinwen <coderWen@126.com>
2020-12-09 18:43:13 +08:00
ibuler
80b03e73f6 feat(celery): 添加celery的health check接口 2020-12-09 18:06:34 +08:00
fit2bot
32dbab2e34 perf: 数据库应用database字段添加allow_null=True (#5196)
* perf: 数据库应用database字段修改为required

* perf: 数据库应用database字段添加allow_null=True

Co-authored-by: Bai <bugatti_it@163.com>
2020-12-09 13:44:07 +08:00
ibuler
b189e363cc revert(system): 暂时去掉system组件 2020-12-09 11:24:44 +08:00
Bai
4c3a655239 perf: 用户序列类禁止修改source字段 2020-12-08 20:54:33 +08:00
Bai
5533114db5 feat: 用户授权应用树按组织节点进行区分 2020-12-08 20:37:07 +08:00
Jiangjie.Bai
4c469afa95 feat: 取消资产配置相关字段只读模式 (#5182)
* feat: 取消资产配置相关字段只读模式

* feat: 取消资产配置相关字段只读模式
2020-12-08 20:32:48 +08:00
fit2bot
2ccc5beeda perf(Dockerfile): 不再使用zh_CN.UTF-8, en_US.UTF-8 应该也是可以的 (#5190)
* perf(Dockerfile): 不再使用zh_CN.UTF-8, en_US.UTF-8 应该也是可以的

* fix: 还原回原来的LANG设置

* perf: 合并层数

* feat: 修改Dockerfile

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Bai <bugatti_it@163.com>
2020-12-08 20:22:48 +08:00
xinwen
4b67d6925e feat(asset): api 添加推送系统用户到多个资产 2020-12-08 18:08:44 +08:00
fit2bot
dd979f582a stash (#5178)
* Dev (#4791)

* fix(xpack): 修复last login太长的问题 (#4786)

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

* perf: 更新密码中也发送邮件 (#4789)

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

* fix(terminal): 修复获取螺旋的异步api

* fix(terminal): 修复有的录像存储有问题的导致下载录像的bug

* fix(orgs): 修复组织添加用户bug

* perf(requirements): 修改jms-storage==0.0.34 (#4797)

Co-authored-by: Bai <bugatti_it@163.com>

Co-authored-by: fit2bot <68588906+fit2bot@users.noreply.github.com>
Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Bai <bugatti_it@163.com>

* stash

* feat(system): 添加系统app

* stash

* fix: 修复一些bug

Co-authored-by: xinwen <coderWen@126.com>
Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Bai <bugatti_it@163.com>
Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
2020-12-08 14:26:18 +08:00
Bai
042ea5e137 feat: 授权应用树API返回org_name字段 2020-12-08 11:01:09 +08:00
ibuler
2a6f68c7ba revert: 还原原来的jms,自动运行migraionts 2020-12-07 19:16:27 +08:00
fit2bot
43b5e97b95 feat(excel): 添加Excel导入/导出 (#5124)
* refactor(drf_renderer): 添加 ExcelRenderer 支持导出excel文件格式; 优化CSVRenderer, 抽象 BaseRenderer

* perf(renderer): 支持导出资源详情

* refactor(drf_parser): 添加 ExcelParser 支持导入excel文件格式; 优化CSVParser, 抽象 BaseParser

* refactor(drf_parser): 添加 ExcelParser 支持导入excel文件格式; 优化CSVParser, 抽象 BaseParser 2

* perf(renderer): 捕获renderer处理异常

* perf: 添加excel依赖包

* perf(drf): 优化导入导出错误日志

* perf: 添加依赖包 pyexcel-io==0.6.4

* perf: 添加依赖包pyexcel-xlsx==0.6.0

* feat: 修改drf/renderer&parser变量命名

* feat: 修改drf/renderer的bug

* feat: 修改drf/renderer&parser变量命名

Co-authored-by: Bai <bugatti_it@163.com>
2020-12-07 15:23:05 +08:00
ibuler
619b521ea1 fix: 修改语言i18n 2020-12-05 13:22:22 +08:00
fit2bot
3447eeda68 fix(applications): 修改attrs不能为null (#5172)
Co-authored-by: Bai <bugatti_it@163.com>
2020-12-04 13:10:59 +08:00
fit2bot
75ef413ea5 fix(applications): 修改attrs不能为null (#5171)
Co-authored-by: Bai <bugatti_it@163.com>
2020-12-04 10:24:10 +08:00
fit2bot
662c9092dc reactor(dockerfile): 使用debian构建docker (#5169)
Co-authored-by: ibuler <ibuler@qq.com>
2020-12-03 19:14:28 +08:00
ibuler
c8d54b28e2 perf: 优化变量命名 2020-12-03 14:23:16 +08:00
ibuler
96cd307d1f perf: 优化entrypoint.sh 2020-12-03 14:23:16 +08:00
ibuler
6385cb3f86 perf: 优化启动,不再自动运行migrations 2020-12-03 14:23:16 +08:00
Bai
36e9d8101a fix: 添加迁移文件: Node ordering 2020-12-03 11:16:27 +08:00
ibuler
3354ab8ce9 fix(req): fix wheel version 2020-12-03 10:47:21 +08:00
Bai
89ec6ba6ef fix: Node ordering [parent_key, value]; 修复默认组织Default节点显示问题(存在key为0的Default节点) 2020-12-03 10:45:25 +08:00
Bai
af40e46a75 fix: 优化迁移Default节点 2020-12-03 10:29:00 +08:00
Bai
86fcd3c251 fix: 添加迁移文件(如果需要,将Default节点的key从0修改为1) 2020-12-03 10:29:00 +08:00
fit2bot
c2d5928273 build(pip): 锁定pip版本 (#5152)
* build(pip): 锁定pip版本

* fix: 锁定pip版本

* fix(req): 锁定加密库版本

* fix(build): 引用pip缓存

Co-authored-by: ibuler <ibuler@qq.com>
2020-12-02 11:09:39 +08:00
xinwen
e656ba70ec fix(assets): 推送动态系统用户未指定 username 取全部 usernames 2020-12-01 20:08:54 +08:00
xinwen
bb807e6251 fix(perms): 新建授权时动态用户可能推送不成功 2020-12-01 20:08:54 +08:00
Bai
bbd6cae3d7 perf(org): 优化获取org_name字段 2020-11-30 15:21:56 +08:00
Bai
c3b09dd800 perf(perms): 优化用户授权树返回org_name字段;添加thread_local属性org_mapper减少查询次数 2020-11-30 15:21:56 +08:00
Bai
6d427b9834 fix: 禁止删除组织根节点 2020-11-30 14:19:20 +08:00
xinwen
610aaf5244 fix(assets): 动态系统用户和用户关系变化时没有推送到资产 2020-11-26 15:20:09 +08:00
xinwen
df2f1b3e6e perf(User): 用户列表在大规模数据情况下慢 2020-11-26 12:32:18 +08:00
fit2bot
f26b7a470a perf(celery-task): 优化检查节点资产数量的 Celery 任务 (#5052)
Co-authored-by: xinwen <coderWen@126.com>
2020-11-25 17:30:07 +08:00
xinwen
a4667f3312 fix(Node): Node 保存的时候,在信号里设置 parent_key 2020-11-25 16:35:12 +08:00
xinwen
91081d9423 refactor(perms): 在动态用户所绑定的授权规则中,如授权给用户组,当用户组增加成员后,动态系统用户下没有相应增加用户,因此也不会自动推送 (#5084) (#5086) 2020-11-24 19:31:45 +08:00
fit2bot
3041697edc fix(orgs): 兼容旧的组织用户关系接口 (#5088)
Co-authored-by: xinwen <coderWen@126.com>
2020-11-24 19:09:14 +08:00
xinwen
75d7530ea5 fix(perms): 在动态用户所绑定的授权规则中,如授权给用户组,当用户组增加成员后,动态系统用户下没有相应增加用户,因此也不会自动推送 2020-11-24 10:27:03 +08:00
ibuler
975cc41bce perf(build): 优化使用pip mirror 2020-11-22 18:16:45 +08:00
ibuler
439999381d perf(build): 优化构建时用的mirror 2020-11-22 17:51:24 +08:00
xinwen
39ab5978be perf(perms): 获取用户所有授权时转换成 list 2020-11-22 17:24:00 +08:00
ibuler
7be7c8cee1 fix(perms): 修复我的资产页面问题 2020-11-22 16:55:21 +08:00
xinwen
68b22cbdec fix(perms): 修复用户组授权树与资产问题 2020-11-22 15:03:03 +08:00
xinwen
a7c704bea3 perf(celery-task): 优化检查节点资产数量的 Celery 任务 2020-11-22 11:36:10 +08:00
xinwen
21993b0d89 perf(perms): 优化用户授权资产列表加载速度 2020-11-22 11:35:13 +08:00
xinwen
73ccf3be5f fix(perms): 当用户授权为空时,清空旧的授权树 2020-11-22 11:26:39 +08:00
ibuler
bf3056abc4 fix(django3): 修复django3兼容问题 2020-11-20 15:25:37 +08:00
xinwen
f2fd9f5990 perf(assets): 限制搜索授权资产返回的条数 2020-11-20 15:24:33 +08:00
fit2bot
6d39a51c36 [fix]: 兼容django 3 (#5038)
* chore(django): 修改版本依赖

* [fix]: 兼容django 3

* fix(merge): 去掉不用的JSONField

* fix(requirements): 修改加密库的版本

Co-authored-by: ibuler <ibuler@qq.com>
2020-11-19 15:50:31 +08:00
xinwen
7fa94008c9 fix(old-api): 调整旧的组织与用户关联接口 2020-11-19 15:21:16 +08:00
Jiangjie.Bai
9685a25dc6 Merge pull request #5034 from jumpserver/dev
fix(perms): nodes-with-assets 接口添加刷新重构树
2020-11-18 11:53:12 +08:00
xinwen
1af4fcd381 fix(perms): nodes-with-assets 接口添加刷新重构树 2020-11-18 11:47:50 +08:00
Jiangjie.Bai
177055acdc Merge pull request #5032 from jumpserver/dev
fix(assets): 修复获取org_root的问题
2020-11-18 11:29:53 +08:00
ibuler
6ec0b3ad54 fix(assets): 修复获取org_root的问题 2020-11-18 11:23:39 +08:00
Orange
49dd611292 Merge pull request #5029 from jumpserver/dev
Dev
2020-11-17 19:46:36 +08:00
xinwen
f557c1dace fix(assets): model 添加 asset 默认排序 2020-11-17 19:40:49 +08:00
xinwen
6e87b94789 fix(command): 系统设置-安全设置-告警接收邮件字段如果为空,则更新不了 2020-11-17 19:19:08 +08:00
xinwen
b0dba35e5a fix(public-api): 缺少SECURITY_PASSWORD_EXPIRATION_TIME字段 2020-11-17 19:11:39 +08:00
ibuler
d0b19f20c3 perf(tickets): 优化授权申请工单 2020-11-17 19:10:23 +08:00
xinwen
3e78d627f8 fix(perms): 作业中心-批量命令-选择系统用户之后,左侧资产列表未筛选,还是全部资产 2020-11-17 18:45:45 +08:00
Jiangjie.Bai
0763404235 Merge pull request #5021 from jumpserver/dev
Dev
2020-11-17 16:48:07 +08:00
ibuler
31cd441a34 fix(assets): 修复资产导入时填写节点引起的空节点名称的问题 2020-11-17 16:41:17 +08:00
ibuler
40c0aac5a9 fix(ops): 修复run as 可能引起的返回多个asset user 2020-11-17 16:39:13 +08:00
ibuler
83099dcd16 fix(ops): 修复task run as的问题 2020-11-17 16:39:13 +08:00
ibuler
0db72bd00f fix(i18n): 修复js18n的问题 2020-11-17 16:29:09 +08:00
Bai
732b8cc0b8 fix(ops): 修复AdHocExecution字段task_display长度问题 2020-11-17 16:27:41 +08:00
Bai
a9f90b4e31 perf(terminal): 修改数据库字段长度(command_stroage/replay_storage name 128) 2020-11-17 15:59:42 +08:00
Bai
cf1fbabca1 fix(command): 修复批量命令执行可能获取到host为None的问题 2020-11-17 15:25:11 +08:00
ibuler
cbcefe8bd3 fix(ops): 修复因为更改controlmaster引起的连接不服用维内托 2020-11-16 15:22:25 +08:00
ibuler
133a2e4714 fix(assets): 修复动态系统用户推送的bug 2020-11-16 15:07:01 +08:00
fit2bot
b4b9149d5d chore(docs): 修改readme (#5005)
* chore(docs): 修改readme

* chore(docs): 修改文档拼写

Co-authored-by: ibuler <ibuler@qq.com>
2020-11-16 14:52:07 +08:00
fit2bot
9af4d5f76f fix(crypto): 有时解密失败 (#5003)
* fix(nodes): 节点默认按 value 排序

* fix(crypto): 有时解密失败

Co-authored-by: xinwen <coderWen@126.com>
2020-11-16 14:47:27 +08:00
Orange
96d26cc96f Merge pull request #4991 from jumpserver/dev
fix(system_user): 修复更新系统用户时ad_domain字段为空提交失败的问题
2020-11-13 14:57:23 +08:00
Bai
18d8f59bb5 fix(system_user): 修复更新系统用户时ad_domain字段为空提交失败的问题 2020-11-13 14:56:15 +08:00
老广
841f707b6d Merge pull request #4982 from jumpserver/dev
Dev
2020-11-12 14:12:35 +08:00
xinwen
448c5db3bb fix(orgs): 添加旧的 member 相关 api 2020-11-12 11:20:42 +08:00
Bai
75b886675e perf(i18n): 更新翻译 2020-11-12 11:14:23 +08:00
Bai
24e22115de perf(i18n): 更新翻译 2020-11-12 11:14:23 +08:00
Bai
b18ead0ffa perf(i18n): 更新翻译 2020-11-12 11:01:48 +08:00
xinwen
6e8922da1c fix(trans): 完善翻译 2020-11-12 10:12:25 +08:00
Bai
dcb38ef534 perf(session): 修改变量名terminate 2020-11-11 19:10:53 +08:00
Bai
8a693d9fa7 feat(session): session列表返回can_termination字段值;设置所有db协议类型会话不可被终断和监控 2020-11-11 17:49:54 +08:00
xinwen
487932590b fix(terminal): 扩展 Terminal name 长度 2020-11-11 15:01:30 +08:00
peijianbo
79b5aa68c8 feat(terminal):危险命令告警功能 2020-11-10 18:31:16 +08:00
Bai
50a4735b07 pref(cloud): 添加 Azure 依赖包 2020-11-10 11:13:00 +08:00
Bai
1183109354 perf(github): 更新github issue模版 2020-11-10 10:30:15 +08:00
xinwen
202e619c4b feat(assets): 添加系统用户资产列表 api 2020-11-10 10:23:51 +08:00
xinwen
179cb7531c feat(assets): 管理用户的资产列表增加 options 方法 2020-11-10 10:23:51 +08:00
ibuler
987f840431 fix(i18n): 修复重置密码那的i18n问题 2020-11-10 10:17:55 +08:00
fit2bot
f04544e8df feat(MFA): 修改文案Google Authenticator为手机验证器 (#4964)
* feat(MFA): 修改文案Google Authenticator为手机验证器

* feat(MFA): 修改文案手机验证器 为 MFA验证器

* feat(MFA): 修改文案手机验证器 为 MFA验证器2

Co-authored-by: Bai <bugatti_it@163.com>
2020-11-09 19:08:24 +08:00
fit2bot
cd6dc6a722 fix(perms): 由于组织不对,导致生成或显示授权树错误 (#4957)
* perf(perms): 优化授权树生成速度

* fix(perms): 由于组织不对,导致生成或显示授权树错误

Co-authored-by: xinwen <coderWen@126.com>
2020-11-09 17:30:50 +08:00
Bai
150552d734 perf(requirements): 升级依赖版本jms-storage==0.0.35 2020-11-09 17:29:10 +08:00
Bai
388314ca5a fix(applications): 修复应用列表会返回所有组织下数据的问题 2020-11-09 16:46:38 +08:00
Bai
26d00329e7 fix(assets): 修复计算node full value时,获取node value 有可能为 __proxy__ 的问题 2020-11-06 10:20:48 +08:00
xinwen
e93be8f828 feat(crypto): 支持国密算法 2020-11-05 19:04:50 +08:00
Bai
2690092faf perf(ldap): LDAP用户搜索,本地忽略大小写,远端支持模糊 2020-11-05 14:57:08 +08:00
Bai
eabaae81ac perf(application): 优化RemoteApp应用Chrome序列类的字符串主键关联字段 2020-11-05 14:13:45 +08:00
Bai
6df331cbed perf(perms): 用户/用户组授权的所有应用API返回attrs属性 2020-11-05 11:25:32 +08:00
xinwen
0390e37fd5 feat(orgs): relation 增加搜索功能 2020-11-05 10:40:00 +08:00
xinwen
44d9aff573 fix(orgs): 改正单词拼写 2020-11-05 09:58:58 +08:00
xinwen
2b4f8bd11c feat(ops): Task 支持批量操作 2020-11-05 09:54:51 +08:00
xinwen
231332585d fix(perms): 重建授权树冲突时,响应里加 code 2020-11-03 17:53:49 +08:00
ibuler
531de188d6 perf(systemuser): 优化系统用户家目录权限更改 2020-11-03 17:51:02 +08:00
ibuler
0c1f717fb2 feat(assets): 推送系统用户增加comment 2020-11-03 17:51:02 +08:00
xinwen
9d9177ed05 refactor(terminal): 去掉 Session 中 Terminal 的外键关系 2020-11-03 15:00:44 +08:00
xinwen
ab77d5db4b fix(orgs): org-member-relation url 拼写错误 2020-11-03 14:49:50 +08:00
ibuler
eadecb83ed fix: 修改系统用户节点关系的抖索 2020-11-03 14:33:15 +08:00
ibuler
5d6088abd3 fix(assets): 修复nodes display pop 引起的bug 2020-11-03 11:22:36 +08:00
xinwen
38f7c123e5 fix(audits): sso 登录日志没有 type 2020-11-03 11:18:56 +08:00
xinwen
d7daf7071a fix(ticket): 工单申请资产的时候审批人不能搜索 2020-11-03 10:53:31 +08:00
Bai
795245d7f4 perf(perms): 授权给用户应用列表API添加dispaly字段 2020-11-02 10:26:39 +08:00
Bai
7ea2a0d6a5 perf(perms): 应用授权规则序列类添加applications类型校验 2020-10-30 17:25:34 +08:00
xinwen
c90b9d70dc perf(perms): 优化根据资产获取授权的系统用户 2020-10-30 15:59:19 +08:00
Bai
f6c24f809c perf(application): 修改DoaminAPI返回application数量;修改Application数据库datbase字段required=False 2020-10-30 15:58:46 +08:00
Bai
e369a8d51f perf(readme): 修改Readme 2020-10-30 15:44:42 +08:00
Bai
c74c9f51f0 perf(readme): 修改Readme 2020-10-30 15:44:05 +08:00
ibuler
57bf9ca8b1 perf(assets): 优化更新子节点名称的算法 2020-10-30 14:17:09 +08:00
Bai
ddc2d1106b perf(perms): 修改授权授权应用API,添加category/type过滤字段 2020-10-30 12:54:33 +08:00
ibuler
15992c636a perf: 优化node full value 2020-10-30 10:50:45 +08:00
Bai
36cd18ab9a perf(perms): 修改变量名 2020-10-30 10:47:32 +08:00
Bai
676ee93837 perf(perms): 优化方法名称;授权查询语句; 2020-10-30 10:47:32 +08:00
fit2bot
c02f8e499b feat: 添加资产导入时可以直接写节点 (#4868)
* feat: 优化资产导入, 可以添加节点全称,并自动创建

* feat: 添加资产导入时可以直接写节点

* fix: 修改错误

* fix: 添加node value校验,不能包含/

* chore: merge migrations

* perf: 去掉full value replace

Co-authored-by: ibuler <ibuler@qq.com>
2020-10-30 10:16:49 +08:00
ibuler
4ebb4d1b6d chore: resolve conflict 2020-10-29 19:19:20 +08:00
Bai
5e7650d719 perf(application): RemoteApp应用序列类返回asset_info字段 2020-10-29 05:48:01 -05:00
Bai
bf302f47e5 perf(application): 修改RemoteA序列类asset required=False 2020-10-29 05:48:01 -05:00
Bai
1ddc228449 perf(application): RemoteApp序列类字段asset,设置为CharPrimaryKeyRelatedField,修改其他字段的required=Flase 2020-10-29 05:48:01 -05:00
Bai
c9065fd96e perf(application): 优化一些小细节 2020-10-29 05:48:01 -05:00
Bai
4a09dc6e3e feat(assets): 修改GatewayModel ip字段类型为CharField 2020-10-29 05:48:01 -05:00
Bai
55bfb942e2 perf(applications): 修改应用序列类字段label 2020-10-29 05:48:01 -05:00
Bai
9aed51ffe9 perf(applications): 修改应用序列类字段长度限制 2020-10-29 05:48:01 -05:00
Bai
a98816462f perf(applications): 添加DB序列类字段翻译 2020-10-29 05:48:01 -05:00
Bai
abe32e6c79 perf(perms): 添加应用/应用授权API的type_display/category_display字段 2020-10-29 05:48:01 -05:00
Bai
77c8ca5863 perf(perms): 应用授权表添加字段,type和category 2020-10-29 05:48:01 -05:00
Bai
8fa15b3378 perf(assets/terminal): 资产系统用户和Session会话添加协议选项: mysql/oracle/postgresql 2020-10-29 05:48:01 -05:00
Bai
a3507975fb perf(application): 修改获取远程应用连接参数的API(2) 2020-10-29 05:48:01 -05:00
Bai
76ca6d587d perf(application): 修改获取远程应用连接参数的API 2020-10-29 05:48:01 -05:00
Bai
038582a8c1 feat(applications): 修改应用/应用授权的迁移文件,解决多种应用/应用授权name字段重复的问题 2020-10-29 05:48:01 -05:00
Bai
ca2fc3cb5e feat(applications): 修改ApplicationAPI方法获取序列类的逻辑 2020-10-29 05:48:01 -05:00
Bai
cc30b766f8 feat(applications): 修改ApplicationAPI方法method判断->action 2020-10-29 05:48:01 -05:00
Michael Bai
b7bd88b8a0 feat(applications): 修改ApplicationAPI方法options 2020-10-29 05:48:01 -05:00
Bai
5518e1e00f perf(application): 优化Application获取序列类attrs字段适配 2020-10-29 05:48:01 -05:00
Bai
0632e88f5d feat(application): 修改Application Model的domain字段选项2 2020-10-29 05:48:01 -05:00
Bai
9dc2255894 feat(application): 修改Application Model的domain字段选项 2020-10-29 05:48:01 -05:00
Bai
1baf35004d refactor(perms): 添加应用授权规则迁移文件;迁移旧的应用授权(db/remoteapp/k8sapp)到新的应用授权 2020-10-29 05:48:01 -05:00
Bai
5acff310f7 perf(application): 修改迁移文件,迁移应用包含id字段 2020-10-29 05:48:01 -05:00
Bai
fdded8b90f refactor(perms): 修改授权规则的目录结构(asset、application) 2020-10-29 05:48:01 -05:00
Bai
1d550cbe64 feat(perms): 添加ApplicationPermission API(包含用户/用户组/授权/校验等API) 2020-10-29 05:48:01 -05:00
Bai
4847b7a680 feat(perms): 添加ApplicationPermission Model 和 API(包含ViewSet和RelationViewSet) 2020-10-29 05:48:01 -05:00
Bai
1c551b4fe8 feat(application): 迁移old_application到new_application 2020-10-29 05:48:01 -05:00
Bai
6ffba739f2 perf(requirements): 添加依赖django-mysql==3.9.0 2020-10-29 05:48:01 -05:00
ibuler
0282346945 perf: 修改创建 2020-10-29 05:48:01 -05:00
ibuler
f6d9af8beb perf(application): 优化type优先级 2020-10-29 05:48:01 -05:00
ibuler
ba4e6e9a9f refacter: 重构application 2020-10-29 05:48:01 -05:00
ibuler
874a3eeebf perf(sessions): 优化命令 2020-10-29 18:27:36 +08:00
ibuler
dd793a4eca perf: 优化日志保存策略 2020-10-29 18:27:36 +08:00
xinwen
f7e6c14bc5 fix(assets): 向资产推送系统用户bug 2020-10-28 21:40:40 -05:00
xinwen
f6031d6f5d fix(logger): 把 drf 异常放到单独的日志文件中 2020-10-28 21:26:35 -05:00
xinwen
5e779e6542 fix(systemuser): 系统用户添加 ad_domain 字段 2020-10-28 21:23:29 -05:00
xinwen
7031b7f28b fix(auth): 修复用户登录失败次数出现0次 2020-10-28 06:06:57 -05:00
xinwen
e2f540a1f4 fix(assets): 网关的密码不能包含特殊字符 2020-10-28 06:05:53 -05:00
ibuler
108a1da212 chore: 修改github 语言识别 2020-10-26 20:51:09 -05:00
xinwen
b4a8cb768b fix(assets): 系统用户与用户组发生变化时报错 2020-10-26 05:31:30 -05:00
xinwen
6b2f606430 fix(tickets): 工单申请资产授权通过人显示不对 2020-10-26 02:03:12 -05:00
xinwen
70a8db895d fix(migrations): 生成一下遗漏的 migrations 2020-10-23 17:00:37 +08:00
xinwen
0043dc6110 fix(assets): 资产列表添加默认 date_created 排序 2020-10-23 17:00:37 +08:00
xinwen
87d2798612 fix(assets): 资产列表不能用到assets_amount字段 2020-10-23 16:54:19 +08:00
ibuler
e2d8eee629 fix(i18n): 修改收藏夹的翻译 2020-10-23 16:52:06 +08:00
xinwen
8404db8cef fix(assets): 修改 AssetViewSet.filter_fields 2020-10-23 02:25:04 -05:00
Bai
fd7f379b10 perf(requirements): 升级依赖django-timezone-field==4.0 2020-10-21 13:01:28 +08:00
ibuler
111c63ee6a perf: 修改beat版本 2020-10-20 15:02:11 +08:00
ibuler
4eb5d51840 fix: domain端口可能随便填写的问题 2020-10-20 15:01:06 +08:00
ibuler
7f53a80855 fix: 修改textfield 不再限制长度 2020-10-20 15:00:22 +08:00
ibuler
90afabdcb2 fix(perms): 修复用户的资产不区分组织的问题 2020-10-20 14:56:23 +08:00
ibuler
de405be753 fix(perms): 修复asset permission导入的bug 2020-10-20 14:46:31 +08:00
Bai
f84b845385 perf(config): 升级依赖redis==3.5.3; 添加CACHES配置: health_check_interval=30; 解决因网络不稳定导致的redis连接失败异常 2020-10-19 04:45:34 -05:00
xinwen
b1ac3fa94f fix(orgs): 更新用户时org_roles参数为None时不更新组织角色 2020-10-15 04:59:25 -05:00
821 changed files with 33695 additions and 20047 deletions

View File

@@ -6,4 +6,5 @@ tmp/*
django.db
celerybeat.pid
### Vagrant ###
.vagrant/
.vagrant/
apps/xpack/.git

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
*.mmdb filter=lfs diff=lfs merge=lfs -text
*.mo filter=lfs diff=lfs merge=lfs -text

View File

@@ -2,8 +2,9 @@
name: 需求建议
about: 提出针对本项目的想法和建议
title: "[Feature] "
labels: 待处理, 需求
assignees: 'ibuler'
labels: 类型:需求
assignees: ibuler
---
**请描述您的需求或者改进建议.**

View File

@@ -2,7 +2,7 @@
name: Bug 提交
about: 提交产品缺陷帮助我们更好的改进
title: "[Bug] "
labels: bug, 待处理
labels: 类型:bug
assignees: wojiushixiaobai
---

View File

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

2
.gitignore vendored
View File

@@ -15,6 +15,7 @@ dump.rdb
.tox
.cache/
.idea/
.vscode/
db.sqlite3
config.py
config.yml
@@ -38,3 +39,4 @@ logs/*
.vagrant/
release/*
releashe
/apps/script.py

View File

@@ -1,5 +1,6 @@
FROM registry.fit2cloud.com/public/python:v3 as stage-build
MAINTAINER Jumpserver Team <ibuler@qq.com>
# 编译代码
FROM python:3.8.6-slim as stage-build
MAINTAINER JumpServer Team <ibuler@qq.com>
ARG VERSION
ENV VERSION=$VERSION
@@ -7,34 +8,50 @@ WORKDIR /opt/jumpserver
ADD . .
RUN cd utils && bash -ixeu build.sh
FROM registry.fit2cloud.com/public/python:v3
# 构建运行时环境
FROM python:3.8.6-slim
ARG PIP_MIRROR=https://pypi.douban.com/simple
ENV PIP_MIRROR=$PIP_MIRROR
ARG MYSQL_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql57-community-el6/
ENV MYSQL_MIRROR=$MYSQL_MIRROR
ARG PIP_JMS_MIRROR=https://pypi.douban.com/simple
ENV PIP_JMS_MIRROR=$PIP_JMS_MIRROR
WORKDIR /opt/jumpserver
COPY ./requirements ./requirements
RUN useradd jumpserver
RUN yum -y install epel-release && \
echo -e "[mysql]\nname=mysql\nbaseurl=${MYSQL_MIRROR}\ngpgcheck=0\nenabled=1" > /etc/yum.repos.d/mysql.repo
RUN yum -y install $(cat requirements/rpm_requirements.txt)
RUN pip install --upgrade pip setuptools==49.6.0 wheel -i ${PIP_MIRROR} && \
pip config set global.index-url ${PIP_MIRROR}
RUN pip install $(grep 'jms' requirements/requirements.txt) -i https://pypi.org/simple
RUN pip install -r requirements/requirements.txt
COPY ./requirements/deb_requirements.txt ./requirements/deb_requirements.txt
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
&& sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
&& apt update \
&& apt -y install telnet iproute2 redis-tools default-mysql-client vim wget curl locales procps \
&& apt -y install $(cat requirements/deb_requirements.txt) \
&& rm -rf /var/lib/apt/lists/* \
&& localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8 \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& sed -i "s@# alias l@alias l@g" ~/.bashrc \
&& echo "set mouse-=a" > ~/.vimrc
COPY ./requirements/requirements.txt ./requirements/requirements.txt
RUN pip install --upgrade pip==20.2.4 setuptools==49.6.0 wheel==0.34.2 -i ${PIP_MIRROR} \
&& pip install --no-cache-dir $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install --no-cache-dir -r requirements/requirements.txt -i ${PIP_MIRROR} \
&& rm -rf ~/.cache/pip
COPY --from=stage-build /opt/jumpserver/release/jumpserver /opt/jumpserver
RUN mkdir -p /root/.ssh/ && echo -e "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null" > /root/.ssh/config
RUN mkdir -p /root/.ssh/ \
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null" > /root/.ssh/config
RUN mkdir -p /opt/jumpserver/oracle/ \
&& wget https://download.jumpserver.org/public/instantclient-basiclite-linux.x64-21.1.0.0.0.tar > /dev/null \
&& tar xf instantclient-basiclite-linux.x64-21.1.0.0.0.tar -C /opt/jumpserver/oracle/ \
&& echo "/opt/jumpserver/oracle/instantclient_21_1" > /etc/ld.so.conf.d/oracle-instantclient.conf \
&& ldconfig \
&& rm -f instantclient-basiclite-linux.x64-21.1.0.0.0.tar
RUN echo > config.yml
VOLUME /opt/jumpserver/data
VOLUME /opt/jumpserver/logs
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
EXPOSE 8070
EXPOSE 8080

268
README.md
View File

@@ -1,222 +1,107 @@
# JumpServer 多云环境下更好用的堡垒机
<p align="center"><a href="https://jumpserver.org"><img src="https://download.jumpserver.org/images/jumpserver-logo.svg" alt="JumpServer" width="300" /></a></p>
<h3 align="center">多云环境下更好用的堡垒机</h3>
<p align="center">
<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0"><img src="https://shields.io/github/license/jumpserver/jumpserver" alt="License: GPL v2"></a>
<a href="https://shields.io/github/downloads/jumpserver/jumpserver/total"><img src="https://shields.io/github/downloads/jumpserver/jumpserver/total" alt=" release"></a>
<a href="https://hub.docker.com/u/jumpserver"><img src="https://img.shields.io/docker/pulls/jumpserver/jms_all.svg" alt="Codacy"></a>
<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>
--------------------------
- [ENGLISH](https://github.com/jumpserver/jumpserver/blob/master/README_EN.md)
[![Python3](https://img.shields.io/badge/python-3.6-green.svg?style=plastic)](https://www.python.org/)
[![Django](https://img.shields.io/badge/django-2.2-brightgreen.svg?style=plastic)](https://www.djangoproject.com/)
[![Docker Pulls](https://img.shields.io/docker/pulls/jumpserver/jms_all.svg)](https://hub.docker.com/u/jumpserver)
|Developer Wanted|
|------------------|
|JumpServer 正在寻找开发者,一起为改变世界做些贡献吧,哪怕一点点,联系我 <ibuler@fit2cloud.com> |
JumpServer 是全球首款开源的堡垒机,使用 GNU GPL v2.0 开源协议,是符合 4A 规范的运维安全审计系统。
JumpServer 使用 Python / Django 为主进行开发,遵循 Web 2.0 规范,配备了业界领先的 Web Terminal 方案,交互界面美观、用户体验好。
JumpServer 使用 Python 开发,遵循 Web 2.0 规范,配备了业界领先的 Web Terminal 方案,交互界面美观、用户体验好。
JumpServer 采纳分布式架构,支持多机房跨区域部署,支持横向扩展,无资产数量及并发限制。
改变世界,从一点点开始
改变世界,从一点点开始 ...
> 注: [KubeOperator](https://github.com/KubeOperator/KubeOperator) 是 JumpServer 团队在 Kubernetes 领域的的又一全新力作,欢迎关注和使用。
> 如需进一步了解 JumpServer 开源项目,推荐阅读 [JumpServer 的初心和使命](https://mp.weixin.qq.com/s/S6q_2rP_9MwaVwyqLQnXzA)
## 特色优势
### 特色优势
- 开源: 零门槛,线上快速获取和安装;
- 分布式: 轻松支持大规模并发访问;
- 无插件: 仅需浏览器,极致的 Web Terminal 使用体验;
- 多云支持: 一套系统,同时管理不同云上面的资产;
- 云端存储: 审计录像云端存储,永不丢失;
- 多租户: 一套系统,多个子公司和部门同时使用
- 多租户: 一套系统,多个子公司和部门同时使用
- 多应用支持: 数据库Windows远程应用Kubernetes。
## 版本说明
### UI 展示
自 v2.0.0 发布后, JumpServer 版本号命名将变更为v大版本.功能版本.Bug修复版本。比如
![UI展示](https://www.jumpserver.org/images/screenshot/1.png)
```
v2.0.1 是 v2.0.0 之后的Bug修复版本
v2.1.0 是 v2.0.0 之后的功能版本。
```
### 在线体验
像其它优秀开源项目一样JumpServer 每个月会发布一个功能版本,并同时维护 3 个功能版本。比如:
- 环境地址:<https://demo.jumpserver.org/>
```
在 v2.4 发布前,我们会同时维护 v2.1、v2.2、v2.3
在 v2.4 发布后,我们会同时维护 v2.2、v2.3、v2.4v2.1 会停止维护。
```
| :warning: 注意 |
| :--------------------------- |
| 该环境仅作体验目的使用,我们会定时清理、重置数据! |
| 请勿修改体验环境用户的密码! |
| 请勿在环境中添加业务生产环境地址、用户名密码等敏感信息! |
## 功能列表
<table>
<tr>
<td rowspan="8">身份认证<br>Authentication</td>
<td rowspan="5">登录认证</td>
<td>资源统一登录与认证</td>
</tr>
<tr>
<td>LDAP/AD 认证</td>
</tr>
<tr>
<td>RADIUS 认证</td>
</tr>
<tr>
<td>OpenID 认证(实现单点登录)</td>
</tr>
<tr>
<td>CAS 认证 (实现单点登录)</td>
</tr>
<tr>
<td rowspan="2">MFA认证</td>
<td>MFA 二次认证Google Authenticator</td>
</tr>
<tr>
<td>RADIUS 二次认证</td>
</tr>
<tr>
<td>登录复核X-PACK</td>
<td>用户登录行为受管理员的监管与控制</td>
</tr>
<tr>
<td rowspan="11">账号管理<br>Account</td>
<td rowspan="2">集中账号</td>
<td>管理用户管理</td>
</tr>
<tr>
<td>系统用户管理</td>
</tr>
<tr>
<td rowspan="4">统一密码</td>
<td>资产密码托管</td>
</tr>
<tr>
<td>自动生成密码</td>
</tr>
<tr>
<td>自动推送密码</td>
</tr>
<tr>
<td>密码过期设置</td>
</tr>
<tr>
<td rowspan="2">批量改密X-PACK</td>
<td>定期批量改密</td>
</tr>
<tr>
<td>多种密码策略</td>
</tr>
<tr>
<td>多云纳管X-PACK</td>
<td>对私有云、公有云资产自动统一纳管</td>
</tr>
<tr>
<td>收集用户X-PACK</td>
<td>自定义任务定期收集主机用户</td>
</tr>
<tr>
<td>密码匣子X-PACK</td>
<td>统一对资产主机的用户密码进行查看、更新、测试操作</td>
</tr>
<tr>
<td rowspan="15">授权控制<br>Authorization</td>
<td>多维授权</td>
<td>对用户、用户组、资产、资产节点、应用以及系统用户进行授权</td>
</tr>
<tr>
<td rowspan="4">资产授权</td>
<td>资产以树状结构进行展示</td>
</tr>
<tr>
<td>资产和节点均可灵活授权</td>
</tr>
<tr>
<td>节点内资产自动继承授权</td>
</tr>
<tr>
<td>子节点自动继承父节点授权</td>
</tr>
<tr>
<td rowspan="2">应用授权</td>
<td>实现更细粒度的应用级授权</td>
</tr>
<tr>
<td>MySQL 数据库应用、RemoteApp 远程应用X-PACK</td>
</tr>
<tr>
<td>动作授权</td>
<td>实现对授权资产的文件上传、下载以及连接动作的控制</td>
</tr>
<tr>
<td>时间授权</td>
<td>实现对授权资源使用时间段的限制</td>
</tr>
<tr>
<td>特权指令</td>
<td>实现对特权指令的使用(支持黑白名单)</td>
</tr>
<tr>
<td>命令过滤</td>
<td>实现对授权系统用户所执行的命令进行控制</td>
</tr>
<tr>
<td>文件传输</td>
<td>SFTP 文件上传/下载</td>
</tr>
<tr>
<td>文件管理</td>
<td>实现 Web SFTP 文件管理</td>
</tr>
<tr>
<td>工单管理X-PACK</td>
<td>支持对用户登录请求行为进行控制</td>
</tr>
<tr>
<td>组织管理X-PACK</td>
<td>实现多租户管理与权限隔离</td>
</tr>
<tr>
<td rowspan="7">安全审计<br>Audit</td>
<td>操作审计</td>
<td>用户操作行为审计</td>
</tr>
<tr>
<td rowspan="2">会话审计</td>
<td>在线会话内容审计</td>
</tr>
<tr>
<td>历史会话内容审计</td>
</tr>
<tr>
<td rowspan="2">录像审计</td>
<td>支持对 Linux、Windows 等资产操作的录像进行回放审计</td>
</tr>
<tr>
<td>支持对 RemoteAppX-PACK、MySQL 等应用操作的录像进行回放审计</td>
</tr>
<tr>
<td>指令审计</td>
<td>支持对资产和应用等操作的命令进行审计</td>
</tr>
<tr>
<td>文件传输</td>
<td>可对文件的上传、下载记录进行审计</td>
</tr>
</table>
## 快速开始
### 快速开始
- [极速安装](https://docs.jumpserver.org/zh/master/install/setup_by_fast/)
- [完整文档](https://docs.jumpserver.org)
- [演示视频](https://jumpserver.oss-cn-hangzhou.aliyuncs.com/jms-media/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91Jumpserver%20%E5%A0%A1%E5%9E%92%E6%9C%BA%20V1.5.0%20%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%20-%20final.mp4)
- [演示视频](https://www.bilibili.com/video/BV1ZV41127GB)
- [手动安装](https://github.com/jumpserver/installer)
## 组件项目
### 组件项目
- [Lina](https://github.com/jumpserver/lina) JumpServer Web UI 项目
- [Luna](https://github.com/jumpserver/luna) JumpServer Web Terminal 项目
- [Koko](https://github.com/jumpserver/koko) JumpServer 字符协议 Connector 项目,替代原来 Python 版本的 [Coco](https://github.com/jumpserver/coco)
- [Guacamole](https://github.com/jumpserver/docker-guacamole) JumpServer 图形协议 Connector 项目,依赖 [Apache Guacamole](https://guacamole.apache.org/)
- [KoKo](https://github.com/jumpserver/koko) JumpServer 字符协议 Connector 项目,替代原来 Python 版本的 [Coco](https://github.com/jumpserver/coco)
- [Lion](https://github.com/jumpserver/lion-release) JumpServer 图形协议 Connector 项目,依赖 [Apache Guacamole](https://guacamole.apache.org/)
- [Clients](https://github.com/jumpserver/clients) JumpServer 客户端 项目
- [Installer](https://github.com/jumpserver/installer) JumpServer 安装包 项目
## JumpServer 企业版
### 社区
如果您在使用过程中有任何疑问或对建议,欢迎提交 [GitHub Issue](https://github.com/jumpserver/jumpserver/issues/new/choose) 或加入到我们的社区当中进行进一步交流沟通。
#### 微信交流群
<img src="https://download.jumpserver.org/images/wecom-group.jpeg" alt="微信群二维码" width="200"/>
### 贡献
如果有你好的想法创意,或者帮助我们修复了 Bug, 欢迎提交 Pull Request
感谢以下贡献者,让 JumpServer 更加完善
<a href="https://github.com/jumpserver/jumpserver/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/jumpserver" />
</a>
<a href="https://github.com/jumpserver/koko/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/koko" />
</a>
<a href="https://github.com/jumpserver/lina/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/lina" />
</a>
<a href="https://github.com/jumpserver/luna/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/luna" />
</a>
### 致谢
- [Apache Guacamole](https://guacamole.apache.org/) Web页面连接 RDP, SSH, VNC协议设备JumpServer 图形化组件 Lion 依赖
- [OmniDB](https://omnidb.org/) Web页面连接使用数据库JumpServer Web数据库依赖
### JumpServer 企业版
- [申请企业版试用](https://jinshuju.net/f/kyOYpi)
> 注:企业版支持离线安装,申请通过后会提供高速下载链接。
## 案例研究
### 案例研究
- [JumpServer 堡垒机护航顺丰科技超大规模资产安全运维](https://blog.fit2cloud.com/?p=1147)
- [JumpServer 堡垒机让“大智慧”的混合 IT 运维更智慧](https://blog.fit2cloud.com/?p=882)
@@ -227,7 +112,7 @@ v2.1.0 是 v2.0.0 之后的功能版本。
- [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687)
- [江苏农信JumpServer堡垒机助力行业云安全运维](https://blog.fit2cloud.com/?p=666)。
## 安全说明
### 安全说明
JumpServer是一款安全产品请参考 [基本安全建议](https://docs.jumpserver.org/zh/master/install/install_security/) 部署安装.
@@ -237,12 +122,13 @@ JumpServer是一款安全产品请参考 [基本安全建议](https://docs.ju
- support@fit2cloud.com
- 400-052-0755
## License & Copyright
### License & Copyright
Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved.
Copyright (c) 2014-2021 飞致云 FIT2CLOUD, All rights reserved.
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/gpl-2.0.html
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

View File

@@ -1,57 +1,91 @@
## Jumpserver
<p align="center"><a href="https://jumpserver.org"><img src="https://download.jumpserver.org/images/jumpserver-logo.svg" alt="JumpServer" width="300" /></a></p>
<h3 align="center">Open Source Bastion Host</h3>
![Total visitor](https://visitor-count-badge.herokuapp.com/total.svg?repo_id=jumpserver)
![Visitors in today](https://visitor-count-badge.herokuapp.com/today.svg?repo_id=jumpserver)
[![Python3](https://img.shields.io/badge/python-3.6-green.svg?style=plastic)](https://www.python.org/)
[![Django](https://img.shields.io/badge/django-2.1-brightgreen.svg?style=plastic)](https://www.djangoproject.com/)
[![Ansible](https://img.shields.io/badge/ansible-2.4.2.0-blue.svg?style=plastic)](https://www.ansible.com/)
[![Paramiko](https://img.shields.io/badge/paramiko-2.4.1-green.svg?style=plastic)](http://www.paramiko.org/)
<p align="center">
<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0"><img src="https://shields.io/github/license/jumpserver/jumpserver" alt="License: GPL v2"></a>
<a href="https://shields.io/github/downloads/jumpserver/jumpserver/total"><img src="https://shields.io/github/downloads/jumpserver/jumpserver/total" alt=" release"></a>
<a href="https://hub.docker.com/u/jumpserver"><img src="https://img.shields.io/docker/pulls/jumpserver/jms_all.svg" alt="Codacy"></a>
<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>
JumpServer is the world's first open-source Bastion Host and is licensed under the GNU GPL v2.0. It is a 4A-compliant professional operation and maintenance security audit system.
JumpServer uses Python / Django for development, follows Web 2.0 specifications, and is equipped with an industry-leading Web Terminal solution that provides a beautiful user interface and great user experience
JumpServer adopts a distributed architecture to support multi-branch deployment across multiple cross-regional areas. The central node provides APIs, and login nodes are deployed in each branch. It can be scaled horizontally without concurrency restrictions.
Change the world by taking every little step
----
### Advantages
- [中文版](https://github.com/jumpserver/jumpserver/blob/master/README_EN.md)
- Open Source: huge transparency and free to access with quick installation process.
- Distributed: support large-scale concurrent access with ease.
- No Plugin required: all you need is a browser, the ultimate Web Terminal experience.
- Multi-Cloud supported: a unified system to manage assets on different clouds at the same time
- Cloud storage: audit records are stored in the cloud. Data lost no more!
- Multi-Tenant system: multiple subsidiary companies or departments access the same system simultaneously.
- Many applications supported: link to databases, windows remote applications, and Kubernetes cluster, etc.
Jumpserver is the first fully open source bastion in the world, based on the GNU GPL v2.0 open source protocol. Jumpserver is a professional operation and maintenance audit system conforms to 4A specifications.
Jumpserver is developed using Python / Django, conforms to the Web 2.0 specification, and is equipped with the industry-leading Web Terminal solution which have beautiful interface and great user experience.
### JumpServer Component Projects
- [Lina](https://github.com/jumpserver/lina) JumpServer Web UI
- [Luna](https://github.com/jumpserver/luna) JumpServer Web Terminal
- [KoKo](https://github.com/jumpserver/koko) JumpServer Character protocaol Connector, replace original Python Version [Coco](https://github.com/jumpserver/coco)
- [Lion](https://github.com/jumpserver/lion-release) JumpServer Graphics protocol Connectorrely on [Apache Guacamole](https://guacamole.apache.org/)
Jumpserver adopts a distributed architecture to support multi-branch deployment across multiple areas. The central node provides APIs, and login nodes are deployed in each branch. It can be scaled horizontally without concurrency restrictions.
### Contribution
If you have any good ideas or helping us to fix bugs, please submit a Pull Request and accept our thanks :)
Change the world, starting from little things.
Thanks to the following contributors for making JumpServer better everyday!
----
<a href="https://github.com/jumpserver/jumpserver/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/jumpserver" />
</a>
### Features
<a href="https://github.com/jumpserver/koko/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/koko" />
</a>
![Jumpserver 功能](https://jumpserver-release.oss-cn-hangzhou.aliyuncs.com/Jumpserver148.jpeg "Jumpserver 功能")
<a href="https://github.com/jumpserver/lina/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/lina" />
</a>
### Start
<a href="https://github.com/jumpserver/luna/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/luna" />
</a>
Quick start [Docker Install](http://docs.jumpserver.org/zh/docs/dockerinstall.html)
### Thanks to
- [Apache Guacamole](https://guacamole.apache.org/) Web page connection RDP, SSH, VNC protocol equipment. JumpServer graphical connection dependent.
- [OmniDB](https://omnidb.org/) Web page connection to databases. JumpServer Web database dependent.
Step by Step deployment. [Docs](http://docs.jumpserver.org/zh/docs/step_by_step.html)
Full documentation [Docs](http://docs.jumpserver.org)
### JumpServer Enterprise Version
- [Apply for it](https://jinshuju.net/f/kyOYpi)
### Demo、Video 和 Snapshot
### Case Study
We provide online demo, demo video and screenshots to get you started quickly.
- [JumpServer 堡垒机护航顺丰科技超大规模资产安全运维](https://blog.fit2cloud.com/?p=1147)
- [JumpServer 堡垒机让“大智慧”的混合 IT 运维更智慧](https://blog.fit2cloud.com/?p=882)
- [携程 JumpServer 堡垒机部署与运营实战](https://blog.fit2cloud.com/?p=851)
- [小红书的JumpServer堡垒机大规模资产跨版本迁移之路](https://blog.fit2cloud.com/?p=516)
- [JumpServer堡垒机助力中手游提升多云环境下安全运维能力](https://blog.fit2cloud.com/?p=732)
- [中通快递JumpServer主机安全运维实践](https://blog.fit2cloud.com/?p=708)
- [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687)
- [江苏农信JumpServer堡垒机助力行业云安全运维](https://blog.fit2cloud.com/?p=666)。
[Demo](https://demo.jumpserver.org/auth/login/?next=/)
[Video](https://fit2cloud2-offline-installer.oss-cn-beijing.aliyuncs.com/tools/Jumpserver%20%E4%BB%8B%E7%BB%8Dv1.4.mp4)
[Snapshot](http://docs.jumpserver.org/zh/docs/snapshot.html)
### For safety instructions
### SDK
JumpServer is a security product. Please refer to [Basic Security Recommendations](https://docs.jumpserver.org/zh/master/install/install_security/) for deployment and installation.
We provide the SDK for your other systems to quickly interact with the Jumpserver API.
- [Python](https://github.com/jumpserver/jumpserver-python-sdk) Jumpserver other components use this SDK to complete the interaction.
- [Java](https://github.com/KaiJunYan/jumpserver-java-sdk.git) 恺珺同学提供的Java版本的SDK thanks to 恺珺 for provide Java SDK
If you find a security problem, please contact us directly
- ibuler@fit2cloud.com
- support@fit2cloud.com
- 400-052-0755
### License & Copyright
Copyright (c) 2014-2019 Beijing Duizhan Tech, Inc., All rights reserved.
Copyright (c) 2014-2021 Beijing Duizhan Tech, Inc., All rights reserved.
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

9
SECURITY.md Normal file
View File

@@ -0,0 +1,9 @@
# 安全说明
JumpServer 是一款正在成长的安全产品, 请参考 [基本安全建议](https://docs.jumpserver.org/zh/master/install/install_security/) 部署安装.
如果你发现安全问题,请直接联系我们,我们携手让世界更好:
- ibuler@fit2cloud.com
- support@fit2cloud.com
- 400-052-0755

2
apps/.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
*.js linguist-language=python
*.html linguist-language=python

3
apps/acls/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@@ -0,0 +1,3 @@
from .login_acl import *
from .login_asset_acl import *
from .login_asset_check import *

View File

@@ -0,0 +1,20 @@
from common.permissions import IsOrgAdmin, HasQueryParamsUserAndIsCurrentOrgMember
from common.drf.api import JMSBulkModelViewSet
from ..models import LoginACL
from .. import serializers
from ..filters import LoginAclFilter
__all__ = ['LoginACLViewSet', ]
class LoginACLViewSet(JMSBulkModelViewSet):
queryset = LoginACL.objects.all()
filterset_class = LoginAclFilter
search_fields = ('name',)
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.LoginACLSerializer
def get_permissions(self):
if self.action in ["retrieve", "list"]:
self.permission_classes = (IsOrgAdmin, HasQueryParamsUserAndIsCurrentOrgMember)
return super().get_permissions()

View File

@@ -0,0 +1,14 @@
from orgs.mixins.api import OrgBulkModelViewSet
from common.permissions import IsOrgAdmin
from .. import models, serializers
__all__ = ['LoginAssetACLViewSet']
class LoginAssetACLViewSet(OrgBulkModelViewSet):
model = models.LoginAssetACL
filterset_fields = ('name', )
search_fields = filterset_fields
permission_classes = (IsOrgAdmin, )
serializer_class = serializers.LoginAssetACLSerializer

View File

@@ -0,0 +1,75 @@
from rest_framework.response import Response
from rest_framework.generics import CreateAPIView
from common.permissions import IsAppUser
from common.utils import reverse, lazyproperty
from orgs.utils import tmp_to_org
from tickets.api import GenericTicketStatusRetrieveCloseAPI
from ..models import LoginAssetACL
from .. import serializers
__all__ = ['LoginAssetCheckAPI', 'LoginAssetConfirmStatusAPI']
class LoginAssetCheckAPI(CreateAPIView):
permission_classes = (IsAppUser,)
serializer_class = serializers.LoginAssetCheckSerializer
def create(self, request, *args, **kwargs):
is_need_confirm, response_data = self.check_if_need_confirm()
return Response(data=response_data, status=200)
def check_if_need_confirm(self):
queries = {
'user': self.serializer.user, 'asset': self.serializer.asset,
'system_user': self.serializer.system_user,
'action': LoginAssetACL.ActionChoices.login_confirm
}
with tmp_to_org(self.serializer.org):
acl = LoginAssetACL.filter(**queries).valid().first()
if not acl:
is_need_confirm = False
response_data = {}
else:
is_need_confirm = True
response_data = self._get_response_data_of_need_confirm(acl)
response_data['need_confirm'] = is_need_confirm
return is_need_confirm, response_data
def _get_response_data_of_need_confirm(self, acl):
ticket = LoginAssetACL.create_login_asset_confirm_ticket(
user=self.serializer.user,
asset=self.serializer.asset,
system_user=self.serializer.system_user,
assignees=acl.reviewers.all(),
org_id=self.serializer.org.id
)
confirm_status_url = reverse(
view_name='api-acls:login-asset-confirm-status',
kwargs={'pk': str(ticket.id)}
)
ticket_detail_url = reverse(
view_name='api-tickets:ticket-detail',
kwargs={'pk': str(ticket.id)},
external=True, api_to_ui=True
)
ticket_detail_url = '{url}?type={type}'.format(url=ticket_detail_url, type=ticket.type)
ticket_assignees = ticket.current_node.first().ticket_assignees.all()
data = {
'check_confirm_status': {'method': 'GET', 'url': confirm_status_url},
'close_confirm': {'method': 'DELETE', 'url': confirm_status_url},
'ticket_detail_url': ticket_detail_url,
'reviewers': [str(ticket_assignee.assignee) for ticket_assignee in ticket_assignees]
}
return data
@lazyproperty
def serializer(self):
serializer = self.get_serializer(data=self.request.data)
serializer.is_valid(raise_exception=True)
return serializer
class LoginAssetConfirmStatusAPI(GenericTicketStatusRetrieveCloseAPI):
pass

5
apps/acls/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class AclsConfig(AppConfig):
name = 'acls'

15
apps/acls/filters.py Normal file
View File

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

View File

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

View File

@@ -0,0 +1,98 @@
# Generated by Django 3.1.12 on 2021-09-26 02:47
import django
from django.conf import settings
from django.db import migrations, models, transaction
from acls.models import LoginACL
LOGIN_CONFIRM_ZH = '登录复核'
LOGIN_CONFIRM_EN = 'Login confirm'
DEFAULT_TIME_PERIODS = [{'id': i, 'value': '00:00~00:00'} for i in range(7)]
def has_zh(name: str) -> bool:
for i in name:
if u'\u4e00' <= i <= u'\u9fff':
return True
return False
def migrate_login_confirm(apps, schema_editor):
login_acl_model = apps.get_model("acls", "LoginACL")
login_confirm_model = apps.get_model("authentication", "LoginConfirmSetting")
with transaction.atomic():
for instance in login_confirm_model.objects.filter(is_active=True):
user = instance.user
reviewers = instance.reviewers.all()
login_confirm = LOGIN_CONFIRM_ZH if has_zh(user.name) else LOGIN_CONFIRM_EN
date_created = instance.date_created.strftime('%Y-%m-%d %H:%M:%S')
if reviewers.count() == 0:
continue
data = {
'user': user,
'name': f'{user.name}-{login_confirm} ({date_created})',
'created_by': instance.created_by,
'action': LoginACL.ActionChoices.confirm,
'rules': {'ip_group': ['*'], 'time_period': DEFAULT_TIME_PERIODS}
}
instance = login_acl_model.objects.create(**data)
instance.reviewers.set(reviewers)
def migrate_ip_group(apps, schema_editor):
login_acl_model = apps.get_model("acls", "LoginACL")
updates = list()
with transaction.atomic():
for instance in login_acl_model.objects.exclude(action=LoginACL.ActionChoices.confirm):
instance.rules = {'ip_group': instance.ip_group, 'time_period': DEFAULT_TIME_PERIODS}
updates.append(instance)
login_acl_model.objects.bulk_update(updates, ['rules', ])
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acls', '0001_initial'),
('authentication', '0004_ssotoken'),
]
operations = [
migrations.AlterField(
model_name='loginacl',
name='action',
field=models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow'), ('confirm', 'Login confirm')],
default='reject', max_length=64, verbose_name='Action'),
),
migrations.AddField(
model_name='loginacl',
name='reviewers',
field=models.ManyToManyField(blank=True, related_name='login_confirm_acls',
to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
migrations.AlterField(
model_name='loginacl',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
related_name='login_acls', to=settings.AUTH_USER_MODEL, verbose_name='User'),
),
migrations.AddField(
model_name='loginacl',
name='rules',
field=models.JSONField(default=dict, verbose_name='Rule'),
),
migrations.RunPython(migrate_login_confirm),
migrations.RunPython(migrate_ip_group),
migrations.RemoveField(
model_name='loginacl',
name='ip_group',
),
migrations.AlterModelOptions(
name='loginacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login acl'},
),
migrations.AlterModelOptions(
name='loginassetacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login asset acl'},
),
]

View File

View File

@@ -0,0 +1,2 @@
from .login_acl import *
from .login_asset_acl import *

35
apps/acls/models/base.py Normal file
View File

@@ -0,0 +1,35 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.validators import MinValueValidator, MaxValueValidator
from common.mixins import CommonModelMixin
__all__ = ['BaseACL', 'BaseACLQuerySet']
class BaseACLQuerySet(models.QuerySet):
def active(self):
return self.filter(is_active=True)
def inactive(self):
return self.filter(is_active=False)
def valid(self):
return self.active()
def invalid(self):
return self.inactive()
class BaseACL(CommonModelMixin):
name = models.CharField(max_length=128, verbose_name=_('Name'))
priority = models.IntegerField(
default=50, verbose_name=_("Priority"),
help_text=_("1-100, the lower the value will be match first"),
validators=[MinValueValidator(1), MaxValueValidator(100)]
)
is_active = models.BooleanField(default=True, verbose_name=_("Active"))
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
class Meta:
abstract = True

View File

@@ -0,0 +1,128 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from .base import BaseACL, BaseACLQuerySet
from common.utils import get_request_ip, get_ip_city
from common.utils.ip import contains_ip
from common.utils.time_period import contains_time_period
from common.utils.timezone import local_now_display
class ACLManager(models.Manager):
def valid(self):
return self.get_queryset().valid()
class LoginACL(BaseACL):
class ActionChoices(models.TextChoices):
reject = 'reject', _('Reject')
allow = 'allow', _('Allow')
confirm = 'confirm', _('Login confirm')
# 用户
user = models.ForeignKey(
'users.User', on_delete=models.CASCADE, verbose_name=_('User'),
related_name='login_acls'
)
# 规则
rules = models.JSONField(default=dict, verbose_name=_('Rule'))
# 动作
action = models.CharField(
max_length=64, verbose_name=_('Action'),
choices=ActionChoices.choices, default=ActionChoices.reject
)
reviewers = models.ManyToManyField(
'users.User', verbose_name=_("Reviewers"),
related_name="login_confirm_acls", blank=True
)
objects = ACLManager.from_queryset(BaseACLQuerySet)()
class Meta:
ordering = ('priority', '-date_updated', 'name')
verbose_name = _('Login acl')
def __str__(self):
return self.name
@property
def action_reject(self):
return self.action == self.ActionChoices.reject
@property
def action_allow(self):
return self.action == self.ActionChoices.allow
@classmethod
def filter_acl(cls, user):
return user.login_acls.all().valid().distinct()
@staticmethod
def allow_user_confirm_if_need(user, ip):
acl = LoginACL.filter_acl(user).filter(
action=LoginACL.ActionChoices.confirm
).first()
acl = acl if acl and acl.reviewers.exists() else None
if not acl:
return False, acl
ip_group = acl.rules.get('ip_group')
time_periods = acl.rules.get('time_period')
is_contain_ip = contains_ip(ip, ip_group)
is_contain_time_period = contains_time_period(time_periods)
return is_contain_ip and is_contain_time_period, acl
@staticmethod
def allow_user_to_login(user, ip):
acl = LoginACL.filter_acl(user).exclude(
action=LoginACL.ActionChoices.confirm
).first()
if not acl:
return True, ''
ip_group = acl.rules.get('ip_group')
time_periods = acl.rules.get('time_period')
is_contain_ip = contains_ip(ip, ip_group)
is_contain_time_period = contains_time_period(time_periods)
reject_type = ''
if is_contain_ip and is_contain_time_period:
# 满足条件
allow = acl.action_allow
if not allow:
reject_type = 'ip' if is_contain_ip else 'time'
else:
# 不满足条件
# 如果acl本身允许那就拒绝如果本身拒绝那就允许
allow = not acl.action_allow
if not allow:
reject_type = 'ip' if not is_contain_ip else 'time'
return allow, reject_type
@staticmethod
def construct_confirm_ticket_meta(request=None):
login_ip = get_request_ip(request) if request else ''
login_ip = login_ip or '0.0.0.0'
login_city = get_ip_city(login_ip)
login_datetime = local_now_display()
ticket_meta = {
'apply_login_ip': login_ip,
'apply_login_city': login_city,
'apply_login_datetime': login_datetime,
}
return ticket_meta
def create_confirm_ticket(self, request=None):
from tickets import const
from tickets.models import Ticket
from orgs.models import Organization
ticket_title = _('Login confirm') + ' {}'.format(self.user)
ticket_meta = self.construct_confirm_ticket_meta(request)
data = {
'title': ticket_title,
'type': const.TicketType.login_confirm.value,
'meta': ticket_meta,
'org_id': Organization.ROOT_ID,
}
ticket = Ticket.objects.create(**data)
ticket.create_process_map_and_node(self.reviewers.all())
ticket.open(self.user)
return ticket

View File

@@ -0,0 +1,103 @@
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.models import OrgModelMixin, OrgManager
from .base import BaseACL, BaseACLQuerySet
from common.utils.ip import contains_ip
class ACLManager(OrgManager):
def valid(self):
return self.get_queryset().valid()
class LoginAssetACL(BaseACL, OrgModelMixin):
class ActionChoices(models.TextChoices):
login_confirm = 'login_confirm', _('Login confirm')
# 条件
users = models.JSONField(verbose_name=_('User'))
system_users = models.JSONField(verbose_name=_('System User'))
assets = models.JSONField(verbose_name=_('Asset'))
# 动作
action = models.CharField(
max_length=64, choices=ActionChoices.choices, default=ActionChoices.login_confirm,
verbose_name=_('Action')
)
# 动作: 附加字段
# - login_confirm
reviewers = models.ManyToManyField(
'users.User', related_name='review_login_asset_acls', blank=True,
verbose_name=_("Reviewers")
)
objects = ACLManager.from_queryset(BaseACLQuerySet)()
class Meta:
unique_together = ('name', 'org_id')
ordering = ('priority', '-date_updated', 'name')
verbose_name = _('Login asset acl')
def __str__(self):
return self.name
@classmethod
def filter(cls, user, asset, system_user, action):
queryset = cls.objects.filter(action=action)
queryset = cls.filter_user(user, queryset)
queryset = cls.filter_asset(asset, queryset)
queryset = cls.filter_system_user(system_user, queryset)
return queryset
@classmethod
def filter_user(cls, user, queryset):
queryset = queryset.filter(
Q(users__username_group__contains=user.username) |
Q(users__username_group__contains='*')
)
return queryset
@classmethod
def filter_asset(cls, asset, queryset):
queryset = queryset.filter(
Q(assets__hostname_group__contains=asset.hostname) |
Q(assets__hostname_group__contains='*')
)
ids = [q.id for q in queryset if contains_ip(asset.ip, q.assets.get('ip_group', []))]
queryset = cls.objects.filter(id__in=ids)
return queryset
@classmethod
def filter_system_user(cls, system_user, queryset):
queryset = queryset.filter(
Q(system_users__name_group__contains=system_user.name) |
Q(system_users__name_group__contains='*')
).filter(
Q(system_users__username_group__contains=system_user.username) |
Q(system_users__username_group__contains='*')
).filter(
Q(system_users__protocol_group__contains=system_user.protocol) |
Q(system_users__protocol_group__contains='*')
)
return queryset
@classmethod
def create_login_asset_confirm_ticket(cls, user, asset, system_user, assignees, org_id):
from tickets.const import TicketType
from tickets.models import Ticket
data = {
'title': _('Login asset confirm') + ' ({})'.format(user),
'type': TicketType.login_asset_confirm,
'meta': {
'apply_login_user': str(user),
'apply_login_asset': str(asset),
'apply_login_system_user': str(system_user),
},
'org_id': org_id,
}
ticket = Ticket.objects.create(**data)
ticket.create_process_map_and_node(assignees)
ticket.open(applicant=user)
return ticket

View File

@@ -0,0 +1,3 @@
from .login_acl import *
from .login_asset_acl import *
from .login_asset_check import *

View File

@@ -0,0 +1,56 @@
from django.utils.translation import ugettext as _
from rest_framework import serializers
from common.drf.serializers import BulkModelSerializer
from common.drf.serializers import MethodSerializer
from jumpserver.utils import has_valid_xpack_license
from ..models import LoginACL
from .rules import RuleSerializer
__all__ = ['LoginACLSerializer', ]
common_help_text = _('Format for comma-delimited string, with * indicating a match all. ')
class LoginACLSerializer(BulkModelSerializer):
user_display = serializers.ReadOnlyField(source='user.username', label=_('Username'))
reviewers_display = serializers.SerializerMethodField(label=_('Reviewers'))
action_display = serializers.ReadOnlyField(source='get_action_display', label=_('Action'))
reviewers_amount = serializers.IntegerField(read_only=True, source='reviewers.count')
rules = MethodSerializer()
class Meta:
model = LoginACL
fields_mini = ['id', 'name']
fields_small = fields_mini + [
'priority', 'rules', 'action', 'action_display',
'is_active', 'user', 'user_display',
'date_created', 'date_updated', 'reviewers_amount',
'comment', 'created_by'
]
fields_fk = ['user', 'user_display']
fields_m2m = ['reviewers', 'reviewers_display']
fields = fields_small + fields_fk + fields_m2m
extra_kwargs = {
'priority': {'default': 50},
'is_active': {'default': True},
"reviewers": {'allow_null': False, 'required': 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.confirm, None)
action._choices = choices
def get_rules_serializer(self):
return RuleSerializer()
def get_reviewers_display(self, obj):
return ','.join([str(user) for user in obj.reviewers.all()])

View File

@@ -0,0 +1,105 @@
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from assets.models import SystemUser
from acls import models
from orgs.models import Organization
__all__ = ['LoginAssetACLSerializer']
common_help_text = _('Format for comma-delimited string, with * indicating a match all. ')
class LoginAssetACLUsersSerializer(serializers.Serializer):
username_group = serializers.ListField(
default=['*'], child=serializers.CharField(max_length=128), label=_('Username'),
help_text=common_help_text
)
class LoginAssetACLAssestsSerializer(serializers.Serializer):
ip_group_help_text = _(
'Format for comma-delimited string, 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)'
)
ip_group = serializers.ListField(
default=['*'], child=serializers.CharField(max_length=1024), label=_('IP'),
help_text=ip_group_help_text
)
hostname_group = serializers.ListField(
default=['*'], child=serializers.CharField(max_length=128), label=_('Hostname'),
help_text=common_help_text
)
class LoginAssetACLSystemUsersSerializer(serializers.Serializer):
protocol_group_help_text = _(
'Format for comma-delimited string, with * indicating a match all. '
'Protocol options: {}'
)
name_group = serializers.ListField(
default=['*'], child=serializers.CharField(max_length=128), label=_('Name'),
help_text=common_help_text
)
username_group = serializers.ListField(
default=['*'], child=serializers.CharField(max_length=128), label=_('Username'),
help_text=common_help_text
)
protocol_group = serializers.ListField(
default=['*'], child=serializers.CharField(max_length=16), label=_('Protocol'),
help_text=protocol_group_help_text.format(
', '.join([SystemUser.Protocol.ssh, SystemUser.Protocol.telnet])
)
)
@staticmethod
def validate_protocol_group(protocol_group):
unsupported_protocols = set(protocol_group) - set(SystemUser.ASSET_CATEGORY_PROTOCOLS + ['*'])
if unsupported_protocols:
error = _('Unsupported protocols: {}').format(unsupported_protocols)
raise serializers.ValidationError(error)
return protocol_group
class LoginAssetACLSerializer(BulkOrgResourceModelSerializer):
users = LoginAssetACLUsersSerializer()
assets = LoginAssetACLAssestsSerializer()
system_users = LoginAssetACLSystemUsersSerializer()
reviewers_amount = serializers.IntegerField(read_only=True, source='reviewers.count')
action_display = serializers.ReadOnlyField(source='get_action_display', label=_('Action'))
class Meta:
model = models.LoginAssetACL
fields_mini = ['id', 'name']
fields_small = fields_mini + [
'users', 'system_users', 'assets',
'is_active',
'date_created', 'date_updated',
'priority', 'action', 'action_display', 'comment', 'created_by', 'org_id'
]
fields_m2m = ['reviewers', 'reviewers_amount']
fields = fields_small + fields_m2m
extra_kwargs = {
"reviewers": {'allow_null': False, 'required': True},
'priority': {'default': 50},
'is_active': {'default': True},
}
def validate_reviewers(self, reviewers):
org_id = self.fields['org_id'].default()
org = Organization.get_instance(org_id)
if not org:
error = _('The organization `{}` does not exist'.format(org_id))
raise serializers.ValidationError(error)
users = org.get_members()
valid_reviewers = list(set(reviewers) & set(users))
if not valid_reviewers:
error = _('None of the reviewers belong to Organization `{}`'.format(org.name))
raise serializers.ValidationError(error)
return valid_reviewers

View File

@@ -0,0 +1,71 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from orgs.utils import tmp_to_root_org
from common.utils import get_object_or_none, lazyproperty
from users.models import User
from assets.models import Asset, SystemUser
__all__ = ['LoginAssetCheckSerializer']
class LoginAssetCheckSerializer(serializers.Serializer):
user_id = serializers.UUIDField(required=True, allow_null=False)
asset_id = serializers.UUIDField(required=True, allow_null=False)
system_user_id = serializers.UUIDField(required=True, allow_null=False)
system_user_username = serializers.CharField(max_length=128, default='')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = None
self.asset = None
self._system_user = None
self._system_user_username = None
def validate_user_id(self, user_id):
self.user = self.validate_object_exist(User, user_id)
return user_id
def validate_asset_id(self, asset_id):
self.asset = self.validate_object_exist(Asset, asset_id)
return asset_id
def validate_system_user_id(self, system_user_id):
self._system_user = self.validate_object_exist(SystemUser, system_user_id)
return system_user_id
def validate_system_user_username(self, system_user_username):
system_user_id = self.initial_data.get('system_user_id')
system_user = self.validate_object_exist(SystemUser, system_user_id)
if self._system_user.login_mode == SystemUser.LOGIN_MANUAL \
and not system_user.username \
and not system_user.username_same_with_user \
and not system_user_username:
error = 'Missing parameter: system_user_username'
raise serializers.ValidationError(error)
self._system_user_username = system_user_username
return system_user_username
@staticmethod
def validate_object_exist(model, field_id):
with tmp_to_root_org():
obj = get_object_or_none(model, pk=field_id)
if not obj:
error = '{} Model object does not exist'.format(model.__name__)
raise serializers.ValidationError(error)
return obj
@lazyproperty
def system_user(self):
if self._system_user.username_same_with_user:
username = self.user.username
elif self._system_user.login_mode == SystemUser.LOGIN_MANUAL:
username = self._system_user_username
else:
username = self._system_user.username
self._system_user.username = username
return self._system_user
@lazyproperty
def org(self):
return self.asset.org

View File

@@ -0,0 +1 @@
from .rules import *

View File

@@ -0,0 +1,34 @@
# coding: utf-8
#
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from common.utils import get_logger
from common.utils.ip import is_ip_address, is_ip_network, is_ip_segment
logger = get_logger(__file__)
__all__ = ['RuleSerializer']
def ip_group_child_validator(ip_group_child):
is_valid = ip_group_child == '*' \
or is_ip_address(ip_group_child) \
or is_ip_network(ip_group_child) \
or is_ip_segment(ip_group_child)
if not is_valid:
error = _('IP address invalid: `{}`').format(ip_group_child)
raise serializers.ValidationError(error)
class RuleSerializer(serializers.Serializer):
ip_group_help_text = _(
'Format for comma-delimited string, 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 '
)
ip_group = serializers.ListField(
default=['*'], label=_('IP'), help_text=ip_group_help_text,
child=serializers.CharField(max_length=1024, validators=[ip_group_child_validator]))
time_period = serializers.ListField(default=[], label=_('Time Period'))

3
apps/acls/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -0,0 +1 @@
from .api_urls import *

View File

@@ -0,0 +1,18 @@
from django.urls import path
from rest_framework_bulk.routes import BulkRouter
from .. import api
app_name = 'acls'
router = BulkRouter()
router.register(r'login-acls', api.LoginACLViewSet, 'login-acl')
router.register(r'login-asset-acls', api.LoginAssetACLViewSet, 'login-asset-acl')
urlpatterns = [
path('login-asset/check/', api.LoginAssetCheckAPI.as_view(), name='login-asset-check'),
path('login-asset-confirm/<uuid:pk>/status/', api.LoginAssetConfirmStatusAPI.as_view(), name='login-asset-confirm-status')
]
urlpatterns += router.urls

0
apps/acls/utils.py Normal file
View File

View File

@@ -1,3 +1,4 @@
from .application import *
from .account import *
from .mixin import *
from .remote_app import *
from .database_app import *
from .k8s_app import *

View File

@@ -0,0 +1,58 @@
# coding: utf-8
#
from django_filters import rest_framework as filters
from django.db.models import F, Q
from common.drf.filters import BaseFilterSet
from common.drf.api import JMSBulkModelViewSet
from ..models import Account
from ..hands import IsOrgAdminOrAppUser, IsOrgAdmin, NeedMFAVerify
from .. import serializers
class AccountFilterSet(BaseFilterSet):
username = filters.CharFilter(method='do_nothing')
type = filters.CharFilter(field_name='type', lookup_expr='exact')
category = filters.CharFilter(field_name='category', lookup_expr='exact')
app_display = filters.CharFilter(field_name='app_display', lookup_expr='exact')
class Meta:
model = Account
fields = ['app', 'systemuser']
@property
def qs(self):
qs = super().qs
qs = self.filter_username(qs)
return qs
def filter_username(self, qs):
username = self.get_query_param('username')
if not username:
return qs
qs = qs.filter(Q(username=username) | Q(systemuser__username=username)).distinct()
return qs
class ApplicationAccountViewSet(JMSBulkModelViewSet):
model = Account
search_fields = ['username', 'app_display']
filterset_class = AccountFilterSet
filterset_fields = ['username', 'app_display', 'type', 'category', 'app']
serializer_class = serializers.AppAccountSerializer
permission_classes = (IsOrgAdmin,)
def get_queryset(self):
queryset = Account.objects.all() \
.annotate(type=F('app__type')) \
.annotate(app_display=F('app__name')) \
.annotate(systemuser_display=F('systemuser__name')) \
.annotate(category=F('app__category'))
return queryset
class ApplicationAccountSecretViewSet(ApplicationAccountViewSet):
serializer_class = serializers.AppAccountSecretSerializer
permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify]
http_method_names = ['get', 'options']

View File

@@ -0,0 +1,38 @@
# coding: utf-8
#
from orgs.mixins.api import OrgBulkModelViewSet
from rest_framework.decorators import action
from rest_framework.response import Response
from common.tree import TreeNodeSerializer
from common.mixins.api import SuggestionMixin
from ..hands import IsOrgAdminOrAppUser
from .. import serializers
from ..models import Application
__all__ = ['ApplicationViewSet']
class ApplicationViewSet(SuggestionMixin, OrgBulkModelViewSet):
model = Application
filterset_fields = {
'name': ['exact'],
'category': ['exact'],
'type': ['exact', 'in'],
}
search_fields = ('name', 'type', 'category')
permission_classes = (IsOrgAdminOrAppUser,)
serializer_classes = {
'default': serializers.AppSerializer,
'get_tree': TreeNodeSerializer,
'suggestion': serializers.MiniAppSerializer
}
@action(methods=['GET'], detail=False, url_path='tree')
def get_tree(self, request, *args, **kwargs):
show_count = request.query_params.get('show_count', '1') == '1'
queryset = self.filter_queryset(self.get_queryset())
tree_nodes = Application.create_tree_nodes(queryset, show_count=show_count)
serializer = self.get_serializer(tree_nodes, many=True)
return Response(serializer.data)

View File

@@ -1,20 +0,0 @@
# coding: utf-8
#
from orgs.mixins.api import OrgBulkModelViewSet
from .. import models
from .. import serializers
from ..hands import IsOrgAdminOrAppUser
__all__ = [
'DatabaseAppViewSet',
]
class DatabaseAppViewSet(OrgBulkModelViewSet):
model = models.DatabaseApp
filter_fields = ('name',)
search_fields = filter_fields
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.DatabaseAppSerializer

View File

@@ -1,20 +0,0 @@
# coding: utf-8
#
from orgs.mixins.api import OrgBulkModelViewSet
from .. import models
from .. import serializers
from ..hands import IsOrgAdminOrAppUser
__all__ = [
'K8sAppViewSet',
]
class K8sAppViewSet(OrgBulkModelViewSet):
model = models.K8sApp
filter_fields = ('name',)
search_fields = filter_fields
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.K8sAppSerializer

View File

@@ -0,0 +1,55 @@
from django.utils.translation import ugettext as _
from common.tree import TreeNode
from orgs.models import Organization
from ..models import Application
__all__ = ['SerializeApplicationToTreeNodeMixin']
class SerializeApplicationToTreeNodeMixin:
@staticmethod
def filter_organizations(applications):
organization_ids = set(applications.values_list('org_id', flat=True))
organizations = [Organization.get_instance(org_id) for org_id in organization_ids]
organizations.sort(key=lambda x: x.name)
return organizations
@staticmethod
def create_root_node():
name = _('My applications')
node = TreeNode(**{
'id': 'applications',
'name': name,
'title': name,
'pId': '',
'open': True,
'isParent': True,
'meta': {
'type': 'root'
}
})
return node
def serialize_applications_with_org(self, applications):
if not applications:
return []
root_node = self.create_root_node()
tree_nodes = [root_node]
organizations = self.filter_organizations(applications)
for i, org in enumerate(organizations):
# 组织节点
org_node = org.as_tree_node(pid=root_node.id)
tree_nodes.append(org_node)
org_applications = applications.filter(org_id=org.id)
count = org_applications.count()
org_node.name += '({})'.format(count)
# 各应用节点
apps_nodes = Application.create_tree_nodes(
queryset=org_applications, root_node=org_node,
show_empty=False
)
tree_nodes += apps_nodes
return tree_nodes

View File

@@ -1,27 +1,19 @@
# coding: utf-8
#
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.mixins import generics
from ..hands import IsOrgAdmin, IsAppUser
from ..models import RemoteApp
from ..serializers import RemoteAppSerializer, RemoteAppConnectionInfoSerializer
from ..hands import IsAppUser
from .. import models
from ..serializers import RemoteAppConnectionInfoSerializer
from ..permissions import IsRemoteApp
__all__ = [
'RemoteAppViewSet', 'RemoteAppConnectionInfoApi',
'RemoteAppConnectionInfoApi',
]
class RemoteAppViewSet(OrgBulkModelViewSet):
model = RemoteApp
filter_fields = ('name', 'type', 'comment')
search_fields = filter_fields
permission_classes = (IsOrgAdmin,)
serializer_class = RemoteAppSerializer
class RemoteAppConnectionInfoApi(generics.RetrieveAPIView):
model = RemoteApp
permission_classes = (IsAppUser, )
model = models.Application
permission_classes = (IsAppUser, IsRemoteApp)
serializer_class = RemoteAppConnectionInfoSerializer

View File

@@ -1,64 +1,67 @@
# coding: utf-8
#
from django.db.models import TextChoices
from django.utils.translation import ugettext_lazy as _
# RemoteApp
class AppCategory(TextChoices):
db = 'db', _('Database')
remote_app = 'remote_app', _('Remote app')
cloud = 'cloud', 'Cloud'
REMOTE_APP_BOOT_PROGRAM_NAME = '||jmservisor'
REMOTE_APP_TYPE_CHROME = 'chrome'
REMOTE_APP_TYPE_MYSQL_WORKBENCH = 'mysql_workbench'
REMOTE_APP_TYPE_VMWARE_CLIENT = 'vmware_client'
REMOTE_APP_TYPE_CUSTOM = 'custom'
# Fields attribute write_only default => False
REMOTE_APP_TYPE_CHROME_FIELDS = [
{'name': 'chrome_target'},
{'name': 'chrome_username'},
{'name': 'chrome_password', 'write_only': True}
]
REMOTE_APP_TYPE_MYSQL_WORKBENCH_FIELDS = [
{'name': 'mysql_workbench_ip'},
{'name': 'mysql_workbench_name'},
{'name': 'mysql_workbench_port'},
{'name': 'mysql_workbench_username'},
{'name': 'mysql_workbench_password', 'write_only': True}
]
REMOTE_APP_TYPE_VMWARE_CLIENT_FIELDS = [
{'name': 'vmware_target'},
{'name': 'vmware_username'},
{'name': 'vmware_password', 'write_only': True}
]
REMOTE_APP_TYPE_CUSTOM_FIELDS = [
{'name': 'custom_cmdline'},
{'name': 'custom_target'},
{'name': 'custom_username'},
{'name': 'custom_password', 'write_only': True}
]
REMOTE_APP_TYPE_FIELDS_MAP = {
REMOTE_APP_TYPE_CHROME: REMOTE_APP_TYPE_CHROME_FIELDS,
REMOTE_APP_TYPE_MYSQL_WORKBENCH: REMOTE_APP_TYPE_MYSQL_WORKBENCH_FIELDS,
REMOTE_APP_TYPE_VMWARE_CLIENT: REMOTE_APP_TYPE_VMWARE_CLIENT_FIELDS,
REMOTE_APP_TYPE_CUSTOM: REMOTE_APP_TYPE_CUSTOM_FIELDS
}
REMOTE_APP_TYPE_CHOICES = (
(REMOTE_APP_TYPE_CHROME, 'Chrome'),
(REMOTE_APP_TYPE_MYSQL_WORKBENCH, 'MySQL Workbench'),
(REMOTE_APP_TYPE_VMWARE_CLIENT, 'vSphere Client'),
(REMOTE_APP_TYPE_CUSTOM, _('Custom')),
)
@classmethod
def get_label(cls, category):
return dict(cls.choices).get(category, '')
# DatabaseApp
class AppType(TextChoices):
# db category
mysql = 'mysql', 'MySQL'
oracle = 'oracle', 'Oracle'
pgsql = 'postgresql', 'PostgreSQL'
mariadb = 'mariadb', 'MariaDB'
# remote-app category
chrome = 'chrome', 'Chrome'
mysql_workbench = 'mysql_workbench', 'MySQL Workbench'
vmware_client = 'vmware_client', 'vSphere Client'
custom = 'custom', _('Custom')
# cloud category
k8s = 'k8s', 'Kubernetes'
@classmethod
def category_types_mapper(cls):
return {
AppCategory.db: [cls.mysql, cls.oracle, cls.pgsql, cls.mariadb],
AppCategory.remote_app: [cls.chrome, cls.mysql_workbench, cls.vmware_client, cls.custom],
AppCategory.cloud: [cls.k8s]
}
@classmethod
def type_category_mapper(cls):
mapper = {}
for category, tps in cls.category_types_mapper().items():
for tp in tps:
mapper[tp] = category
return mapper
@classmethod
def get_label(cls, tp):
return dict(cls.choices).get(tp, '')
@classmethod
def db_types(cls):
return [tp.value for tp in cls.category_types_mapper()[AppCategory.db]]
@classmethod
def remote_app_types(cls):
return [tp.value for tp in cls.category_types_mapper()[AppCategory.remote_app]]
@classmethod
def cloud_types(cls):
return [tp.value for tp in cls.category_types_mapper()[AppCategory.cloud]]
DATABASE_APP_TYPE_MYSQL = 'mysql'
DATABASE_APP_TYPE_CHOICES = (
(DATABASE_APP_TYPE_MYSQL, 'MySQL'),
)

View File

@@ -11,5 +11,5 @@
"""
from common.permissions import IsAppUser, IsOrgAdmin, IsValidUser, IsOrgAdminOrAppUser
from common.permissions import IsAppUser, IsOrgAdmin, IsValidUser, IsOrgAdminOrAppUser, NeedMFAVerify
from users.models import User, UserGroup

View File

@@ -0,0 +1,140 @@
# Generated by Django 2.2.13 on 2020-10-19 12:01
from django.db import migrations, models
import django.db.models.deletion
import django_mysql.models
import uuid
CATEGORY_DB_LIST = ['mysql', 'oracle', 'postgresql', 'mariadb']
CATEGORY_REMOTE_LIST = ['chrome', 'mysql_workbench', 'vmware_client', 'custom']
CATEGORY_CLOUD_LIST = ['k8s']
CATEGORY_DB = 'db'
CATEGORY_REMOTE = 'remote_app'
CATEGORY_CLOUD = 'cloud'
CATEGORY_LIST = [CATEGORY_DB, CATEGORY_REMOTE, CATEGORY_CLOUD]
def get_application_category(old_app):
_type = old_app.type
if _type in CATEGORY_DB_LIST:
category = CATEGORY_DB
elif _type in CATEGORY_REMOTE_LIST:
category = CATEGORY_REMOTE
elif _type in CATEGORY_CLOUD_LIST:
category = CATEGORY_CLOUD
else:
category = None
return category
def common_to_application_json(old_app):
category = get_application_category(old_app)
date_updated = old_app.date_updated if hasattr(old_app, 'date_updated') else old_app.date_created
return {
'id': old_app.id,
'name': old_app.name,
'type': old_app.type,
'category': category,
'comment': old_app.comment,
'created_by': old_app.created_by,
'date_created': old_app.date_created,
'date_updated': date_updated,
'org_id': old_app.org_id
}
def db_to_application_json(database):
app_json = common_to_application_json(database)
app_json.update({
'attrs': {
'host': database.host,
'port': database.port,
'database': database.database
}
})
return app_json
def remote_to_application_json(remote):
app_json = common_to_application_json(remote)
attrs = {
'asset': str(remote.asset.id),
'path': remote.path,
}
attrs.update(remote.params)
app_json.update({
'attrs': attrs
})
return app_json
def k8s_to_application_json(k8s):
app_json = common_to_application_json(k8s)
app_json.update({
'attrs': {
'cluster': k8s.cluster
}
})
return app_json
def migrate_and_integrate_applications(apps, schema_editor):
db_alias = schema_editor.connection.alias
database_app_model = apps.get_model("applications", "DatabaseApp")
remote_app_model = apps.get_model("applications", "RemoteApp")
k8s_app_model = apps.get_model("applications", "K8sApp")
database_apps = database_app_model.objects.using(db_alias).all()
remote_apps = remote_app_model.objects.using(db_alias).all()
k8s_apps = k8s_app_model.objects.using(db_alias).all()
database_applications = [db_to_application_json(db_app) for db_app in database_apps]
remote_applications = [remote_to_application_json(remote_app) for remote_app in remote_apps]
k8s_applications = [k8s_to_application_json(k8s_app) for k8s_app in k8s_apps]
applications_json = database_applications + remote_applications + k8s_applications
application_model = apps.get_model("applications", "Application")
applications = [
application_model(**application_json)
for application_json in applications_json
if application_json['category'] in CATEGORY_LIST
]
for application in applications:
if application_model.objects.using(db_alias).filter(name=application.name).exists():
application.name = '{}-{}'.format(application.name, application.type)
application.save()
class Migration(migrations.Migration):
dependencies = [
('assets', '0057_fill_node_value_assets_amount_and_parent_key'),
('applications', '0005_k8sapp'),
]
operations = [
migrations.CreateModel(
name='Application',
fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('category', models.CharField(choices=[('db', 'Database'), ('remote_app', 'Remote app'), ('cloud', 'Cloud')], max_length=16, verbose_name='Category')),
('type', models.CharField(choices=[('mysql', 'MySQL'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('mariadb', 'MariaDB'), ('chrome', 'Chrome'), ('mysql_workbench', 'MySQL Workbench'), ('vmware_client', 'vSphere Client'), ('custom', 'Custom'), ('k8s', 'Kubernetes')], max_length=16, verbose_name='Type')),
('attrs', django_mysql.models.JSONField(default=dict)),
('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')),
('domain', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='assets.Domain', verbose_name='Domain')),
],
options={
'ordering': ('name',),
'unique_together': {('org_id', 'name')},
},
),
migrations.RunPython(migrate_and_integrate_applications),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.1 on 2020-11-19 03:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('applications', '0006_application'),
]
operations = [
migrations.AlterField(
model_name='application',
name='attrs',
field=models.JSONField(),
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 3.1 on 2021-01-03 20:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('perms', '0017_auto_20210104_0435'),
('applications', '0007_auto_20201119_1110'),
]
operations = [
migrations.DeleteModel(
name='DatabaseApp',
),
migrations.DeleteModel(
name='K8sApp',
),
migrations.AlterField(
model_name='application',
name='attrs',
field=models.JSONField(default=dict, verbose_name='Attrs'),
),
migrations.DeleteModel(
name='RemoteApp',
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 3.1.6 on 2021-06-23 09:48
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('assets', '0070_auto_20210426_1515'),
('applications', '0008_auto_20210104_0435'),
]
operations = [
migrations.CreateModel(
name='ApplicationUser',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('assets.systemuser',),
),
]

View File

@@ -0,0 +1,76 @@
# Generated by Django 3.1.12 on 2021-08-26 09:07
import assets.models.base
import common.fields.model
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
import uuid
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0076_delete_assetuser'),
('applications', '0009_applicationuser'),
]
operations = [
migrations.CreateModel(
name='HistoricalAccount',
fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username')),
('password', common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
('private_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
('public_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
('date_created', models.DateTimeField(blank=True, editable=False, verbose_name='Date created')),
('date_updated', models.DateTimeField(blank=True, editable=False, verbose_name='Date updated')),
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
('version', models.IntegerField(default=1, verbose_name='Version')),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('app', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='applications.application', verbose_name='Database')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('systemuser', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='assets.systemuser', verbose_name='System user')),
],
options={
'verbose_name': 'historical Account',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='Account',
fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username')),
('password', common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
('private_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
('public_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
('version', models.IntegerField(default=1, verbose_name='Version')),
('app', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='applications.application', verbose_name='Database')),
('systemuser', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.systemuser', verbose_name='System user')),
],
options={
'verbose_name': 'Account',
'unique_together': {('username', 'app', 'systemuser')},
},
bases=(models.Model, assets.models.base.AuthMixin),
),
]

View File

@@ -0,0 +1,40 @@
# Generated by Django 3.1.12 on 2021-08-26 09:59
from django.db import migrations, transaction
from django.db.models import F
def migrate_app_account(apps, schema_editor):
db_alias = schema_editor.connection.alias
app_perm_model = apps.get_model("perms", "ApplicationPermission")
app_account_model = apps.get_model("applications", 'Account')
queryset = app_perm_model.objects \
.exclude(system_users__isnull=True) \
.exclude(applications__isnull=True) \
.annotate(systemuser=F('system_users')) \
.annotate(app=F('applications')) \
.values('app', 'systemuser', 'org_id')
accounts = []
for p in queryset:
if not p['app']:
continue
account = app_account_model(
app_id=p['app'], systemuser_id=p['systemuser'],
version=1, org_id=p['org_id']
)
accounts.append(account)
app_account_model.objects.using(db_alias).bulk_create(accounts, ignore_conflicts=True)
class Migration(migrations.Migration):
dependencies = [
('applications', '0010_appaccount_historicalappaccount'),
]
operations = [
migrations.RunPython(migrate_app_account)
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 3.1.13 on 2021-10-14 14:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('applications', '0011_auto_20210826_1759'),
]
operations = [
migrations.AlterField(
model_name='account',
name='username',
field=models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username'),
),
migrations.AlterField(
model_name='historicalaccount',
name='username',
field=models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username'),
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 3.1.13 on 2021-10-26 09:11
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('applications', '0012_auto_20211014_2209'),
]
operations = [
migrations.AlterModelOptions(
name='application',
options={'ordering': ('name',), 'verbose_name': 'Application'},
),
]

View File

@@ -1,3 +1,2 @@
from .remote_app import *
from .database_app import *
from .k8s_app import *
from .application import *
from .account import *

View File

@@ -0,0 +1,88 @@
from django.db import models
from simple_history.models import HistoricalRecords
from django.utils.translation import ugettext_lazy as _
from common.utils import lazyproperty
from assets.models.base import BaseUser
class Account(BaseUser):
app = models.ForeignKey('applications.Application', on_delete=models.CASCADE, null=True, verbose_name=_('Database'))
systemuser = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user"))
version = models.IntegerField(default=1, verbose_name=_('Version'))
history = HistoricalRecords()
auth_attrs = ['username', 'password', 'private_key', 'public_key']
class Meta:
verbose_name = _('Account')
unique_together = [('username', 'app', 'systemuser')]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.auth_snapshot = {}
def get_or_systemuser_attr(self, attr):
val = getattr(self, attr, None)
if val:
return val
if self.systemuser:
return getattr(self.systemuser, attr, '')
return ''
def load_auth(self):
for attr in self.auth_attrs:
value = self.get_or_systemuser_attr(attr)
self.auth_snapshot[attr] = [getattr(self, attr), value]
setattr(self, attr, value)
def unload_auth(self):
if not self.systemuser:
return
for attr, values in self.auth_snapshot.items():
origin_value, loaded_value = values
current_value = getattr(self, attr, '')
if current_value == loaded_value:
setattr(self, attr, origin_value)
def save(self, *args, **kwargs):
self.unload_auth()
instance = super().save(*args, **kwargs)
self.load_auth()
return instance
@lazyproperty
def category(self):
return self.app.category
@lazyproperty
def type(self):
return self.app.type
@lazyproperty
def app_display(self):
return self.systemuser.name
@property
def username_display(self):
return self.get_or_systemuser_attr('username') or ''
@lazyproperty
def systemuser_display(self):
if not self.systemuser:
return ''
return str(self.systemuser)
@property
def smart_name(self):
username = self.username_display
if self.app:
app = str(self.app)
else:
app = '*'
return '{}@{}'.format(username, app)
def __str__(self):
return self.smart_name

View File

@@ -0,0 +1,231 @@
from collections import defaultdict
from django.db import models
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.models import OrgModelMixin
from common.mixins import CommonModelMixin
from common.tree import TreeNode
from assets.models import Asset, SystemUser
from .. import const
class ApplicationTreeNodeMixin:
id: str
name: str
type: str
category: str
@classmethod
def create_choice_node(cls, c, id_, pid, tp, opened=False, counts=None,
show_empty=True, show_count=True):
count = counts.get(c.value, 0)
if count == 0 and not show_empty:
return None
label = c.label
if count is not None and show_count:
label = '{} ({})'.format(label, count)
data = {
'id': id_,
'name': label,
'title': label,
'pId': pid,
'isParent': bool(count),
'open': opened,
'iconSkin': '',
'meta': {
'type': tp,
'data': {
'name': c.name,
'value': c.value
}
}
}
return TreeNode(**data)
@classmethod
def create_root_tree_node(cls, queryset, show_count=True):
count = queryset.count() if show_count else None
root_id = 'applications'
root_name = _('Applications')
if count is not None and show_count:
root_name = '{} ({})'.format(root_name, count)
node = TreeNode(**{
'id': root_id,
'name': root_name,
'title': root_name,
'pId': '',
'isParent': True,
'open': True,
'iconSkin': '',
'meta': {
'type': 'applications_root',
}
})
return node
@classmethod
def create_category_tree_nodes(cls, root_node, counts=None, show_empty=True, show_count=True):
nodes = []
categories = const.AppType.category_types_mapper().keys()
for category in categories:
i = root_node.id + '_' + category.value
node = cls.create_choice_node(
category, i, pid=root_node.id, tp='category',
counts=counts, opened=False, show_empty=show_empty,
show_count=show_count
)
if not node:
continue
nodes.append(node)
return nodes
@classmethod
def create_types_tree_nodes(cls, root_node, counts, show_empty=True, show_count=True):
nodes = []
type_category_mapper = const.AppType.type_category_mapper()
for tp in const.AppType.type_category_mapper().keys():
category = type_category_mapper.get(tp)
pid = root_node.id + '_' + category.value
i = root_node.id + '_' + tp.value
node = cls.create_choice_node(
tp, i, pid, tp='type', counts=counts, opened=False,
show_empty=show_empty, show_count=show_count
)
if not node:
continue
nodes.append(node)
return nodes
@staticmethod
def get_tree_node_counts(queryset):
counts = defaultdict(int)
values = queryset.values_list('type', 'category')
for i in values:
tp = i[0]
category = i[1]
counts[tp] += 1
counts[category] += 1
return counts
@classmethod
def create_tree_nodes(cls, queryset, root_node=None, show_empty=True, show_count=True):
counts = cls.get_tree_node_counts(queryset)
tree_nodes = []
# 根节点有可能是组织名称
if root_node is None:
root_node = cls.create_root_tree_node(queryset, show_count=show_count)
tree_nodes.append(root_node)
# 类别的节点
tree_nodes += cls.create_category_tree_nodes(
root_node, counts, show_empty=show_empty,
show_count=show_count
)
# 类型的节点
tree_nodes += cls.create_types_tree_nodes(
root_node, counts, show_empty=show_empty,
show_count=show_count
)
# 应用的节点
for app in queryset:
pid = root_node.id + '_' + app.type
tree_nodes.append(app.as_tree_node(pid))
return tree_nodes
def as_tree_node(self, pid):
icon_skin_category_mapper = {
'remote_app': 'chrome',
'db': 'database',
'cloud': 'cloud'
}
icon_skin = icon_skin_category_mapper.get(self.category, 'file')
node = TreeNode(**{
'id': str(self.id),
'name': self.name,
'title': self.name,
'pId': pid,
'isParent': False,
'open': False,
'iconSkin': icon_skin,
'meta': {
'type': 'application',
'data': {
'category': self.category,
'type': self.type,
}
}
})
return node
class Application(CommonModelMixin, OrgModelMixin, ApplicationTreeNodeMixin):
name = models.CharField(max_length=128, verbose_name=_('Name'))
category = models.CharField(
max_length=16, choices=const.AppCategory.choices, verbose_name=_('Category')
)
type = models.CharField(
max_length=16, choices=const.AppType.choices, verbose_name=_('Type')
)
domain = models.ForeignKey(
'assets.Domain', null=True, blank=True, related_name='applications',
on_delete=models.SET_NULL, verbose_name=_("Domain"),
)
attrs = models.JSONField(default=dict, verbose_name=_('Attrs'))
comment = models.TextField(
max_length=128, default='', blank=True, verbose_name=_('Comment')
)
class Meta:
verbose_name = _('Application')
unique_together = [('org_id', 'name')]
ordering = ('name',)
def __str__(self):
category_display = self.get_category_display()
type_display = self.get_type_display()
return f'{self.name}({type_display})[{category_display}]'
@property
def category_remote_app(self):
return self.category == const.AppCategory.remote_app.value
def get_rdp_remote_app_setting(self):
from applications.serializers.attrs import get_serializer_class_by_application_type
if not self.category_remote_app:
raise ValueError(f"Not a remote app application: {self.name}")
serializer_class = get_serializer_class_by_application_type(self.type)
fields = serializer_class().get_fields()
parameters = [self.type]
for field_name in list(fields.keys()):
if field_name in ['asset']:
continue
value = self.attrs.get(field_name)
if not value:
continue
if field_name == 'path':
value = '\"%s\"' % value
parameters.append(str(value))
parameters = ' '.join(parameters)
return {
'program': '||jmservisor',
'working_directory': '',
'parameters': parameters
}
def get_remote_app_asset(self):
asset_id = self.attrs.get('asset')
if not asset_id:
raise ValueError("Remote App not has asset attr")
asset = Asset.objects.filter(id=asset_id).first()
return asset
class ApplicationUser(SystemUser):
class Meta:
proxy = True

View File

@@ -1,42 +0,0 @@
# coding: utf-8
#
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.models import OrgModelMixin
from common.mixins import CommonModelMixin
from .. import const
__all__ = ['DatabaseApp']
class DatabaseApp(CommonModelMixin, OrgModelMixin):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, verbose_name=_('Name'))
type = models.CharField(
default=const.DATABASE_APP_TYPE_MYSQL,
choices=const.DATABASE_APP_TYPE_CHOICES,
max_length=128, verbose_name=_('Type')
)
host = models.CharField(
max_length=128, verbose_name=_('Host'), db_index=True
)
port = models.IntegerField(default=3306, verbose_name=_('Port'))
database = models.CharField(
max_length=128, blank=True, null=True, verbose_name=_('Database'),
db_index=True
)
comment = models.TextField(
max_length=128, default='', blank=True, verbose_name=_('Comment')
)
def __str__(self):
return self.name
class Meta:
unique_together = [('org_id', 'name'), ]
verbose_name = _("DatabaseApp")
ordering = ('name', )

View File

@@ -1,27 +0,0 @@
from django.utils.translation import gettext_lazy as _
from common.db import models
from orgs.mixins.models import OrgModelMixin
class K8sApp(OrgModelMixin, models.JMSModel):
class TYPE(models.ChoiceSet):
K8S = 'k8s', _('Kubernetes')
name = models.CharField(max_length=128, verbose_name=_('Name'))
type = models.CharField(
default=TYPE.K8S, choices=TYPE.choices,
max_length=128, verbose_name=_('Type')
)
cluster = models.CharField(max_length=1024, verbose_name=_('Cluster'))
comment = models.TextField(
max_length=128, default='', blank=True, verbose_name=_('Comment')
)
def __str__(self):
return self.name
class Meta:
unique_together = [('org_id', 'name'), ]
verbose_name = _('KubernetesApp')
ordering = ('name', )

View File

@@ -1,78 +0,0 @@
# coding: utf-8
#
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.models import OrgModelMixin
from common.fields.model import EncryptJsonDictTextField
from .. import const
__all__ = [
'RemoteApp',
]
class RemoteApp(OrgModelMixin):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, verbose_name=_('Name'))
asset = models.ForeignKey(
'assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset')
)
type = models.CharField(
default=const.REMOTE_APP_TYPE_CHROME,
choices=const.REMOTE_APP_TYPE_CHOICES,
max_length=128, verbose_name=_('App type')
)
path = models.CharField(
max_length=128, blank=False, null=False,
verbose_name=_('App path')
)
params = EncryptJsonDictTextField(
max_length=4096, default={}, blank=True, null=True,
verbose_name=_('Parameters')
)
created_by = models.CharField(
max_length=32, null=True, blank=True, verbose_name=_('Created by')
)
date_created = models.DateTimeField(
auto_now_add=True, null=True, blank=True, verbose_name=_('Date created')
)
comment = models.TextField(
max_length=128, default='', blank=True, verbose_name=_('Comment')
)
class Meta:
verbose_name = _("RemoteApp")
unique_together = [('org_id', 'name')]
ordering = ('name', )
def __str__(self):
return self.name
@property
def parameters(self):
"""
返回Guacamole需要的RemoteApp配置参数信息中的parameters参数
"""
_parameters = list()
_parameters.append(self.type)
path = '\"%s\"' % self.path
_parameters.append(path)
for field in const.REMOTE_APP_TYPE_FIELDS_MAP[self.type]:
value = self.params.get(field['name'])
if value is None:
continue
_parameters.append(value)
_parameters = ' '.join(_parameters)
return _parameters
@property
def asset_info(self):
return {
'id': self.asset.id,
'hostname': self.asset.hostname
}

View File

@@ -0,0 +1,9 @@
from rest_framework import permissions
__all__ = ['IsRemoteApp']
class IsRemoteApp(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.category_remote_app

View File

@@ -1,3 +1,2 @@
from .application import *
from .remote_app import *
from .database_app import *
from .k8s_app import *

View File

@@ -0,0 +1,140 @@
# coding: utf-8
#
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from assets.serializers.base import AuthSerializerMixin
from common.drf.serializers import MethodSerializer
from .attrs import (
category_serializer_classes_mapping,
type_serializer_classes_mapping
)
from .. import models
from .. import const
__all__ = [
'AppSerializer', 'MiniAppSerializer', 'AppSerializerMixin',
'AppAccountSerializer', 'AppAccountSecretSerializer'
]
class AppSerializerMixin(serializers.Serializer):
attrs = MethodSerializer()
def get_attrs_serializer(self):
default_serializer = serializers.Serializer(read_only=True)
if isinstance(self.instance, models.Application):
_type = self.instance.type
_category = self.instance.category
else:
_type = self.context['request'].query_params.get('type')
_category = self.context['request'].query_params.get('category')
if _type:
serializer_class = type_serializer_classes_mapping.get(_type)
elif _category:
serializer_class = category_serializer_classes_mapping.get(_category)
else:
serializer_class = default_serializer
if not serializer_class:
serializer_class = default_serializer
if isinstance(serializer_class, type):
serializer = serializer_class()
else:
serializer = serializer_class
return serializer
def create(self, validated_data):
return super().create(validated_data)
def update(self, instance, validated_data):
return super().update(instance, validated_data)
class AppSerializer(AppSerializerMixin, BulkOrgResourceModelSerializer):
category_display = serializers.ReadOnlyField(source='get_category_display', label=_('Category display'))
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display'))
class Meta:
model = models.Application
fields_mini = ['id', 'name']
fields_small = fields_mini + [
'category', 'category_display', 'type', 'type_display',
'attrs', 'date_created', 'date_updated', 'created_by', 'comment'
]
fields_fk = ['domain']
fields = fields_small + fields_fk
read_only_fields = [
'created_by', 'date_created', 'date_updated', 'get_type_display',
]
def validate_attrs(self, attrs):
_attrs = self.instance.attrs if self.instance else {}
_attrs.update(attrs)
return _attrs
class MiniAppSerializer(serializers.ModelSerializer):
class Meta:
model = models.Application
fields = AppSerializer.Meta.fields_mini
class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
category = serializers.ChoiceField(label=_('Category'), choices=const.AppCategory.choices, read_only=True)
category_display = serializers.SerializerMethodField(label=_('Category display'))
type = serializers.ChoiceField(label=_('Type'), choices=const.AppType.choices, read_only=True)
type_display = serializers.SerializerMethodField(label=_('Type display'))
category_mapper = dict(const.AppCategory.choices)
type_mapper = dict(const.AppType.choices)
class Meta:
model = models.Account
fields_mini = ['id', 'username', 'version']
fields_write_only = ['password', 'private_key']
fields_fk = ['systemuser', 'systemuser_display', 'app', 'app_display']
fields = fields_mini + fields_fk + fields_write_only + [
'type', 'type_display', 'category', 'category_display',
]
extra_kwargs = {
'username': {'default': '', 'required': False},
'password': {'write_only': True},
'app_display': {'label': _('Application display')},
'systemuser_display': {'label': _('System User')}
}
use_model_bulk_create = True
model_bulk_create_kwargs = {
'ignore_conflicts': True
}
def get_category_display(self, obj):
return self.category_mapper.get(obj.category)
def get_type_display(self, obj):
return self.type_mapper.get(obj.type)
@classmethod
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('systemuser', 'app')
return queryset
def to_representation(self, instance):
instance.load_auth()
return super().to_representation(instance)
class AppAccountSecretSerializer(AppAccountSerializer):
class Meta(AppAccountSerializer.Meta):
extra_kwargs = {
'password': {'write_only': False},
'private_key': {'write_only': False},
'public_key': {'write_only': False},
'app_display': {'label': _('Application display')},
'systemuser_display': {'label': _('System User')}
}

View File

@@ -0,0 +1 @@
from .attrs import *

View File

@@ -0,0 +1,3 @@
from .remote_app import *
from .db import *
from .cloud import *

View File

@@ -0,0 +1,9 @@
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
__all__ = ['CloudSerializer']
class CloudSerializer(serializers.Serializer):
cluster = serializers.CharField(max_length=1024, label=_('Cluster'), allow_null=True)

View File

@@ -0,0 +1,15 @@
# coding: utf-8
#
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
__all__ = ['DBSerializer']
class DBSerializer(serializers.Serializer):
host = serializers.CharField(max_length=128, label=_('Host'), allow_null=True)
port = serializers.IntegerField(label=_('Port'), allow_null=True)
database = serializers.CharField(
max_length=128, required=True, allow_null=True, label=_('Database')
)

View File

@@ -0,0 +1,61 @@
# coding: utf-8
#
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from common.utils import get_logger, is_uuid, get_object_or_none
from assets.models import Asset
logger = get_logger(__file__)
__all__ = ['RemoteAppSerializer']
class ExistAssetPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def to_internal_value(self, data):
instance = super().to_internal_value(data)
return str(instance.id)
def to_representation(self, _id):
# _id 是 instance.id
if self.pk_field is not None:
return self.pk_field.to_representation(_id)
# 解决删除资产后远程应用更新页面会显示资产ID的问题
asset = get_object_or_none(Asset, id=_id)
if not asset:
return None
return _id
class RemoteAppSerializer(serializers.Serializer):
asset_info = serializers.SerializerMethodField()
asset = ExistAssetPrimaryKeyRelatedField(
queryset=Asset.objects, required=True, label=_("Asset"), allow_null=True
)
path = serializers.CharField(
max_length=128, label=_('Application path'), allow_null=True
)
def validate_asset(self, asset):
if not asset:
raise serializers.ValidationError(_('This field is required.'))
return asset
@staticmethod
def get_asset_info(obj):
asset_id = obj.get('asset')
if not asset_id or not is_uuid(asset_id):
return {}
try:
asset = Asset.objects.get(id=str(asset_id))
except ObjectDoesNotExist as e:
logger.error(e)
return {}
if not asset:
return {}
asset_info = {'id': str(asset.id), 'hostname': asset.hostname}
return asset_info

View File

@@ -0,0 +1,12 @@
from .mysql import *
from .mariadb import *
from .oracle import *
from .pgsql import *
from .chrome import *
from .mysql_workbench import *
from .vmware_client import *
from .custom import *
from .k8s import *

View File

@@ -0,0 +1,26 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from ..application_category import RemoteAppSerializer
__all__ = ['ChromeSerializer']
class ChromeSerializer(RemoteAppSerializer):
CHROME_PATH = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
path = serializers.CharField(
max_length=128, label=_('Application path'), default=CHROME_PATH, allow_null=True,
)
chrome_target = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Target URL'), allow_null=True,
)
chrome_username = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Username'), allow_null=True,
)
chrome_password = serializers.CharField(
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
allow_null=True
)

View File

@@ -0,0 +1,27 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from ..application_category import RemoteAppSerializer
__all__ = ['CustomSerializer']
class CustomSerializer(RemoteAppSerializer):
custom_cmdline = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Operating parameter'),
allow_null=True,
)
custom_target = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Target url'),
allow_null=True,
)
custom_username = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Username'),
allow_null=True,
)
custom_password = serializers.CharField(
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
allow_null=True,
)

View File

@@ -0,0 +1,8 @@
from ..application_category import CloudSerializer
__all__ = ['K8SSerializer']
class K8SSerializer(CloudSerializer):
pass

View File

@@ -0,0 +1,8 @@
from .mysql import MySQLSerializer
__all__ = ['MariaDBSerializer']
class MariaDBSerializer(MySQLSerializer):
pass

View File

@@ -0,0 +1,15 @@
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from ..application_category import DBSerializer
__all__ = ['MySQLSerializer']
class MySQLSerializer(DBSerializer):
port = serializers.IntegerField(default=3306, label=_('Port'), allow_null=True)

View File

@@ -0,0 +1,36 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from ..application_category import RemoteAppSerializer
__all__ = ['MySQLWorkbenchSerializer']
class MySQLWorkbenchSerializer(RemoteAppSerializer):
MYSQL_WORKBENCH_PATH = 'C:\Program Files\MySQL\MySQL Workbench 8.0 CE\MySQLWorkbench.exe'
path = serializers.CharField(
max_length=128, label=_('Application path'), default=MYSQL_WORKBENCH_PATH,
allow_null=True,
)
mysql_workbench_ip = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('IP'),
allow_null=True,
)
mysql_workbench_port = serializers.IntegerField(
required=False, label=_('Port'),
allow_null=True,
)
mysql_workbench_name = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Database'),
allow_null=True,
)
mysql_workbench_username = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Username'),
allow_null=True,
)
mysql_workbench_password = serializers.CharField(
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
allow_null=True,
)

View File

@@ -0,0 +1,12 @@
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from ..application_category import DBSerializer
__all__ = ['OracleSerializer']
class OracleSerializer(DBSerializer):
port = serializers.IntegerField(default=1521, label=_('Port'), allow_null=True)

View File

@@ -0,0 +1,12 @@
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from ..application_category import DBSerializer
__all__ = ['PostgreSerializer']
class PostgreSerializer(DBSerializer):
port = serializers.IntegerField(default=5432, label=_('Port'), allow_null=True)

View File

@@ -0,0 +1,32 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from ..application_category import RemoteAppSerializer
__all__ = ['VMwareClientSerializer']
class VMwareClientSerializer(RemoteAppSerializer):
PATH = r'''
C:\Program Files (x86)\VMware\Infrastructure\Virtual Infrastructure Client\Launcher\VpxClient
.exe
'''
VMWARE_CLIENT_PATH = ''.join(PATH.split())
path = serializers.CharField(
max_length=128, label=_('Application path'), default=VMWARE_CLIENT_PATH,
allow_null=True
)
vmware_target = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Target URL'),
allow_null=True
)
vmware_username = serializers.CharField(
max_length=128, allow_blank=True, required=False, label=_('Username'),
allow_null=True
)
vmware_password = serializers.CharField(
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
allow_null=True
)

View File

@@ -0,0 +1,42 @@
from rest_framework import serializers
from applications import const
from . import application_category, application_type
__all__ = [
'category_serializer_classes_mapping',
'type_serializer_classes_mapping',
'get_serializer_class_by_application_type',
]
# define `attrs` field `category serializers mapping`
# ---------------------------------------------------
category_serializer_classes_mapping = {
const.AppCategory.db.value: application_category.DBSerializer,
const.AppCategory.remote_app.value: application_category.RemoteAppSerializer,
const.AppCategory.cloud.value: application_category.CloudSerializer,
}
# define `attrs` field `type serializers mapping`
# -----------------------------------------------
type_serializer_classes_mapping = {
# db
const.AppType.mysql.value: application_type.MySQLSerializer,
const.AppType.mariadb.value: application_type.MariaDBSerializer,
const.AppType.oracle.value: application_type.OracleSerializer,
const.AppType.pgsql.value: application_type.PostgreSerializer,
# remote-app
const.AppType.chrome.value: application_type.ChromeSerializer,
const.AppType.mysql_workbench.value: application_type.MySQLWorkbenchSerializer,
const.AppType.vmware_client.value: application_type.VMwareClientSerializer,
const.AppType.custom.value: application_type.CustomSerializer,
# cloud
const.AppType.k8s.value: application_type.K8SSerializer
}
def get_serializer_class_by_application_type(_application_type):
return type_serializer_classes_mapping.get(_application_type)

View File

@@ -1,26 +0,0 @@
# coding: utf-8
#
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from common.serializers import AdaptedBulkListSerializer
from .. import models
__all__ = [
'DatabaseAppSerializer',
]
class DatabaseAppSerializer(BulkOrgResourceModelSerializer):
class Meta:
model = models.DatabaseApp
list_serializer_class = AdaptedBulkListSerializer
fields = [
'id', 'name', 'type', 'get_type_display', 'host', 'port',
'database', 'comment', 'created_by', 'date_created', 'date_updated',
]
read_only_fields = [
'created_by', 'date_created', 'date_updated'
'get_type_display',
]

View File

@@ -1,22 +0,0 @@
from rest_framework import serializers
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from .. import models
__all__ = [
'K8sAppSerializer',
]
class K8sAppSerializer(BulkOrgResourceModelSerializer):
type_display = serializers.CharField(source='get_type_display', read_only=True)
class Meta:
model = models.K8sApp
fields = [
'id', 'name', 'type', 'type_display', 'comment', 'created_by',
'date_created', 'date_updated', 'cluster'
]
read_only_fields = [
'id', 'created_by', 'date_created', 'date_updated',
]

View File

@@ -1,86 +1,31 @@
# coding: utf-8
#
import copy
from rest_framework import serializers
from common.serializers import AdaptedBulkListSerializer
from common.fields.serializer import CustomMetaDictField
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from .. import const
from ..models import RemoteApp
from common.utils import get_logger
from ..models import Application
__all__ = [
'RemoteAppSerializer', 'RemoteAppConnectionInfoSerializer',
]
logger = get_logger(__file__)
class RemoteAppParamsDictField(CustomMetaDictField):
type_fields_map = const.REMOTE_APP_TYPE_FIELDS_MAP
default_type = const.REMOTE_APP_TYPE_CHROME
convert_key_remove_type_prefix = False
convert_key_to_upper = False
class RemoteAppSerializer(BulkOrgResourceModelSerializer):
params = RemoteAppParamsDictField()
type_fields_map = const.REMOTE_APP_TYPE_FIELDS_MAP
class Meta:
model = RemoteApp
list_serializer_class = AdaptedBulkListSerializer
fields = [
'id', 'name', 'asset', 'asset_info', 'type', 'get_type_display',
'path', 'params', 'date_created', 'created_by', 'comment',
]
read_only_fields = [
'created_by', 'date_created', 'asset_info',
'get_type_display'
]
def process_params(self, instance, validated_data):
new_params = copy.deepcopy(validated_data.get('params', {}))
tp = validated_data.get('type', '')
if tp != instance.type:
return new_params
old_params = instance.params
fields = self.type_fields_map.get(instance.type, [])
for field in fields:
if not field.get('write_only', False):
continue
field_name = field['name']
new_value = new_params.get(field_name, '')
old_value = old_params.get(field_name, '')
field_value = new_value if new_value else old_value
new_params[field_name] = field_value
return new_params
def update(self, instance, validated_data):
params = self.process_params(instance, validated_data)
validated_data['params'] = params
return super().update(instance, validated_data)
__all__ = ['RemoteAppConnectionInfoSerializer']
class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer):
parameter_remote_app = serializers.SerializerMethodField()
asset = serializers.SerializerMethodField()
class Meta:
model = RemoteApp
model = Application
fields = [
'id', 'name', 'asset', 'parameter_remote_app',
]
read_only_fields = ['parameter_remote_app']
@staticmethod
def get_asset(obj):
return obj.attrs.get('asset')
@staticmethod
def get_parameter_remote_app(obj):
parameter = {
'program': const.REMOTE_APP_BOOT_PROGRAM_NAME,
'working_directory': '',
'parameters': obj.parameters,
}
return parameter
return obj.get_rdp_remote_app_setting()

View File

@@ -1,25 +1,24 @@
# coding:utf-8
#
from django.urls import path, re_path
from django.urls import path
from rest_framework_bulk.routes import BulkRouter
from common import api as capi
from .. import api
app_name = 'applications'
router = BulkRouter()
router.register(r'remote-apps', api.RemoteAppViewSet, 'remote-app')
router.register(r'database-apps', api.DatabaseAppViewSet, 'database-app')
router.register(r'k8s-apps', api.K8sAppViewSet, 'k8s-app')
router.register(r'applications', api.ApplicationViewSet, 'application')
router.register(r'accounts', api.ApplicationAccountViewSet, 'application-account')
router.register(r'account-secrets', api.ApplicationAccountSecretViewSet, 'application-account-secret')
urlpatterns = [
path('remote-apps/<uuid:pk>/connection-info/', api.RemoteAppConnectionInfoApi.as_view(), name='remote-app-connection-info'),
# path('accounts/', api.ApplicationAccountViewSet.as_view(), name='application-account'),
# path('account-secrets/', api.ApplicationAccountSecretViewSet.as_view(), name='application-account-secret')
]
old_version_urlpatterns = [
re_path('(?P<resource>remote-app)/.*', capi.redirect_plural_name_api)
]
urlpatterns += router.urls + old_version_urlpatterns
urlpatterns += router.urls

View File

@@ -1,7 +0,0 @@
# coding:utf-8
from django.urls import path
app_name = 'applications'
urlpatterns = [
]

View File

@@ -4,9 +4,9 @@ from .asset import *
from .label import *
from .system_user import *
from .system_user_relation import *
from .accounts import *
from .node import *
from .domain import *
from .cmd_filter import *
from .asset_user import *
from .gathered_user import *
from .favorite_asset import *

114
apps/assets/api/accounts.py Normal file
View File

@@ -0,0 +1,114 @@
from django.db.models import F, Q
from rest_framework.decorators import action
from django_filters import rest_framework as filters
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from rest_framework.generics import CreateAPIView
from orgs.mixins.api import OrgBulkModelViewSet
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser, NeedMFAVerify
from common.drf.filters import BaseFilterSet
from ..tasks.account_connectivity import test_accounts_connectivity_manual
from ..models import AuthBook, Node
from .. import serializers
__all__ = ['AccountViewSet', 'AccountSecretsViewSet', 'AccountTaskCreateAPI']
class AccountFilterSet(BaseFilterSet):
username = filters.CharFilter(method='do_nothing')
ip = filters.CharFilter(field_name='ip', lookup_expr='exact')
hostname = filters.CharFilter(field_name='hostname', lookup_expr='exact')
node = filters.CharFilter(method='do_nothing')
@property
def qs(self):
qs = super().qs
qs = self.filter_username(qs)
qs = self.filter_node(qs)
return qs
def filter_username(self, qs):
username = self.get_query_param('username')
if not username:
return qs
qs = qs.filter(Q(username=username) | Q(systemuser__username=username)).distinct()
return qs
def filter_node(self, qs):
node_id = self.get_query_param('node')
if not node_id:
return qs
node = get_object_or_404(Node, pk=node_id)
node_ids = node.get_all_children(with_self=True).values_list('id', flat=True)
node_ids = list(node_ids)
qs = qs.filter(asset__nodes__in=node_ids)
return qs
class Meta:
model = AuthBook
fields = [
'asset', 'systemuser', 'id',
]
class AccountViewSet(OrgBulkModelViewSet):
model = AuthBook
filterset_fields = ("username", "asset", "systemuser", 'ip', 'hostname')
search_fields = ('username', 'ip', 'hostname', 'systemuser__username')
filterset_class = AccountFilterSet
serializer_classes = {
'default': serializers.AccountSerializer,
'verify_account': serializers.AssetTaskSerializer
}
permission_classes = (IsOrgAdmin,)
def get_queryset(self):
queryset = super().get_queryset() \
.annotate(ip=F('asset__ip')) \
.annotate(hostname=F('asset__hostname'))
return queryset
@action(methods=['post'], detail=True, url_path='verify')
def verify_account(self, request, *args, **kwargs):
account = super().get_object()
task = test_accounts_connectivity_manual.delay([account])
return Response(data={'task': task.id})
class AccountSecretsViewSet(AccountViewSet):
"""
因为可能要导出所有账号,所以单独建立了一个 viewset
"""
serializer_classes = {
'default': serializers.AccountSecretSerializer
}
permission_classes = (IsOrgAdmin, NeedMFAVerify)
http_method_names = ['get']
class AccountTaskCreateAPI(CreateAPIView):
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.AccountTaskSerializer
filterset_fields = AccountViewSet.filterset_fields
search_fields = AccountViewSet.search_fields
filterset_class = AccountViewSet.filterset_class
def get_accounts(self):
queryset = AuthBook.objects.all()
queryset = self.filter_queryset(queryset)
return queryset
def perform_create(self, serializer):
accounts = self.get_accounts()
task = test_accounts_connectivity_manual.delay(accounts)
data = getattr(serializer, '_data', {})
data["task"] = task.id
setattr(serializer, '_data', data)
return task
def get_exception_handler(self):
def handler(e, context):
return Response({"error": str(e)}, status=400)
return handler

View File

@@ -1,106 +1,30 @@
from django.db import transaction
from django.db.models import Count
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext as _
from rest_framework import status
from rest_framework.response import Response
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.mixins import generics
from orgs.mixins.api import OrgBulkModelViewSet
from common.utils import get_logger
from ..hands import IsOrgAdmin
from ..models import AdminUser, Asset
from ..models import SystemUser
from .. import serializers
from ..tasks import test_admin_user_connectivity_manual
logger = get_logger(__file__)
__all__ = [
'AdminUserViewSet', 'ReplaceNodesAdminUserApi',
'AdminUserTestConnectiveApi', 'AdminUserAuthApi',
'AdminUserAssetsListView',
]
__all__ = ['AdminUserViewSet']
# 兼容一下老的 api
class AdminUserViewSet(OrgBulkModelViewSet):
"""
Admin user api set, for add,delete,update,list,retrieve resource
"""
model = AdminUser
filter_fields = ("name", "username")
search_fields = filter_fields
model = SystemUser
filterset_fields = ("name", "username")
search_fields = filterset_fields
serializer_class = serializers.AdminUserSerializer
permission_classes = (IsOrgAdmin,)
ordering_fields = ('name',)
ordering = ('name', )
def get_queryset(self):
queryset = super().get_queryset()
queryset = super().get_queryset().filter(type=SystemUser.Type.admin)
queryset = queryset.annotate(assets_amount=Count('assets'))
return queryset
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
has_related_asset = instance.assets.exists()
if has_related_asset:
data = {'msg': _('Deleted failed, There are related assets')}
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
return super().destroy(request, *args, **kwargs)
class AdminUserAuthApi(generics.UpdateAPIView):
model = AdminUser
serializer_class = serializers.AdminUserAuthSerializer
permission_classes = (IsOrgAdmin,)
class ReplaceNodesAdminUserApi(generics.UpdateAPIView):
model = AdminUser
serializer_class = serializers.ReplaceNodeAdminUserSerializer
permission_classes = (IsOrgAdmin,)
def update(self, request, *args, **kwargs):
admin_user = self.get_object()
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
nodes = serializer.validated_data['nodes']
assets = []
for node in nodes:
assets.extend([asset.id for asset in node.get_all_assets()])
with transaction.atomic():
Asset.objects.filter(id__in=assets).update(admin_user=admin_user)
return Response({"msg": "ok"})
else:
return Response({'error': serializer.errors}, status=400)
class AdminUserTestConnectiveApi(generics.RetrieveAPIView):
"""
Test asset admin user assets_connectivity
"""
model = AdminUser
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.TaskIDSerializer
def retrieve(self, request, *args, **kwargs):
admin_user = self.get_object()
task = test_admin_user_connectivity_manual.delay(admin_user)
return Response({"task": task.id})
class AdminUserAssetsListView(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.AssetSimpleSerializer
filter_fields = ("hostname", "ip")
http_method_names = ['get']
search_fields = filter_fields
def get_object(self):
pk = self.kwargs.get('pk')
return get_object_or_404(AdminUser, pk=pk)
def get_queryset(self):
admin_user = self.get_object()
return admin_user.get_related_assets()

View File

@@ -2,43 +2,58 @@
#
from assets.api import FilterAssetByNodeMixin
from rest_framework.viewsets import ModelViewSet
from rest_framework.generics import RetrieveAPIView
from rest_framework.generics import RetrieveAPIView, ListAPIView
from django.shortcuts import get_object_or_404
from django.db.models import Q
from common.utils import get_logger, get_object_or_none
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser, IsSuperUser
from common.mixins.api import SuggestionMixin
from users.models import User, UserGroup
from users.serializers import UserSerializer, UserGroupSerializer
from users.filters import UserFilter
from perms.models import AssetPermission
from perms.serializers import AssetPermissionSerializer
from perms.filters import AssetPermissionFilter
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.mixins import generics
from ..models import Asset, Node, Platform
from .. import serializers
from ..tasks import (
update_asset_hardware_info_manual, test_asset_connectivity_manual
update_assets_hardware_info_manual, test_assets_connectivity_manual,
test_system_users_connectivity_a_asset, push_system_users_a_asset
)
from ..filters import FilterAssetByNodeFilterBackend, LabelFilterBackend, IpInFilterBackend
logger = get_logger(__file__)
__all__ = [
'AssetViewSet', 'AssetPlatformRetrieveApi',
'AssetGatewayListApi', 'AssetPlatformViewSet',
'AssetTaskCreateApi',
'AssetTaskCreateApi', 'AssetsTaskCreateApi',
'AssetPermUserListApi', 'AssetPermUserPermissionsListApi',
'AssetPermUserGroupListApi', 'AssetPermUserGroupPermissionsListApi',
]
class AssetViewSet(FilterAssetByNodeMixin, OrgBulkModelViewSet):
class AssetViewSet(SuggestionMixin, FilterAssetByNodeMixin, OrgBulkModelViewSet):
"""
API endpoint that allows Asset to be viewed or edited.
"""
model = Asset
filter_fields = (
"hostname", "ip", "systemuser__id", "admin_user__id", "platform__base",
"is_active", 'ip'
)
filterset_fields = {
'hostname': ['exact'],
'ip': ['exact'],
'system_users__id': ['exact'],
'platform__base': ['exact'],
'is_active': ['exact'],
'protocols': ['exact', 'icontains']
}
search_fields = ("hostname", "ip")
ordering_fields = ("hostname", "ip", "port", "cpu_cores")
ordering = ('hostname', )
serializer_classes = {
'default': serializers.AssetSerializer,
'display': serializers.AssetDisplaySerializer,
'suggestion': serializers.MiniAssetSerializer
}
permission_classes = (IsOrgAdminOrAppUser,)
extra_filter_backends = [FilterAssetByNodeFilterBackend, LabelFilterBackend, IpInFilterBackend]
@@ -74,7 +89,7 @@ class AssetPlatformViewSet(ModelViewSet):
queryset = Platform.objects.all()
permission_classes = (IsSuperUser,)
serializer_class = serializers.PlatformSerializer
filter_fields = ['name', 'base']
filterset_fields = ['name', 'base']
search_fields = ['name']
def get_permissions(self):
@@ -90,32 +105,73 @@ class AssetPlatformViewSet(ModelViewSet):
return super().check_object_permissions(request, obj)
class AssetTaskCreateApi(generics.CreateAPIView):
model = Asset
serializer_class = serializers.AssetTaskSerializer
permission_classes = (IsOrgAdmin,)
class AssetsTaskMixin:
def get_object(self):
pk = self.kwargs.get("pk")
instance = get_object_or_404(Asset, pk=pk)
return instance
def perform_assets_task(self, serializer):
data = serializer.validated_data
action = data['action']
assets = data.get('assets', [])
if action == "refresh":
task = update_assets_hardware_info_manual.delay(assets)
else:
# action == 'test':
task = test_assets_connectivity_manual.delay(assets)
return task
def perform_create(self, serializer):
asset = self.get_object()
action = serializer.validated_data["action"]
if action == "refresh":
task = update_asset_hardware_info_manual.delay(asset)
else:
task = test_asset_connectivity_manual.delay(asset)
task = self.perform_assets_task(serializer)
self.set_task_to_serializer_data(serializer, task)
def set_task_to_serializer_data(self, serializer, task):
data = getattr(serializer, '_data', {})
data["task"] = task.id
setattr(serializer, '_data', data)
class AssetTaskCreateApi(AssetsTaskMixin, generics.CreateAPIView):
model = Asset
serializer_class = serializers.AssetTaskSerializer
permission_classes = (IsOrgAdmin,)
def create(self, request, *args, **kwargs):
pk = self.kwargs.get('pk')
request.data['asset'] = pk
request.data['assets'] = [pk]
return super().create(request, *args, **kwargs)
def perform_asset_task(self, serializer):
data = serializer.validated_data
action = data['action']
if action not in ['push_system_user', 'test_system_user']:
return
asset = data['asset']
system_users = data.get('system_users')
if not system_users:
system_users = asset.get_all_systemusers()
if action == 'push_system_user':
task = push_system_users_a_asset.delay(system_users, asset=asset)
elif action == 'test_system_user':
task = test_system_users_connectivity_a_asset.delay(system_users, asset=asset)
else:
task = None
return task
def perform_create(self, serializer):
task = self.perform_asset_task(serializer)
if not task:
task = self.perform_assets_task(serializer)
self.set_task_to_serializer_data(serializer, task)
class AssetsTaskCreateApi(AssetsTaskMixin, generics.CreateAPIView):
model = Asset
serializer_class = serializers.AssetsTaskSerializer
permission_classes = (IsOrgAdmin,)
class AssetGatewayListApi(generics.ListAPIView):
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.GatewayWithAuthSerializer
model = Asset
def get_queryset(self):
asset_id = self.kwargs.get('pk')
@@ -124,3 +180,102 @@ class AssetGatewayListApi(generics.ListAPIView):
return []
queryset = asset.domain.gateways.filter(protocol='ssh')
return queryset
class BaseAssetPermUserOrUserGroupListApi(ListAPIView):
permission_classes = (IsOrgAdmin,)
def get_object(self):
asset_id = self.kwargs.get('pk')
asset = get_object_or_404(Asset, pk=asset_id)
return asset
def get_asset_related_perms(self):
asset = self.get_object()
nodes = asset.get_all_nodes(flat=True)
perms = AssetPermission.objects.filter(Q(assets=asset) | Q(nodes__in=nodes))
return perms
class AssetPermUserListApi(BaseAssetPermUserOrUserGroupListApi):
filterset_class = UserFilter
search_fields = ('username', 'email', 'name', 'id', 'source', 'role')
serializer_class = UserSerializer
def get_queryset(self):
perms = self.get_asset_related_perms()
users = User.objects.filter(
Q(assetpermissions__in=perms) | Q(groups__assetpermissions__in=perms)
).distinct()
return users
class AssetPermUserGroupListApi(BaseAssetPermUserOrUserGroupListApi):
serializer_class = UserGroupSerializer
def get_queryset(self):
perms = self.get_asset_related_perms()
user_groups = UserGroup.objects.filter(assetpermissions__in=perms).distinct()
return user_groups
class BaseAssetPermUserOrUserGroupPermissionsListApiMixin(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
model = AssetPermission
serializer_class = AssetPermissionSerializer
filterset_class = AssetPermissionFilter
search_fields = ('name',)
def get_object(self):
asset_id = self.kwargs.get('pk')
asset = get_object_or_404(Asset, pk=asset_id)
return asset
def filter_asset_related(self, queryset):
asset = self.get_object()
nodes = asset.get_all_nodes(flat=True)
perms = queryset.filter(Q(assets=asset) | Q(nodes__in=nodes))
return perms
def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
queryset = self.filter_asset_related(queryset)
return queryset
class AssetPermUserPermissionsListApi(BaseAssetPermUserOrUserGroupPermissionsListApiMixin):
def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
queryset = self.filter_user_related(queryset)
queryset = queryset.distinct()
return queryset
def filter_user_related(self, queryset):
user = self.get_perm_user()
user_groups = user.groups.all()
perms = queryset.filter(Q(users=user) | Q(user_groups__in=user_groups))
return perms
def get_perm_user(self):
user_id = self.kwargs.get('perm_user_id')
user = get_object_or_404(User, pk=user_id)
return user
class AssetPermUserGroupPermissionsListApi(BaseAssetPermUserOrUserGroupPermissionsListApiMixin):
def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
queryset = self.filter_user_group_related(queryset)
queryset = queryset.distinct()
return queryset
def filter_user_group_related(self, queryset):
user_group = self.get_perm_user_group()
perms = queryset.filter(user_groups=user_group)
return perms
def get_perm_user_group(self):
user_group_id = self.kwargs.get('perm_user_group_id')
user_group = get_object_or_404(UserGroup, pk=user_group_id)
return user_group

View File

@@ -1,157 +0,0 @@
# -*- coding: utf-8 -*-
#
import coreapi
from django.conf import settings
from rest_framework.response import Response
from rest_framework import generics, filters
from rest_framework_bulk import BulkModelViewSet
from common.permissions import IsOrgAdminOrAppUser, NeedMFAVerify
from common.utils import get_object_or_none, get_logger
from common.mixins import CommonApiMixin
from ..backends import AssetUserManager
from ..models import Asset, Node, SystemUser
from .. import serializers
from ..tasks import (
test_asset_users_connectivity_manual, push_system_user_a_asset_manual
)
__all__ = [
'AssetUserViewSet', 'AssetUserAuthInfoViewSet', 'AssetUserTaskCreateAPI',
]
logger = get_logger(__name__)
class AssetUserFilterBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
kwargs = {}
for field in view.filter_fields:
value = request.GET.get(field)
if not value:
continue
if field == "node_id":
value = get_object_or_none(Node, pk=value)
kwargs["node"] = value
continue
elif field == "asset_id":
field = "asset"
kwargs[field] = value
if kwargs:
queryset = queryset.filter(**kwargs)
logger.debug("Filter {}".format(kwargs))
return queryset
class AssetUserSearchBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
value = request.GET.get('search')
if not value:
return queryset
queryset = queryset.search(value)
return queryset
class AssetUserLatestFilterBackend(filters.BaseFilterBackend):
def get_schema_fields(self, view):
return [
coreapi.Field(
name='latest', location='query', required=False,
type='string', example='1',
description='Only the latest version'
)
]
def filter_queryset(self, request, queryset, view):
latest = request.GET.get('latest') == '1'
if latest:
queryset = queryset.distinct()
return queryset
class AssetUserViewSet(CommonApiMixin, BulkModelViewSet):
serializer_classes = {
'default': serializers.AssetUserWriteSerializer,
'display': serializers.AssetUserReadSerializer,
'retrieve': serializers.AssetUserReadSerializer,
}
permission_classes = [IsOrgAdminOrAppUser]
filter_fields = [
"id", "ip", "hostname", "username",
"asset_id", "node_id",
"prefer", "prefer_id",
]
search_fields = ["ip", "hostname", "username"]
filter_backends = [
AssetUserFilterBackend, AssetUserSearchBackend,
AssetUserLatestFilterBackend,
]
def allow_bulk_destroy(self, qs, filtered):
return False
def get_object(self):
pk = self.kwargs.get("pk")
if pk is None:
return
queryset = self.get_queryset()
obj = queryset.get(id=pk)
return obj
def get_exception_handler(self):
def handler(e, context):
logger.error(e, exc_info=True)
return Response({"error": str(e)}, status=400)
return handler
def perform_destroy(self, instance):
manager = AssetUserManager()
manager.delete(instance)
def get_queryset(self):
manager = AssetUserManager()
queryset = manager.all()
return queryset
class AssetUserAuthInfoViewSet(AssetUserViewSet):
serializer_classes = {"default": serializers.AssetUserAuthInfoSerializer}
http_method_names = ['get', 'post']
permission_classes = [IsOrgAdminOrAppUser]
def get_permissions(self):
if settings.SECURITY_VIEW_AUTH_NEED_MFA:
self.permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify]
return super().get_permissions()
class AssetUserTaskCreateAPI(generics.CreateAPIView):
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.AssetUserTaskSerializer
filter_backends = AssetUserViewSet.filter_backends
filter_fields = AssetUserViewSet.filter_fields
def get_asset_users(self):
manager = AssetUserManager()
queryset = manager.all()
for cls in self.filter_backends:
queryset = cls().filter_queryset(self.request, queryset, self)
return list(queryset)
def perform_create(self, serializer):
asset_users = self.get_asset_users()
# action = serializer.validated_data["action"]
# only this
# if action == "test":
task = test_asset_users_connectivity_manual.delay(asset_users)
data = getattr(serializer, '_data', {})
data["task"] = task.id
setattr(serializer, '_data', data)
return task
def get_exception_handler(self):
def handler(e, context):
return Response({"error": str(e)}, status=400)
return handler

View File

@@ -1,29 +1,36 @@
# -*- coding: utf-8 -*-
#
from rest_framework.response import Response
from rest_framework.generics import CreateAPIView
from django.shortcuts import get_object_or_404
from common.utils import reverse
from common.utils import lazyproperty
from orgs.mixins.api import OrgBulkModelViewSet
from ..hands import IsOrgAdmin
from tickets.api import GenericTicketStatusRetrieveCloseAPI
from ..hands import IsOrgAdmin, IsAppUser
from ..models import CommandFilter, CommandFilterRule
from .. import serializers
__all__ = ['CommandFilterViewSet', 'CommandFilterRuleViewSet']
__all__ = [
'CommandFilterViewSet', 'CommandFilterRuleViewSet', 'CommandConfirmAPI',
'CommandConfirmStatusAPI'
]
class CommandFilterViewSet(OrgBulkModelViewSet):
model = CommandFilter
filter_fields = ("name",)
search_fields = filter_fields
filterset_fields = ("name",)
search_fields = filterset_fields
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.CommandFilterSerializer
class CommandFilterRuleViewSet(OrgBulkModelViewSet):
model = CommandFilterRule
filter_fields = ("content",)
search_fields = filter_fields
filterset_fields = ("content",)
search_fields = filterset_fields
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.CommandFilterRuleSerializer
@@ -35,3 +42,50 @@ class CommandFilterRuleViewSet(OrgBulkModelViewSet):
return cmd_filter.rules.all()
class CommandConfirmAPI(CreateAPIView):
permission_classes = (IsAppUser,)
serializer_class = serializers.CommandConfirmSerializer
def create(self, request, *args, **kwargs):
ticket = self.create_command_confirm_ticket()
response_data = self.get_response_data(ticket)
return Response(data=response_data, status=200)
def create_command_confirm_ticket(self):
ticket = self.serializer.cmd_filter_rule.create_command_confirm_ticket(
run_command=self.serializer.data.get('run_command'),
session=self.serializer.session,
cmd_filter_rule=self.serializer.cmd_filter_rule,
org_id=self.serializer.org.id
)
return ticket
@staticmethod
def get_response_data(ticket):
confirm_status_url = reverse(
view_name='api-assets:command-confirm-status',
kwargs={'pk': str(ticket.id)}
)
ticket_detail_url = reverse(
view_name='api-tickets:ticket-detail',
kwargs={'pk': str(ticket.id)},
external=True, api_to_ui=True
)
ticket_detail_url = '{url}?type={type}'.format(url=ticket_detail_url, type=ticket.type)
ticket_assignees = ticket.current_node.first().ticket_assignees.all()
return {
'check_confirm_status': {'method': 'GET', 'url': confirm_status_url},
'close_confirm': {'method': 'DELETE', 'url': confirm_status_url},
'ticket_detail_url': ticket_detail_url,
'reviewers': [str(ticket_assignee.assignee) for ticket_assignee in ticket_assignees]
}
@lazyproperty
def serializer(self):
serializer = self.get_serializer(data=self.request.data)
serializer.is_valid(raise_exception=True)
return serializer
class CommandConfirmStatusAPI(GenericTicketStatusRetrieveCloseAPI):
pass

View File

@@ -1,7 +1,9 @@
# ~*~ coding: utf-8 ~*~
from rest_framework.views import APIView, Response
from django.views.generic.detail import SingleObjectMixin
from django.utils.translation import ugettext as _
from rest_framework.views import APIView, Response
from rest_framework.serializers import ValidationError
from common.utils import get_logger
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
@@ -16,10 +18,12 @@ __all__ = ['DomainViewSet', 'GatewayViewSet', "GatewayTestConnectionApi"]
class DomainViewSet(OrgBulkModelViewSet):
model = Domain
filter_fields = ("name", )
search_fields = filter_fields
filterset_fields = ("name", )
search_fields = filterset_fields
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.DomainSerializer
ordering_fields = ('name',)
ordering = ('name', )
def get_serializer_class(self):
if self.request.query_params.get('gateway'):
@@ -29,9 +33,9 @@ class DomainViewSet(OrgBulkModelViewSet):
class GatewayViewSet(OrgBulkModelViewSet):
model = Gateway
filter_fields = ("domain__name", "name", "username", "ip", "domain")
filterset_fields = ("domain__name", "name", "username", "ip", "domain")
search_fields = ("domain__name", "name", "username", "ip")
permission_classes = (IsOrgAdmin,)
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.GatewaySerializer
@@ -42,6 +46,10 @@ class GatewayTestConnectionApi(SingleObjectMixin, APIView):
def post(self, request, *args, **kwargs):
self.object = self.get_object(Gateway.objects.all())
local_port = self.request.data.get('port') or self.object.port
try:
local_port = int(local_port)
except ValueError:
raise ValidationError({'port': _('Number required')})
ok, e = self.object.test_connective(local_port=local_port)
if ok:
return Response("ok")

View File

@@ -13,7 +13,7 @@ __all__ = ['FavoriteAssetViewSet']
class FavoriteAssetViewSet(BulkModelViewSet):
serializer_class = FavoriteAssetSerializer
permission_classes = (IsValidUser,)
filter_fields = ['asset']
filterset_fields = ['asset']
def dispatch(self, request, *args, **kwargs):
with tmp_to_root_org():

View File

@@ -18,5 +18,5 @@ class GatheredUserViewSet(OrgModelViewSet):
permission_classes = [IsOrgAdmin]
extra_filter_backends = [AssetRelatedByNodeFilterBackend]
filter_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__hostname', 'asset_id']
filterset_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__hostname', 'asset_id']
search_fields = ['username', 'asset__ip', 'asset__hostname']

View File

@@ -28,8 +28,8 @@ __all__ = ['LabelViewSet']
class LabelViewSet(OrgBulkModelViewSet):
model = Label
filter_fields = ("name", "value")
search_fields = filter_fields
filterset_fields = ("name", "value")
search_fields = filterset_fields
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.LabelSerializer

View File

@@ -1,14 +1,15 @@
from typing import List
from common.utils.common import timeit
from assets.models import Node, Asset
from assets.pagination import AssetLimitOffsetPagination
from common.utils import lazyproperty, dict_get_any, is_uuid, get_object_or_none
from assets.pagination import NodeAssetTreePagination
from common.utils import lazyproperty
from assets.utils import get_node, is_query_node_all_assets
class SerializeToTreeNodeMixin:
permission_classes = ()
@timeit
def serialize_nodes(self, nodes: List[Node], with_asset_amount=False):
if with_asset_amount:
def _name(node: Node):
@@ -25,7 +26,7 @@ class SerializeToTreeNodeMixin:
'isParent': True,
'open': node.is_org_root(),
'meta': {
'node': {
'data': {
"id": node.id,
"key": node.key,
"value": node.value,
@@ -45,6 +46,7 @@ class SerializeToTreeNodeMixin:
return platform
return default
@timeit
def serialize_assets(self, assets, node_key=None):
if node_key is None:
get_pid = lambda asset: getattr(asset, 'parent_key', '')
@@ -63,12 +65,13 @@ class SerializeToTreeNodeMixin:
'chkDisabled': not asset.is_active,
'meta': {
'type': 'asset',
'asset': {
'data': {
'id': asset.id,
'hostname': asset.hostname,
'ip': asset.ip,
'protocols': asset.protocols_as_list,
'platform': asset.platform_base,
'org_name': asset.org_name
},
}
}
@@ -78,7 +81,7 @@ class SerializeToTreeNodeMixin:
class FilterAssetByNodeMixin:
pagination_class = AssetLimitOffsetPagination
pagination_class = NodeAssetTreePagination
@lazyproperty
def is_query_node_all_assets(self):

View File

@@ -5,28 +5,30 @@ from collections import namedtuple, defaultdict
from rest_framework import status
from rest_framework.serializers import ValidationError
from rest_framework.response import Response
from rest_framework.decorators import action
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404, Http404
from django.utils.decorators import method_decorator
from django.db.models.signals import m2m_changed
from common.const.http import POST
from common.exceptions import SomeoneIsDoingThis
from common.const.signals import PRE_REMOVE, POST_REMOVE
from assets.models import Asset
from common.utils import get_logger, get_object_or_none
from common.tree import TreeNodeSerializer
from common.const.distributed_lock_key import UPDATE_NODE_TREE_LOCK_KEY
from orgs.mixins.api import OrgModelViewSet
from orgs.mixins import generics
from orgs.lock import org_level_transaction_lock
from orgs.utils import current_org
from ..hands import IsOrgAdmin
from ..models import Node
from ..tasks import (
update_node_assets_hardware_info_manual,
test_node_assets_connectivity_manual,
check_node_assets_amount_task
)
from .. import serializers
from .mixin import SerializeToTreeNodeMixin
from assets.locks import NodeAddChildrenLock
logger = get_logger(__file__)
@@ -41,7 +43,7 @@ __all__ = [
class NodeViewSet(OrgModelViewSet):
model = Node
filter_fields = ('value', 'key', 'id')
filterset_fields = ('value', 'key', 'id')
search_fields = ('value', )
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.NodeSerializer
@@ -52,6 +54,11 @@ class NodeViewSet(OrgModelViewSet):
serializer.validated_data["key"] = child_key
serializer.save()
@action(methods=[POST], detail=False, url_path='check_assets_amount_task')
def check_assets_amount_task(self, request):
task = check_node_assets_amount_task.delay(current_org.id)
return Response(data={'task': task.id})
def perform_update(self, serializer):
node = self.get_object()
if node.is_org_root() and node.value != serializer.validated_data['value']:
@@ -61,8 +68,11 @@ class NodeViewSet(OrgModelViewSet):
def destroy(self, request, *args, **kwargs):
node = self.get_object()
if node.has_children_or_has_assets():
error = _("Deletion failed and the node contains children or assets")
if node.is_org_root():
error = _("You can't delete the root node ({})".format(node.value))
return Response(data={'error': error}, status=status.HTTP_403_FORBIDDEN)
if node.has_offspring_assets():
error = _("Deletion failed and the node contains assets")
return Response(data={'error': error}, status=status.HTTP_403_FORBIDDEN)
return super().destroy(request, *args, **kwargs)
@@ -105,22 +115,27 @@ class NodeChildrenApi(generics.ListCreateAPIView):
return super().initial(request, *args, **kwargs)
def perform_create(self, serializer):
data = serializer.validated_data
_id = data.get("id")
value = data.get("value")
if not value:
value = self.instance.get_next_child_preset_name()
node = self.instance.create_child(value=value, _id=_id)
# 避免查询 full value
node._full_value = node.value
serializer.instance = node
with NodeAddChildrenLock(self.instance):
data = serializer.validated_data
_id = data.get("id")
value = data.get("value")
if not value:
value = self.instance.get_next_child_preset_name()
node = self.instance.create_child(value=value, _id=_id)
# 避免查询 full value
node._full_value = node.value
serializer.instance = node
def get_object(self):
pk = self.kwargs.get('pk') or self.request.query_params.get('id')
key = self.request.query_params.get("key")
if not pk and not key:
node = Node.org_root()
self.is_initial = True
if current_org.is_root():
node = None
else:
node = Node.org_root()
return node
if pk:
node = get_object_or_404(Node, pk=pk)
@@ -128,16 +143,26 @@ class NodeChildrenApi(generics.ListCreateAPIView):
node = get_object_or_404(Node, key=key)
return node
def get_org_root_queryset(self, query_all):
if query_all:
return Node.objects.all()
else:
return Node.org_root_nodes()
def get_queryset(self):
query_all = self.request.query_params.get("all", "0") == "all"
if not self.instance:
return Node.objects.none()
if self.is_initial and current_org.is_root():
return self.get_org_root_queryset(query_all)
if self.is_initial:
with_self = True
else:
with_self = False
if not self.instance:
return Node.objects.none()
if query_all:
queryset = self.instance.get_all_children(with_self=with_self)
else:
@@ -169,12 +194,12 @@ class NodeChildrenAsTreeApi(SerializeToTreeNodeMixin, NodeChildrenApi):
def get_assets(self):
include_assets = self.request.query_params.get('assets', '0') == '1'
if not include_assets:
if not self.instance or not include_assets:
return []
assets = self.instance.get_assets().only(
"id", "hostname", "ip", "os",
"org_id", "protocols",
)
"id", "hostname", "ip", "os", "platform_id",
"org_id", "protocols", "is_active",
).prefetch_related('platform')
return self.serialize_assets(assets, self.instance.key)
@@ -198,19 +223,16 @@ class NodeAddChildrenApi(generics.UpdateAPIView):
serializer_class = serializers.NodeAddChildrenSerializer
instance = None
def put(self, request, *args, **kwargs):
def update(self, request, *args, **kwargs):
""" 同时支持 put 和 patch 方法"""
instance = self.get_object()
nodes_id = request.data.get("nodes")
children = [get_object_or_none(Node, id=pk) for pk in nodes_id]
node_ids = request.data.get("nodes")
children = Node.objects.filter(id__in=node_ids)
for node in children:
if not node:
continue
node.parent = instance
return Response("OK")
@method_decorator(org_level_transaction_lock(UPDATE_NODE_TREE_LOCK_KEY), name='patch')
@method_decorator(org_level_transaction_lock(UPDATE_NODE_TREE_LOCK_KEY), name='put')
class NodeAddAssetsApi(generics.UpdateAPIView):
model = Node
serializer_class = serializers.NodeAssetsSerializer
@@ -223,8 +245,6 @@ class NodeAddAssetsApi(generics.UpdateAPIView):
instance.assets.add(*tuple(assets))
@method_decorator(org_level_transaction_lock(UPDATE_NODE_TREE_LOCK_KEY), name='patch')
@method_decorator(org_level_transaction_lock(UPDATE_NODE_TREE_LOCK_KEY), name='put')
class NodeRemoveAssetsApi(generics.UpdateAPIView):
model = Node
serializer_class = serializers.NodeAssetsSerializer
@@ -237,12 +257,13 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
node.assets.remove(*assets)
# 把孤儿资产添加到 root 节点
orphan_assets = Asset.objects.filter(id__in=[a.id for a in assets], nodes__isnull=True).distinct()
orphan_assets = Asset.objects.filter(
id__in=[a.id for a in assets],
nodes__isnull=True
).distinct()
Node.org_root().assets.add(*orphan_assets)
@method_decorator(org_level_transaction_lock(UPDATE_NODE_TREE_LOCK_KEY), name='patch')
@method_decorator(org_level_transaction_lock(UPDATE_NODE_TREE_LOCK_KEY), name='put')
class MoveAssetsToNodeApi(generics.UpdateAPIView):
model = Node
serializer_class = serializers.NodeAssetsSerializer

View File

@@ -3,38 +3,46 @@ from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from common.utils import get_logger
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser, IsAppUser
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser, IsValidUser
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.mixins import generics
from orgs.utils import tmp_to_org
from common.mixins.api import SuggestionMixin
from orgs.utils import tmp_to_root_org
from ..models import SystemUser, Asset
from .. import serializers
from ..serializers import SystemUserWithAuthInfoSerializer
from ..serializers import SystemUserWithAuthInfoSerializer, SystemUserTempAuthSerializer
from ..tasks import (
push_system_user_to_assets_manual, test_system_user_connectivity_manual,
push_system_user_a_asset_manual,
push_system_user_to_assets
)
logger = get_logger(__file__)
__all__ = [
'SystemUserViewSet', 'SystemUserAuthInfoApi', 'SystemUserAssetAuthInfoApi',
'SystemUserCommandFilterRuleListApi', 'SystemUserTaskApi',
'SystemUserCommandFilterRuleListApi', 'SystemUserTaskApi', 'SystemUserAssetsListView',
'SystemUserTempAuthInfoApi', 'SystemUserAppAuthInfoApi',
]
class SystemUserViewSet(OrgBulkModelViewSet):
class SystemUserViewSet(SuggestionMixin, OrgBulkModelViewSet):
"""
System user api set, for add,delete,update,list,retrieve resource
"""
model = SystemUser
filter_fields = ("name", "username", "protocol")
search_fields = filter_fields
filterset_fields = {
'name': ['exact'],
'username': ['exact'],
'protocol': ['exact', 'in'],
'type': ['exact', 'in'],
}
search_fields = filterset_fields
serializer_class = serializers.SystemUserSerializer
serializer_classes = {
'default': serializers.SystemUserSerializer,
'list': serializers.SystemUserListSerializer,
'suggestion': serializers.MiniSystemUserSerializer
}
ordering_fields = ('name', 'protocol', 'login_mode')
ordering = ('name', )
permission_classes = (IsOrgAdminOrAppUser,)
@@ -52,6 +60,25 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView):
return Response(status=204)
class SystemUserTempAuthInfoApi(generics.CreateAPIView):
model = SystemUser
permission_classes = (IsValidUser,)
serializer_class = SystemUserTempAuthSerializer
def create(self, request, *args, **kwargs):
serializer = super().get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
pk = kwargs.get('pk')
user = self.request.user
data = serializer.validated_data
instance_id = data.get('instance_id')
with tmp_to_root_org():
instance = get_object_or_404(SystemUser, pk=pk)
instance.set_temp_auth(instance_id, user.id, data)
return Response(serializer.data, status=201)
class SystemUserAssetAuthInfoApi(generics.RetrieveAPIView):
"""
Get system user with asset auth info
@@ -60,41 +87,48 @@ class SystemUserAssetAuthInfoApi(generics.RetrieveAPIView):
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = SystemUserWithAuthInfoSerializer
def get_exception_handler(self):
def handler(e, context):
return Response({"error": str(e)}, status=400)
return handler
def get_object(self):
instance = super().get_object()
asset_id = self.kwargs.get('asset_id')
user_id = self.request.query_params.get("user_id")
username = self.request.query_params.get("username")
instance.load_asset_more_auth(asset_id, username, user_id)
return instance
class SystemUserAppAuthInfoApi(generics.RetrieveAPIView):
"""
Get system user with asset auth info
"""
model = SystemUser
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = SystemUserWithAuthInfoSerializer
def get_object(self):
instance = super().get_object()
username = instance.username
if instance.username_same_with_user:
username = self.request.query_params.get("username")
asset_id = self.kwargs.get('aid')
asset = get_object_or_404(Asset, pk=asset_id)
with tmp_to_org(asset.org_id):
instance.load_asset_special_auth(asset=asset, username=username)
return instance
app_id = self.kwargs.get('app_id')
user_id = self.request.query_params.get("user_id")
instance.load_app_more_auth(app_id, user_id)
return instance
class SystemUserTaskApi(generics.CreateAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.SystemUserTaskSerializer
def do_push(self, system_user, asset=None):
if asset is None:
def do_push(self, system_user, asset_ids=None):
if asset_ids is None:
task = push_system_user_to_assets_manual.delay(system_user)
else:
username = self.request.query_params.get('username')
task = push_system_user_a_asset_manual.delay(
system_user, asset, username=username
task = push_system_user_to_assets.delay(
system_user.id, asset_ids, username=username
)
return task
@staticmethod
def do_test(system_user, asset=None):
task = test_system_user_connectivity_manual.delay(system_user)
def do_test(system_user, asset_ids):
task = test_system_user_connectivity_manual.delay(system_user, asset_ids)
return task
def get_object(self):
@@ -104,11 +138,20 @@ class SystemUserTaskApi(generics.CreateAPIView):
def perform_create(self, serializer):
action = serializer.validated_data["action"]
asset = serializer.validated_data.get('asset')
if asset:
assets = [asset]
else:
assets = serializer.validated_data.get('assets') or []
asset_ids = [asset.id for asset in assets]
asset_ids = asset_ids if asset_ids else None
system_user = self.get_object()
if action == 'push':
task = self.do_push(system_user, asset)
task = self.do_push(system_user, asset_ids)
else:
task = self.do_test(system_user, asset)
task = self.do_test(system_user, asset_ids)
data = getattr(serializer, '_data', {})
data["task"] = task.id
setattr(serializer, '_data', data)
@@ -125,3 +168,18 @@ class SystemUserCommandFilterRuleListApi(generics.ListAPIView):
pk = self.kwargs.get('pk', None)
system_user = get_object_or_404(SystemUser, pk=pk)
return system_user.cmd_filter_rules
class SystemUserAssetsListView(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.AssetSimpleSerializer
filterset_fields = ("hostname", "ip")
search_fields = filterset_fields
def get_object(self):
pk = self.kwargs.get('pk')
return get_object_or_404(SystemUser, pk=pk)
def get_queryset(self):
system_user = self.get_object()
return system_user.get_all_assets()

View File

@@ -1,30 +1,36 @@
# -*- coding: utf-8 -*-
#
from collections import defaultdict
from django.db.models import F, Value
from django.db.models import F, Value, Model
from django.db.models.signals import m2m_changed
from django.db.models.functions import Concat
from common.permissions import IsOrgAdmin
from common.utils import get_logger
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.utils import current_org
from .. import models, serializers
__all__ = [
'SystemUserAssetRelationViewSet', 'SystemUserNodeRelationViewSet',
'SystemUserUserRelationViewSet',
'SystemUserUserRelationViewSet', 'BaseRelationViewSet',
]
logger = get_logger(__name__)
class RelationMixin:
model: Model
def get_queryset(self):
queryset = self.model.objects.all()
org_id = current_org.org_id()
if org_id is not None:
if not current_org.is_root():
org_id = current_org.org_id()
queryset = queryset.filter(systemuser__org_id=org_id)
queryset = queryset.annotate(systemuser_display=Concat(
F('systemuser__name'), Value('('), F('systemuser__username'),
Value(')')
F('systemuser__name'), Value('('),
F('systemuser__username'), Value(')')
))
return queryset
@@ -40,10 +46,11 @@ class RelationMixin:
system_users_objects_map[i.systemuser].append(_id)
sender = self.get_sender()
for system_user, objects in system_users_objects_map.items():
for system_user, object_ids in system_users_objects_map.items():
logger.debug('System user relation changed, send m2m_changed signals')
m2m_changed.send(
sender=sender, instance=system_user, action='post_add',
reverse=False, model=model, pk_set=objects
reverse=False, model=model, pk_set=set(object_ids)
)
def get_sender(self):
@@ -65,12 +72,12 @@ class SystemUserAssetRelationViewSet(BaseRelationViewSet):
serializer_class = serializers.SystemUserAssetRelationSerializer
model = models.SystemUser.assets.through
permission_classes = (IsOrgAdmin,)
filter_fields = [
filterset_fields = [
'id', 'asset', 'systemuser',
]
search_fields = [
"id", "asset__hostname", "asset__ip",
"systemuser__name", "systemuser__username"
"systemuser__name", "systemuser__username",
]
def get_objects_attr(self):
@@ -91,11 +98,11 @@ class SystemUserNodeRelationViewSet(BaseRelationViewSet):
serializer_class = serializers.SystemUserNodeRelationSerializer
model = models.SystemUser.nodes.through
permission_classes = (IsOrgAdmin,)
filter_fields = [
filterset_fields = [
'id', 'node', 'systemuser',
]
search_fields = [
"node__value", "systemuser__name", "systemuser_username"
"node__value", "systemuser__name", "systemuser__username"
]
def get_objects_attr(self):
@@ -112,7 +119,7 @@ class SystemUserUserRelationViewSet(BaseRelationViewSet):
serializer_class = serializers.SystemUserUserRelationSerializer
model = models.SystemUser.users.through
permission_classes = (IsOrgAdmin,)
filter_fields = [
filterset_fields = [
'id', 'user', 'systemuser',
]
search_fields = [

View File

@@ -1,16 +1,6 @@
from __future__ import unicode_literals
from django.apps import AppConfig
from django.db.models.signals import post_migrate
def initial_some_nodes():
from .models import Node
Node.initial_some_nodes()
def initial_some_nodes_callback(sender, **kwargs):
initial_some_nodes()
class AssetsConfig(AppConfig):
@@ -19,7 +9,3 @@ class AssetsConfig(AppConfig):
def ready(self):
super().ready()
from . import signals_handler
try:
initial_some_nodes()
except Exception:
post_migrate.connect(initial_some_nodes_callback, sender=self)

View File

@@ -1 +0,0 @@
from .manager import AssetUserManager

View File

@@ -1,48 +0,0 @@
# -*- coding: utf-8 -*-
#
from abc import abstractmethod
from ..models import Asset
class BaseBackend:
@abstractmethod
def all(self):
pass
@abstractmethod
def filter(self, username=None, hostname=None, ip=None, assets=None,
node=None, prefer_id=None, **kwargs):
pass
@abstractmethod
def search(self, item):
pass
@abstractmethod
def get_queryset(self):
pass
@abstractmethod
def delete(self, union_id):
pass
@staticmethod
def qs_to_values(qs):
values = qs.values(
'hostname', 'ip', "asset_id",
'username', 'password', 'private_key', 'public_key',
'score', 'version',
"asset_username", "union_id",
'date_created', 'date_updated',
'org_id', 'backend',
)
return values
@staticmethod
def make_assets_as_id(assets):
if not assets:
return []
if isinstance(assets[0], Asset):
assets = [a.id for a in assets]
return assets

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