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
f37b3316
Commit
f37b3316
authored
Jan 23, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge with dev
parents
5bbad019
9dbf4983
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
69 changed files
with
552 additions
and
302 deletions
+552
-302
README.md
README.md
+1
-30
api.py
apps/assets/api.py
+3
-5
hands.py
apps/assets/hands.py
+1
-1
label.py
apps/assets/models/label.py
+1
-1
user.py
apps/assets/models/user.py
+0
-1
serializers.py
apps/assets/serializers.py
+1
-11
admin_user_assets.html
apps/assets/templates/assets/admin_user_assets.html
+1
-1
asset_group_detail.html
apps/assets/templates/assets/asset_group_detail.html
+1
-1
asset_group_list.html
apps/assets/templates/assets/asset_group_list.html
+0
-4
cluster_assets.html
apps/assets/templates/assets/cluster_assets.html
+1
-1
label_list.html
apps/assets/templates/assets/label_list.html
+2
-5
system_user_asset.html
apps/assets/templates/assets/system_user_asset.html
+1
-1
cluster.py
apps/assets/views/cluster.py
+0
-5
api.py
apps/common/api.py
+0
-5
fields.py
apps/common/fields.py
+6
-5
forms.py
apps/common/forms.py
+38
-10
models.py
apps/common/models.py
+16
-3
basic_setting.html
apps/common/templates/common/basic_setting.html
+3
-0
email_setting.html
apps/common/templates/common/email_setting.html
+3
-0
ldap_setting.html
apps/common/templates/common/ldap_setting.html
+3
-0
terminal_setting.html
apps/common/templates/common/terminal_setting.html
+129
-0
view_urls.py
apps/common/urls/view_urls.py
+1
-0
views.py
apps/common/views.py
+35
-4
settings.py
apps/jumpserver/settings.py
+16
-3
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+0
-0
models.py
apps/ops/models.py
+1
-1
utils.py
apps/ops/utils.py
+3
-1
jumpserver.css
apps/static/css/jumpserver.css
+1
-1
admin.png
apps/static/img/avatar/admin.png
+0
-0
user.png
apps/static/img/avatar/user.png
+0
-0
logo-text.png
apps/static/img/logo-text.png
+0
-0
_footer.html
apps/templates/_footer.html
+2
-1
_header_bar.html
apps/templates/_header_bar.html
+6
-7
_user_profile.html
apps/templates/_user_profile.html
+2
-5
flash_message_standalone.html
apps/templates/flash_message_standalone.html
+1
-1
index.html
apps/templates/index.html
+1
-1
api.py
apps/terminal/api.py
+17
-4
__init__.py
apps/terminal/backends/__init__.py
+33
-3
base.py
apps/terminal/backends/command/base.py
+6
-0
db.py
apps/terminal/backends/command/db.py
+26
-6
es.py
apps/terminal/backends/command/es.py
+38
-0
models.py
apps/terminal/backends/command/models.py
+21
-0
multi.py
apps/terminal/backends/command/multi.py
+27
-0
forms.py
apps/terminal/forms.py
+13
-1
models.py
apps/terminal/models.py
+23
-0
serializers.py
apps/terminal/serializers.py
+3
-3
signals_handler.py
apps/terminal/signals_handler.py
+0
-4
terminal_modal_accept.html
apps/terminal/templates/terminal/terminal_modal_accept.html
+1
-0
terminal_update.html
apps/terminal/templates/terminal/terminal_update.html
+1
-0
terminal_tags.py
apps/terminal/templatetags/terminal_tags.py
+3
-4
api_urls.py
apps/terminal/urls/api_urls.py
+2
-1
command.py
apps/terminal/views/command.py
+3
-3
session.py
apps/terminal/views/session.py
+2
-2
api.py
apps/users/api.py
+20
-4
forms.py
apps/users/forms.py
+0
-1
hands.py
apps/users/hands.py
+1
-1
serializers.py
apps/users/serializers.py
+6
-0
_user.html
apps/users/templates/users/_user.html
+1
-7
forgot_password.html
apps/users/templates/users/forgot_password.html
+1
-1
login.html
apps/users/templates/users/login.html
+1
-1
reset_password.html
apps/users/templates/users/reset_password.html
+1
-1
user_detail.html
apps/users/templates/users/user_detail.html
+7
-6
user_list.html
apps/users/templates/users/user_list.html
+1
-1
api_urls.py
apps/users/urls/api_urls.py
+2
-0
utils.py
apps/users/utils.py
+3
-1
login.py
apps/users/views/login.py
+5
-2
install.md
docs/install.md
+1
-129
requirements.txt
requirements/requirements.txt
+3
-1
No files found.
README.md
View file @
f37b3316
...
@@ -26,36 +26,7 @@ Jumpserver是一款使用Python, Django开发的开源跳板机系统, 助力互
...
@@ -26,36 +26,7 @@ Jumpserver是一款使用Python, Django开发的开源跳板机系统, 助力互
### Install 安装
### Install 安装
1. 安装 Python3
[
详细安装
](
https://github.com/jumpserver/jumpserver/wiki/v0.5.0-%E5%9F%BA%E4%BA%8E-CentOS7
)
略
2. 安装依赖
```
$ cd requirements && yum -y install $(cat rpm_requirements.txt) && pip install -r requirements.txt
```
3. 修改配置文件
```
$ cp config_example.py config.py
```
4. 修改表结构
```
$ cd apps && python manage.py makemigrations && python manage.py migrate
```
5. 运行
```
$ python run_server.py
```
6. 其它
整合luna,coco需要nginx来配合, 详见详细安装文档
### Usage 使用
### Usage 使用
...
...
apps/assets/api.py
View file @
f37b3316
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
# Copyright (C) 2014-201
7
Beijing DuiZhan Technology Co.,Ltd. All Rights Reserved.
# Copyright (C) 2014-201
8
Beijing DuiZhan Technology Co.,Ltd. All Rights Reserved.
#
#
# Licensed under the GNU General Public License v2.0 (the "License");
# Licensed under the GNU General Public License v2.0 (the "License");
# you may not use this file except in compliance with the License.
# you may not use this file except in compliance with the License.
...
@@ -87,7 +87,7 @@ class AssetGroupViewSet(CustomFilterMixin, BulkModelViewSet):
...
@@ -87,7 +87,7 @@ class AssetGroupViewSet(CustomFilterMixin, BulkModelViewSet):
"""
"""
Asset group api set, for add,delete,update,list,retrieve resource
Asset group api set, for add,delete,update,list,retrieve resource
"""
"""
queryset
=
AssetGroup
.
objects
.
all
()
queryset
=
AssetGroup
.
objects
.
all
()
.
annotate
(
asset_count
=
Count
(
"assets"
))
serializer_class
=
serializers
.
AssetGroupSerializer
serializer_class
=
serializers
.
AssetGroupSerializer
permission_classes
=
(
IsSuperUser
,)
permission_classes
=
(
IsSuperUser
,)
...
@@ -298,9 +298,7 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
...
@@ -298,9 +298,7 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
class
LabelViewSet
(
BulkModelViewSet
):
class
LabelViewSet
(
BulkModelViewSet
):
queryset
=
Label
.
objects
.
annotate
(
asset_count
=
Count
(
"assets"
))
\
queryset
=
Label
.
objects
.
annotate
(
asset_count
=
Count
(
"assets"
))
.
annotate
(
admin_user_count
=
Count
(
"adminuser"
))
\
.
annotate
(
system_user_count
=
Count
(
"systemuser"
))
permission_classes
=
(
IsSuperUser
,)
permission_classes
=
(
IsSuperUser
,)
serializer_class
=
serializers
.
LabelSerializer
serializer_class
=
serializers
.
LabelSerializer
...
...
apps/assets/hands.py
View file @
f37b3316
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
Other module of this app shouldn't connect with other app.
Other module of this app shouldn't connect with other app.
:copyright: (c) 2014-201
7
by Jumpserver Team.
:copyright: (c) 2014-201
8
by Jumpserver Team.
:license: GPL v2, see LICENSE for more details.
:license: GPL v2, see LICENSE for more details.
"""
"""
...
...
apps/assets/models/label.py
View file @
f37b3316
...
@@ -16,7 +16,7 @@ class Label(models.Model):
...
@@ -16,7 +16,7 @@ class Label(models.Model):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
name
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Name"
))
name
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Name"
))
value
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Value"
))
value
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Value"
))
category
=
models
.
CharField
(
max_length
=
128
,
choices
=
CATEGORY_CHOICES
,
verbose_name
=
_
(
"Category"
))
category
=
models
.
CharField
(
max_length
=
128
,
choices
=
CATEGORY_CHOICES
,
default
=
USER_CATEGORY
,
verbose_name
=
_
(
"Category"
))
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
"Is active"
))
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
"Is active"
))
comment
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
"Comment"
))
comment
=
models
.
TextField
(
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
"Comment"
))
date_created
=
models
.
DateTimeField
(
date_created
=
models
.
DateTimeField
(
...
...
apps/assets/models/user.py
View file @
f37b3316
...
@@ -30,7 +30,6 @@ class AssetUser(models.Model):
...
@@ -30,7 +30,6 @@ class AssetUser(models.Model):
_password
=
models
.
CharField
(
max_length
=
256
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Password'
))
_password
=
models
.
CharField
(
max_length
=
256
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Password'
))
_private_key
=
models
.
TextField
(
max_length
=
4096
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'SSH private key'
),
validators
=
[
private_key_validator
,
])
_private_key
=
models
.
TextField
(
max_length
=
4096
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'SSH private key'
),
validators
=
[
private_key_validator
,
])
_public_key
=
models
.
TextField
(
max_length
=
4096
,
blank
=
True
,
verbose_name
=
_
(
'SSH public key'
))
_public_key
=
models
.
TextField
(
max_length
=
4096
,
blank
=
True
,
verbose_name
=
_
(
'SSH public key'
))
labels
=
models
.
ManyToManyField
(
'assets.Label'
,
blank
=
True
,
verbose_name
=
_
(
"Labels"
))
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
)
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
)
date_updated
=
models
.
DateTimeField
(
auto_now
=
True
)
date_updated
=
models
.
DateTimeField
(
auto_now
=
True
)
...
...
apps/assets/serializers.py
View file @
f37b3316
...
@@ -22,7 +22,7 @@ class AssetGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer):
...
@@ -22,7 +22,7 @@ class AssetGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer):
@staticmethod
@staticmethod
def
get_assets_amount
(
obj
):
def
get_assets_amount
(
obj
):
return
obj
.
asset
s
.
count
()
return
obj
.
asset
_count
class
AssetUpdateSystemUserSerializer
(
serializers
.
ModelSerializer
):
class
AssetUpdateSystemUserSerializer
(
serializers
.
ModelSerializer
):
...
@@ -288,8 +288,6 @@ class MyAssetGroupGrantedSerializer(serializers.ModelSerializer):
...
@@ -288,8 +288,6 @@ class MyAssetGroupGrantedSerializer(serializers.ModelSerializer):
class
LabelSerializer
(
serializers
.
ModelSerializer
):
class
LabelSerializer
(
serializers
.
ModelSerializer
):
asset_count
=
serializers
.
SerializerMethodField
()
asset_count
=
serializers
.
SerializerMethodField
()
admin_user_count
=
serializers
.
SerializerMethodField
()
system_user_count
=
serializers
.
SerializerMethodField
()
class
Meta
:
class
Meta
:
model
=
Label
model
=
Label
...
@@ -300,14 +298,6 @@ class LabelSerializer(serializers.ModelSerializer):
...
@@ -300,14 +298,6 @@ class LabelSerializer(serializers.ModelSerializer):
def
get_asset_count
(
obj
):
def
get_asset_count
(
obj
):
return
obj
.
asset_count
return
obj
.
asset_count
@staticmethod
def
get_admin_user_count
(
obj
):
return
obj
.
admin_user_count
@staticmethod
def
get_system_user_count
(
obj
):
return
obj
.
system_user_count
def
get_field_names
(
self
,
declared_fields
,
info
):
def
get_field_names
(
self
,
declared_fields
,
info
):
fields
=
super
()
.
get_field_names
(
declared_fields
,
info
)
fields
=
super
()
.
get_field_names
(
declared_fields
,
info
)
fields
.
extend
([
'get_category_display'
])
fields
.
extend
([
'get_category_display'
])
...
...
apps/assets/templates/assets/admin_user_assets.html
View file @
f37b3316
...
@@ -121,7 +121,7 @@ function initTable() {
...
@@ -121,7 +121,7 @@ function initTable() {
{
data
:
"type"
},
{
data
:
"is_connective"
}],
{
data
:
"type"
},
{
data
:
"is_connective"
}],
op_html
:
$
(
'#actions'
).
html
()
op_html
:
$
(
'#actions'
).
html
()
};
};
jumpserver
.
initDataTable
(
options
);
jumpserver
.
init
ServerSide
DataTable
(
options
);
}
}
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
...
...
apps/assets/templates/assets/asset_group_detail.html
View file @
f37b3316
...
@@ -184,7 +184,7 @@ function initTable() {
...
@@ -184,7 +184,7 @@ function initTable() {
{
data
:
"get_type_display"
},
{
data
:
"is_connective"
},
{
data
:
"id"
}],
{
data
:
"get_type_display"
},
{
data
:
"is_connective"
},
{
data
:
"id"
}],
op_html
:
$
(
'#actions'
).
html
()
op_html
:
$
(
'#actions'
).
html
()
};
};
jumpserver
.
initDataTable
(
options
);
jumpserver
.
init
ServerSide
DataTable
(
options
);
}
}
...
...
apps/assets/templates/assets/asset_group_list.html
View file @
f37b3316
...
@@ -34,10 +34,6 @@ $(document).ready(function(){
...
@@ -34,10 +34,6 @@ $(document).ready(function(){
var
detail_btn
=
'<a href="{% url "assets:asset-group-detail" pk=DEFAULT_PK %}">'
+
cellData
+
'</a>'
;
var
detail_btn
=
'<a href="{% url "assets:asset-group-detail" pk=DEFAULT_PK %}">'
+
cellData
+
'</a>'
;
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
}},
}},
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
)
{
var
innerHtml
=
cellData
.
length
>
30
?
cellData
.
substring
(
0
,
30
)
+
'...'
:
cellData
;
$
(
td
).
html
(
'<a href="javascript:void(0);" data-toggle="tooltip" title="'
+
cellData
+
'">'
+
innerHtml
+
'</a>'
);
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "assets:asset-group-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
update_btn
=
'<a href="{% url "assets:asset-group-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn_asset_group_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn_asset_group_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
...
...
apps/assets/templates/assets/cluster_assets.html
View file @
f37b3316
...
@@ -176,7 +176,7 @@ function initTable() {
...
@@ -176,7 +176,7 @@ function initTable() {
{
data
:
"get_type_display"
},
{
data
:
"is_connective"
},
{
data
:
"id"
}],
{
data
:
"get_type_display"
},
{
data
:
"is_connective"
},
{
data
:
"id"
}],
op_html
:
$
(
'#actions'
).
html
()
op_html
:
$
(
'#actions'
).
html
()
};
};
jumpserver
.
initDataTable
(
options
);
jumpserver
.
init
ServerSide
DataTable
(
options
);
}
}
...
...
apps/assets/templates/assets/label_list.html
View file @
f37b3316
...
@@ -14,8 +14,6 @@
...
@@ -14,8 +14,6 @@
<th
class=
"text-center"
>
{% trans 'Name' %}
</th>
<th
class=
"text-center"
>
{% trans 'Name' %}
</th>
<th
class=
"text-center"
>
{% trans 'Value' %}
</th>
<th
class=
"text-center"
>
{% trans 'Value' %}
</th>
<th
class=
"text-center"
>
{% trans 'Asset' %}
</th>
<th
class=
"text-center"
>
{% trans 'Asset' %}
</th>
<th
class=
"text-center"
>
{% trans 'Admin user' %}
</th>
<th
class=
"text-center"
>
{% trans 'System user' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
</tr>
</tr>
</thead>
</thead>
...
@@ -36,7 +34,7 @@ function initTable() {
...
@@ -36,7 +34,7 @@ function initTable() {
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
}},
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "assets:cluster-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
update_btn
=
'<a href="{% url "assets:cluster-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn_cluster_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn_cluster_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
$
(
td
).
html
(
update_btn
+
del_btn
)
$
(
td
).
html
(
update_btn
+
del_btn
)
...
@@ -44,8 +42,7 @@ function initTable() {
...
@@ -44,8 +42,7 @@ function initTable() {
ajax_url
:
'{% url "api-assets:label-list" %}?sort=name'
,
ajax_url
:
'{% url "api-assets:label-list" %}?sort=name'
,
columns
:
[
columns
:
[
{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"value"
},
{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"value"
},
{
data
:
"asset_count"
},
{
data
:
"admin_user_count"
},
{
data
:
"asset_count"
},
{
data
:
"id"
}
{
data
:
"system_user_count"
},
{
data
:
"id"
}
],
],
op_html
:
$
(
'#actions'
).
html
()
op_html
:
$
(
'#actions'
).
html
()
};
};
...
...
apps/assets/templates/assets/system_user_asset.html
View file @
f37b3316
...
@@ -121,7 +121,7 @@ function initAssetsTable() {
...
@@ -121,7 +121,7 @@ function initAssetsTable() {
columns
:
[{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"port"
},
{
data
:
"hostname"
}],
columns
:
[{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"port"
},
{
data
:
"hostname"
}],
op_html
:
$
(
'#actions'
).
html
()
op_html
:
$
(
'#actions'
).
html
()
};
};
jumpserver
.
initDataTable
(
options
);
jumpserver
.
init
ServerSide
DataTable
(
options
);
}
}
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
...
...
apps/assets/views/cluster.py
View file @
f37b3316
...
@@ -60,11 +60,6 @@ class ClusterUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView)
...
@@ -60,11 +60,6 @@ class ClusterUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView)
success_url
=
reverse_lazy
(
'assets:cluster-list'
)
success_url
=
reverse_lazy
(
'assets:cluster-list'
)
success_message
=
update_success_msg
success_message
=
update_success_msg
def
form_valid
(
self
,
form
):
cluster
=
form
.
save
(
commit
=
False
)
cluster
.
save
()
return
super
()
.
form_valid
(
form
)
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
'app'
:
_
(
'assets'
),
'app'
:
_
(
'assets'
),
...
...
apps/common/api.py
View file @
f37b3316
...
@@ -63,8 +63,6 @@ class LDAPTestingAPI(APIView):
...
@@ -63,8 +63,6 @@ class LDAPTestingAPI(APIView):
search_filter
=
serializer
.
validated_data
[
"AUTH_LDAP_SEARCH_FILTER"
]
search_filter
=
serializer
.
validated_data
[
"AUTH_LDAP_SEARCH_FILTER"
]
attr_map
=
serializer
.
validated_data
[
"AUTH_LDAP_USER_ATTR_MAP"
]
attr_map
=
serializer
.
validated_data
[
"AUTH_LDAP_USER_ATTR_MAP"
]
print
(
serializer
.
validated_data
)
try
:
try
:
attr_map
=
json
.
loads
(
attr_map
)
attr_map
=
json
.
loads
(
attr_map
)
except
json
.
JSONDecodeError
:
except
json
.
JSONDecodeError
:
...
@@ -77,9 +75,6 @@ class LDAPTestingAPI(APIView):
...
@@ -77,9 +75,6 @@ class LDAPTestingAPI(APIView):
except
Exception
as
e
:
except
Exception
as
e
:
return
Response
({
"error"
:
str
(
e
)},
status
=
401
)
return
Response
({
"error"
:
str
(
e
)},
status
=
401
)
print
(
search_ou
)
print
(
search_filter
%
({
"user"
:
"*"
}))
print
(
attr_map
.
values
())
ok
=
conn
.
search
(
search_ou
,
search_filter
%
({
"user"
:
"*"
}),
ok
=
conn
.
search
(
search_ou
,
search_filter
%
({
"user"
:
"*"
}),
attributes
=
list
(
attr_map
.
values
()))
attributes
=
list
(
attr_map
.
values
()))
if
not
ok
:
if
not
ok
:
...
...
apps/common/fields.py
View file @
f37b3316
...
@@ -5,6 +5,7 @@ import json
...
@@ -5,6 +5,7 @@ import json
from
django
import
forms
from
django
import
forms
from
django.utils
import
six
from
django.utils
import
six
from
django.core.exceptions
import
ValidationError
from
django.core.exceptions
import
ValidationError
from
django.utils.translation
import
ugettext
as
_
class
DictField
(
forms
.
Field
):
class
DictField
(
forms
.
Field
):
...
@@ -18,16 +19,16 @@ class DictField(forms.Field):
...
@@ -18,16 +19,16 @@ class DictField(forms.Field):
# we don't need to handle that explicitly.
# we don't need to handle that explicitly.
if
isinstance
(
value
,
six
.
string_types
):
if
isinstance
(
value
,
six
.
string_types
):
try
:
try
:
print
(
value
)
value
=
json
.
loads
(
value
)
value
=
json
.
loads
(
value
)
return
value
return
value
except
json
.
JSONDecodeError
:
except
json
.
JSONDecodeError
:
pass
return
ValidationError
(
_
(
"Not a valid json"
))
value
=
{}
else
:
return
value
return
ValidationError
(
_
(
"Not a string type"
))
def
validate
(
self
,
value
):
def
validate
(
self
,
value
):
print
(
value
)
if
isinstance
(
value
,
ValidationError
):
raise
value
if
not
value
and
self
.
required
:
if
not
value
and
self
.
required
:
raise
ValidationError
(
self
.
error_messages
[
'required'
],
code
=
'required'
)
raise
ValidationError
(
self
.
error_messages
[
'required'
],
code
=
'required'
)
...
...
apps/common/forms.py
View file @
f37b3316
...
@@ -4,7 +4,9 @@ import json
...
@@ -4,7 +4,9 @@ import json
from
django
import
forms
from
django
import
forms
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.html
import
escape
from
django.db
import
transaction
from
django.db
import
transaction
from
django.conf
import
settings
from
.models
import
Setting
from
.models
import
Setting
from
.fields
import
DictField
from
.fields
import
DictField
...
@@ -24,34 +26,38 @@ def to_form_value(value):
...
@@ -24,34 +26,38 @@ def to_form_value(value):
data
=
value
data
=
value
return
data
return
data
except
json
.
JSONDecodeError
:
except
json
.
JSONDecodeError
:
return
''
return
""
class
BaseForm
(
forms
.
Form
):
class
BaseForm
(
forms
.
Form
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
super
()
.
__init__
(
*
args
,
**
kwargs
)
settings
=
Setting
.
objects
.
all
()
db_
settings
=
Setting
.
objects
.
all
()
for
name
,
field
in
self
.
fields
.
items
():
for
name
,
field
in
self
.
fields
.
items
():
db_value
=
getattr
(
settings
,
name
)
.
value
db_value
=
getattr
(
db_settings
,
name
)
.
value
if
db_value
:
django_value
=
getattr
(
settings
,
name
)
if
hasattr
(
settings
,
name
)
else
None
if
db_value
is
False
or
db_value
:
field
.
initial
=
to_form_value
(
db_value
)
field
.
initial
=
to_form_value
(
db_value
)
elif
django_value
is
False
or
django_value
:
field
.
initial
=
to_form_value
(
to_model_value
(
django_value
))
def
save
(
self
):
def
save
(
self
,
category
=
"default"
):
if
not
self
.
is_bound
:
if
not
self
.
is_bound
:
raise
ValueError
(
"Form is not bound"
)
raise
ValueError
(
"Form is not bound"
)
settings
=
Setting
.
objects
.
all
()
db_
settings
=
Setting
.
objects
.
all
()
if
self
.
is_valid
():
if
self
.
is_valid
():
with
transaction
.
atomic
():
with
transaction
.
atomic
():
for
name
,
value
in
self
.
cleaned_data
.
items
():
for
name
,
value
in
self
.
cleaned_data
.
items
():
field
=
self
.
fields
[
name
]
field
=
self
.
fields
[
name
]
if
isinstance
(
field
.
widget
,
forms
.
PasswordInput
)
and
not
value
:
if
isinstance
(
field
.
widget
,
forms
.
PasswordInput
)
and
not
value
:
continue
continue
if
value
==
to_form_value
(
getattr
(
settings
,
name
)
.
value
):
if
value
==
to_form_value
(
getattr
(
db_
settings
,
name
)
.
value
):
continue
continue
defaults
=
{
defaults
=
{
'name'
:
name
,
'name'
:
name
,
'category'
:
category
,
'value'
:
to_model_value
(
value
)
'value'
:
to_model_value
(
value
)
}
}
Setting
.
objects
.
update_or_create
(
defaults
=
defaults
,
name
=
name
)
Setting
.
objects
.
update_or_create
(
defaults
=
defaults
,
name
=
name
)
...
@@ -72,9 +78,6 @@ class BasicSettingForm(BaseForm):
...
@@ -72,9 +78,6 @@ class BasicSettingForm(BaseForm):
max_length
=
1024
,
label
=
_
(
"Email Subject Prefix"
),
max_length
=
1024
,
label
=
_
(
"Email Subject Prefix"
),
initial
=
"[Jumpserver] "
initial
=
"[Jumpserver] "
)
)
AUTH_LDAP
=
forms
.
BooleanField
(
label
=
_
(
"Enable LDAP Auth"
),
initial
=
False
,
required
=
False
)
class
EmailSettingForm
(
BaseForm
):
class
EmailSettingForm
(
BaseForm
):
...
@@ -129,3 +132,28 @@ class LDAPSettingForm(BaseForm):
...
@@ -129,3 +132,28 @@ class LDAPSettingForm(BaseForm):
AUTH_LDAP_START_TLS
=
forms
.
BooleanField
(
AUTH_LDAP_START_TLS
=
forms
.
BooleanField
(
label
=
_
(
"Use SSL"
),
initial
=
False
,
required
=
False
label
=
_
(
"Use SSL"
),
initial
=
False
,
required
=
False
)
)
class
TerminalSettingForm
(
BaseForm
):
SORT_BY_CHOICES
=
(
(
'hostname'
,
_
(
'Hostname'
)),
(
'ip'
,
_
(
'IP'
)),
)
TERMINAL_ASSET_LIST_SORT_BY
=
forms
.
ChoiceField
(
choices
=
SORT_BY_CHOICES
,
initial
=
'hostname'
,
label
=
_
(
"List sort by"
)
)
TERMINAL_HEARTBEAT_INTERVAL
=
forms
.
IntegerField
(
initial
=
5
,
label
=
_
(
"Heartbeat interval"
),
help_text
=
_
(
"Units: seconds"
)
)
TERMINAL_PASSWORD_AUTH
=
forms
.
BooleanField
(
initial
=
True
,
required
=
False
,
label
=
_
(
"Password auth"
)
)
TERMINAL_PUBLIC_KEY_AUTH
=
forms
.
BooleanField
(
initial
=
True
,
required
=
False
,
label
=
_
(
"Public key auth"
)
)
TERMINAL_COMMAND_STORAGE
=
DictField
(
label
=
_
(
"Command storage"
),
help_text
=
_
(
"Set terminal storage setting, `default` is the using as default,"
"You can set other storage and some terminal using"
)
)
apps/common/models.py
View file @
f37b3316
...
@@ -2,6 +2,7 @@ import json
...
@@ -2,6 +2,7 @@ import json
import
ldap
import
ldap
from
django.db
import
models
from
django.db
import
models
from
django.db.utils
import
ProgrammingError
,
OperationalError
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.conf
import
settings
from
django.conf
import
settings
from
django_auth_ldap.config
import
LDAPSearch
from
django_auth_ldap.config
import
LDAPSearch
...
@@ -24,6 +25,7 @@ class SettingManager(models.Manager):
...
@@ -24,6 +25,7 @@ class SettingManager(models.Manager):
class
Setting
(
models
.
Model
):
class
Setting
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
"Name"
))
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
"Name"
))
value
=
models
.
TextField
(
verbose_name
=
_
(
"Value"
))
value
=
models
.
TextField
(
verbose_name
=
_
(
"Value"
))
category
=
models
.
CharField
(
max_length
=
128
,
default
=
"default"
)
enabled
=
models
.
BooleanField
(
verbose_name
=
_
(
"Enabled"
),
default
=
True
)
enabled
=
models
.
BooleanField
(
verbose_name
=
_
(
"Enabled"
),
default
=
True
)
comment
=
models
.
TextField
(
verbose_name
=
_
(
"Comment"
))
comment
=
models
.
TextField
(
verbose_name
=
_
(
"Comment"
))
...
@@ -33,17 +35,28 @@ class Setting(models.Model):
...
@@ -33,17 +35,28 @@ class Setting(models.Model):
return
self
.
name
return
self
.
name
@property
@property
def
value_
(
self
):
def
cleaned_value
(
self
):
try
:
try
:
return
json
.
loads
(
self
.
value
)
return
json
.
loads
(
self
.
value
)
except
json
.
JSONDecodeError
:
except
json
.
JSONDecodeError
:
return
None
return
None
@cleaned_value.setter
def
cleaned_value
(
self
,
item
):
try
:
v
=
json
.
dumps
(
item
)
self
.
value
=
v
except
json
.
JSONDecodeError
as
e
:
raise
ValueError
(
"Json dump error: {}"
.
format
(
str
(
e
)))
@classmethod
@classmethod
def
refresh_all_settings
(
cls
):
def
refresh_all_settings
(
cls
):
try
:
settings_list
=
cls
.
objects
.
all
()
settings_list
=
cls
.
objects
.
all
()
for
setting
in
settings_list
:
for
setting
in
settings_list
:
setting
.
refresh_setting
()
setting
.
refresh_setting
()
except
(
ProgrammingError
,
OperationalError
):
pass
def
refresh_setting
(
self
):
def
refresh_setting
(
self
):
try
:
try
:
...
@@ -53,9 +66,9 @@ class Setting(models.Model):
...
@@ -53,9 +66,9 @@ class Setting(models.Model):
setattr
(
settings
,
self
.
name
,
value
)
setattr
(
settings
,
self
.
name
,
value
)
if
self
.
name
==
"AUTH_LDAP"
:
if
self
.
name
==
"AUTH_LDAP"
:
if
self
.
value_
and
settings
.
AUTH_LDAP_BACKEND
not
in
settings
.
AUTHENTICATION_BACKENDS
:
if
self
.
cleaned_value
and
settings
.
AUTH_LDAP_BACKEND
not
in
settings
.
AUTHENTICATION_BACKENDS
:
settings
.
AUTHENTICATION_BACKENDS
.
insert
(
0
,
settings
.
AUTH_LDAP_BACKEND
)
settings
.
AUTHENTICATION_BACKENDS
.
insert
(
0
,
settings
.
AUTH_LDAP_BACKEND
)
elif
not
self
.
value_
and
settings
.
AUTH_LDAP_BACKEND
in
settings
.
AUTHENTICATION_BACKENDS
:
elif
not
self
.
cleaned_value
and
settings
.
AUTH_LDAP_BACKEND
in
settings
.
AUTHENTICATION_BACKENDS
:
settings
.
AUTHENTICATION_BACKENDS
.
remove
(
settings
.
AUTH_LDAP_BACKEND
)
settings
.
AUTHENTICATION_BACKENDS
.
remove
(
settings
.
AUTH_LDAP_BACKEND
)
if
self
.
name
==
"AUTH_LDAP_SEARCH_FILTER"
:
if
self
.
name
==
"AUTH_LDAP_SEARCH_FILTER"
:
...
...
apps/common/templates/common/basic_setting.html
View file @
f37b3316
...
@@ -20,6 +20,9 @@
...
@@ -20,6 +20,9 @@
<li>
<li>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
</li>
</li>
<li>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</ul>
</ul>
</div>
</div>
<div
class=
"tab-content"
>
<div
class=
"tab-content"
>
...
...
apps/common/templates/common/email_setting.html
View file @
f37b3316
...
@@ -20,6 +20,9 @@
...
@@ -20,6 +20,9 @@
<li>
<li>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
</li>
</li>
<li>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</ul>
</ul>
</div>
</div>
<div
class=
"tab-content"
>
<div
class=
"tab-content"
>
...
...
apps/common/templates/common/ldap_setting.html
View file @
f37b3316
...
@@ -20,6 +20,9 @@
...
@@ -20,6 +20,9 @@
<li
class=
"active"
>
<li
class=
"active"
>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
</li>
</li>
<li>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</ul>
</ul>
</div>
</div>
<div
class=
"tab-content"
>
<div
class=
"tab-content"
>
...
...
apps/common/templates/common/terminal_setting.html
0 → 100644
View file @
f37b3316
{% extends 'base.html' %}
{% load static %}
{% load bootstrap3 %}
{% load i18n %}
{% load common_tags %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"panel-options"
>
<ul
class=
"nav nav-tabs"
>
<li>
<a
href=
"{% url 'settings:basic-setting' %}"
class=
"text-center"
><i
class=
"fa fa-cubes"
></i>
{% trans 'Basic setting' %}
</a>
</li>
<li>
<a
href=
"{% url 'settings:email-setting' %}"
class=
"text-center"
><i
class=
"fa fa-envelope"
></i>
{% trans 'Email setting' %}
</a>
</li>
<li>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
</li>
<li
class=
"active"
>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
<div
class=
"col-sm-12"
style=
"padding-left:0"
>
<div
class=
"ibox-content"
style=
"border-width: 0;padding-top: 40px;"
>
<form
action=
""
method=
"post"
class=
"form-horizontal"
>
{% if form.non_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
{% csrf_token %}
<h3>
{% trans "Basic setting" %}
</h3>
{% for field in form %}
{% if not field.field|is_bool_field %}
{% bootstrap_field field layout="horizontal" %}
{% else %}
<div
class=
"form-group"
>
<label
for=
"{{ field.id_for_label }}"
class=
"col-sm-2 control-label"
>
{{ field.label }}
</label>
<div
class=
"col-sm-8"
>
<div
class=
"col-sm-1"
>
{{ field }}
</div>
<div
class=
"col-sm-9"
>
<span
class=
"help-block"
>
{{ field.help_text }}
</span>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans "Command storage" %}
</h3>
<table
class=
"table table-hover "
id=
"task-history-list-table"
>
<thead>
<tr>
<th>
{% trans 'Name' %}
</th>
<th>
{% trans 'Type' %}
</th>
</tr>
</thead>
<tbody>
{% for name, setting in command_storage.items %}
<tr>
<td>
{{ name }}
</td>
<td>
{{ setting.TYPE }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{#
<button
class=
"btn btn-default btn-circle btn-add-command-storage"
data-toggle=
"modal"
data-target=
"#add_command_storage_model"
tabindex=
"0"
type=
"button"
><i
class=
"fa fa-plus"
></i></button>
#}
{#
<div
class=
"hr-line-dashed"
></div>
#}
{#
<h3>
{% trans "Replay storage" %}
</h3>
#}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-default"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
$
(
document
).
ready
(
function
()
{
})
.
on
(
"click"
,
".btn-test"
,
function
()
{
var
data
=
{};
var
form
=
$
(
"form"
).
serializeArray
();
$
.
each
(
form
,
function
(
i
,
field
)
{
data
[
field
.
name
]
=
field
.
value
;
});
var
the_url
=
"{% url 'api-common:ldap-testing' %}"
;
function
error
(
message
)
{
toastr
.
error
(
message
)
}
function
success
(
message
)
{
toastr
.
success
(
message
.
msg
)
}
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
data
),
method
:
"POST"
,
flash_message
:
false
,
success
:
success
,
error
:
error
});
})
.
on
(
'click'
,
''
,
function
()
{
})
</script>
{% endblock %}
apps/common/urls/view_urls.py
View file @
f37b3316
...
@@ -10,4 +10,5 @@ urlpatterns = [
...
@@ -10,4 +10,5 @@ urlpatterns = [
url
(
r'^$'
,
views
.
BasicSettingView
.
as_view
(),
name
=
'basic-setting'
),
url
(
r'^$'
,
views
.
BasicSettingView
.
as_view
(),
name
=
'basic-setting'
),
url
(
r'^email/$'
,
views
.
EmailSettingView
.
as_view
(),
name
=
'email-setting'
),
url
(
r'^email/$'
,
views
.
EmailSettingView
.
as_view
(),
name
=
'email-setting'
),
url
(
r'^ldap/$'
,
views
.
LDAPSettingView
.
as_view
(),
name
=
'ldap-setting'
),
url
(
r'^ldap/$'
,
views
.
LDAPSettingView
.
as_view
(),
name
=
'ldap-setting'
),
url
(
r'^terminal/$'
,
views
.
TerminalSettingView
.
as_view
(),
name
=
'terminal-setting'
),
]
]
apps/common/views.py
View file @
f37b3316
from
django.views.generic
import
View
,
TemplateView
from
django.views.generic
import
TemplateView
from
django.shortcuts
import
render
,
redirect
from
django.shortcuts
import
render
,
redirect
from
django.contrib
import
messages
from
django.contrib
import
messages
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.conf
import
settings
from
.forms
import
EmailSettingForm
,
LDAPSettingForm
,
BasicSettingForm
from
.forms
import
EmailSettingForm
,
LDAPSettingForm
,
BasicSettingForm
,
\
TerminalSettingForm
from
.models
import
Setting
from
.mixins
import
AdminUserRequiredMixin
from
.mixins
import
AdminUserRequiredMixin
from
.signals
import
ldap_auth_enable
from
.signals
import
ldap_auth_enable
...
@@ -25,8 +28,6 @@ class BasicSettingView(AdminUserRequiredMixin, TemplateView):
...
@@ -25,8 +28,6 @@ class BasicSettingView(AdminUserRequiredMixin, TemplateView):
form
=
self
.
form_class
(
request
.
POST
)
form
=
self
.
form_class
(
request
.
POST
)
if
form
.
is_valid
():
if
form
.
is_valid
():
form
.
save
()
form
.
save
()
if
"AUTH_LDAP"
in
form
.
cleaned_data
:
ldap_auth_enable
.
send
(
form
.
cleaned_data
[
"AUTH_LDAP"
])
msg
=
_
(
"Update setting successfully, please restart program"
)
msg
=
_
(
"Update setting successfully, please restart program"
)
messages
.
success
(
request
,
msg
)
messages
.
success
(
request
,
msg
)
return
redirect
(
'settings:basic-setting'
)
return
redirect
(
'settings:basic-setting'
)
...
@@ -79,6 +80,8 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
...
@@ -79,6 +80,8 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
form
=
self
.
form_class
(
request
.
POST
)
form
=
self
.
form_class
(
request
.
POST
)
if
form
.
is_valid
():
if
form
.
is_valid
():
form
.
save
()
form
.
save
()
if
"AUTH_LDAP"
in
form
.
cleaned_data
:
ldap_auth_enable
.
send
(
form
.
cleaned_data
[
"AUTH_LDAP"
])
msg
=
_
(
"Update setting successfully, please restart program"
)
msg
=
_
(
"Update setting successfully, please restart program"
)
messages
.
success
(
request
,
msg
)
messages
.
success
(
request
,
msg
)
return
redirect
(
'settings:ldap-setting'
)
return
redirect
(
'settings:ldap-setting'
)
...
@@ -86,3 +89,31 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
...
@@ -86,3 +89,31 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
context
=
self
.
get_context_data
()
context
=
self
.
get_context_data
()
context
.
update
({
"form"
:
form
})
context
.
update
({
"form"
:
form
})
return
render
(
request
,
self
.
template_name
,
context
)
return
render
(
request
,
self
.
template_name
,
context
)
class
TerminalSettingView
(
AdminUserRequiredMixin
,
TemplateView
):
form_class
=
TerminalSettingForm
template_name
=
"common/terminal_setting.html"
def
get_context_data
(
self
,
**
kwargs
):
command_storage
=
settings
.
TERMINAL_COMMAND_STORAGE
context
=
{
'app'
:
_
(
'Settings'
),
'action'
:
_
(
'Terminal setting'
),
'form'
:
self
.
form_class
(),
'command_storage'
:
command_storage
,
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
def
post
(
self
,
request
):
form
=
self
.
form_class
(
request
.
POST
)
if
form
.
is_valid
():
form
.
save
()
msg
=
_
(
"Update setting successfully, please restart program"
)
messages
.
success
(
request
,
msg
)
return
redirect
(
'settings:terminal-setting'
)
else
:
context
=
self
.
get_context_data
()
context
.
update
({
"form"
:
form
})
return
render
(
request
,
self
.
template_name
,
context
)
apps/jumpserver/settings.py
View file @
f37b3316
...
@@ -274,7 +274,7 @@ EMAIL_HOST_USER = CONFIG.EMAIL_HOST_USER
...
@@ -274,7 +274,7 @@ EMAIL_HOST_USER = CONFIG.EMAIL_HOST_USER
EMAIL_HOST_PASSWORD
=
CONFIG
.
EMAIL_HOST_PASSWORD
EMAIL_HOST_PASSWORD
=
CONFIG
.
EMAIL_HOST_PASSWORD
EMAIL_USE_SSL
=
CONFIG
.
EMAIL_USE_SSL
EMAIL_USE_SSL
=
CONFIG
.
EMAIL_USE_SSL
EMAIL_USE_TLS
=
CONFIG
.
EMAIL_USE_TLS
EMAIL_USE_TLS
=
CONFIG
.
EMAIL_USE_TLS
EMAIL_SUBJECT_PREFIX
=
CONFIG
.
EMAIL_SUBJECT_PREFIX
EMAIL_SUBJECT_PREFIX
=
CONFIG
.
EMAIL_SUBJECT_PREFIX
or
''
REST_FRAMEWORK
=
{
REST_FRAMEWORK
=
{
# Use Django's standard `django.contrib.auth` permissions,
# Use Django's standard `django.contrib.auth` permissions,
...
@@ -298,7 +298,7 @@ REST_FRAMEWORK = {
...
@@ -298,7 +298,7 @@ REST_FRAMEWORK = {
'DATETIME_FORMAT'
:
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S
%
z'
,
'DATETIME_FORMAT'
:
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S
%
z'
,
'DATETIME_INPUT_FORMATS'
:
[
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S
%
z'
],
'DATETIME_INPUT_FORMATS'
:
[
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S
%
z'
],
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE'
:
15
#
'PAGE_SIZE': 15
}
}
AUTHENTICATION_BACKENDS
=
[
AUTHENTICATION_BACKENDS
=
[
...
@@ -373,7 +373,20 @@ CAPTCHA_FOREGROUND_COLOR = '#001100'
...
@@ -373,7 +373,20 @@ CAPTCHA_FOREGROUND_COLOR = '#001100'
CAPTCHA_NOISE_FUNCTIONS
=
(
'captcha.helpers.noise_dots'
,)
CAPTCHA_NOISE_FUNCTIONS
=
(
'captcha.helpers.noise_dots'
,)
CAPTCHA_TEST_MODE
=
CONFIG
.
CAPTCHA_TEST_MODE
CAPTCHA_TEST_MODE
=
CONFIG
.
CAPTCHA_TEST_MODE
COMMAND_STORAGE_BACKEND
=
'terminal.backends.command.db'
COMMAND_STORAGE
=
{
'ENGINE'
:
'terminal.backends.command.db'
,
}
TERMINAL_COMMAND_STORAGE
=
{
"default"
:
{
"TYPE"
:
"server"
,
},
# 'ali-es': {
# 'TYPE': 'elasticsearch',
# 'HOSTS': ['http://elastic:changeme@localhost:9200'],
# },
}
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
BOOTSTRAP3
=
{
BOOTSTRAP3
=
{
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
f37b3316
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
f37b3316
This diff is collapsed.
Click to expand it.
apps/ops/models.py
View file @
f37b3316
...
@@ -165,7 +165,7 @@ class AdHoc(models.Model):
...
@@ -165,7 +165,7 @@ class AdHoc(models.Model):
if
item
and
isinstance
(
item
,
list
):
if
item
and
isinstance
(
item
,
list
):
self
.
_tasks
=
json
.
dumps
(
item
)
self
.
_tasks
=
json
.
dumps
(
item
)
else
:
else
:
raise
SyntaxError
(
'Tasks should be a list
'
)
raise
SyntaxError
(
'Tasks should be a list
: {}'
.
format
(
item
)
)
@property
@property
def
hosts
(
self
):
def
hosts
(
self
):
...
...
apps/ops/utils.py
View file @
f37b3316
...
@@ -16,6 +16,8 @@ def update_or_create_ansible_task(
...
@@ -16,6 +16,8 @@ def update_or_create_ansible_task(
run_as_admin
=
False
,
run_as
=
""
,
become_info
=
None
,
run_as_admin
=
False
,
run_as
=
""
,
become_info
=
None
,
created_by
=
None
,
created_by
=
None
,
):
):
if
not
hosts
or
not
tasks
or
not
task_name
:
return
defaults
=
{
defaults
=
{
'name'
:
task_name
,
'name'
:
task_name
,
...
@@ -41,7 +43,7 @@ def update_or_create_ansible_task(
...
@@ -41,7 +43,7 @@ def update_or_create_ansible_task(
new_adhoc
.
become
=
become_info
new_adhoc
.
become
=
become_info
if
not
adhoc
or
adhoc
!=
new_adhoc
:
if
not
adhoc
or
adhoc
!=
new_adhoc
:
logger
.
debug
(
"Task create new adhoc: {}"
.
format
(
task_name
))
print
(
"Task create new adhoc: {}"
.
format
(
task_name
))
new_adhoc
.
save
()
new_adhoc
.
save
()
task
.
latest_adhoc
=
new_adhoc
task
.
latest_adhoc
=
new_adhoc
created
=
True
created
=
True
...
...
apps/static/css/jumpserver.css
View file @
f37b3316
...
@@ -303,7 +303,7 @@ div.dataTables_wrapper div.dataTables_filter {
...
@@ -303,7 +303,7 @@ div.dataTables_wrapper div.dataTables_filter {
.profile-element
div
:first-child
{
.profile-element
div
:first-child
{
line-height
:
60px
;
line-height
:
60px
;
width
:
70px
;
/*width: 70px;*/
float
:
left
;
float
:
left
;
text-align
:
center
;
text-align
:
center
;
}
}
...
...
apps/static/img/avatar/admin.png
View replaced file @
5bbad019
View file @
f37b3316
106 KB
|
W:
|
H:
11.5 KB
|
W:
|
H:
2-up
Swipe
Onion skin
apps/static/img/avatar/user.png
View replaced file @
5bbad019
View file @
f37b3316
61.3 KB
|
W:
|
H:
11.5 KB
|
W:
|
H:
2-up
Swipe
Onion skin
apps/static/img/logo-text.png
0 → 100644
View file @
f37b3316
12.4 KB
apps/templates/_footer.html
View file @
f37b3316
...
@@ -4,6 +4,6 @@
...
@@ -4,6 +4,6 @@
<img
style=
"display: none"
src=
"http://www.jumpserver.org/img/evaluate_avatar1.jpg"
>
<img
style=
"display: none"
src=
"http://www.jumpserver.org/img/evaluate_avatar1.jpg"
>
</div>
</div>
<div>
<div>
<strong>
Copyright
</strong>
北京堆栈科技有限公司
©
2014-201
7
<strong>
Copyright
</strong>
北京堆栈科技有限公司
©
2014-201
8
</div>
</div>
</div>
</div>
\ No newline at end of file
apps/templates/_header_bar.html
View file @
f37b3316
...
@@ -10,9 +10,9 @@
...
@@ -10,9 +10,9 @@
<!--</form>-->
<!--</form>-->
</div>
</div>
<ul
class=
"nav navbar-top-links navbar-right"
>
<ul
class=
"nav navbar-top-links navbar-right"
>
<li>
{#
<li>
#}
<span
class=
"m-r-sm text-muted welcome-message"
>
{% trans 'Welcome to use Jumpserver system' %}
</span>
{#
<span
class=
"m-r-sm text-muted welcome-message"
>
{% trans 'Welcome to use Jumpserver system' %}
</span>
#}
</li>
{#
</li>
#}
<li
class=
"dropdown"
>
<li
class=
"dropdown"
>
<a
class=
"dropdown-toggle count-info"
data-toggle=
"dropdown"
href=
"#"
>
<a
class=
"dropdown-toggle count-info"
data-toggle=
"dropdown"
href=
"#"
>
<span
class=
"m-r-sm text-muted welcome-message"
>
{% trans 'Help' %}
</span>
<span
class=
"m-r-sm text-muted welcome-message"
>
{% trans 'Help' %}
</span>
...
@@ -22,11 +22,10 @@
...
@@ -22,11 +22,10 @@
{% if request.user.is_authenticated %}
{% if request.user.is_authenticated %}
<a
data-toggle=
"dropdown"
class=
"dropdown-toggle"
href=
"#"
>
<a
data-toggle=
"dropdown"
class=
"dropdown-toggle"
href=
"#"
>
<span
class=
"m-r-sm text-muted welcome-message"
>
<span
class=
"m-r-sm text-muted welcome-message"
>
<img
alt=
"image"
class=
"img-circle"
width=
"40"
height=
"40"
src=
"{{ request.user.avatar_url }}"
/>
<img
alt=
"image"
class=
"img-circle"
width=
"30"
height=
"30"
src=
"{{ request.user.avatar_url }}"
/>
<strong
class=
"font-bold"
>
{{ request.user.name }}
<span
style=
"font-size: 13px;font-weight: 400"
>
{{ request.user.name }}
<span
style=
"color: #8095a8"
></span>
<b
class=
"caret"
></b>
<b
class=
"caret"
></b>
</s
trong
>
</s
pan
>
</span>
</span>
</a>
</a>
<ul
class=
"dropdown-menu animated fadeInRight m-t-xs"
>
<ul
class=
"dropdown-menu animated fadeInRight m-t-xs"
>
...
...
apps/templates/_user_profile.html
View file @
f37b3316
...
@@ -2,11 +2,8 @@
...
@@ -2,11 +2,8 @@
{% load i18n %}
{% load i18n %}
<li
class=
"nav-header"
>
<li
class=
"nav-header"
>
<div
class=
"dropdown profile-element"
>
<div
class=
"dropdown profile-element"
>
<div>
<div
href=
"http://www.jumpserver.org"
target=
"_blank"
>
<img
alt=
"image"
height=
"40"
src=
"/static/img/logo.png"
/>
<img
alt=
"image"
height=
"55"
src=
"/static/img/logo-text.png"
style=
"margin-left: 10px"
/>
</div>
<div>
<a
href=
"http://www.jumpserver.org"
target=
"_blank"
>
Jumpserver
</a>
</div>
</div>
</div>
</div>
<div
class=
"clearfix"
></div>
<div
class=
"clearfix"
></div>
...
...
apps/templates/flash_message_standalone.html
View file @
f37b3316
...
@@ -52,7 +52,7 @@
...
@@ -52,7 +52,7 @@
Copyright Jumpserver.org
Copyright Jumpserver.org
</div>
</div>
<div
class=
"col-md-6 text-right"
>
<div
class=
"col-md-6 text-right"
>
<small>
2014-201
7
</small>
<small>
2014-201
8
</small>
</div>
</div>
</div>
</div>
</div>
</div>
...
...
apps/templates/index.html
View file @
f37b3316
...
@@ -164,7 +164,7 @@
...
@@ -164,7 +164,7 @@
{% for login in last_login_ten %}
{% for login in last_login_ten %}
<div
class=
"feed-element"
>
<div
class=
"feed-element"
>
<a
href=
"#"
class=
"pull-left"
>
<a
href=
"#"
class=
"pull-left"
>
<img
alt=
"image"
class=
"img-circle"
src=
"
/static/img/root.png
"
>
<img
alt=
"image"
class=
"img-circle"
src=
"
{% static 'img/avatar/user.png' %}
"
>
</a>
</a>
<div
class=
"media-body "
>
<div
class=
"media-body "
>
{% ifequal login.is_finished 0 %}
{% ifequal login.is_finished 0 %}
...
...
apps/terminal/api.py
View file @
f37b3316
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
from
collections
import
OrderedDict
from
collections
import
OrderedDict
import
copy
import
logging
import
logging
import
os
import
os
import
uuid
import
uuid
...
@@ -21,7 +20,8 @@ from .serializers import TerminalSerializer, StatusSerializer, \
...
@@ -21,7 +20,8 @@ from .serializers import TerminalSerializer, StatusSerializer, \
SessionSerializer
,
TaskSerializer
,
ReplaySerializer
SessionSerializer
,
TaskSerializer
,
ReplaySerializer
from
.hands
import
IsSuperUserOrAppUser
,
IsAppUser
,
\
from
.hands
import
IsSuperUserOrAppUser
,
IsAppUser
,
\
IsSuperUserOrAppUserOrUserReadonly
IsSuperUserOrAppUserOrUserReadonly
from
.backends
import
get_command_store
,
SessionCommandSerializer
from
.backends
import
get_command_store
,
get_multi_command_store
,
\
SessionCommandSerializer
logger
=
logging
.
getLogger
(
__file__
)
logger
=
logging
.
getLogger
(
__file__
)
...
@@ -141,7 +141,9 @@ class StatusViewSet(viewsets.ModelViewSet):
...
@@ -141,7 +141,9 @@ class StatusViewSet(viewsets.ModelViewSet):
session
=
serializer
.
save
()
session
=
serializer
.
save
()
return
session
return
session
else
:
else
:
msg
=
"session data is not valid {}"
.
format
(
serializer
.
errors
)
msg
=
"session data is not valid {}: {}"
.
format
(
serializer
.
errors
,
str
(
serializer
.
data
)
)
logger
.
error
(
msg
)
logger
.
error
(
msg
)
return
None
return
None
...
@@ -195,6 +197,7 @@ class CommandViewSet(viewsets.ViewSet):
...
@@ -195,6 +197,7 @@ class CommandViewSet(viewsets.ViewSet):
"""
"""
command_store
=
get_command_store
()
command_store
=
get_command_store
()
multi_command_storage
=
get_multi_command_store
()
serializer_class
=
SessionCommandSerializer
serializer_class
=
SessionCommandSerializer
permission_classes
=
(
IsSuperUserOrAppUser
,)
permission_classes
=
(
IsSuperUserOrAppUser
,)
...
@@ -215,7 +218,7 @@ class CommandViewSet(viewsets.ViewSet):
...
@@ -215,7 +218,7 @@ class CommandViewSet(viewsets.ViewSet):
return
Response
({
"msg"
:
msg
},
status
=
401
)
return
Response
({
"msg"
:
msg
},
status
=
401
)
def
list
(
self
,
request
,
*
args
,
**
kwargs
):
def
list
(
self
,
request
,
*
args
,
**
kwargs
):
queryset
=
list
(
self
.
command_store
.
all
()
)
queryset
=
self
.
multi_command_storage
.
filter
(
)
serializer
=
self
.
serializer_class
(
queryset
,
many
=
True
)
serializer
=
self
.
serializer_class
(
queryset
,
many
=
True
)
return
Response
(
serializer
.
data
)
return
Response
(
serializer
.
data
)
...
@@ -258,3 +261,13 @@ class SessionReplayViewSet(viewsets.ViewSet):
...
@@ -258,3 +261,13 @@ class SessionReplayViewSet(viewsets.ViewSet):
return
redirect
(
url
)
return
redirect
(
url
)
else
:
else
:
return
HttpResponseNotFound
()
return
HttpResponseNotFound
()
class
TerminalConfig
(
APIView
):
permission_classes
=
(
IsAppUser
,)
def
get
(
self
,
request
):
user
=
request
.
user
terminal
=
user
.
terminal
configs
=
terminal
.
config
return
Response
(
configs
,
status
=
200
)
apps/terminal/backends/__init__.py
View file @
f37b3316
...
@@ -2,9 +2,39 @@ from importlib import import_module
...
@@ -2,9 +2,39 @@ from importlib import import_module
from
django.conf
import
settings
from
django.conf
import
settings
from
.command.serializers
import
SessionCommandSerializer
from
.command.serializers
import
SessionCommandSerializer
TYPE_ENGINE_MAPPING
=
{
'elasticsearch'
:
'terminal.backends.command.es'
,
}
def
get_command_store
():
def
get_command_store
():
command_engine
=
import_module
(
settings
.
COMMAND_STORAGE_BACKEND
)
params
=
settings
.
COMMAND_STORAGE
command_store
=
command_engine
.
CommandStore
()
engine_class
=
import_module
(
params
[
'ENGINE'
])
return
command_store
storage
=
engine_class
.
CommandStore
(
params
)
return
storage
def
get_terminal_command_store
():
storage_list
=
{}
for
name
,
params
in
settings
.
TERMINAL_COMMAND_STORAGE
.
items
():
tp
=
params
[
'TYPE'
]
if
tp
==
'server'
:
storage
=
get_command_store
()
else
:
if
not
TYPE_ENGINE_MAPPING
.
get
(
tp
):
raise
AssertionError
(
"Command storage type should in {}"
.
format
(
', '
.
join
(
TYPE_ENGINE_MAPPING
.
keys
()))
)
engine_class
=
import_module
(
TYPE_ENGINE_MAPPING
[
tp
])
storage
=
engine_class
.
CommandStore
(
params
)
storage_list
[
name
]
=
storage
return
storage_list
def
get_multi_command_store
():
from
.command.multi
import
CommandStore
storage_list
=
get_terminal_command_store
()
.
values
()
storage
=
CommandStore
(
storage_list
)
return
storage
apps/terminal/backends/command/base.py
View file @
f37b3316
...
@@ -19,3 +19,9 @@ class CommandBase(object):
...
@@ -19,3 +19,9 @@ class CommandBase(object):
input
=
None
,
session
=
None
):
input
=
None
,
session
=
None
):
pass
pass
@abc.abstractmethod
def
count
(
self
,
date_from
=
None
,
date_to
=
None
,
user
=
None
,
asset
=
None
,
system_user
=
None
,
input
=
None
,
session
=
None
):
pass
apps/terminal/backends/command/db.py
View file @
f37b3316
...
@@ -8,7 +8,7 @@ from .base import CommandBase
...
@@ -8,7 +8,7 @@ from .base import CommandBase
class
CommandStore
(
CommandBase
):
class
CommandStore
(
CommandBase
):
def
__init__
(
self
):
def
__init__
(
self
,
params
):
from
terminal.models
import
Command
from
terminal.models
import
Command
self
.
model
=
Command
self
.
model
=
Command
...
@@ -37,7 +37,9 @@ class CommandStore(CommandBase):
...
@@ -37,7 +37,9 @@ class CommandStore(CommandBase):
))
))
return
self
.
model
.
objects
.
bulk_create
(
_commands
)
return
self
.
model
.
objects
.
bulk_create
(
_commands
)
def
filter
(
self
,
date_from
=
None
,
date_to
=
None
,
@staticmethod
def
make_filter_kwargs
(
date_from
=
None
,
date_to
=
None
,
user
=
None
,
asset
=
None
,
system_user
=
None
,
user
=
None
,
asset
=
None
,
system_user
=
None
,
input
=
None
,
session
=
None
):
input
=
None
,
session
=
None
):
filter_kwargs
=
{}
filter_kwargs
=
{}
...
@@ -60,10 +62,28 @@ class CommandStore(CommandBase):
...
@@ -60,10 +62,28 @@ class CommandStore(CommandBase):
if
session
:
if
session
:
filter_kwargs
[
'session'
]
=
session
filter_kwargs
[
'session'
]
=
session
return
filter_kwargs
def
filter
(
self
,
date_from
=
None
,
date_to
=
None
,
user
=
None
,
asset
=
None
,
system_user
=
None
,
input
=
None
,
session
=
None
):
filter_kwargs
=
self
.
make_filter_kwargs
(
date_from
=
date_from
,
date_to
=
date_to
,
user
=
user
,
asset
=
asset
,
system_user
=
system_user
,
input
=
input
,
session
=
session
,
)
queryset
=
self
.
model
.
objects
.
filter
(
**
filter_kwargs
)
queryset
=
self
.
model
.
objects
.
filter
(
**
filter_kwargs
)
return
queryset
return
[
command
.
to_dict
()
for
command
in
queryset
]
def
count
(
self
,
date_from
=
None
,
date_to
=
None
,
user
=
None
,
asset
=
None
,
system_user
=
None
,
input
=
None
,
session
=
None
):
filter_kwargs
=
self
.
make_filter_kwargs
(
date_from
=
date_from
,
date_to
=
date_to
,
user
=
user
,
asset
=
asset
,
system_user
=
system_user
,
input
=
input
,
session
=
session
,
)
count
=
self
.
model
.
objects
.
filter
(
**
filter_kwargs
)
.
count
()
return
count
def
all
(
self
):
"""返回所有数据"""
return
self
.
model
.
objects
.
iterator
()
apps/terminal/backends/command/es.py
0 → 100644
View file @
f37b3316
# -*- coding: utf-8 -*-
#
from
jms_es_sdk
import
ESStore
from
.base
import
CommandBase
class
CommandStore
(
CommandBase
,
ESStore
):
def
__init__
(
self
,
params
):
hosts
=
params
.
get
(
'HOSTS'
,
[
'http://localhost'
])
ESStore
.
__init__
(
self
,
hosts
=
hosts
)
def
save
(
self
,
command
):
return
ESStore
.
save
(
self
,
command
)
def
bulk_save
(
self
,
commands
):
return
ESStore
.
bulk_save
(
self
,
commands
)
def
filter
(
self
,
date_from
=
None
,
date_to
=
None
,
user
=
None
,
asset
=
None
,
system_user
=
None
,
input
=
None
,
session
=
None
):
data
=
ESStore
.
filter
(
self
,
date_from
=
date_from
,
date_to
=
date_to
,
user
=
user
,
asset
=
asset
,
system_user
=
system_user
,
input
=
input
,
session
=
session
)
return
[
item
[
"_source"
]
for
item
in
data
[
"hits"
]
if
item
]
def
count
(
self
,
date_from
=
None
,
date_to
=
None
,
user
=
None
,
asset
=
None
,
system_user
=
None
,
input
=
None
,
session
=
None
):
amount
=
ESStore
.
count
(
self
,
date_from
=
date_from
,
date_to
=
date_to
,
user
=
user
,
asset
=
asset
,
system_user
=
system_user
,
input
=
input
,
session
=
session
)
return
amount
apps/terminal/backends/command/models.py
View file @
f37b3316
...
@@ -18,5 +18,26 @@ class AbstractSessionCommand(models.Model):
...
@@ -18,5 +18,26 @@ class AbstractSessionCommand(models.Model):
class
Meta
:
class
Meta
:
abstract
=
True
abstract
=
True
@classmethod
def
from_dict
(
cls
,
d
):
self
=
cls
()
for
k
,
v
in
d
.
items
():
setattr
(
self
,
k
,
v
)
return
self
@classmethod
def
from_multi_dict
(
cls
,
l
):
commands
=
[]
for
d
in
l
:
command
=
cls
.
from_dict
(
d
)
commands
.
append
(
command
)
return
commands
def
to_dict
(
self
):
d
=
{}
for
field
in
self
.
_meta
.
fields
:
d
[
field
.
name
]
=
getattr
(
self
,
field
.
name
)
return
d
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
input
return
self
.
input
apps/terminal/backends/command/multi.py
0 → 100644
View file @
f37b3316
# -*- coding: utf-8 -*-
#
from
.base
import
CommandBase
class
CommandStore
(
CommandBase
):
def
__init__
(
self
,
storage_list
):
self
.
storage_list
=
storage_list
def
filter
(
self
,
**
kwargs
):
queryset
=
[]
for
storage
in
self
.
storage_list
:
queryset
.
extend
(
storage
.
filter
(
**
kwargs
))
return
sorted
(
queryset
,
key
=
lambda
command
:
command
[
"timestamp"
],
reverse
=
True
)
def
count
(
self
,
**
kwargs
):
amount
=
0
for
storage
in
self
.
storage_list
:
amount
+=
storage
.
count
(
**
kwargs
)
return
amount
def
save
(
self
,
command
):
pass
def
bulk_save
(
self
,
commands
):
pass
apps/terminal/forms.py
View file @
f37b3316
...
@@ -2,15 +2,27 @@
...
@@ -2,15 +2,27 @@
#
#
from
django
import
forms
from
django
import
forms
from
django.conf
import
settings
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
.models
import
Terminal
from
.models
import
Terminal
def
get_all_command_storage
():
# storage_choices = []
from
common.models
import
Setting
Setting
.
refresh_all_settings
()
for
k
,
v
in
settings
.
TERMINAL_COMMAND_STORAGE
.
items
():
yield
(
k
,
k
)
class
TerminalForm
(
forms
.
ModelForm
):
class
TerminalForm
(
forms
.
ModelForm
):
command_storage
=
forms
.
ChoiceField
(
choices
=
get_all_command_storage
(),
label
=
_
(
"Command storage"
))
class
Meta
:
class
Meta
:
model
=
Terminal
model
=
Terminal
fields
=
[
'name'
,
'remote_addr'
,
'ssh_port'
,
'http_port'
,
'comment'
]
fields
=
[
'name'
,
'remote_addr'
,
'ssh_port'
,
'http_port'
,
'comment'
,
'command_storage'
]
help_texts
=
{
help_texts
=
{
'ssh_port'
:
_
(
"Coco ssh listen port"
),
'ssh_port'
:
_
(
"Coco ssh listen port"
),
'http_port'
:
_
(
"Coco http/ws listen port"
),
'http_port'
:
_
(
"Coco http/ws listen port"
),
...
...
apps/terminal/models.py
View file @
f37b3316
...
@@ -4,6 +4,7 @@ import uuid
...
@@ -4,6 +4,7 @@ import uuid
from
django.db
import
models
from
django.db
import
models
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.conf
import
settings
from
users.models
import
User
from
users.models
import
User
from
.backends.command.models
import
AbstractSessionCommand
from
.backends.command.models
import
AbstractSessionCommand
...
@@ -15,6 +16,8 @@ class Terminal(models.Model):
...
@@ -15,6 +16,8 @@ class Terminal(models.Model):
remote_addr
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
'Remote Address'
))
remote_addr
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
'Remote Address'
))
ssh_port
=
models
.
IntegerField
(
verbose_name
=
_
(
'SSH Port'
),
default
=
2222
)
ssh_port
=
models
.
IntegerField
(
verbose_name
=
_
(
'SSH Port'
),
default
=
2222
)
http_port
=
models
.
IntegerField
(
verbose_name
=
_
(
'HTTP Port'
),
default
=
5000
)
http_port
=
models
.
IntegerField
(
verbose_name
=
_
(
'HTTP Port'
),
default
=
5000
)
command_storage
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Command storage"
),
default
=
'default'
)
replay_storage
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Replay storage"
),
default
=
'default'
)
user
=
models
.
OneToOneField
(
User
,
related_name
=
'terminal'
,
verbose_name
=
'Application User'
,
null
=
True
,
on_delete
=
models
.
CASCADE
)
user
=
models
.
OneToOneField
(
User
,
related_name
=
'terminal'
,
verbose_name
=
'Application User'
,
null
=
True
,
on_delete
=
models
.
CASCADE
)
is_accepted
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'Is Accepted'
)
is_accepted
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'Is Accepted'
)
is_deleted
=
models
.
BooleanField
(
default
=
False
)
is_deleted
=
models
.
BooleanField
(
default
=
False
)
...
@@ -33,6 +36,26 @@ class Terminal(models.Model):
...
@@ -33,6 +36,26 @@ class Terminal(models.Model):
self
.
user
.
is_active
=
active
self
.
user
.
is_active
=
active
self
.
user
.
save
()
self
.
user
.
save
()
def
get_common_storage
(
self
):
storage_all
=
settings
.
TERMINAL_COMMAND_STORAGE
if
self
.
command_storage
in
storage_all
:
storage
=
storage_all
.
get
(
self
.
command_storage
)
else
:
storage
=
storage_all
.
get
(
'default'
)
return
{
"TERMINAL_COMMAND_STORAGE"
:
storage
}
def
get_replay_storage
(
self
):
pass
@property
def
config
(
self
):
configs
=
{}
for
k
in
dir
(
settings
):
if
k
.
startswith
(
'TERMINAL'
):
configs
[
k
]
=
getattr
(
settings
,
k
)
configs
.
update
(
self
.
get_common_storage
())
return
configs
def
create_app_user
(
self
):
def
create_app_user
(
self
):
random
=
uuid
.
uuid4
()
.
hex
[:
6
]
random
=
uuid
.
uuid4
()
.
hex
[:
6
]
user
,
access_key
=
User
.
create_app_user
(
name
=
"{}-{}"
.
format
(
self
.
name
,
random
),
comment
=
self
.
comment
)
user
,
access_key
=
User
.
create_app_user
(
name
=
"{}-{}"
.
format
(
self
.
name
,
random
),
comment
=
self
.
comment
)
...
...
apps/terminal/serializers.py
View file @
f37b3316
...
@@ -5,7 +5,7 @@ from django.utils import timezone
...
@@ -5,7 +5,7 @@ from django.utils import timezone
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
.models
import
Terminal
,
Status
,
Session
,
Task
from
.models
import
Terminal
,
Status
,
Session
,
Task
from
.backends
import
get_command_store
from
.backends
import
get_
multi_
command_store
class
TerminalSerializer
(
serializers
.
ModelSerializer
):
class
TerminalSerializer
(
serializers
.
ModelSerializer
):
...
@@ -43,14 +43,14 @@ class TerminalSerializer(serializers.ModelSerializer):
...
@@ -43,14 +43,14 @@ class TerminalSerializer(serializers.ModelSerializer):
class
SessionSerializer
(
serializers
.
ModelSerializer
):
class
SessionSerializer
(
serializers
.
ModelSerializer
):
command_amount
=
serializers
.
SerializerMethodField
()
command_amount
=
serializers
.
SerializerMethodField
()
command_store
=
get_command_store
()
command_store
=
get_
multi_
command_store
()
class
Meta
:
class
Meta
:
model
=
Session
model
=
Session
fields
=
'__all__'
fields
=
'__all__'
def
get_command_amount
(
self
,
obj
):
def
get_command_amount
(
self
,
obj
):
return
len
(
self
.
command_store
.
filter
(
session
=
obj
.
session
))
return
self
.
command_store
.
count
(
session
=
str
(
obj
.
id
))
class
StatusSerializer
(
serializers
.
ModelSerializer
):
class
StatusSerializer
(
serializers
.
ModelSerializer
):
...
...
apps/terminal/signals_handler.py
View file @
f37b3316
...
@@ -13,10 +13,6 @@ RUNNING = False
...
@@ -13,10 +13,6 @@ RUNNING = False
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
@shared_task
@register_as_period_task
(
interval
=
3600
)
@after_app_ready_start
@after_app_shutdown_clean
def
set_session_info_cache
():
def
set_session_info_cache
():
logger
.
debug
(
""
)
logger
.
debug
(
""
)
from
.utils
import
get_session_asset_list
,
get_session_user_list
,
\
from
.utils
import
get_session_asset_list
,
get_session_user_list
,
\
...
...
apps/terminal/templates/terminal/terminal_modal_accept.html
View file @
f37b3316
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
{% bootstrap_field form.remote_addr layout="horizontal" %}
{% bootstrap_field form.remote_addr layout="horizontal" %}
{% bootstrap_field form.ssh_port layout="horizontal" %}
{% bootstrap_field form.ssh_port layout="horizontal" %}
{% bootstrap_field form.http_port layout="horizontal" %}
{% bootstrap_field form.http_port layout="horizontal" %}
{% bootstrap_field form.command_storage layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
</form>
</form>
...
...
apps/terminal/templates/terminal/terminal_update.html
View file @
f37b3316
...
@@ -35,6 +35,7 @@
...
@@ -35,6 +35,7 @@
{% bootstrap_field form.remote_addr layout="horizontal" %}
{% bootstrap_field form.remote_addr layout="horizontal" %}
{% bootstrap_field form.ssh_port layout="horizontal" %}
{% bootstrap_field form.ssh_port layout="horizontal" %}
{% bootstrap_field form.http_port layout="horizontal" %}
{% bootstrap_field form.http_port layout="horizontal" %}
{% bootstrap_field form.command_storage layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Other' %}
</h3>
<h3>
{% trans 'Other' %}
</h3>
...
...
apps/terminal/templatetags/terminal_tags.py
View file @
f37b3316
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
from
django
import
template
from
django
import
template
from
..backends
import
get_command_store
from
..backends
import
get_
multi_
command_store
register
=
template
.
Library
()
register
=
template
.
Library
()
command_store
=
get_command_store
()
command_store
=
get_
multi_
command_store
()
@register.filter
@register.filter
def
get_session_command_amount
(
session_id
):
def
get_session_command_amount
(
session_id
):
return
len
(
command_store
.
filter
(
session
=
str
(
session_id
)))
return
command_store
.
count
(
session
=
session_id
)
apps/terminal/urls/api_urls.py
View file @
f37b3316
...
@@ -20,7 +20,8 @@ urlpatterns = [
...
@@ -20,7 +20,8 @@ urlpatterns = [
url
(
r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$'
,
url
(
r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$'
,
api
.
SessionReplayViewSet
.
as_view
({
'get'
:
'retrieve'
,
'post'
:
'create'
}),
api
.
SessionReplayViewSet
.
as_view
({
'get'
:
'retrieve'
,
'post'
:
'create'
}),
name
=
'session-replay'
),
name
=
'session-replay'
),
url
(
r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key'
,
api
.
TerminalTokenApi
.
as_view
(),
name
=
'terminal-access-key'
)
url
(
r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key'
,
api
.
TerminalTokenApi
.
as_view
(),
name
=
'terminal-access-key'
),
url
(
r'^v1/terminal/config'
,
api
.
TerminalConfig
.
as_view
(),
name
=
'terminal-config'
),
]
]
urlpatterns
+=
router
.
urls
urlpatterns
+=
router
.
urls
apps/terminal/views/command.py
View file @
f37b3316
...
@@ -9,10 +9,10 @@ from django.utils.translation import ugettext as _
...
@@ -9,10 +9,10 @@ from django.utils.translation import ugettext as _
from
common.mixins
import
DatetimeSearchMixin
from
common.mixins
import
DatetimeSearchMixin
from
..models
import
Command
from
..models
import
Command
from
..
import
utils
from
..
import
utils
from
..backends
import
get_command_store
from
..backends
import
get_
multi_
command_store
__all__
=
[
'CommandListView'
]
__all__
=
[
'CommandListView'
]
comm
and_store
=
get
_command_store
()
comm
on_storage
=
get_multi
_command_store
()
class
CommandListView
(
DatetimeSearchMixin
,
ListView
):
class
CommandListView
(
DatetimeSearchMixin
,
ListView
):
...
@@ -39,7 +39,7 @@ class CommandListView(DatetimeSearchMixin, ListView):
...
@@ -39,7 +39,7 @@ class CommandListView(DatetimeSearchMixin, ListView):
filter_kwargs
[
'system_user'
]
=
self
.
system_user
filter_kwargs
[
'system_user'
]
=
self
.
system_user
if
self
.
command
:
if
self
.
command
:
filter_kwargs
[
'input'
]
=
self
.
command
filter_kwargs
[
'input'
]
=
self
.
command
queryset
=
comm
and_stor
e
.
filter
(
**
filter_kwargs
)
queryset
=
comm
on_storag
e
.
filter
(
**
filter_kwargs
)
return
queryset
return
queryset
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
...
...
apps/terminal/views/session.py
View file @
f37b3316
...
@@ -10,7 +10,7 @@ from django.conf import settings
...
@@ -10,7 +10,7 @@ from django.conf import settings
from
users.utils
import
AdminUserRequiredMixin
from
users.utils
import
AdminUserRequiredMixin
from
common.mixins
import
DatetimeSearchMixin
from
common.mixins
import
DatetimeSearchMixin
from
..models
import
Session
,
Command
,
Terminal
from
..models
import
Session
,
Command
,
Terminal
from
..backends
import
get_command_store
from
..backends
import
get_
multi_
command_store
from
..
import
utils
from
..
import
utils
...
@@ -19,7 +19,7 @@ __all__ = [
...
@@ -19,7 +19,7 @@ __all__ = [
'SessionDetailView'
,
'SessionDetailView'
,
]
]
command_store
=
get_command_store
()
command_store
=
get_
multi_
command_store
()
class
SessionListView
(
AdminUserRequiredMixin
,
DatetimeSearchMixin
,
ListView
):
class
SessionListView
(
AdminUserRequiredMixin
,
DatetimeSearchMixin
,
ListView
):
...
...
apps/users/api.py
View file @
f37b3316
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
from
rest_framework
import
generics
from
rest_framework
import
generics
from
rest_framework.permissions
import
AllowAny
from
rest_framework.permissions
import
AllowAny
,
IsAuthenticated
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
rest_framework.views
import
APIView
from
rest_framework.views
import
APIView
from
rest_framework_bulk
import
BulkModelViewSet
from
rest_framework_bulk
import
BulkModelViewSet
from
.serializers
import
UserSerializer
,
UserGroupSerializer
,
\
from
.serializers
import
UserSerializer
,
UserGroupSerializer
,
\
UserGroupUpdateMemeberSerializer
,
UserPKUpdateSerializer
,
\
UserGroupUpdateMemeberSerializer
,
UserPKUpdateSerializer
,
\
UserUpdateGroupSerializer
UserUpdateGroupSerializer
,
ChangeUserPasswordSerializer
from
.tasks
import
write_login_log_async
from
.tasks
import
write_login_log_async
from
.models
import
User
,
UserGroup
from
.models
import
User
,
UserGroup
from
.permissions
import
IsSuperUser
,
IsValidUser
,
IsCurrentUserOrReadOnly
from
.permissions
import
IsSuperUser
,
IsValidUser
,
IsCurrentUserOrReadOnly
...
@@ -24,10 +24,21 @@ class UserViewSet(CustomFilterMixin, BulkModelViewSet):
...
@@ -24,10 +24,21 @@ class UserViewSet(CustomFilterMixin, BulkModelViewSet):
queryset
=
User
.
objects
.
exclude
(
role
=
"App"
)
queryset
=
User
.
objects
.
exclude
(
role
=
"App"
)
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
serializer_class
=
UserSerializer
serializer_class
=
UserSerializer
permission_classes
=
(
IsSuperUser
,)
permission_classes
=
(
IsSuperUser
,
IsAuthenticated
)
filter_fields
=
(
'username'
,
'email'
,
'name'
,
'id'
)
filter_fields
=
(
'username'
,
'email'
,
'name'
,
'id'
)
class
ChangeUserPasswordApi
(
generics
.
RetrieveUpdateAPIView
):
permission_classes
=
(
IsSuperUser
,)
queryset
=
User
.
objects
.
all
()
serializer_class
=
ChangeUserPasswordSerializer
def
perform_update
(
self
,
serializer
):
user
=
self
.
get_object
()
user
.
password_raw
=
serializer
.
validated_data
[
"password"
]
user
.
save
()
class
UserUpdateGroupApi
(
generics
.
RetrieveUpdateAPIView
):
class
UserUpdateGroupApi
(
generics
.
RetrieveUpdateAPIView
):
queryset
=
User
.
objects
.
all
()
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserUpdateGroupSerializer
serializer_class
=
UserUpdateGroupSerializer
...
@@ -37,6 +48,7 @@ class UserUpdateGroupApi(generics.RetrieveUpdateAPIView):
...
@@ -37,6 +48,7 @@ class UserUpdateGroupApi(generics.RetrieveUpdateAPIView):
class
UserResetPasswordApi
(
generics
.
UpdateAPIView
):
class
UserResetPasswordApi
(
generics
.
UpdateAPIView
):
queryset
=
User
.
objects
.
all
()
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserSerializer
serializer_class
=
UserSerializer
permission_classes
=
(
IsAuthenticated
,)
def
perform_update
(
self
,
serializer
):
def
perform_update
(
self
,
serializer
):
# Note: we are not updating the user object here.
# Note: we are not updating the user object here.
...
@@ -128,7 +140,11 @@ class UserAuthApi(APIView):
...
@@ -128,7 +140,11 @@ class UserAuthApi(APIView):
user_agent
=
request
.
data
.
get
(
'HTTP_USER_AGENT'
,
''
)
user_agent
=
request
.
data
.
get
(
'HTTP_USER_AGENT'
,
''
)
if
not
login_ip
:
if
not
login_ip
:
login_ip
=
request
.
META
.
get
(
'HTTP_X_FORWARDED_FOR'
)
or
request
.
META
.
get
(
"REMOTE_ADDR"
)
x_forwarded_for
=
request
.
META
.
get
(
'HTTP_X_FORWARDED_FOR'
,
''
)
.
split
(
','
)
if
x_forwarded_for
:
login_ip
=
x_forwarded_for
[
0
]
else
:
login_ip
=
request
.
META
.
get
(
"REMOTE_ADDR"
)
user
,
msg
=
check_user_valid
(
user
,
msg
=
check_user_valid
(
username
=
username
,
password
=
password
,
username
=
username
,
password
=
password
,
...
...
apps/users/forms.py
View file @
f37b3316
...
@@ -172,7 +172,6 @@ class UserBulkUpdateForm(forms.ModelForm):
...
@@ -172,7 +172,6 @@ class UserBulkUpdateForm(forms.ModelForm):
if
self
.
data
.
get
(
field
)
is
not
None
:
if
self
.
data
.
get
(
field
)
is
not
None
:
changed_fields
.
append
(
field
)
changed_fields
.
append
(
field
)
print
(
changed_fields
)
cleaned_data
=
{
k
:
v
for
k
,
v
in
self
.
cleaned_data
.
items
()
cleaned_data
=
{
k
:
v
for
k
,
v
in
self
.
cleaned_data
.
items
()
if
k
in
changed_fields
}
if
k
in
changed_fields
}
users
=
cleaned_data
.
pop
(
'users'
,
''
)
users
=
cleaned_data
.
pop
(
'users'
,
''
)
...
...
apps/users/hands.py
View file @
f37b3316
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
Other module of this app shouldn't connect with other app.
Other module of this app shouldn't connect with other app.
:copyright: (c) 2014-201
7
by Jumpserver Team.
:copyright: (c) 2014-201
8
by Jumpserver Team.
:license: GPL v2, see LICENSE for more details.
:license: GPL v2, see LICENSE for more details.
"""
"""
...
...
apps/users/serializers.py
View file @
f37b3316
...
@@ -71,3 +71,9 @@ class UserGroupUpdateMemeberSerializer(serializers.ModelSerializer):
...
@@ -71,3 +71,9 @@ class UserGroupUpdateMemeberSerializer(serializers.ModelSerializer):
model
=
UserGroup
model
=
UserGroup
fields
=
[
'id'
,
'users'
]
fields
=
[
'id'
,
'users'
]
class
ChangeUserPasswordSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
User
fields
=
[
'password'
]
apps/users/templates/users/_user.html
View file @
f37b3316
...
@@ -11,8 +11,8 @@
...
@@ -11,8 +11,8 @@
<form
method=
"post"
class=
"form-horizontal"
action=
""
enctype=
"multipart/form-data"
>
<form
method=
"post"
class=
"form-horizontal"
action=
""
enctype=
"multipart/form-data"
>
{% csrf_token %}
{% csrf_token %}
<h3>
{% trans 'Account' %}
</h3>
<h3>
{% trans 'Account' %}
</h3>
{% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.email layout="horizontal" %}
{% bootstrap_field form.email layout="horizontal" %}
{% bootstrap_field form.groups layout="horizontal" %}
{% bootstrap_field form.groups layout="horizontal" %}
...
@@ -32,12 +32,6 @@
...
@@ -32,12 +32,6 @@
<span
class=
"help-block "
>
{{ form.date_expired.errors }}
</span>
<span
class=
"help-block "
>
{{ form.date_expired.errors }}
</span>
</div>
</div>
</div>
</div>
{#
<div
class=
"form-group"
>
#}
{#
<label
for=
"{{ form.enable_otp.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Enable OTP' %}
</label>
#}
{#
<div
class=
"col-sm-8"
>
#}
{# {{ form.enable_otp }}#}
{#
</div>
#}
{#
</div>
#}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Profile' %}
</h3>
<h3>
{% trans 'Profile' %}
</h3>
{% bootstrap_field form.phone layout="horizontal" %}
{% bootstrap_field form.phone layout="horizontal" %}
...
...
apps/users/templates/users/forgot_password.html
View file @
f37b3316
...
@@ -55,7 +55,7 @@
...
@@ -55,7 +55,7 @@
Copyright Jumpserver.org
Copyright Jumpserver.org
</div>
</div>
<div
class=
"col-md-6 text-right"
>
<div
class=
"col-md-6 text-right"
>
<small>
© 2014-201
7
</small>
<small>
© 2014-201
8
</small>
</div>
</div>
</div>
</div>
</div>
</div>
...
...
apps/users/templates/users/login.html
View file @
f37b3316
...
@@ -78,7 +78,7 @@
...
@@ -78,7 +78,7 @@
Copyright Jumpserver.org
Copyright Jumpserver.org
</div>
</div>
<div
class=
"col-md-6 text-right"
>
<div
class=
"col-md-6 text-right"
>
<small>
© 2014-201
7
</small>
<small>
© 2014-201
8
</small>
</div>
</div>
</div>
</div>
</div>
</div>
...
...
apps/users/templates/users/reset_password.html
View file @
f37b3316
...
@@ -74,7 +74,7 @@
...
@@ -74,7 +74,7 @@
Copyright Jumpserver.org
Copyright Jumpserver.org
</div>
</div>
<div
class=
"col-md-6 text-right"
>
<div
class=
"col-md-6 text-right"
>
<small>
© 2014-201
7
</small>
<small>
© 2014-201
8
</small>
</div>
</div>
</div>
</div>
</div>
</div>
...
...
apps/users/templates/users/user_detail.html
View file @
f37b3316
...
@@ -24,8 +24,9 @@
...
@@ -24,8 +24,9 @@
<li
class=
"pull-right"
>
<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 btn-default"
href=
"{% url 'users:user-update' pk=user_object.id %}"
><i
class=
"fa fa-edit"
></i>
{% trans 'Update' %}
</a>
</li>
</li>
<li
class=
"pull-right"
>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline
btn-danger btn-delete-user
"
>
<a
class=
"btn btn-outline
{% if request.user != user_object and user_object.username != "
admin
"
%}
btn-danger
btn-delete-user
{%
else
%}
disabled
{%
endif
%}
"
>
<i
class=
"fa fa-trash-o"
></i>
{% trans 'Delete' %}
<i
class=
"fa fa-trash-o"
></i>
{% trans 'Delete' %}
</a>
</a>
</li>
</li>
...
@@ -128,7 +129,7 @@
...
@@ -128,7 +129,7 @@
<td><span
class=
"pull-right"
>
<td><span
class=
"pull-right"
>
<div
class=
"switch"
>
<div
class=
"switch"
>
<div
class=
"onoffswitch"
>
<div
class=
"onoffswitch"
>
<input
type=
"checkbox"
{%
if
user_object
.
is_active
%}
checked
{%
endif
%}
class=
"onoffswitch-checkbox"
id=
"is_active"
>
<input
type=
"checkbox"
{%
if
user_object
.
is_active
%}
checked
{%
endif
%}
{%
if
request
.
user =
=
user_object
%}
disabled
{%
endif
%}
class=
"onoffswitch-checkbox"
id=
"is_active"
>
<label
class=
"onoffswitch-label"
for=
"is_active"
>
<label
class=
"onoffswitch-label"
for=
"is_active"
>
<span
class=
"onoffswitch-inner"
></span>
<span
class=
"onoffswitch-inner"
></span>
<span
class=
"onoffswitch-switch"
></span>
<span
class=
"onoffswitch-switch"
></span>
...
@@ -156,7 +157,7 @@
...
@@ -156,7 +157,7 @@
<td>
{% trans 'Send reset password mail' %}:
</td>
<td>
{% trans 'Send reset password mail' %}:
</td>
<td>
<td>
<span
class=
"pull-right"
>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn-reset-password"
style=
"width: 54px"
>
{% trans 'Send' %}
</button>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
{%
if
request
.
user =
=
user_object
%}
disabled=
"disabled"
{%
endif
%}
id=
"btn-reset-password"
style=
"width: 54px"
>
{% trans 'Send' %}
</button>
</span>
</span>
</td>
</td>
</tr>
</tr>
...
@@ -164,7 +165,7 @@
...
@@ -164,7 +165,7 @@
<td>
{% trans 'Send reset ssh key mail' %}:
</td>
<td>
{% trans 'Send reset ssh key mail' %}:
</td>
<td>
<td>
<span
class=
"pull-right"
>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn-reset-pk"
style=
"width: 54px;"
>
{% trans 'Send' %}
</button>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
{%
if
request
.
user =
=
user_object
%}
disabled=
"disabled"
{%
endif
%}
id=
"btn-reset-pk"
style=
"width: 54px;"
>
{% trans 'Send' %}
</button>
</span>
</span>
</td>
</td>
</tr>
</tr>
...
@@ -331,7 +332,7 @@ $(document).ready(function() {
...
@@ -331,7 +332,7 @@ $(document).ready(function() {
}
}
swal({
swal({
title: "{% trans '
Are
you
sure
?
' %}",
title: "{% trans '
Are
you
sure
?
' %}",
text: "{% trans "This will reset the user
'
s
password
.
A
password
-
reset
email
will
be
sent
to
the
user
\
's mailbox."
%}",
text: "{% trans "This will reset the user
password and send a reset mail"
%}",
type: "warning",
type: "warning",
showCancelButton: true,
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonColor: "#DD6B55",
...
@@ -356,7 +357,7 @@ $(document).ready(function() {
...
@@ -356,7 +357,7 @@ $(document).ready(function() {
}
}
swal({
swal({
title: "{% trans '
Are
you
sure
?
' %}",
title: "{% trans '
Are
you
sure
?
' %}",
text: "{% trans '
This
will
reset
the
user
\
's public key.
'
%
}
",
text: "{% trans '
This
will
reset
the
user
public
key
and
send
a
reset
mail
' %}",
type: "warning",
type: "warning",
showCancelButton: true,
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonColor: "#DD6B55",
...
...
apps/users/templates/users/user_list.html
View file @
f37b3316
...
@@ -76,7 +76,7 @@ function initTable() {
...
@@ -76,7 +76,7 @@ function initTable() {
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
=
'<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
=
""
;
var
del_btn
=
""
;
if
(
rowData
.
id
===
1
||
rowData
.
username
===
"admin"
||
rowData
.
username
===
"{{ user.username }}"
)
{
if
(
rowData
.
id
===
1
||
rowData
.
username
===
"admin"
||
rowData
.
username
===
"{{
request.
user.username }}"
)
{
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
)
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
)
.
replace
(
'99991938'
,
rowData
.
name
);
.
replace
(
'99991938'
,
rowData
.
name
);
...
...
apps/users/urls/api_urls.py
View file @
f37b3316
...
@@ -19,6 +19,8 @@ urlpatterns = [
...
@@ -19,6 +19,8 @@ urlpatterns = [
url
(
r'^v1/token/$'
,
api
.
UserToken
.
as_view
(),
name
=
'user-token'
),
url
(
r'^v1/token/$'
,
api
.
UserToken
.
as_view
(),
name
=
'user-token'
),
url
(
r'^v1/profile/$'
,
api
.
UserProfile
.
as_view
(),
name
=
'user-profile'
),
url
(
r'^v1/profile/$'
,
api
.
UserProfile
.
as_view
(),
name
=
'user-profile'
),
url
(
r'^v1/auth/$'
,
api
.
UserAuthApi
.
as_view
(),
name
=
'user-auth'
),
url
(
r'^v1/auth/$'
,
api
.
UserAuthApi
.
as_view
(),
name
=
'user-auth'
),
url
(
r'^v1/users/(?P<pk>[0-9a-zA-Z\-]{36})/password/$'
,
api
.
ChangeUserPasswordApi
.
as_view
(),
name
=
'change-user-password'
),
url
(
r'^v1/users/(?P<pk>[0-9a-zA-Z\-]{36})/password/reset/$'
,
url
(
r'^v1/users/(?P<pk>[0-9a-zA-Z\-]{36})/password/reset/$'
,
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password'
),
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password'
),
url
(
r'^v1/users/(?P<pk>[0-9a-zA-Z\-]{36})/pubkey/reset/$'
,
url
(
r'^v1/users/(?P<pk>[0-9a-zA-Z\-]{36})/pubkey/reset/$'
,
...
...
apps/users/utils.py
View file @
f37b3316
...
@@ -180,7 +180,9 @@ def validate_ip(ip):
...
@@ -180,7 +180,9 @@ def validate_ip(ip):
def
write_login_log
(
username
,
type
=
''
,
ip
=
''
,
user_agent
=
''
):
def
write_login_log
(
username
,
type
=
''
,
ip
=
''
,
user_agent
=
''
):
if
not
(
ip
and
validate_ip
(
ip
)):
if
not
(
ip
and
validate_ip
(
ip
)):
ip
=
'0.0.0.0'
ip
=
ip
[:
15
]
city
=
"Unknown"
else
:
city
=
get_ip_city
(
ip
)
city
=
get_ip_city
(
ip
)
LoginLog
.
objects
.
create
(
LoginLog
.
objects
.
create
(
username
=
username
,
type
=
type
,
username
=
username
,
type
=
type
,
...
...
apps/users/views/login.py
View file @
f37b3316
...
@@ -53,8 +53,11 @@ class UserLoginView(FormView):
...
@@ -53,8 +53,11 @@ class UserLoginView(FormView):
if
not
self
.
request
.
session
.
test_cookie_worked
():
if
not
self
.
request
.
session
.
test_cookie_worked
():
return
HttpResponse
(
_
(
"Please enable cookies and try again."
))
return
HttpResponse
(
_
(
"Please enable cookies and try again."
))
auth_login
(
self
.
request
,
form
.
get_user
())
auth_login
(
self
.
request
,
form
.
get_user
())
login_ip
=
self
.
request
.
META
.
get
(
'HTTP_X_FORWARDED_FOR'
)
or
\
x_forwarded_for
=
self
.
request
.
META
.
get
(
'HTTP_X_FORWARDED_FOR'
,
''
)
.
split
(
','
)
self
.
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
if
x_forwarded_for
and
x_forwarded_for
[
0
]:
login_ip
=
x_forwarded_for
[
0
]
else
:
login_ip
=
self
.
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
user_agent
=
self
.
request
.
META
.
get
(
'HTTP_USER_AGENT'
,
''
)
user_agent
=
self
.
request
.
META
.
get
(
'HTTP_USER_AGENT'
,
''
)
write_login_log_async
.
delay
(
write_login_log_async
.
delay
(
self
.
request
.
user
.
username
,
type
=
'W'
,
self
.
request
.
user
.
username
,
type
=
'W'
,
...
...
docs/install.md
View file @
f37b3316
## Jumpserver v0.4.0 版本安装详细过程
More see
[
安装文档
](
https://github.com/jumpserver/jumpserver/wiki/v0.5.0-%E5%9F%BA%E4%BA%8E-CentOS7
)
### 环境
-
系统: CentOS 6.5 x86
\_
64 mini
-
Python: 版本 3.6 大部分功能兼容 2.7
-
安装目录
-
/opt/jumpserver
-
/opt/coco
#### 一. 环境准备
##### 1.1 安装基本工具和库
$ yum -y install sqlite-devel git epel-release
$ yum -y install sshpass python-devel libffi-devel openssl-devel
$ yum -y install gcc gcc-c++
##### 1.2 安装Python 3.6 和 虚拟环境
略
#### 二. Jumpserver安装
##### 2.1 下载仓库代码
$ cd /opt
$ git clone https://github.com/jumpserver/jumpserver.git
$ cd jumpserver
$ git checkout dev
##### 2.2 安装依赖
$ cd requirements
$ sudo yum -y install `cat rpm_requirements.txt`
$ pip install -r requirements.txt -i https://pypi.doubanio.com/simple
// 解决Mac安装ldap提示 Modules/LDAPObject.c:18:10: fatal error: 'sasl.h' file not found
pip install python-ldap \
--global-option=build_ext \
--global-option="-I$(xcrun --show-sdk-path)/usr/include/sasl"
##### 2.3 准备配置文件
$ cd ..
$ cp config_example.py config.py
$ vim config.py
// 默认使用的是 DevelpmentConfig 所以应该去修改这部分
class DevelopmentConfig(Config):
EMAIL_HOST = 'smtp.exmail.qq.com'
EMAIL_PORT = 465
EMAIL_HOST_USER = 'ask@jumpserver.org'
EMAIL_HOST_PASSWORD = 'xxx'
EMAIL_USE_SSL = True // 端口是 465 设置 True 否则 False
EMAIL_USE_TLS = False // 端口是 587 设置为 True 否则 False
SITE_URL = 'http://localhost:8080' // 发送邮件会使用这个地址
##### 2.4 初始化数据库
$ cd utils
$ sh make_migrations.sh
$ sh init_db.sh
##### 2.5 安装redis server
$ yum -y install redis
$ service redis start
**2.6 启动**
```
$ cd ..
$ python run_server.py
```
访问 http://ip:8080
账号密码: admin admin
**2.7 测试使用**
-
创建用户
会发送邮件,测试是否正常修改密码,登录
-
创建管理用户
创建一个管理用户, 创建资产时需要关联
-
创建资产
创建一个 资产,关联刚创建的管理用户
-
创建系统用户
系统用户是用来登录资产的,授权时需要
-
创建授权规则
关联用户,资产,系统用户 形成授权规则,授权的系统用户会自动推送到资产上
#### 三. 安装 SSH SERVER - COCO
**3.1 下载代码库**
```
$ cd /opt
$ git clone https://github.com/jumpserver/coco.git
```
**3.2 安装依赖**
```
$ cd coco
$ pip install -r requirements.txt # -i https://pypi.doubanio.com/simple
```
**3.3 启动**
```
$ python run_server.py
```
说明: Coco启动后会向jumpserver注册,请去 jumpserver页面 - 应用程序 - terminal - coco - Accept 允许, 这时 coco就 运行在 2222端口,可以ssh来连接
命令行:
```
ssh admin@YourServerIP -p2222
```
**3.5 测试**
-
测试登录 ssh server
-
测试跳转
-
测试命令记录回
[
1
]:
https://segmentfault.com/a/1190000000654227
[
2
]:
https://github.com/jumpserver/jumpserver.git
[
3
]:
https://github.com/jumpserver/coco.git
requirements/requirements.txt
View file @
f37b3316
...
@@ -56,6 +56,8 @@ uritemplate==3.0.0
...
@@ -56,6 +56,8 @@ uritemplate==3.0.0
urllib3==1.22
urllib3==1.22
vine==1.1.4
vine==1.1.4
gunicorn==19.7.1
gunicorn==19.7.1
django_celery_beat==1.1.0
https://github.com/celery/django-celery-beat/zipball/master#egg=django-celery-beat
#django_celery_beat==1.1.0
ephem==3.7.6.0
ephem==3.7.6.0
python-gssapi==0.6.4
python-gssapi==0.6.4
jms-es-sdk
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