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
d0eafc8b
Commit
d0eafc8b
authored
Apr 25, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
[Update] Merge
parents
8b98c20d
caa5060e
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
184 additions
and
21 deletions
+184
-21
admin_user.py
apps/assets/serializers/admin_user.py
+3
-0
asset.py
apps/assets/serializers/asset.py
+2
-2
cmd_filter.py
apps/assets/serializers/cmd_filter.py
+3
-0
domain.py
apps/assets/serializers/domain.py
+4
-0
label.py
apps/assets/serializers/label.py
+3
-2
system_user.py
apps/assets/serializers/system_user.py
+3
-0
middleware.py
apps/authentication/backends/openid/middleware.py
+3
-3
mixins.py
apps/common/mixins.py
+58
-0
serializers.py
apps/common/serializers.py
+9
-0
serializers.py
apps/orgs/serializers.py
+4
-4
asset_permission_list.html
apps/perms/templates/perms/asset_permission_list.html
+3
-0
v1.py
apps/terminal/serializers/v1.py
+3
-3
user.py
apps/users/api/user.py
+64
-0
v1.py
apps/users/serializers/v1.py
+3
-3
user_detail.html
apps/users/templates/users/user_detail.html
+2
-2
user_list.html
apps/users/templates/users/user_list.html
+8
-2
user.py
apps/users/views/user.py
+9
-0
No files found.
apps/assets/serializers/admin_user.py
View file @
d0eafc8b
...
...
@@ -3,6 +3,8 @@
from
django.core.cache
import
cache
from
rest_framework
import
serializers
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
Node
,
AdminUser
from
..const
import
ADMIN_USER_CONN_CACHE_KEY
...
...
@@ -18,6 +20,7 @@ class AdminUserSerializer(serializers.ModelSerializer):
reachable_amount
=
serializers
.
SerializerMethodField
()
class
Meta
:
list_serializer_class
=
AdaptedBulkListSerializer
model
=
AdminUser
fields
=
'__all__'
...
...
apps/assets/serializers/asset.py
View file @
d0eafc8b
# -*- coding: utf-8 -*-
#
from
rest_framework
import
serializers
from
rest_framework_bulk.serializers
import
BulkListSerializer
from
common.mixins
import
BulkSerializerMixin
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
Asset
from
.system_user
import
AssetSystemUserSerializer
...
...
@@ -19,7 +19,7 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
"""
class
Meta
:
model
=
Asset
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
fields
=
'__all__'
validators
=
[]
...
...
apps/assets/serializers/cmd_filter.py
View file @
d0eafc8b
...
...
@@ -3,6 +3,7 @@
from
rest_framework
import
serializers
from
common.fields
import
ChoiceDisplayField
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
CommandFilter
,
CommandFilterRule
,
SystemUser
...
...
@@ -12,6 +13,7 @@ class CommandFilterSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
CommandFilter
list_serializer_class
=
AdaptedBulkListSerializer
fields
=
'__all__'
...
...
@@ -21,3 +23,4 @@ class CommandFilterRuleSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
CommandFilterRule
fields
=
'__all__'
list_serializer_class
=
AdaptedBulkListSerializer
apps/assets/serializers/domain.py
View file @
d0eafc8b
...
...
@@ -2,6 +2,8 @@
#
from
rest_framework
import
serializers
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
Domain
,
Gateway
...
...
@@ -12,6 +14,7 @@ class DomainSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
Domain
fields
=
'__all__'
list_serializer_class
=
AdaptedBulkListSerializer
@staticmethod
def
get_asset_count
(
obj
):
...
...
@@ -25,6 +28,7 @@ class DomainSerializer(serializers.ModelSerializer):
class
GatewaySerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Gateway
list_serializer_class
=
AdaptedBulkListSerializer
fields
=
[
'id'
,
'name'
,
'ip'
,
'port'
,
'protocol'
,
'username'
,
'domain'
,
'is_active'
,
'date_created'
,
'date_updated'
,
...
...
apps/assets/serializers/label.py
View file @
d0eafc8b
# -*- coding: utf-8 -*-
#
from
rest_framework
import
serializers
from
rest_framework_bulk.serializers
import
BulkListSerializer
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
Label
...
...
@@ -12,7 +13,7 @@ class LabelSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
Label
fields
=
'__all__'
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
@staticmethod
def
get_asset_count
(
obj
):
...
...
apps/assets/serializers/system_user.py
View file @
d0eafc8b
from
rest_framework
import
serializers
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
SystemUser
,
Asset
from
.base
import
AuthSerializer
...
...
@@ -17,6 +19,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
SystemUser
exclude
=
(
'_password'
,
'_private_key'
,
'_public_key'
)
list_serializer_class
=
AdaptedBulkListSerializer
def
get_field_names
(
self
,
declared_fields
,
info
):
fields
=
super
(
SystemUserSerializer
,
self
)
.
get_field_names
(
declared_fields
,
info
)
...
...
apps/authentication/backends/openid/middleware.py
View file @
d0eafc8b
...
...
@@ -23,14 +23,15 @@ class OpenIDAuthenticationMiddleware(MiddlewareMixin):
def
process_request
(
self
,
request
):
# Don't need openid auth if AUTH_OPENID is False
if
not
settings
.
AUTH_OPENID
:
logger
.
debug
(
"Not settings.AUTH_OPENID"
)
return
# Don't need check single logout if user not authenticated
if
not
request
.
user
.
is_authenticated
:
logger
.
info
(
"User is not authenticated"
)
logger
.
debug
(
"User is not authenticated"
)
return
elif
not
request
.
session
[
BACKEND_SESSION_KEY
]
.
endswith
(
BACKEND_OPENID_AUTH_CODE
):
logger
.
info
(
"BACKEND_SESSION_KEY is not BACKEND_OPENID_AUTH_CODE"
)
logger
.
debug
(
"BACKEND_SESSION_KEY is not BACKEND_OPENID_AUTH_CODE"
)
return
# Check openid user single logout or not with access_token
...
...
@@ -39,7 +40,6 @@ class OpenIDAuthenticationMiddleware(MiddlewareMixin):
client
.
openid_connect_client
.
userinfo
(
token
=
request
.
session
.
get
(
OIDT_ACCESS_TOKEN
)
)
except
Exception
as
e
:
logout
(
request
)
logger
.
error
(
e
)
apps/common/mixins.py
View file @
d0eafc8b
...
...
@@ -4,6 +4,10 @@ from django.db import models
from
django.http
import
JsonResponse
from
django.utils
import
timezone
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework.utils
import
html
from
rest_framework.settings
import
api_settings
from
rest_framework.exceptions
import
ValidationError
from
rest_framework.fields
import
SkipField
class
NoDeleteQuerySet
(
models
.
query
.
QuerySet
):
...
...
@@ -89,6 +93,60 @@ class BulkSerializerMixin(object):
return
ret
class
BulkListSerializerMixin
(
object
):
"""
Become rest_framework_bulk doing bulk update raise Exception:
'QuerySet' object has no attribute 'pk' when doing bulk update
so rewrite it .
https://github.com/miki725/django-rest-framework-bulk/issues/68
"""
def
to_internal_value
(
self
,
data
):
"""
List of dicts of native values <- List of dicts of primitive datatypes.
"""
if
html
.
is_html_input
(
data
):
data
=
html
.
parse_html_list
(
data
)
if
not
isinstance
(
data
,
list
):
message
=
self
.
error_messages
[
'not_a_list'
]
.
format
(
input_type
=
type
(
data
)
.
__name__
)
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
},
code
=
'not_a_list'
)
if
not
self
.
allow_empty
and
len
(
data
)
==
0
:
if
self
.
parent
and
self
.
partial
:
raise
SkipField
()
message
=
self
.
error_messages
[
'empty'
]
raise
ValidationError
({
api_settings
.
NON_FIELD_ERRORS_KEY
:
[
message
]
},
code
=
'empty'
)
ret
=
[]
errors
=
[]
for
item
in
data
:
try
:
# prepare child serializer to only handle one instance
self
.
child
.
instance
=
self
.
instance
.
get
(
id
=
item
[
'id'
])
if
self
.
instance
else
None
self
.
child
.
initial_data
=
item
# raw
validated
=
self
.
child
.
run_validation
(
item
)
except
ValidationError
as
exc
:
errors
.
append
(
exc
.
detail
)
else
:
ret
.
append
(
validated
)
errors
.
append
({})
if
any
(
errors
):
raise
ValidationError
(
errors
)
return
ret
class
DatetimeSearchMixin
:
date_format
=
'
%
Y-
%
m-
%
d'
date_from
=
date_to
=
None
...
...
apps/common/serializers.py
0 → 100644
View file @
d0eafc8b
# -*- coding: utf-8 -*-
#
from
.mixins
import
BulkListSerializerMixin
from
rest_framework_bulk.serializers
import
BulkListSerializer
class
AdaptedBulkListSerializer
(
BulkListSerializerMixin
,
BulkListSerializer
):
pass
apps/orgs/serializers.py
View file @
d0eafc8b
from
rest_framework.serializers
import
ModelSerializer
from
rest_framework
import
serializers
from
rest_framework_bulk
import
BulkListSerializer
from
users.models
import
User
,
UserGroup
from
assets.models
import
Asset
,
Domain
,
AdminUser
,
SystemUser
,
Label
from
perms.models
import
AssetPermission
from
common.serializers
import
AdaptedBulkListSerializer
from
.utils
import
set_current_org
,
get_current_org
from
.models
import
Organization
from
.mixins
import
OrgMembershipSerializerMixin
...
...
@@ -14,7 +14,7 @@ from .mixins import OrgMembershipSerializerMixin
class
OrgSerializer
(
ModelSerializer
):
class
Meta
:
model
=
Organization
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
fields
=
'__all__'
read_only_fields
=
[
'created_by'
,
'date_created'
]
...
...
@@ -70,12 +70,12 @@ class OrgReadSerializer(ModelSerializer):
class
OrgMembershipAdminSerializer
(
OrgMembershipSerializerMixin
,
ModelSerializer
):
class
Meta
:
model
=
Organization
.
admins
.
through
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
fields
=
'__all__'
class
OrgMembershipUserSerializer
(
OrgMembershipSerializerMixin
,
ModelSerializer
):
class
Meta
:
model
=
Organization
.
users
.
through
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
fields
=
'__all__'
apps/perms/templates/perms/asset_permission_list.html
View file @
d0eafc8b
...
...
@@ -130,6 +130,9 @@ function format(d) {
if
(
d
.
system_users
.
length
>
0
)
{
data
+=
makeLabel
([
"{% trans 'System user' %}"
,
d
.
system_users
.
join
(
", "
)])
}
if
(
d
.
actions
.
length
>
0
)
{
data
+=
makeLabel
([
"{% trans 'Action' %}"
,
d
.
actions
.
join
(
", "
)])
}
return
data
}
...
...
apps/terminal/serializers/v1.py
View file @
d0eafc8b
# -*- coding: utf-8 -*-
#
from
rest_framework
import
serializers
from
rest_framework_bulk.serializers
import
BulkListSerializer
from
common.mixins
import
BulkSerializerMixin
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
Terminal
,
Status
,
Session
,
Task
...
...
@@ -29,7 +29,7 @@ class SessionSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class
Meta
:
model
=
Session
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
fields
=
'__all__'
...
...
@@ -44,7 +44,7 @@ class TaskSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class
Meta
:
fields
=
'__all__'
model
=
Task
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
class
ReplaySerializer
(
serializers
.
Serializer
):
...
...
apps/users/api/user.py
View file @
d0eafc8b
...
...
@@ -5,6 +5,7 @@ from django.core.cache import cache
from
django.contrib.auth
import
logout
from
django.utils.translation
import
ugettext
as
_
from
rest_framework
import
status
from
rest_framework
import
generics
from
rest_framework.response
import
Response
from
rest_framework.permissions
import
IsAuthenticated
...
...
@@ -52,9 +53,72 @@ class UserViewSet(IDInFilterMixin, BulkModelViewSet):
self
.
permission_classes
=
(
IsOrgAdminOrAppUser
,)
return
super
()
.
get_permissions
()
def
_deny_permission
(
self
,
instance
):
"""
check current user has permission to handle instance
(update, destroy, bulk_update, bulk destroy)
"""
return
not
self
.
request
.
user
.
is_superuser
and
instance
.
is_superuser
def
destroy
(
self
,
request
,
*
args
,
**
kwargs
):
"""
rewrite because limit org_admin destroy superuser
"""
instance
=
self
.
get_object
()
if
self
.
_deny_permission
(
instance
):
data
=
{
'msg'
:
_
(
"You do not have permission."
)}
return
Response
(
data
=
data
,
status
=
status
.
HTTP_403_FORBIDDEN
)
return
super
()
.
destroy
(
request
,
*
args
,
**
kwargs
)
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
"""
rewrite because limit org_admin update superuser
"""
instance
=
self
.
get_object
()
if
self
.
_deny_permission
(
instance
):
data
=
{
'msg'
:
_
(
"You do not have permission."
)}
return
Response
(
data
=
data
,
status
=
status
.
HTTP_403_FORBIDDEN
)
return
super
()
.
update
(
request
,
*
args
,
**
kwargs
)
def
_bulk_deny_permission
(
self
,
instances
):
deny_instances
=
[
i
for
i
in
instances
if
self
.
_deny_permission
(
i
)]
if
len
(
deny_instances
)
>
0
:
return
True
else
:
return
False
def
allow_bulk_destroy
(
self
,
qs
,
filtered
):
if
self
.
_bulk_deny_permission
(
filtered
):
return
False
return
qs
.
count
()
!=
filtered
.
count
()
def
bulk_update
(
self
,
request
,
*
args
,
**
kwargs
):
"""
rewrite because limit org_admin update superuser
"""
partial
=
kwargs
.
pop
(
'partial'
,
False
)
# restrict the update to the filtered queryset
queryset
=
self
.
filter_queryset
(
self
.
get_queryset
())
if
self
.
_bulk_deny_permission
(
queryset
):
data
=
{
'msg'
:
_
(
"You do not have permission."
)}
return
Response
(
data
=
data
,
status
=
status
.
HTTP_403_FORBIDDEN
)
serializer
=
self
.
get_serializer
(
queryset
,
data
=
request
.
data
,
many
=
True
,
partial
=
partial
,
)
try
:
serializer
.
is_valid
(
raise_exception
=
True
)
except
Exception
as
e
:
data
=
{
'error'
:
str
(
e
)}
return
Response
(
data
=
data
,
status
=
status
.
HTTP_400_BAD_REQUEST
)
self
.
perform_bulk_update
(
serializer
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_200_OK
)
class
UserChangePasswordApi
(
generics
.
RetrieveUpdateAPIView
):
permission_classes
=
(
IsOrgAdmin
,)
...
...
apps/users/serializers/v1.py
View file @
d0eafc8b
...
...
@@ -3,10 +3,10 @@
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework
import
serializers
from
rest_framework_bulk
import
BulkListSerializer
from
common.utils
import
get_signer
,
validate_ssh_public_key
from
common.mixins
import
BulkSerializerMixin
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
User
,
UserGroup
signer
=
get_signer
()
...
...
@@ -16,7 +16,7 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class
Meta
:
model
=
User
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
fields
=
[
'id'
,
'name'
,
'username'
,
'email'
,
'groups'
,
'groups_display'
,
'role'
,
'role_display'
,
'avatar_url'
,
'wechat'
,
'phone'
,
...
...
@@ -52,7 +52,7 @@ class UserGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class
Meta
:
model
=
UserGroup
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
Adapted
BulkListSerializer
fields
=
'__all__'
read_only_fields
=
[
'created_by'
]
...
...
apps/users/templates/users/user_detail.html
View file @
d0eafc8b
...
...
@@ -22,11 +22,11 @@
<a
href=
"{% url 'users:user-granted-asset' pk=user_object.id %}"
class=
"text-center"
><i
class=
"fa fa-cubes"
></i>
{% trans 'Asset granted' %}
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline
btn-default
"
href=
"{% url 'users:user-update' pk=user_object.id %}"
><i
class=
"fa fa-edit"
></i>
{% trans 'Update' %}
</a>
<a
class=
"btn btn-outline
{% if user_object.is_superuser and not request.user.is_superuser %} disabled {% else %} btn-default {% endif %}
"
href=
"{% url 'users:user-update' pk=user_object.id %}"
><i
class=
"fa fa-edit"
></i>
{% trans 'Update' %}
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline {% if request.user
!= user_object and user_object.username != "
admin
"
%}
btn-danger
btn-delete-user
{%
else
%}
disabled
{%
endif
%}"
>
<a
class=
"btn btn-outline {% if request.user
== user_object or user_object.username == "
admin
"
or
user_object
.
is_superuser
and
not
request
.
user
.
is_superuser
%}
disabled
{%
else
%}
btn-danger
btn-delete-user
{%
endif
%}"
>
<i
class=
"fa fa-trash-o"
></i>
{% trans 'Delete' %}
</a>
</li>
...
...
apps/users/templates/users/user_list.html
View file @
d0eafc8b
...
...
@@ -77,10 +77,16 @@ function initTable() {
}
}},
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "users:user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'00000000-0000-0000-0000-000000000000'
,
cellData
);
var
update_btn
=
""
;
if
(
rowData
.
role
===
'Admin'
&&
(
'{{ request.user.role }}'
!==
'Admin'
))
{
update_btn
=
'<a class="btn btn-xs disabled btn-info">{% trans "Update" %}</a>'
;
}
else
{
update_btn
=
'<a href="{% url "users:user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'00000000-0000-0000-0000-000000000000'
,
cellData
);
}
var
del_btn
=
""
;
if
(
rowData
.
id
===
1
||
rowData
.
username
===
"admin"
||
rowData
.
username
===
"{{ request.user.username }}"
)
{
if
(
rowData
.
id
===
1
||
rowData
.
username
===
"admin"
||
rowData
.
username
===
"{{ request.user.username }}"
||
(
rowData
.
role
===
'Admin'
&&
(
'{{ request.user.role }}'
!==
'Admin'
))
)
{
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
)
.
replace
(
'99991938'
,
rowData
.
name
);
...
...
apps/users/views/user.py
View file @
d0eafc8b
...
...
@@ -107,6 +107,15 @@ class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
success_url
=
reverse_lazy
(
'users:user-list'
)
success_message
=
update_success_msg
def
_deny_permission
(
self
):
obj
=
self
.
get_object
()
return
not
self
.
request
.
user
.
is_superuser
and
obj
.
is_superuser
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
if
self
.
_deny_permission
():
return
redirect
(
self
.
success_url
)
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
check_rules
=
get_password_check_rules
()
context
=
{
...
...
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