Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
c31b56dd
Commit
c31b56dd
authored
Nov 11, 2019
by
BaiJiangJie
Browse files
Options
Browse Files
Download
Plain Diff
[Update] Merge local branch dev to dev_ldap2
parents
0a08ba3b
0d2fc27a
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
153 additions
and
89 deletions
+153
-89
node.py
apps/assets/models/node.py
+1
-1
_asset_list_modal.html
apps/assets/templates/assets/_asset_list_modal.html
+1
-1
_node_tree.html
apps/assets/templates/assets/_node_tree.html
+2
-2
asset_list.html
apps/assets/templates/assets/asset_list.html
+12
-9
conf.py
apps/jumpserver/conf.py
+1
-0
signals_handler.py
apps/perms/signals_handler.py
+0
-7
api.py
apps/settings/api.py
+25
-5
serializers.py
apps/settings/serializers.py
+3
-0
api_urls.py
apps/settings/urls/api_urls.py
+1
-0
forms.py
apps/users/forms.py
+21
-1
__init__.py
apps/users/serializers/__init__.py
+2
-2
group.py
apps/users/serializers/group.py
+69
-0
user.py
apps/users/serializers/user.py
+1
-59
signals_handler.py
apps/users/signals_handler.py
+13
-2
_user.html
apps/users/templates/users/_user.html
+1
-0
No files found.
apps/assets/models/node.py
View file @
c31b56dd
...
...
@@ -68,7 +68,7 @@ class TreeMixin:
@classmethod
def
refresh_node_assets
(
cls
,
t
=
None
):
logger
.
debug
(
"Refresh node
tree
assets"
)
logger
.
debug
(
"Refresh node assets"
)
key
=
cls
.
tree_assets_cache_key
ttl
=
cls
.
tree_cache_time
if
not
t
:
...
...
apps/assets/templates/assets/_asset_list_modal.html
View file @
c31b56dd
...
...
@@ -25,7 +25,7 @@
<div
class=
"wrapper wrapper-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px
;overflow: auto;max-height: 500px
"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0;padding-left: 1px"
>
<div
class=
"file-manager "
>
...
...
apps/assets/templates/assets/_node_tree.html
View file @
c31b56dd
...
...
@@ -32,8 +32,7 @@
}
</style>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox treebox float-e-margins"
style=
"overflow:auto;"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0;padding-left: 1px"
>
<div
class=
"file-manager"
id=
"tree-node-id"
>
<div
id=
"{% block treeID %}nodeTree{% endblock %}"
class=
"ztree"
>
...
...
@@ -306,6 +305,7 @@ function defaultCallback(action) {
$
(
document
).
ready
(
function
()
{
$
(
'.treebox'
).
css
(
'height'
,
window
.
innerHeight
-
180
);
})
.
on
(
'click'
,
'.btn-show-current-asset'
,
function
(){
hideRMenu
();
...
...
apps/assets/templates/assets/asset_list.html
View file @
c31b56dd
...
...
@@ -426,13 +426,15 @@ $(document).ready(function(){
function
success
(
data
)
{
url
=
setUrlParam
(
the_url
,
'spm'
,
data
.
spm
);
requestApi
({
url
:
url
,
method
:
'DELETE'
,
success
:
refreshPage
,
flash_message
:
false
,
});
url
:
url
,
method
:
'DELETE'
,
success
:
function
()
{
var
msg
=
"{% trans 'Asset Deleted.' %}"
;
swal
(
"{% trans 'Asset Delete' %}"
,
msg
,
"success"
);
refreshPage
();
},
flash_message
:
false
,
});
}
function
fail
()
{
var
msg
=
"{% trans 'Asset Deleting failed.' %}"
;
...
...
@@ -440,10 +442,11 @@ $(document).ready(function(){
}
requestApi
({
url
:
"{% url 'api-common:resources-cache' %}"
,
method
:
'POST'
,
body
:
JSON
.
stringify
(
data
),
success
:
success
,
error
:
fail
method
:
'POST'
,
body
:
JSON
.
stringify
(
data
),
success
:
success
,
error
:
fail
,
flash_message
:
false
})
})
}
...
...
apps/jumpserver/conf.py
View file @
c31b56dd
...
...
@@ -395,6 +395,7 @@ defaults = {
'FLOWER_URL'
:
"127.0.0.1:5555"
,
'DEFAULT_ORG_SHOW_ALL_USERS'
:
True
,
'PERIOD_TASK_ENABLED'
:
True
,
'WINDOWS_SKIP_ALL_MANUAL_PASSWORD'
:
False
,
}
...
...
apps/perms/signals_handler.py
View file @
c31b56dd
...
...
@@ -11,13 +11,6 @@ from .utils.asset_permission import AssetPermissionUtilV2
logger
=
get_logger
(
__file__
)
permission_m2m_senders
=
(
AssetPermission
.
nodes
.
through
,
AssetPermission
.
assets
.
through
,
AssetPermission
.
users
.
through
,
AssetPermission
.
user_groups
.
through
,
)
@receiver
([
post_save
,
post_delete
],
sender
=
AssetPermission
)
@on_transaction_commit
...
...
apps/settings/api.py
View file @
c31b56dd
...
...
@@ -21,7 +21,10 @@ from .utils import (
from
.tasks
import
sync_ldap_user_task
from
common.permissions
import
IsOrgAdmin
,
IsSuperUser
from
common.utils
import
get_logger
from
.serializers
import
MailTestSerializer
,
LDAPTestSerializer
,
LDAPUserSerializer
from
.serializers
import
(
MailTestSerializer
,
LDAPTestSerializer
,
LDAPUserSerializer
,
PublicSettingSerializer
,
)
from
users.models
import
User
...
...
@@ -29,7 +32,7 @@ logger = get_logger(__file__)
class
MailTestingAPI
(
APIView
):
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
SuperUser
,)
serializer_class
=
MailTestSerializer
success_message
=
_
(
"Test mail sent to {}, please check"
)
...
...
@@ -68,7 +71,7 @@ class MailTestingAPI(APIView):
class
LDAPTestingAPI
(
APIView
):
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
SuperUser
,)
serializer_class
=
LDAPTestSerializer
success_message
=
_
(
"Test ldap success"
)
...
...
@@ -114,7 +117,7 @@ class LDAPTestingAPI(APIView):
class
LDAPUserListApi
(
generics
.
ListAPIView
):
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
SuperUser
,)
serializer_class
=
LDAPUserSerializer
def
get_queryset_from_cache
(
self
):
...
...
@@ -200,7 +203,7 @@ class LDAPUserListApi(generics.ListAPIView):
class
LDAPUserImportAPI
(
APIView
):
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
SuperUser
,)
def
get_ldap_users
(
self
):
username_list
=
self
.
request
.
data
.
get
(
'username_list'
,
[])
...
...
@@ -229,6 +232,7 @@ class LDAPUserImportAPI(APIView):
class
LDAPCacheRefreshAPI
(
generics
.
RetrieveAPIView
):
permission_classes
=
(
IsSuperUser
,)
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
try
:
...
...
@@ -318,3 +322,19 @@ class CommandStorageDeleteAPI(APIView):
storage_name
=
str
(
request
.
data
.
get
(
'name'
))
Setting
.
delete_storage
(
'TERMINAL_COMMAND_STORAGE'
,
storage_name
)
return
Response
({
"msg"
:
_
(
'Delete succeed'
)},
status
=
200
)
class
PublicSettingApi
(
generics
.
RetrieveAPIView
):
permission_classes
=
()
serializer_class
=
PublicSettingSerializer
def
get_object
(
self
):
c
=
settings
.
CONFIG
instance
=
{
"data"
:
{
"WINDOWS_SKIP_ALL_MANUAL_PASSWORD"
:
c
.
WINDOWS_SKIP_ALL_MANUAL_PASSWORD
}
}
return
instance
apps/settings/serializers.py
View file @
c31b56dd
...
...
@@ -29,3 +29,6 @@ class LDAPUserSerializer(serializers.Serializer):
email
=
serializers
.
CharField
()
existing
=
serializers
.
BooleanField
(
read_only
=
True
)
class
PublicSettingSerializer
(
serializers
.
Serializer
):
data
=
serializers
.
DictField
(
read_only
=
True
)
apps/settings/urls/api_urls.py
View file @
c31b56dd
...
...
@@ -16,4 +16,5 @@ urlpatterns = [
path
(
'terminal/replay-storage/delete/'
,
api
.
ReplayStorageDeleteAPI
.
as_view
(),
name
=
'replay-storage-delete'
),
path
(
'terminal/command-storage/create/'
,
api
.
CommandStorageCreateAPI
.
as_view
(),
name
=
'command-storage-create'
),
path
(
'terminal/command-storage/delete/'
,
api
.
CommandStorageDeleteAPI
.
as_view
(),
name
=
'command-storage-delete'
),
path
(
'public/'
,
api
.
PublicSettingApi
.
as_view
(),
name
=
'public-setting'
),
]
apps/users/forms.py
View file @
c31b56dd
...
...
@@ -2,6 +2,7 @@
from
django
import
forms
from
django.utils.translation
import
gettext_lazy
as
_
from
django.conf
import
settings
from
common.utils
import
validate_ssh_public_key
from
orgs.mixins.forms
import
OrgModelForm
...
...
@@ -21,6 +22,20 @@ class UserCheckOtpCodeForm(forms.Form):
otp_code
=
forms
.
CharField
(
label
=
_
(
'MFA code'
),
max_length
=
6
)
def
get_source_choices
():
choices_all
=
dict
(
User
.
SOURCE_CHOICES
)
choices
=
[
(
User
.
SOURCE_LOCAL
,
choices_all
[
User
.
SOURCE_LOCAL
]),
]
if
settings
.
AUTH_LDAP
:
choices
.
append
((
User
.
SOURCE_LDAP
,
choices_all
[
User
.
SOURCE_LDAP
]))
if
settings
.
AUTH_OPENID
:
choices
.
append
((
User
.
SOURCE_OPENID
,
choices_all
[
User
.
SOURCE_OPENID
]))
if
settings
.
AUTH_RADIUS
:
choices
.
append
((
User
.
SOURCE_RADIUS
,
choices_all
[
User
.
SOURCE_RADIUS
]))
return
choices
class
UserCreateUpdateFormMixin
(
OrgModelForm
):
role_choices
=
((
i
,
n
)
for
i
,
n
in
User
.
ROLE_CHOICES
if
i
!=
User
.
ROLE_APP
)
password
=
forms
.
CharField
(
...
...
@@ -31,6 +46,10 @@ class UserCreateUpdateFormMixin(OrgModelForm):
choices
=
role_choices
,
required
=
True
,
initial
=
User
.
ROLE_USER
,
label
=
_
(
"Role"
)
)
source
=
forms
.
ChoiceField
(
choices
=
get_source_choices
,
required
=
True
,
initial
=
User
.
SOURCE_LOCAL
,
label
=
_
(
"Source"
)
)
public_key
=
forms
.
CharField
(
label
=
_
(
'ssh public key'
),
max_length
=
5000
,
required
=
False
,
widget
=
forms
.
Textarea
(
attrs
=
{
'placeholder'
:
_
(
'ssh-rsa AAAA...'
)}),
...
...
@@ -41,7 +60,8 @@ class UserCreateUpdateFormMixin(OrgModelForm):
model
=
User
fields
=
[
'username'
,
'name'
,
'email'
,
'groups'
,
'wechat'
,
'phone'
,
'role'
,
'date_expired'
,
'comment'
,
'otp_level'
'source'
,
'phone'
,
'role'
,
'date_expired'
,
'comment'
,
'otp_level'
]
widgets
=
{
'otp_level'
:
forms
.
RadioSelect
(),
...
...
apps/users/serializers/__init__.py
View file @
c31b56dd
# -*- coding: utf-8 -*-
#
from
.v1
import
*
\ No newline at end of file
from
.user
import
*
from
.group
import
*
apps/users/serializers/group.py
0 → 100644
View file @
c31b56dd
# -*- coding: utf-8 -*-
#
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework
import
serializers
from
common.fields
import
StringManyToManyField
from
common.serializers
import
AdaptedBulkListSerializer
from
orgs.mixins.serializers
import
BulkOrgResourceModelSerializer
from
..models
import
User
,
UserGroup
from
..
import
utils
__all__
=
[
'UserGroupSerializer'
,
'UserGroupListSerializer'
,
'UserGroupUpdateMemberSerializer'
]
class
UserGroupSerializer
(
BulkOrgResourceModelSerializer
):
users
=
serializers
.
PrimaryKeyRelatedField
(
required
=
False
,
many
=
True
,
queryset
=
User
.
objects
,
label
=
_
(
'User'
)
)
class
Meta
:
model
=
UserGroup
list_serializer_class
=
AdaptedBulkListSerializer
fields
=
[
'id'
,
'name'
,
'users'
,
'comment'
,
'date_created'
,
'created_by'
,
]
extra_kwargs
=
{
'created_by'
:
{
'label'
:
_
(
'Created by'
),
'read_only'
:
True
}
}
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
self
.
set_fields_queryset
()
def
set_fields_queryset
(
self
):
users_field
=
self
.
fields
[
'users'
]
users_field
.
child_relation
.
queryset
=
utils
.
get_current_org_members
()
def
validate_users
(
self
,
users
):
for
user
in
users
:
if
user
.
is_super_auditor
:
msg
=
_
(
'Auditors cannot be join in the user group'
)
raise
serializers
.
ValidationError
(
msg
)
return
users
class
UserGroupListSerializer
(
UserGroupSerializer
):
users
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
class
UserGroupUpdateMemberSerializer
(
serializers
.
ModelSerializer
):
users
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
User
.
objects
)
class
Meta
:
model
=
UserGroup
fields
=
[
'id'
,
'users'
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
self
.
set_fields_queryset
()
def
set_fields_queryset
(
self
):
users_field
=
self
.
fields
[
'users'
]
users_field
.
child_relation
.
queryset
=
utils
.
get_current_org_members
()
apps/users/serializers/
v1
.py
→
apps/users/serializers/
user
.py
View file @
c31b56dd
...
...
@@ -6,19 +6,14 @@ from rest_framework import serializers
from
common.utils
import
validate_ssh_public_key
from
common.mixins
import
BulkSerializerMixin
from
common.fields
import
StringManyToManyField
from
common.serializers
import
AdaptedBulkListSerializer
from
common.permissions
import
CanUpdateDeleteUser
from
orgs.mixins.serializers
import
BulkOrgResourceModelSerializer
from
..models
import
User
,
UserGroup
from
..
import
utils
__all__
=
[
'UserSerializer'
,
'UserPKUpdateSerializer'
,
'UserUpdateGroupSerializer'
,
'UserGroupSerializer'
,
'UserGroupListSerializer'
,
'UserGroupUpdateMemberSerializer'
,
'ChangeUserPasswordSerializer'
,
'ResetOTPSerializer'
,
'ChangeUserPasswordSerializer'
,
'ResetOTPSerializer'
,
]
...
...
@@ -49,7 +44,6 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
'is_valid'
:
{
'label'
:
_
(
'Is valid'
)},
'is_expired'
:
{
'label'
:
_
(
'Is expired'
)},
'avatar_url'
:
{
'label'
:
_
(
'Avatar url'
)},
'source'
:
{
'read_only'
:
True
},
'created_by'
:
{
'read_only'
:
True
,
'allow_blank'
:
True
},
'can_update'
:
{
'read_only'
:
True
},
'can_delete'
:
{
'read_only'
:
True
},
...
...
@@ -127,58 +121,6 @@ class UserUpdateGroupSerializer(serializers.ModelSerializer):
fields
=
[
'id'
,
'groups'
]
class
UserGroupSerializer
(
BulkOrgResourceModelSerializer
):
users
=
serializers
.
PrimaryKeyRelatedField
(
required
=
False
,
many
=
True
,
queryset
=
User
.
objects
,
label
=
_
(
'User'
)
)
class
Meta
:
model
=
UserGroup
list_serializer_class
=
AdaptedBulkListSerializer
fields
=
[
'id'
,
'name'
,
'users'
,
'comment'
,
'date_created'
,
'created_by'
,
]
extra_kwargs
=
{
'created_by'
:
{
'label'
:
_
(
'Created by'
),
'read_only'
:
True
}
}
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
self
.
set_fields_queryset
()
def
set_fields_queryset
(
self
):
users_field
=
self
.
fields
[
'users'
]
users_field
.
child_relation
.
queryset
=
utils
.
get_current_org_members
()
def
validate_users
(
self
,
users
):
for
user
in
users
:
if
user
.
is_super_auditor
:
msg
=
_
(
'Auditors cannot be join in the user group'
)
raise
serializers
.
ValidationError
(
msg
)
return
users
class
UserGroupListSerializer
(
UserGroupSerializer
):
users
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
class
UserGroupUpdateMemberSerializer
(
serializers
.
ModelSerializer
):
users
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
User
.
objects
)
class
Meta
:
model
=
UserGroup
fields
=
[
'id'
,
'users'
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
self
.
set_fields_queryset
()
def
set_fields_queryset
(
self
):
users_field
=
self
.
fields
[
'users'
]
users_field
.
child_relation
.
queryset
=
utils
.
get_current_org_members
()
class
ChangeUserPasswordSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
...
...
apps/users/signals_handler.py
View file @
c31b56dd
...
...
@@ -2,11 +2,11 @@
#
from
django.dispatch
import
receiver
# from django.db.models.signals import post_save
from
django.db.models.signals
import
post_save
,
m2m_changed
from
common.utils
import
get_logger
from
.signals
import
post_user_create
#
from .models import User
from
.models
import
User
logger
=
get_logger
(
__file__
)
...
...
@@ -28,3 +28,14 @@ def on_user_create(sender, user=None, **kwargs):
logger
.
info
(
" - Sending welcome mail ..."
.
format
(
user
.
name
))
if
user
.
email
:
send_user_created_mail
(
user
)
@receiver
(
m2m_changed
,
sender
=
User
.
groups
.
through
)
def
on_user_groups_change
(
sender
,
instance
=
None
,
action
=
''
,
**
kwargs
):
"""
资产节点发生变化时,刷新节点
"""
if
action
.
startswith
(
'post'
):
logger
.
debug
(
"User group member change signal recv: {}"
.
format
(
instance
))
from
perms.utils
import
AssetPermissionUtilV2
AssetPermissionUtilV2
.
expire_all_user_tree_cache
()
apps/users/templates/users/_user.html
View file @
c31b56dd
...
...
@@ -21,6 +21,7 @@
<h3>
{% trans 'Auth' %}
</h3>
{% block password %}{% endblock %}
{% bootstrap_field form.otp_level layout="horizontal" %}
{% bootstrap_field form.source layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Security and Role' %}
</h3>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment