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
a79c3dd1
Commit
a79c3dd1
authored
Feb 06, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Fixture] 添加command log backends, 未来支持es
parent
0869931e
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
566 additions
and
243 deletions
+566
-243
api.py
apps/applications/api.py
+2
-1
user.py
apps/assets/models/user.py
+10
-0
views.py
apps/assets/views.py
+7
-9
__init__.py
apps/audits/__init__.py
+1
-0
api.py
apps/audits/api.py
+19
-5
__init__.py
apps/audits/backends/__init__.py
+6
-0
__init__.py
apps/audits/backends/command/__init__.py
+0
-0
base.py
apps/audits/backends/command/base.py
+19
-0
db.py
apps/audits/backends/command/db.py
+45
-0
serializers.py
apps/audits/backends/command/serializers.py
+21
-0
models.py
apps/audits/models.py
+35
-38
serializers.py
apps/audits/serializers.py
+2
-10
command_log_list.html
apps/audits/templates/audits/command_log_list.html
+15
-16
proxy_log_detail.html
apps/audits/templates/audits/proxy_log_detail.html
+3
-3
proxy_log_list.html
apps/audits/templates/audits/proxy_log_list.html
+39
-30
api_urls.py
apps/audits/urls/api_urls.py
+2
-1
views.py
apps/audits/views.py
+0
-0
common_tags.py
apps/common/templatetags/common_tags.py
+25
-4
utils.py
apps/common/utils.py
+6
-4
middleware.py
apps/jumpserver/middleware.py
+14
-0
settings.py
apps/jumpserver/settings.py
+3
-0
api.py
apps/perms/api.py
+43
-0
forms.py
apps/perms/forms.py
+0
-11
hands.py
apps/perms/hands.py
+4
-4
models.py
apps/perms/models.py
+33
-12
asset_permission_detail.html
apps/perms/templates/perms/asset_permission_detail.html
+66
-4
asset_permission_user.html
apps/perms/templates/perms/asset_permission_user.html
+28
-23
tests.py
apps/perms/tests.py
+3
-1
api_urls.py
apps/perms/urls/api_urls.py
+6
-1
utils.py
apps/perms/utils.py
+36
-5
views.py
apps/perms/views.py
+22
-3
jumpserver.js
apps/static/js/jumpserver.js
+22
-22
authentication.py
apps/users/authentication.py
+0
-1
forms.py
apps/users/forms.py
+28
-35
group.py
apps/users/views/group.py
+1
-0
deb_requirements.txt
requirements/deb_requirements.txt
+0
-0
mac_requirements.py
requirements/mac_requirements.py
+0
-0
requirements.txt
requirements/requirements.txt
+0
-0
rpm_requirements.txt
requirements/rpm_requirements.txt
+0
-0
No files found.
apps/applications/api.py
View file @
a79c3dd1
# -*- coding: utf-8 -*-
#
from
collections
import
OrderedDict
from
django.core.cache
import
cache
from
django.conf
import
settings
import
copy
...
...
@@ -35,7 +36,7 @@ class TerminalRegisterView(ListCreateAPIView):
if
serializer
.
is_valid
():
terminal
=
serializer
.
save
()
app_user
,
access_key
=
terminal
.
create_related_app_user
()
data
=
{}
data
=
OrderedDict
()
data
[
'terminal'
]
=
copy
.
deepcopy
(
serializer
.
data
)
data
[
'user'
]
=
app_user
.
to_json
()
data
[
'access_key_id'
]
=
access_key
.
id
...
...
apps/assets/models/user.py
View file @
a79c3dd1
...
...
@@ -167,6 +167,16 @@ class SystemUser(models.Model):
def
asset_group_amount
(
self
):
return
self
.
asset_groups
.
count
()
def
to_json
(
self
):
return
{
'id'
:
self
.
id
,
'name'
:
self
.
name
,
'username'
:
self
.
username
,
'protocol'
:
self
.
protocol
,
'auth_method'
:
self
.
auth_method
,
'auto_push'
:
self
.
auto_push
,
}
class
Meta
:
ordering
=
[
'name'
]
...
...
apps/assets/views.py
View file @
a79c3dd1
...
...
@@ -233,9 +233,6 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
form_class
=
forms
.
AssetGroupForm
template_name
=
'assets/asset_group_create.html'
success_url
=
reverse_lazy
(
'assets:asset-group-list'
)
#ordering = '-id'
# Todo: Asset group create template select assets so hard, need be resolve next
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
...
...
@@ -249,7 +246,8 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
def
form_valid
(
self
,
form
):
asset_group
=
form
.
save
()
assets_id_list
=
self
.
request
.
POST
.
getlist
(
'assets'
,
[])
assets
=
[
get_object_or_404
(
Asset
,
id
=
int
(
asset_id
))
for
asset_id
in
assets_id_list
]
assets
=
[
get_object_or_404
(
Asset
,
id
=
int
(
asset_id
))
for
asset_id
in
assets_id_list
]
asset_group
.
created_by
=
self
.
request
.
user
.
username
or
'Admin'
asset_group
.
assets
.
add
(
*
tuple
(
assets
))
asset_group
.
save
()
...
...
@@ -284,7 +282,8 @@ class AssetGroupDetailView(AdminUserRequiredMixin, DetailView):
'app'
:
_
(
'Assets'
),
'action'
:
_
(
'Asset group detail'
),
'assets_remain'
:
assets_remain
,
'assets'
:
[
asset
for
asset
in
Asset
.
objects
.
all
()
if
asset
not
in
assets_remain
],
'assets'
:
[
asset
for
asset
in
Asset
.
objects
.
all
()
if
asset
not
in
assets_remain
],
'system_users'
:
system_users
,
'system_users_remain'
:
system_users_remain
,
}
...
...
@@ -349,10 +348,9 @@ class IDCCreateView(AdminUserRequiredMixin, CreateView):
return
super
(
IDCCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
def
form_valid
(
self
,
form
):
IDC
=
form
.
save
(
commit
=
False
)
IDC
.
created_by
=
self
.
request
.
user
.
username
or
'System'
IDC
.
save
()
# IDC_add_success_next(user)
idc
=
form
.
save
(
commit
=
False
)
idc
.
created_by
=
self
.
request
.
user
.
username
or
'System'
idc
.
save
()
return
super
(
IDCCreateView
,
self
)
.
form_valid
(
form
)
...
...
apps/audits/__init__.py
View file @
a79c3dd1
apps/audits/api.py
View file @
a79c3dd1
...
...
@@ -5,11 +5,12 @@
from
__future__
import
absolute_import
,
unicode_literals
from
rest_framework
import
generics
,
viewsets
from
rest_framework.views
import
APIView
,
Response
from
rest_framework_bulk
import
BulkModelViewSet
from
audits.backends
import
command_store
from
audits.backends.command.serializers
import
CommandLogSerializer
from
.
import
models
,
serializers
from
.hands
import
IsSuperUserOrAppUser
,
Terminal
,
IsAppUser
from
.hands
import
IsSuperUserOrAppUser
,
IsAppUser
class
ProxyLogReceiveView
(
generics
.
CreateAPIView
):
...
...
@@ -47,8 +48,21 @@ class ProxyLogViewSet(viewsets.ModelViewSet):
permission_classes
=
(
IsSuperUserOrAppUser
,)
class
CommandLogViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
models
.
CommandLog
.
objects
.
all
()
serializer_class
=
serializers
.
CommandLogSerializer
class
CommandLogViewSet
(
BulkModelViewSet
):
"""接受app发送来的command log, 格式如下
{
"proxy_log_id": 23,
"user": "admin",
"asset": "localhost",
"system_user": "web",
"command_no": 1,
"command": "whoami",
"output": "d2hvbWFp", # base64.b64encode(s)
"timestamp": 1485238673.0
}
"""
queryset
=
command_store
.
all
()
serializer_class
=
CommandLogSerializer
permission_classes
=
(
IsSuperUserOrAppUser
,)
apps/audits/backends/__init__.py
0 → 100644
View file @
a79c3dd1
from
importlib
import
import_module
from
django.conf
import
settings
command_engine
=
import_module
(
settings
.
COMMAND_STORE_BACKEND
)
command_store
=
command_engine
.
CommandStore
()
from
.command.serializers
import
CommandLogSerializer
mac_requirements
.py
→
apps/audits/backends/command/__init__
.py
View file @
a79c3dd1
File moved
apps/audits/backends/command/base.py
0 → 100644
View file @
a79c3dd1
# coding: utf-8
import
abc
class
CommandBase
(
object
):
__metaclass__
=
abc
.
ABCMeta
@abc.abstractmethod
def
save
(
self
,
proxy_log_id
,
user
,
asset
,
system_user
,
command_no
,
command
,
output
,
timestamp
):
pass
@abc.abstractmethod
def
filter
(
self
,
date_from
=
None
,
date_to
=
None
,
user
=
''
,
asset
=
''
,
system_user
=
''
,
command
=
''
):
pass
apps/audits/backends/command/db.py
0 → 100644
View file @
a79c3dd1
# ~*~ coding: utf-8 ~*~
from
.base
import
CommandBase
from
audits.models
import
CommandLog
class
CommandStore
(
CommandBase
):
model
=
CommandLog
queryset
=
[]
def
save
(
self
,
proxy_log_id
,
user
,
asset
,
system_user
,
command_no
,
command
,
output
,
timestamp
):
self
.
model
.
objects
.
create
(
proxy_log_id
=
proxy_log_id
,
user
=
user
,
asset
=
asset
,
system_user
=
system_user
,
command_no
=
command_no
,
command
=
command
,
output
=
output
,
timestamp
=
timestamp
)
def
filter
(
self
,
date_from_ts
=
None
,
date_to_ts
=
None
,
user
=
''
,
asset
=
''
,
system_user
=
''
,
command
=
''
,
proxy_log_id
=
''
):
filter_kwargs
=
{}
if
date_from_ts
:
filter_kwargs
[
'timestamp__gte'
]
=
date_from_ts
if
date_to_ts
:
filter_kwargs
[
'timestamp__lte'
]
=
date_to_ts
if
user
:
filter_kwargs
[
'user'
]
=
user
if
asset
:
filter_kwargs
[
'asset'
]
=
asset
if
system_user
:
filter_kwargs
[
'system_user'
]
=
system_user
if
command
:
filter_kwargs
[
'command__icontains'
]
=
command
if
proxy_log_id
:
filter_kwargs
[
'proxy_log_id'
]
=
proxy_log_id
if
filter_kwargs
:
self
.
queryset
=
self
.
model
.
objects
.
filter
(
**
filter_kwargs
)
return
self
.
queryset
def
all
(
self
):
"""返回所有数据"""
return
self
.
model
.
objects
.
iterator
()
apps/audits/backends/command/serializers.py
0 → 100644
View file @
a79c3dd1
# ~*~ coding: utf-8 ~*~
import
base64
from
rest_framework
import
serializers
from
audits.models
import
CommandLog
from
audits.backends
import
command_store
class
CommandLogSerializer
(
serializers
.
ModelSerializer
):
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
class
Meta
:
model
=
CommandLog
fields
=
'__all__'
def
save
(
self
):
try
:
output
=
self
.
validated_data
[
'output'
]
self
.
validated_data
[
'output'
]
=
base64
.
b64decode
(
output
)
except
IndexError
:
pass
return
command_store
.
save
(
**
dict
(
self
.
validated_data
))
apps/audits/models.py
View file @
a79c3dd1
...
...
@@ -24,7 +24,8 @@ class LoginLog(models.Model):
verbose_name
=
_
(
'Login city'
))
user_agent
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'User agent'
))
date_login
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Date login'
))
date_login
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Date login'
))
class
Meta
:
db_table
=
'login_log'
...
...
@@ -37,56 +38,52 @@ class ProxyLog(models.Model):
(
'WT'
,
'Web Terminal'
),
)
user
name
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username
'
))
name
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
_
(
'Name
'
))
hostname
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Hostname
'
))
ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
verbose_name
=
_
(
'IP'
))
system_user
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'System user'
))
login_type
=
models
.
CharField
(
choices
=
LOGIN_TYPE_CHOICE
,
max_length
=
2
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Login type'
))
terminal
=
models
.
CharField
(
max_length
=
32
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Terminal'
))
user
=
models
.
CharField
(
max_length
=
32
,
verbose_name
=
_
(
'User
'
))
asset
=
models
.
CharField
(
max_length
=
32
,
verbose_name
=
_
(
'Asset
'
))
system_user
=
models
.
CharField
(
max_length
=
32
,
verbose_name
=
_
(
'System user
'
))
login_type
=
models
.
CharField
(
choices
=
LOGIN_TYPE_CHOICE
,
max_length
=
2
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Login type'
))
terminal
=
models
.
CharField
(
max_length
=
32
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Terminal'
))
log_file
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
,
null
=
True
)
was_failed
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Did connect failed'
))
is_finished
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Is finished'
))
date_start
=
models
.
DateTimeField
(
auto_created
=
True
,
verbose_name
=
_
(
'Date start'
))
date_finished
=
models
.
DateTimeField
(
null
=
True
,
verbose_name
=
_
(
'Date finished'
))
is_failed
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Did connect failed'
))
is_finished
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Is finished'
))
date_start
=
models
.
DateTimeField
(
auto_created
=
True
,
verbose_name
=
_
(
'Date start'
))
date_finished
=
models
.
DateTimeField
(
null
=
True
,
verbose_name
=
_
(
'Date finished'
))
def
__unicode__
(
self
):
return
'
%
s-
%
s-
%
s-
%
s'
%
(
self
.
username
,
self
.
hostname
,
self
.
system_user
,
self
.
id
)
@property
def
commands_dict
(
self
):
commands
=
self
.
command_log
.
all
()
return
[{
"command_no"
:
command
.
command_no
,
"command"
:
command
.
command
,
"output"
:
command
.
output_decode
,
"datetime"
:
command
.
datetime
,
}
for
command
in
commands
]
return
'
%
s-
%
s-
%
s'
%
(
self
.
user
,
self
.
asset
,
self
.
system_user
)
class
Meta
:
ordering
=
[
'-date_start'
,
'user
name
'
]
ordering
=
[
'-date_start'
,
'user'
]
class
CommandLog
(
models
.
Model
):
proxy_log
=
models
.
ForeignKey
(
ProxyLog
,
on_delete
=
models
.
CASCADE
,
related_name
=
'commands'
)
proxy_log_id
=
models
.
IntegerField
()
user
=
models
.
CharField
(
max_length
=
48
,
db_index
=
True
)
asset
=
models
.
CharField
(
max_length
=
128
,
db_index
=
True
)
system_user
=
models
.
CharField
(
max_length
=
48
,
db_index
=
True
)
command_no
=
models
.
IntegerField
()
command
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
)
command
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
,
db_index
=
True
)
output
=
models
.
TextField
(
blank
=
True
)
datetime
=
models
.
DateTimeField
(
null
=
True
)
timestamp
=
models
.
FloatField
(
null
=
True
,
db_index
=
True
)
def
__unicode__
(
self
):
return
'
%
s:
%
s'
%
(
self
.
id
,
self
.
command
)
@property
def
output_decode
(
self
):
try
:
return
base64
.
b64decode
(
self
.
output
)
.
decode
(
'utf-8'
)
\
.
replace
(
'
\n
'
,
'<br />'
)
except
UnicodeDecodeError
:
return
'UnicodeDecodeError'
class
Meta
:
db_table
=
'command_log'
ordering
=
[
'command_no'
,
'command'
]
class
RecordLog
(
models
.
Model
):
proxy_log_id
=
models
.
IntegerField
()
output
=
models
.
TextField
(
verbose_name
=
_
(
'Output'
))
timestamp
=
models
.
FloatField
(
null
=
True
)
def
__unicode__
(
self
):
return
'Record:
%
s'
%
self
.
proxy_log_id
apps/audits/serializers.py
View file @
a79c3dd1
...
...
@@ -13,10 +13,7 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
models
.
ProxyLog
fields
=
[
'id'
,
'name'
,
'username'
,
'hostname'
,
'ip'
,
'system_user'
,
'login_type'
,
'terminal'
,
'log_file'
,
'was_failed'
,
'is_finished'
,
'date_start'
,
'date_finished'
,
'time'
,
'command_length'
,
"commands_dict"
]
fields
=
'__all__'
@staticmethod
def
get_time
(
obj
):
...
...
@@ -27,10 +24,5 @@ class ProxyLogSerializer(serializers.ModelSerializer):
@staticmethod
def
get_command_length
(
obj
):
return
len
(
obj
.
commands
.
all
())
return
2
class
CommandLogSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
models
.
CommandLog
fields
=
'__all__'
apps/audits/templates/audits/command_log_list.html
View file @
a79c3dd1
...
...
@@ -23,32 +23,31 @@
</div>
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"user
name
"
>
<select
class=
"select2 form-control"
name=
"user"
>
<option
value=
""
>
{% trans 'User' %}
</option>
{% for u
ser
in user_list %}
<option
value=
"{{ u
ser.username }}"
{%
if
user
.
username =
=
username
%}
selected
{%
endif
%}
>
{{ user
.username }}
</option>
{% for u in user_list %}
<option
value=
"{{ u
.username }}"
{%
if
user =
=
u
.
username
%}
selected
{%
endif
%}
>
{{ u
.username }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"
ip
"
>
<select
class=
"select2 form-control"
name=
"
asset
"
>
<option
value=
""
>
{% trans 'Asset' %}
</option>
{% for a
sset
in asset_list %}
<option
value=
"{{ a
sset.ip }}"
{%
if
asset
.
ip =
=
ip
%}
selected
{%
endif
%}
>
{{ asset
.ip }}
</option>
{% for a in asset_list %}
<option
value=
"{{ a
.ip }}"
{%
if
asset =
=
a
.
ip
%}
selected
{%
endif
%}
>
{{ a
.ip }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"system_user"
>
{#
<option
value=
""
>
{{ system_user }}
</option>
#}
<option
value=
""
>
{% trans 'System user' %}
</option>
{% for s
ystem_user
in system_user_list %}
<option
value=
"{{ s
ystem_user.username }}"
{%
if
system_user
.
username =
=
system_user
%}
selected
{%
endif
%}
>
{{ system_user
.username }}
</option>
{% for s in system_user_list %}
<option
value=
"{{ s
.username }}"
{%
if
s
.
username =
=
system_user
%}
selected
{%
endif
%}
>
{{ s
.username }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"
keyword"
placeholder=
"Search"
value=
"{{ keywor
d }}"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"
command"
placeholder=
"Command"
value=
"{{ comman
d }}"
>
</div>
<div
class=
"input-group"
>
<div
class=
"input-group-btn"
>
...
...
@@ -78,12 +77,12 @@
<tr>
<td>
{{ command.id }}
</td>
<td>
{{ command.command }}
</td>
<td>
{{ command.
proxy_log.username
}}
</td>
<td>
{{ command.
proxy_log.ip
}}
</td>
<td>
{{ command.
proxy_log.
system_user }}
</td>
<td><a
href=
"{% url 'audits:proxy-log-detail' pk=command.proxy_log
.id %}"
>
{{ command.proxy_log.
id}}
</a></td>
<td>
{{ command.
datetim
e }}
</td>
<td>
{{ command.output_decode|safe }}
</td>
<td>
{{ command.
user
}}
</td>
<td>
{{ command.
asset
}}
</td>
<td>
{{ command.system_user }}
</td>
<td><a
href=
"{% url 'audits:proxy-log-detail' pk=command.proxy_log
_id %}"
>
{{ command.proxy_log_
id}}
</a></td>
<td>
{{ command.
timestamp|ts_to_dat
e }}
</td>
<td>
<pre
style=
"border: none; background: none"
>
{{ command.output|to_html|safe }}
</pre>
</td>
</tr>
{% endfor %}
</tbody>
...
...
apps/audits/templates/audits/proxy_log_detail.html
View file @
a79c3dd1
...
...
@@ -19,7 +19,7 @@
</ul>
</div>
<div
class=
"tab-content"
>
<div
class=
"col-sm-
7
"
style=
"padding-left: 0;"
>
<div
class=
"col-sm-
11
"
style=
"padding-left: 0;"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<span
style=
"float: left"
>
{% trans 'Command log list' %}
<b>
{{ user_object.name }}
</b></span>
...
...
@@ -52,8 +52,8 @@
<tr>
<td>
{{ command.command_no }}
</td>
<td>
{{ command.command }}
</td>
<td>
{{ command.output_decode|safe }}
</td>
<td>
{{ command.
datetime
}}
</td>
<td>
<pre
style=
"border: none;background: none"
>
{{ command.output|to_html|safe}}
</pre>
</td>
<td>
{{ command.
timestamp|ts_to_date
}}
</td>
</tr>
{% endfor %}
</tbody>
...
...
apps/audits/templates/audits/proxy_log_list.html
View file @
a79c3dd1
...
...
@@ -47,7 +47,7 @@
</select>
</div>
<div
class=
"input-group"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"
Comman
d"
value=
"{{ keyword }}"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"
Keywor
d"
value=
"{{ keyword }}"
>
</div>
<div
class=
"input-group"
>
<div
class=
"input-group-btn"
>
...
...
@@ -61,44 +61,53 @@
{% block table_head %}
<th
class=
"text-center"
>
{% trans 'ID' %}
</th>
<th
class=
"text-center"
>
{% trans 'User
name
' %}
</th>
<th
class=
"text-center"
>
{% trans '
IP
' %}
</th>
<th
class=
"text-center"
>
{% trans 'User' %}
</th>
<th
class=
"text-center"
>
{% trans '
Asset
' %}
</th>
<th
class=
"text-center"
>
{% trans 'System user' %}
</th>
<th
class=
"text-center"
>
{% trans 'Command' %}
</th>
<th
class=
"text-center"
>
{% trans 'Success' %}
</th>
<th
class=
"text-center"
>
{% trans 'Finished' %}
</th>
<th
class=
"text-center"
>
{% trans 'R/M' %}
</th>
<th
class=
"text-center"
>
{% trans 'Date start' %}
</th>
<th
class=
"text-center"
>
{% trans 'Time' %}
</th>
{% endblock %}
{% block table_body %}
{% for proxy_log in proxy_log_list %}
<tr
class=
"gradeX"
>
<td
class=
"text-center"
>
<a
href=
"{% url 'audits:proxy-log-detail' pk=proxy_log.id %}"
>
{{ proxy_log.id }}
</a>
</td>
<td
class=
"text-center"
>
{{ proxy_log.username }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.ip }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.system_user }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.commands.all|length}}
</td>
<td
class=
"text-center"
>
{% if proxy_log.was_failed %}
<i
class=
"fa fa-times text-danger"
></i>
{% else %}
<i
class=
"fa fa-check text-navy"
></i>
{% endif %}
</td>
<td
class=
"text-center"
>
{% if proxy_log.is_finished %}
<i
class=
"fa fa-check text-navy"
></i>
{% else %}
<i
class=
"fa fa-times text-danger"
></i>
{% endif %}
</td>
<td
class=
"text-center"
>
{{ proxy_log.date_start }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}
</td>
</tr>
{% endfor %}
{% for proxy_log in proxy_log_list %}
<tr
class=
"gradeX"
>
<td
class=
"text-center"
>
<a
href=
"{% url 'audits:proxy-log-detail' pk=proxy_log.id %}"
>
{{ proxy_log.id }}
</a>
</td>
<td
class=
"text-center"
>
{{ proxy_log.user }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.asset }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.system_user }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.commands.all|length}}
</td>
<td
class=
"text-center"
>
{% if proxy_log.is_failed %}
<i
class=
"fa fa-times text-danger"
></i>
{% else %}
<i
class=
"fa fa-check text-navy"
></i>
{% endif %}
</td>
{% if proxy_log.is_finished %}
<td
class=
"text-center"
>
<i
class=
"fa fa-check text-navy"
></i>
</td>
<td
class=
"text-center"
>
<a><span
class=
"text-navy"
><i
class=
"fa fa-play-circle"
></i></span></a>
</td>
{% else %}
<td
class=
"text-center"
>
<i
class=
"fa fa-times text-danger"
></i>
</td>
<td
class=
"text-center"
>
<a><span
class=
"text-danger"
><i
class=
"fa fa-eye"
></i></span></a>
</td>
{% endif %}
<td
class=
"text-center"
>
{{ proxy_log.date_start }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}
</td>
</tr>
{% endfor %}
{% endblock %}
{% block custom_foot_js %}
...
...
apps/audits/urls/api_urls.py
View file @
a79c3dd1
...
...
@@ -10,7 +10,8 @@ router.register(r'v1/proxy-log', api.ProxyLogViewSet, 'proxy-log')
router
.
register
(
r'v1/command-log'
,
api
.
CommandLogViewSet
,
'command-log'
)
urlpatterns
=
[
url
(
r'^v1/proxy-log/receive/$'
,
api
.
ProxyLogReceiveView
.
as_view
(),
name
=
'proxy-log-receive'
),
url
(
r'^v1/proxy-log/receive/$'
,
api
.
ProxyLogReceiveView
.
as_view
(),
name
=
'proxy-log-receive'
),
]
urlpatterns
+=
router
.
urls
apps/audits/views.py
View file @
a79c3dd1
This diff is collapsed.
Click to expand it.
apps/common/templatetags/common_tags.py
View file @
a79c3dd1
...
...
@@ -3,7 +3,8 @@
from
django
import
template
from
django.utils
import
timezone
from
django.conf
import
settings
from
django.utils.html
import
escape
from
audits.backends
import
command_store
register
=
template
.
Library
()
...
...
@@ -41,10 +42,30 @@ def join_attr(seq, attr=None, sep=None):
sep
=
', '
if
attr
is
not
None
:
seq
=
[
getattr
(
obj
,
attr
)
for
obj
in
seq
]
print
(
seq
)
return
sep
.
join
(
seq
)
@register.filter
def
int_to_str
(
value
):
return
str
(
value
)
\ No newline at end of file
return
str
(
value
)
@register.filter
def
ts_to_date
(
ts
):
try
:
ts
=
float
(
ts
)
except
TypeError
:
ts
=
0
dt
=
timezone
.
datetime
.
fromtimestamp
(
ts
)
.
\
replace
(
tzinfo
=
timezone
.
get_current_timezone
())
return
dt
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
@register.filter
def
to_html
(
s
):
return
escape
(
s
)
.
replace
(
'
\n
'
,
'<br />'
)
@register.filter
def
proxy_log_commands
(
log_id
):
return
command_store
.
filter
(
proxy_log_id
=
log_id
)
\ No newline at end of file
apps/common/utils.py
View file @
a79c3dd1
...
...
@@ -33,8 +33,10 @@ from .compat import to_bytes, to_string
SECRET_KEY
=
settings
.
SECRET_KEY
def
reverse
(
view_name
,
urlconf
=
None
,
args
=
None
,
kwargs
=
None
,
current_app
=
None
,
external
=
False
):
url
=
dj_reverse
(
view_name
,
urlconf
=
urlconf
,
args
=
args
,
kwargs
=
kwargs
,
current_app
=
current_app
)
def
reverse
(
view_name
,
urlconf
=
None
,
args
=
None
,
kwargs
=
None
,
current_app
=
None
,
external
=
False
):
url
=
dj_reverse
(
view_name
,
urlconf
=
urlconf
,
args
=
args
,
kwargs
=
kwargs
,
current_app
=
current_app
)
if
external
:
url
=
settings
.
SITE_URL
.
strip
(
'/'
)
+
url
...
...
@@ -44,8 +46,8 @@ def reverse(view_name, urlconf=None, args=None, kwargs=None, current_app=None, e
def
get_object_or_none
(
model
,
**
kwargs
):
try
:
obj
=
model
.
objects
.
get
(
**
kwargs
)
except
model
.
DoesNotExist
:
obj
=
None
except
(
model
.
FieldError
,
model
.
DoesNotExist
)
:
return
None
return
obj
...
...
apps/jumpserver/middleware.py
0 → 100644
View file @
a79c3dd1
# ~*~ coding: utf-8 ~*~
import
pytz
from
django.utils
import
timezone
from
django.utils.deprecation
import
MiddlewareMixin
class
TimezoneMiddleware
(
MiddlewareMixin
):
def
process_request
(
self
,
request
):
tzname
=
request
.
META
.
get
(
'TZ'
)
if
tzname
:
timezone
.
activate
(
pytz
.
timezone
(
tzname
))
else
:
timezone
.
deactivate
()
apps/jumpserver/settings.py
View file @
a79c3dd1
...
...
@@ -79,6 +79,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
'jumpserver.middleware.TimezoneMiddleware'
,
]
ROOT_URLCONF
=
'jumpserver.urls'
...
...
@@ -323,3 +324,5 @@ CACHES = {
CAPTCHA_IMAGE_SIZE
=
(
75
,
33
)
CAPTCHA_FOREGROUND_COLOR
=
'#001100'
COMMAND_STORE_BACKEND
=
'audits.backends.command.db'
apps/perms/api.py
View file @
a79c3dd1
...
...
@@ -14,6 +14,7 @@ from .models import AssetPermission
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
AssetGroup
,
Asset
,
\
AssetGroup
,
AssetGroupSerializer
,
SystemUser
from
.
import
serializers
from
.utils
import
associate_system_users_and_assets
class
AssetPermissionViewSet
(
viewsets
.
ModelViewSet
):
...
...
@@ -35,11 +36,32 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
queryset
=
get_user_group_asset_permissions
(
user_group
)
return
queryset
# Todo: 忘记为何要重写get_serializer_class了
def
get_serializer_class
(
self
):
if
getattr
(
self
,
'user_id'
,
''
):
return
serializers
.
UserAssetPermissionSerializer
return
serializers
.
AssetPermissionSerializer
def
associate_system_users_and_assets
(
self
,
serializer
):
assets
=
serializer
.
validated_data
.
get
(
'assets'
,
[])
asset_groups
=
serializer
.
validated_data
.
get
(
'asset_groups'
,
[])
system_users
=
serializer
.
validated_data
.
get
(
'system_users'
,
[])
if
serializer
.
partial
:
instance
=
self
.
get_object
()
assets
.
extend
(
list
(
instance
.
assets
.
all
()))
asset_groups
.
extend
(
list
(
instance
.
asset_groups
.
all
()))
system_users
.
extend
(
list
(
instance
.
system_users
.
all
()))
print
(
'Run'
)
associate_system_users_and_assets
(
system_users
,
assets
,
asset_groups
)
def
perform_create
(
self
,
serializer
):
self
.
associate_system_users_and_assets
(
serializer
)
return
super
(
AssetPermissionViewSet
,
self
)
.
perform_create
(
serializer
)
def
perform_update
(
self
,
serializer
):
self
.
associate_system_users_and_assets
(
serializer
)
return
super
(
AssetPermissionViewSet
,
self
)
.
perform_update
(
serializer
)
class
RevokeUserAssetPermission
(
APIView
):
permission_classes
=
(
IsSuperUser
,)
...
...
@@ -58,6 +80,27 @@ class RevokeUserAssetPermission(APIView):
return
Response
({
'msg'
:
'failed'
},
status
=
404
)
class
RemoveSystemUserAssetPermission
(
APIView
):
"""将系统用户从授权中移除, Detail页面会调用"""
permission_classes
=
(
IsSuperUser
,)
def
put
(
self
,
request
,
*
args
,
**
kwargs
):
response
=
[]
asset_permission_id
=
kwargs
.
pop
(
'pk'
)
system_users_id
=
request
.
data
.
get
(
'system_users'
)
print
(
system_users_id
)
asset_permission
=
get_object_or_404
(
AssetPermission
,
id
=
asset_permission_id
)
if
not
isinstance
(
system_users_id
,
list
):
system_users_id
=
[
system_users_id
]
for
system_user_id
in
system_users_id
:
system_user
=
get_object_or_none
(
SystemUser
,
id
=
system_user_id
)
if
system_user
:
asset_permission
.
system_users
.
remove
(
system_user
)
response
.
append
(
system_user
.
to_json
())
return
Response
(
response
,
status
=
200
)
class
RevokeUserGroupAssetPermission
(
APIView
):
permission_classes
=
(
IsSuperUser
,)
...
...
apps/perms/forms.py
View file @
a79c3dd1
...
...
@@ -6,19 +6,9 @@ from django.utils.translation import ugettext_lazy as _
# from .hands import User, UserGroup, Asset, AssetGroup, SystemUser
from
.models
import
AssetPermission
from
.hands
import
associate_system_users_with_assets
class
AssetPermissionForm
(
forms
.
ModelForm
):
def
save
(
self
,
commit
=
True
):
instance
=
super
(
AssetPermissionForm
,
self
)
.
save
(
commit
=
commit
)
assets
=
instance
.
assets
.
all
()
asset_groups
=
instance
.
asset_groups
.
all
()
system_users
=
instance
.
system_users
.
all
()
associate_system_users_with_assets
(
system_users
,
assets
,
asset_groups
)
return
instance
class
Meta
:
model
=
AssetPermission
fields
=
[
...
...
@@ -48,4 +38,3 @@ class AssetPermissionForm(forms.ModelForm):
'asset_groups'
:
'* Asset or Asset group at least one required'
,
'system_users'
:
'* required'
,
}
apps/perms/hands.py
View file @
a79c3dd1
...
...
@@ -7,9 +7,9 @@ from assets.models import Asset, AssetGroup, SystemUser
from
assets.serializers
import
AssetGrantedSerializer
,
AssetGroupSerializer
def
associate_system_users_with_assets
(
system_users
,
assets
,
asset_groups
):
def
push_system_user
(
assets
,
system_user
):
print
(
'Push system user
%
s'
%
system_user
.
name
)
for
asset
in
assets
:
asset
.
system_users
.
add
(
*
tuple
(
system_users
))
print
(
'
\t
Asset:
%
s'
%
asset
.
ip
)
for
asset_group
in
asset_groups
:
asset_group
.
system_users
.
add
(
*
tuple
(
system_users
))
apps/perms/models.py
View file @
a79c3dd1
...
...
@@ -4,6 +4,7 @@ import functools
from
django.db
import
models
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils
import
timezone
from
django.db.models.signals
import
m2m_changed
from
users.models
import
User
,
UserGroup
from
assets.models
import
Asset
,
AssetGroup
,
SystemUser
...
...
@@ -16,18 +17,26 @@ class AssetPermission(models.Model):
# ('U', 'user'),
# ('G', 'user group'),
# )
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
users
=
models
.
ManyToManyField
(
User
,
related_name
=
'asset_permissions'
,
blank
=
True
)
user_groups
=
models
.
ManyToManyField
(
UserGroup
,
related_name
=
'asset_permissions'
,
blank
=
True
)
assets
=
models
.
ManyToManyField
(
Asset
,
related_name
=
'granted_by_permissions'
,
blank
=
True
)
asset_groups
=
models
.
ManyToManyField
(
AssetGroup
,
related_name
=
'granted_by_permissions'
,
blank
=
True
)
system_users
=
models
.
ManyToManyField
(
SystemUser
,
related_name
=
'granted_by_permissions'
)
# private_for = models.CharField(choices=PRIVATE_FOR_CHOICE, max_length=1, default='N', blank=True,
# verbose_name=_('Private for'))
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Active'
))
date_expired
=
models
.
DateTimeField
(
default
=
date_expired_default
,
verbose_name
=
_
(
'Date expired'
))
created_by
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Created by'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Date created'
))
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
users
=
models
.
ManyToManyField
(
User
,
related_name
=
'asset_permissions'
,
blank
=
True
)
user_groups
=
models
.
ManyToManyField
(
UserGroup
,
related_name
=
'asset_permissions'
,
blank
=
True
)
assets
=
models
.
ManyToManyField
(
Asset
,
related_name
=
'granted_by_permissions'
,
blank
=
True
)
asset_groups
=
models
.
ManyToManyField
(
AssetGroup
,
related_name
=
'granted_by_permissions'
,
blank
=
True
)
system_users
=
models
.
ManyToManyField
(
SystemUser
,
related_name
=
'granted_by_permissions'
)
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Active'
))
date_expired
=
models
.
DateTimeField
(
default
=
date_expired_default
,
verbose_name
=
_
(
'Date expired'
))
created_by
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Created by'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Date created'
))
comment
=
models
.
TextField
(
verbose_name
=
_
(
'Comment'
),
blank
=
True
)
def
__unicode__
(
self
):
...
...
@@ -68,3 +77,15 @@ class AssetPermission(models.Model):
class
Meta
:
db_table
=
'asset_permission'
# def change_permission(sender, **kwargs):
# print('Sender: %s' % sender)
# for k, v in kwargs.items():
# print('%s: %s' % (k, v))
# print()
#
# m2m_changed.connect(change_permission, sender=AssetPermission.assets.through)
apps/perms/templates/perms/asset_permission_detail.html
View file @
a79c3dd1
...
...
@@ -169,16 +169,16 @@
</tr>
<tr>
<td
colspan=
"2"
class=
"no-borders"
>
<button
type=
"button"
class=
"btn btn-info btn-small"
id=
"btn_add_
user_group
"
>
{% trans 'Join' %}
</button>
<button
type=
"button"
class=
"btn btn-info btn-small"
id=
"btn_add_
system_user
"
>
{% trans 'Join' %}
</button>
</td>
</tr>
</form>
{% for system_user in system_users %}
<tr>
<td
><b
class=
"bdg
_user_group"
data-g
id=
{{
system_user
.
id
}}
>
{{ system_user.name }}
</b></td>
<td
><b
class=
"bdg
-system-user"
data-u
id=
{{
system_user
.
id
}}
>
{{ system_user.name }}
</b></td>
<td>
<button
class=
"btn btn-danger btn-xs btn
_delete_user_group
"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
<button
class=
"btn btn-danger btn-xs btn
-del"
data-uid=
"{{ system_user.id }}
"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
</td>
</tr>
{% endfor %}
...
...
@@ -196,8 +196,47 @@
{% endblock %}
{% block custom_foot_js %}
<script>
jumpserver
.
system_users_selected
=
{};
function
addSystemUser
(
system_users
)
{
var
the_url
=
"{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}"
;
var
body
=
{
system_users
:
Object
.
assign
([],
system_users
)
};
var
success
=
function
(
data
)
{
window
.
location
.
reload
();
};
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success
:
success
});
}
function
removeSystemUser
(
system_users
,
tr
)
{
var
the_url
=
"{% url 'api-perms:remove-system-user-asset-permission' pk=asset_permission.id %}"
;
var
body
=
{
system_users
:
system_users
};
var
success
=
function
(
data
)
{
tr
.
remove
()
};
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
method
:
'PUT'
,
success
:
success
})
}
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
$
(
'.select2'
).
select2
()
.
on
(
'select2:select'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
jumpserver
.
system_users_selected
[
data
.
id
]
=
data
.
text
;
})
.
on
(
'select2:unselect'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
delete
jumpserver
.
system_users_selected
[
data
.
id
]
})
}).
on
(
'click'
,
'.btn-delete-perm'
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
"{{ asset_permission.name }}"
;
...
...
@@ -205,6 +244,28 @@
var
the_url
=
'{% url "api-perms:asset-permission-detail" pk=99991937 %}'
.
replace
(
'99991937'
,
uid
);
var
redirect_url
=
"{% url 'perms:asset-permission-list' %}"
;
objectDelete
(
$this
,
name
,
the_url
,
redirect_url
);
}).
on
(
'click'
,
'#btn_add_system_user'
,
function
()
{
if
(
Object
.
keys
(
jumpserver
.
system_users_selected
).
length
===
0
)
{
return
false
;
}
var
system_users
=
$
(
'.bdg-system-user'
).
map
(
function
()
{
return
$
(
this
).
data
(
'uid'
);
}).
get
();
$
.
map
(
jumpserver
.
system_users_selected
,
function
(
value
,
index
)
{
system_users
.
push
(
parseInt
(
index
));
$
(
'#opt_'
+
index
).
remove
();
});
addSystemUser
(
system_users
)
}).
on
(
'click'
,
'.btn-del'
,
function
()
{
var
$this
=
$
(
this
);
var
$uid
=
$this
.
data
(
'uid'
);
var
$tr
=
$this
.
closest
(
'tr'
);
var
$badge
=
$tr
.
find
(
'.bdg-system-user'
);
var
$system_user
=
$badge
.
html
()
||
$badge
.
text
();
$
(
'#groups_selected'
).
append
(
'<option value="'
+
$uid
+
'" id="opt_'
+
$uid
+
'">'
+
$system_user
+
'</option>'
);
removeSystemUser
(
$uid
,
$tr
)
})
</script>
{% endblock %}
\ No newline at end of file
apps/perms/templates/perms/asset_permission_user.html
View file @
a79c3dd1
...
...
@@ -108,7 +108,7 @@
<form>
<tr
class=
"no-borders-tr"
>
<td
colspan=
"2"
>
<select
data-placeholder=
"{% trans 'Select user' %}"
class=
"select2"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
<select
data-placeholder=
"{% trans 'Select user' %}"
class=
"select2
user
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for user in users_remain %}
<option
value=
"{{ user.id }}"
>
{{ user.name }}: {{ user.username }}
</option>
{% endfor %}
...
...
@@ -117,7 +117,7 @@
</tr>
<tr
class=
"no-borders-tr"
>
<td
colspan=
"2"
>
<button
type=
"button"
class=
"btn btn-primary btn-sm"
>
{% trans 'Add' %}
</button>
<button
type=
"button"
class=
"btn btn-primary btn-sm
btn-add-user
"
>
{% trans 'Add' %}
</button>
</td>
</tr>
</form>
...
...
@@ -136,7 +136,7 @@
<form>
<tr>
<td
colspan=
"2"
class=
"no-borders"
>
<select
data-placeholder=
"{% trans 'Select user groups' %}"
class=
"select2"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
<select
data-placeholder=
"{% trans 'Select user groups' %}"
class=
"select2
user-group
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for user_group in user_groups_remain %}
<option
value=
"{{ user_group.id }}"
id=
"opt_{{ user_group.id }}"
>
{{ user_group.name }}
</option>
{% endfor %}
...
...
@@ -145,7 +145,7 @@
</tr>
<tr>
<td
colspan=
"2"
class=
"no-borders"
>
<button
type=
"button"
class=
"btn btn-info btn-small"
id=
"btn_add_user_group"
>
{% trans '
Join
' %}
</button>
<button
type=
"button"
class=
"btn btn-info btn-small"
id=
"btn_add_user_group"
>
{% trans '
Add
' %}
</button>
</td>
</tr>
</form>
...
...
@@ -172,25 +172,29 @@
{% endblock %}
{% block custom_foot_js %}
<script>
{
#
function
switch_user_status
(
obj
)
{
#
}
{
#
var
status
=
$
(
obj
).
prop
(
'checked'
);
#
}
{
##
}
{
#
$
.
ajax
({
#
}
{
#
url
:
"{% url 'users:user-active-api' pk=user.id %}"
,
#
}
{
#
type
:
"PUT"
,
#
}
{
#
data
:
{
#
}
{
#
'is_active'
:
status
#
}
{
#
},
#
}
{
#
success
:
function
(
data
,
status
)
{
#
}
{
#
console
.
log
(
data
)
#
}
{
#
},
#
}
{
#
error
:
function
()
{
#
}
{
#
console
.
log
(
'error'
)
#
}
{
#
}
#
}
{
#
})
#
}
{
#
}
#
}
jumpserver
.
users_selected
=
{};
jumpserver
.
user_groups_selected
=
{};
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
});
$
(
'.select2.user'
).
select2
()
.
on
(
'select2:select'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
jumpserver
.
users_selected
[
data
.
id
]
=
data
.
text
;
})
.
on
(
'select2:unselect'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
delete
jumpserver
.
users_selected
[
data
.
id
]
});
$
(
'.select2.user-group'
).
select2
()
.
on
(
'select2:select'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
jumpserver
.
user_groups_selected
[
data
.
id
]
=
data
.
text
;
})
.
on
(
'select2:unselect'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
delete
jumpserver
.
user_groups_selected
[
data
.
id
]
})
}).
on
(
'click'
,
'.btn-add-user'
,
function
()
{
console
.
log
(
jumpserver
.
users_selected
)
})
</script>
{% endblock %}
\ No newline at end of file
apps/perms/tests.py
View file @
a79c3dd1
from
django.test
import
TestCase
# Create your tests here.
from
django.contrib.sessions.backends
import
file
,
db
,
cache
from
django.contrib.auth.views
import
login
\ No newline at end of file
apps/perms/urls/api_urls.py
View file @
a79c3dd1
...
...
@@ -50,7 +50,12 @@ urlpatterns = [
# 验证用户是否有某个资产和系统用户的权限
url
(
r'v1/asset-permission/user/validate/$'
,
api
.
ValidateUserAssetPermissionView
.
as_view
(),
name
=
'validate-user-asset-permission'
)
name
=
'validate-user-asset-permission'
),
# 删除asset permission中的某个系统用户
url
(
r'^v1/asset-permissions/(?P<pk>[0-9]+)/system-user/remove/$'
,
api
.
RemoveSystemUserAssetPermission
.
as_view
(),
name
=
'remove-system-user-asset-permission'
),
]
urlpatterns
+=
router
.
urls
...
...
apps/perms/utils.py
View file @
a79c3dd1
# coding: utf-8
from
__future__
import
absolute_import
,
unicode_literals
from
common.utils
import
setattr_bulk
from
.hands
import
User
,
UserGroup
,
Asset
,
AssetGroup
,
SystemUser
from
.hands
import
User
,
UserGroup
,
Asset
,
AssetGroup
,
SystemUser
,
\
push_system_user
def
get_user_group_granted_asset_groups
(
user_group
):
"""Return asset groups granted of the user group
:param user_group: Instance of :class: ``UserGroup``
:return: {asset_group1: {system_user1, }, asset_group2: {system_user1, system_user2}}
:return: {asset_group1: {system_user1, },
asset_group2: {system_user1, system_user2}}
"""
asset_groups
=
{}
asset_permissions
=
user_group
.
asset_permissions
.
all
()
...
...
@@ -50,7 +54,8 @@ def get_user_granted_asset_groups_direct(user):
"""Return asset groups granted of the user direct nor inherit from user group
:param user: Instance of :class: ``User``
:return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]}
:return: {asset_group: {system_user1, },
asset_group2: {system_user1, system_user2]}
"""
asset_groups
=
{}
asset_permissions_direct
=
user
.
asset_permissions
.
all
()
...
...
@@ -72,7 +77,8 @@ def get_user_granted_asset_groups_inherit_from_user_groups(user):
"""Return asset groups granted of the user and inherit from user group
:param user: Instance of :class: ``User``
:return: {asset_group: {system_user1, }, asset_group2: {system_user1, system_user2]}
:return: {asset_group: {system_user1, },
asset_group2: {system_user1, system_user2]}
"""
asset_groups
=
{}
user_groups
=
user
.
groups
.
all
()
...
...
@@ -103,7 +109,8 @@ def get_user_granted_asset_groups(user):
:return: {asset1: {system_user1, system_user2}, asset2: {...}}
"""
asset_groups_inherit_from_user_groups
=
get_user_granted_asset_groups_inherit_from_user_groups
(
user
)
asset_groups_inherit_from_user_groups
=
\
get_user_granted_asset_groups_inherit_from_user_groups
(
user
)
asset_groups_direct
=
get_user_granted_asset_groups_direct
(
user
)
asset_groups
=
asset_groups_inherit_from_user_groups
...
...
@@ -211,3 +218,27 @@ def get_user_groups_granted_in_asset_group(asset):
def
get_users_granted_in_asset_group
(
asset
):
pass
def
associate_system_users_and_assets
(
system_users
,
assets
,
asset_groups
):
"""关联系统用户和资产, 目的是保存它们的关系, 然后新加入的资产或系统
用户时,推送系统用户到资产
Todo: 这里需要最终Api定下来更改一下, 现在策略是以系统用户为核心推送, 一个系统用户
推送一次
"""
assets_all
=
set
(
assets
)
for
asset_group
in
asset_groups
:
assets_all
|=
set
(
asset_group
.
assets
.
all
())
for
system_user
in
system_users
:
assets_need_push
=
[]
if
system_user
.
auto_push
:
assets_need_push
.
extend
(
[
asset
for
asset
in
assets_all
if
asset
not
in
system_user
.
assets
.
all
()
]
)
system_user
.
assets
.
add
(
*
(
tuple
(
assets_all
)))
push_system_user
(
assets_need_push
,
system_user
)
apps/perms/views.py
View file @
a79c3dd1
...
...
@@ -6,16 +6,18 @@ import functools
from
django.utils.translation
import
ugettext
as
_
from
django.conf
import
settings
from
django.db.models
import
Q
from
django.views.generic
import
TemplateView
,
List
View
from
django.views.generic.edit
import
CreateView
,
DeleteView
,
FormView
,
Update
View
from
django.views.generic
import
ListView
,
CreateView
,
Update
View
from
django.views.generic.edit
import
DeleteView
,
Form
View
from
django.urls
import
reverse_lazy
from
django.contrib.messages.views
import
SuccessMessageMixin
from
django.views.generic.detail
import
DetailView
,
SingleObjectMixin
from
common.utils
import
search_object_attr
from
.hands
import
AdminUserRequiredMixin
,
User
,
UserGroup
,
SystemUser
,
Asset
,
AssetGroup
from
.hands
import
AdminUserRequiredMixin
,
User
,
UserGroup
,
SystemUser
,
\
Asset
,
AssetGroup
from
.models
import
AssetPermission
from
.forms
import
AssetPermissionForm
from
.utils
import
associate_system_users_and_assets
class
AssetPermissionListView
(
AdminUserRequiredMixin
,
ListView
):
...
...
@@ -79,6 +81,16 @@ class AssetPermissionCreateView(AdminUserRequiredMixin,
self
.
object
.
name
,))
return
success_message
def
form_valid
(
self
,
form
):
assets
=
form
.
cleaned_data
[
'assets'
]
asset_groups
=
form
.
cleaned_data
[
'asset_groups'
]
system_users
=
form
.
cleaned_data
[
'system_users'
]
associate_system_users_and_assets
(
system_users
,
assets
,
asset_groups
)
response
=
super
(
AssetPermissionCreateView
,
self
)
.
form_valid
(
form
)
self
.
object
.
created_by
=
self
.
request
.
user
.
name
self
.
object
.
save
()
return
response
class
AssetPermissionUpdateView
(
AdminUserRequiredMixin
,
UpdateView
):
model
=
AssetPermission
...
...
@@ -100,6 +112,13 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
return
success_url
def
form_valid
(
self
,
form
):
assets
=
form
.
cleaned_data
[
'assets'
]
asset_groups
=
form
.
cleaned_data
[
'asset_groups'
]
system_users
=
form
.
cleaned_data
[
'system_users'
]
associate_system_users_and_assets
(
system_users
,
assets
,
asset_groups
)
return
super
(
AssetPermissionUpdateView
,
self
)
.
form_valid
(
form
)
class
AssetPermissionDetailView
(
AdminUserRequiredMixin
,
DetailView
):
template_name
=
'perms/asset_permission_detail.html'
...
...
apps/static/js/jumpserver.js
View file @
a79c3dd1
...
...
@@ -187,28 +187,28 @@ function activeNav() {
}
function
APIUpdateAttr
(
props
)
{
// props = {url: .., body: , success: , error: , method: ,}
props
=
props
||
{};
var
success_message
=
props
.
success_message
||
'Update Successfully!'
;
var
fail_message
=
props
.
fail_message
||
'Error occurred while updating.'
;
$
.
ajax
({
url
:
props
.
url
,
type
:
props
.
method
||
"PATCH"
,
data
:
props
.
body
,
contentType
:
props
.
content_type
||
"application/json; charset=utf-8"
,
dataType
:
props
.
data_type
||
"json"
}).
done
(
function
(
data
,
textStatue
,
jqXHR
)
{
toastr
.
success
(
success_message
);
if
(
typeof
props
.
success
===
'function'
)
{
return
props
.
success
(
data
);
}
}).
fail
(
function
(
jqXHR
,
textStatue
,
errorThrown
)
{
toastr
.
error
(
fail_message
);
if
(
typeof
props
.
error
===
'function'
)
{
return
props
.
error
(
errorThrown
);
}
});
// props = {url: .., body: , success: , error: , method: ,}
props
=
props
||
{};
var
success_message
=
props
.
success_message
||
'Update Successfully!'
;
var
fail_message
=
props
.
fail_message
||
'Error occurred while updating.'
;
$
.
ajax
({
url
:
props
.
url
,
type
:
props
.
method
||
"PATCH"
,
data
:
props
.
body
,
contentType
:
props
.
content_type
||
"application/json; charset=utf-8"
,
dataType
:
props
.
data_type
||
"json"
}).
done
(
function
(
data
,
textStatue
,
jqXHR
)
{
toastr
.
success
(
success_message
);
if
(
typeof
props
.
success
===
'function'
)
{
return
props
.
success
(
data
);
}
}).
fail
(
function
(
jqXHR
,
textStatue
,
errorThrown
)
{
toastr
.
error
(
fail_message
);
if
(
typeof
props
.
error
===
'function'
)
{
return
props
.
error
(
errorThrown
);
}
});
// return true;
}
...
...
apps/users/authentication.py
View file @
a79c3dd1
...
...
@@ -107,7 +107,6 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
if
not
access_key
.
user
.
is_active
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'User disabled.'
))
return
access_key
.
user
,
None
...
...
apps/users/forms.py
View file @
a79c3dd1
...
...
@@ -31,7 +31,9 @@ class UserCreateUpdateForm(forms.ModelForm):
'email'
:
'* required'
,
}
widgets
=
{
'groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Join user groups'
)}),
'groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Join user groups'
)}),
}
...
...
@@ -41,29 +43,11 @@ class UserBulkImportForm(forms.ModelForm):
fields
=
[
'username'
,
'email'
,
'enable_otp'
,
'role'
]
# class UserUpdateForm(forms.ModelForm):
#
# class Meta:
# model = User
# fields = [
# 'name', 'email', 'groups', 'wechat',
# 'phone', 'enable_otp', 'role', 'date_expired', 'comment',
# ]
# help_texts = {
# 'username': '* required',
# 'email': '* required',
# 'groups': '* required'
# }
# widgets = {
# 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}),
# }
class
UserGroupForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
UserGroup
fields
=
[
'name'
,
'comment'
,
'name'
,
'comment'
]
help_texts
=
{
'name'
:
'* required'
...
...
@@ -87,7 +71,8 @@ class UserKeyForm(forms.Form):
def
clean_public_key
(
self
):
public_key
=
self
.
cleaned_data
[
'public_key'
]
if
self
.
user
.
public_key
and
public_key
==
self
.
user
.
public_key
:
raise
forms
.
ValidationError
(
_
(
'Public key should not be the same as your old one.'
))
raise
forms
.
ValidationError
(
_
(
'Public key should not be the '
'same as your old one.'
))
if
not
validate_ssh_public_key
(
public_key
):
raise
forms
.
ValidationError
(
_
(
'Not a valid ssh public key'
))
...
...
@@ -97,7 +82,8 @@ class UserKeyForm(forms.Form):
class
UserPrivateAssetPermissionForm
(
forms
.
ModelForm
):
def
save
(
self
,
commit
=
True
):
self
.
instance
=
super
(
UserPrivateAssetPermissionForm
,
self
)
.
save
(
commit
=
commit
)
self
.
instance
=
super
(
UserPrivateAssetPermissionForm
,
self
)
\
.
save
(
commit
=
commit
)
self
.
instance
.
users
=
[
self
.
user
]
self
.
instance
.
save
()
return
self
.
instance
...
...
@@ -108,19 +94,23 @@ class UserPrivateAssetPermissionForm(forms.ModelForm):
'assets'
,
'asset_groups'
,
'system_users'
,
'name'
,
]
widgets
=
{
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)}),
'asset_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)}),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select system users'
)}),
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)}),
'asset_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)}),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select system users'
)}),
}
class
UserGroupPrivateAssetPermissionForm
(
forms
.
ModelForm
):
def
save
(
self
,
commit
=
True
):
self
.
instance
=
super
(
UserGroupPrivateAssetPermissionForm
,
self
)
.
save
(
commit
=
commit
)
self
.
instance
=
super
(
UserGroupPrivateAssetPermissionForm
,
self
)
\
.
save
(
commit
=
commit
)
self
.
instance
.
user_groups
=
[
self
.
user_group
]
self
.
instance
.
save
()
return
self
.
instance
...
...
@@ -131,12 +121,15 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
'assets'
,
'asset_groups'
,
'system_users'
,
'name'
,
]
widgets
=
{
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)}),
'asset_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)}),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select system users'
)}),
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)}),
'asset_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)}),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select system users'
)}),
}
...
...
apps/users/views/group.py
View file @
a79c3dd1
...
...
@@ -44,6 +44,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, CreateView):
'users'
:
users
})
return
context
# 需要添加组下用户, 而user并不是group的多对多,所以需要手动建立关系
def
form_valid
(
self
,
form
):
user_group
=
form
.
save
()
users_id_list
=
self
.
request
.
POST
.
getlist
(
'users'
,
[])
...
...
deb_requirements.txt
→
requirements/
deb_requirements.txt
View file @
a79c3dd1
File moved
requirements/mac_requirements.py
0 → 100644
View file @
a79c3dd1
requirements.txt
→
requirements
/requirements
.txt
View file @
a79c3dd1
File moved
rpm_requirements.txt
→
r
equirements/r
pm_requirements.txt
View file @
a79c3dd1
File moved
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