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
6751c5a6
Commit
6751c5a6
authored
8 years ago
by
xiaokong1937@gmail.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
reset user password and ssh pk implement
parent
00502ce3
master
auditor_jym
audits
dev
dev_beta
dev_beta_db
gengmei
lagacy-0.4.0
node_service
password
rbac
restrict_access
test
v52
wph
1.5.2
1.5.1
1.5.0
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.1
1.1.0
1.0.0
v1.4.10
v1.4.7
v1.4.4
No related merge requests found
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
160 additions
and
37 deletions
+160
-37
sweetalert.css
apps/static/css/plugins/sweetalert/sweetalert.css
+0
-0
jumpserver.js
apps/static/js/jumpserver.js
+20
-18
sweetalert.min.js
apps/static/js/plugins/sweetalert/sweetalert.min.js
+0
-0
_modal.html
apps/templates/_modal.html
+20
-0
api.py
apps/users/api.py
+23
-0
serializers.py
apps/users/serializers.py
+16
-0
_user_reset_pk_modal.html
apps/users/templates/users/_user_reset_pk_modal.html
+8
-0
user_detail.html
apps/users/templates/users/user_detail.html
+68
-19
urls.py
apps/users/urls.py
+2
-0
utils.py
apps/users/utils.py
+3
-0
No files found.
apps/static/css/plugins/sweetalert/sweetalert.css
0 → 100644
View file @
6751c5a6
This diff is collapsed.
Click to expand it.
apps/static/js/jumpserver.js
View file @
6751c5a6
...
...
@@ -4,10 +4,10 @@
var
checked
=
false
;
function
check_all
(
form
)
{
var
checkboxes
=
document
.
getElementById
(
form
);
if
(
checked
==
false
)
{
checked
=
true
if
(
checked
==
=
false
)
{
checked
=
true
;
}
else
{
checked
=
false
checked
=
false
;
}
for
(
var
i
=
0
;
i
<
checkboxes
.
elements
.
length
;
i
++
)
{
if
(
checkboxes
.
elements
[
i
].
type
==
"checkbox"
)
{
...
...
@@ -51,13 +51,13 @@ function GetRowData(row){
//此函数用于在多选提交时至少要选择一行
function
GetTableDataBox
()
{
var
tabProduct
=
document
.
getElementById
(
"editable"
);
var
tableData
=
new
Array
()
;
var
returnData
=
new
Array
()
;
var
tableData
=
[]
;
var
returnData
=
[]
;
var
checkboxes
=
document
.
getElementById
(
"contents_form"
);
var
id_list
=
new
Array
()
;
var
id_list
=
[]
;
len
=
checkboxes
.
elements
.
length
;
for
(
var
i
=
0
;
i
<
len
;
i
++
)
{
if
(
checkboxes
.
elements
[
i
].
type
==
"checkbox"
&&
checkboxes
.
elements
[
i
].
checked
==
true
&&
checkboxes
.
elements
[
i
].
value
!=
"checkall"
)
{
if
(
checkboxes
.
elements
[
i
].
type
==
"checkbox"
&&
checkboxes
.
elements
[
i
].
checked
==
=
true
&&
checkboxes
.
elements
[
i
].
value
!=
"checkall"
)
{
id_list
.
push
(
i
);
}
}
...
...
@@ -67,7 +67,7 @@ function GetTableDataBox() {
tableData
.
push
(
GetRowData
(
tabProduct
.
rows
[
id_list
[
i
]]));
}
if
(
id_list
.
length
==
0
){
if
(
id_list
.
length
==
=
0
){
alert
(
'请至少选择一行!'
);
}
returnData
.
push
(
tableData
);
...
...
@@ -77,7 +77,7 @@ function GetTableDataBox() {
function
move
(
from
,
to
,
from_o
,
to_o
)
{
$
(
"#"
+
from
+
" option"
).
each
(
function
()
{
if
(
$
(
this
).
prop
(
"selected"
)
==
true
)
{
if
(
$
(
this
).
prop
(
"selected"
)
==
=
true
)
{
$
(
"#"
+
to
).
append
(
this
);
if
(
typeof
from_o
!==
'undefined'
){
$
(
"#"
+
to_o
).
append
(
$
(
"#"
+
from_o
+
" option[value='"
+
this
.
value
+
"']"
));
...
...
@@ -88,7 +88,7 @@ function move(from, to, from_o, to_o) {
function
move_left
(
from
,
to
,
from_o
,
to_o
)
{
$
(
"#"
+
from
+
" option"
).
each
(
function
()
{
if
(
$
(
this
).
prop
(
"selected"
)
==
true
)
{
if
(
$
(
this
).
prop
(
"selected"
)
==
=
true
)
{
$
(
"#"
+
to
).
append
(
this
);
if
(
typeof
from_o
!==
'undefined'
){
$
(
"#"
+
to_o
).
append
(
$
(
"#"
+
from_o
+
" option[value='"
+
this
.
value
+
"']"
));
...
...
@@ -126,8 +126,8 @@ function move_left(from, to, from_o, to_o) {
function
selectAll
(){
// 选择该页面所有option
$
(
'option'
).
each
(
function
(){
$
(
this
).
attr
(
'selected'
,
true
)
})
$
(
this
).
attr
(
'selected'
,
true
)
;
})
;
}
...
...
@@ -156,6 +156,8 @@ function getIDall() {
function
APIUpdateAttr
(
props
)
{
// props = {url: .., body: , success: , error: , method: ,}
props
=
props
||
{};
success_message
=
props
.
success_message
||
'Update Successfully!'
;
fail_message
=
props
.
fail_message
||
'Error occurred while updating.'
;
$
.
ajax
({
url
:
props
.
url
,
type
:
props
.
method
||
"PATCH"
,
...
...
@@ -164,18 +166,18 @@ function APIUpdateAttr(props) {
dataType
:
props
.
data_type
||
"json"
,
}).
done
(
function
(
data
,
textStatue
,
jqXHR
)
{
if
(
typeof
props
.
success
===
'function'
)
{
return
props
.
success
(
data
)
return
props
.
success
(
data
)
;
}
else
{
toastr
.
success
(
'Update Success!'
)
toastr
.
success
(
success_message
);
}
}).
fail
(
function
(
jqXHR
,
textStatue
,
errorThrown
)
{
if
(
typeof
props
.
error
===
'function'
)
{
return
props
.
error
(
errorThrown
)
return
props
.
error
(
errorThrown
)
;
}
else
{
toastr
.
error
(
'Error occurred while updating.'
)
toastr
.
error
(
fail_message
);
}
})
})
;
return
true
;
}
var
jumpserver
=
new
Object
()
;
var
jumpserver
=
{}
;
This diff is collapsed.
Click to expand it.
apps/static/js/plugins/sweetalert/sweetalert.min.js
0 → 100644
View file @
6751c5a6
This diff is collapsed.
Click to expand it.
apps/templates/_modal.html
0 → 100644
View file @
6751c5a6
{% load i18n %}
<div
aria-hidden=
"true"
role=
"dialog"
tabindex=
"-1"
id=
"{% block modal_id %}{% endblock %}"
class=
"modal inmodal"
style=
"display: none;"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content animated fadeIn"
>
<div
class=
"modal-header"
>
<button
data-dismiss=
"modal"
class=
"close"
type=
"button"
><span
aria-hidden=
"true"
>
×
</span><span
class=
"sr-only"
>
Close
</span></button>
<h4
class=
"modal-title"
>
{% block modal_title %}{% endblock %}
</h4>
<small>
{% block modal_comment %}{% endblock %}
</small>
</div>
<div
class=
"modal-body"
>
{% block modal_body %}
{% endblock %}
</div>
<div
class=
"modal-footer"
>
<button
data-dismiss=
"modal"
class=
"btn btn-white"
type=
"button"
>
{% trans "Close" %}
</button>
<button
class=
"btn btn-primary"
type=
"button"
id=
"{% block modal_confirm_id %}{% endblock %}"
>
{% trans 'Confirm' %}
</button>
</div>
</div>
</div>
</div>
This diff is collapsed.
Click to expand it.
apps/users/api.py
View file @
6751c5a6
...
...
@@ -6,6 +6,7 @@ import logging
from
rest_framework
import
generics
from
.serializers
import
UserSerializer
,
UserGroupSerializer
,
UserAttributeSerializer
,
UserGroupEditSerializer
from
.serializers
import
UserPKUpdateSerializer
from
.models
import
User
,
UserGroup
...
...
@@ -49,3 +50,25 @@ class UserAttributeApi(generics.RetrieveUpdateDestroyAPIView):
class
UserGroupEditApi
(
generics
.
RetrieveUpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserGroupEditSerializer
class
UserResetPasswordApi
(
generics
.
UpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserGroupEditSerializer
def
perform_update
(
self
,
serializer
):
# Note: we are not updating the user object here.
# We just do the reset-password staff.
user
=
self
.
get_object
()
from
.utils
import
send_reset_password_mail
send_reset_password_mail
(
user
)
class
UserResetPKApi
(
generics
.
UpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserPKUpdateSerializer
def
perform_update
(
self
,
serializer
):
user
=
self
.
get_object
()
user
.
private_key
=
serializer
.
validated_data
[
'_private_key'
]
user
.
save
()
This diff is collapsed.
Click to expand it.
apps/users/serializers.py
View file @
6751c5a6
# -*- coding: utf-8 -*-
#
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework
import
serializers
from
.models
import
User
,
UserGroup
...
...
@@ -38,3 +40,17 @@ class UserGroupEditSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
User
fields
=
[
'id'
,
'groups'
]
class
UserPKUpdateSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
User
fields
=
[
'id'
,
'_private_key'
]
def
validate__private_key
(
self
,
value
):
from
users.utils
import
validate_ssh_pk
checked
,
reason
=
validate_ssh_pk
(
value
)
if
not
checked
:
raise
serializers
.
ValidationError
(
_
(
'Not a valid ssh private key.'
))
return
value
This diff is collapsed.
Click to expand it.
apps/users/templates/users/_user_reset_pk_modal.html
0 → 100644
View file @
6751c5a6
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}user_reset_pk_modal{% endblock %}
{% block modal_title%}{% trans 'Reset User SSH Private Key' %}{% endblock %}
{% block modal_body %}
<textarea
id=
"txt_pk"
class=
"form-control"
cols=
"30"
rows=
"10"
placeholder=
"-----BEGIN RSA PRIVATE KEY-----"
></textarea>
{% endblock %}
{% block modal_confirm_id %}btn_user_reset_pk{% endblock %}
This diff is collapsed.
Click to expand it.
apps/users/templates/users/user_detail.html
View file @
6751c5a6
...
...
@@ -6,7 +6,9 @@
{% block custom_head_css_js %}
<link
href=
"{% static "
css
/
plugins
/
select2
/
select2
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
sweetalert
/
sweetalert
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
plugins
/
select2
/
select2
.
full
.
min
.
js
"
%}"
></script>
<script
src=
"{% static "
js
/
plugins
/
sweetalert
/
sweetalert
.
min
.
js
"
%}"
></script>
{% endblock %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
...
...
@@ -114,8 +116,8 @@
<table
class=
"table"
>
<tbody>
<tr
class=
"no-borders-tr"
>
<td
width=
"50%"
>
Active
:
</td>
<td><span
style=
"float:
right"
>
<td
width=
"50%"
>
{% trans 'Active' %}
:
</td>
<td><span
class=
"pull-
right"
>
<div
class=
"switch"
>
<div
class=
"onoffswitch"
>
<input
type=
"checkbox"
{%
if
user_object
.
is_active
%}
checked
{%
endif
%}
class=
"onoffswitch-checkbox"
id=
"is_active"
>
...
...
@@ -128,8 +130,8 @@
</span></td>
</tr>
<tr>
<td>
二次验证
:
</td>
<td><span
style=
"float:
right"
>
<td>
{% trans 'Enable OTP' %}
:
</td>
<td><span
class=
"pull-
right"
>
<div
class=
"switch"
>
<div
class=
"onoffswitch"
>
<input
type=
"checkbox"
class=
"onoffswitch-checkbox"
{%
if
user_object
.
enable_otp
%}
checked
{%
endif
%}
...
...
@@ -145,16 +147,16 @@
<tr>
<td>
{% trans 'Reset password' %}:
</td>
<td>
<span
style=
"float:
right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
style=
"width: 54px"
>
{% trans 'Reset' %}
</button>
<span
class=
"pull-
right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn_reset_password"
style=
"width: 54px"
>
{% trans 'Reset' %}
</button>
</span>
</td>
</tr>
<tr>
<td>
{% trans 'Reset ssh key' %}:
</td>
<td>
<span
style=
"float:
right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
style=
"width: 54px;
"
>
{% trans 'Reset' %}
</button>
<span
class=
"pull-
right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn_reset_pk"
style=
"width: 54px;"
data-toggle=
"modal"
data-target=
"#user_reset_pk_modal
"
>
{% trans 'Reset' %}
</button>
</span>
</td>
</tr>
...
...
@@ -191,7 +193,7 @@
<tr>
<td
><b
class=
"bdg_user_group"
data-gid=
{{
group
.
id
}}
>
{{ group.name }}
</b></td>
<td>
<button
class=
"btn btn-danger
btn-sm btn_delete_user_group"
type=
"button"
style=
"float: right;
"
><i
class=
"fa fa-minus"
></i></button>
<button
class=
"btn btn-danger
pull-right btn-sm btn_delete_user_group"
type=
"button
"
><i
class=
"fa fa-minus"
></i></button>
</td>
</tr>
{% endfor %}
...
...
@@ -205,6 +207,7 @@
</div>
</div>
</div>
{% include 'users/_user_reset_pk_modal.html' %}
{% endblock %}
{% block custom_foot_js %}
<script>
...
...
@@ -225,13 +228,13 @@ function updateUserGroups(user_groups) {
$
(
'.group_edit tbody'
).
append
(
'<tr>'
+
'<td><b class="bdg_user_group" data-gid="'
+
index
+
'">'
+
group_name
+
'</b></td>'
+
'<td><button class="btn btn-danger btn-sm
btn_delete_user_group" type="button" style="float: right;
"><i class="fa fa-minus"></i></button></td>'
+
'<td><button class="btn btn-danger btn-sm
pull-right btn_delete_user_group" type="button
"><i class="fa fa-minus"></i></button></td>'
+
'</tr>'
)
});
// clear jumpserver.selected_groups
jumpserver
.
selected_groups
=
{};
toastr
.
success
(
'{% trans "U
pdate s
uccess!" %}'
)
toastr
.
success
(
'{% trans "U
serGroup Update S
uccess!" %}'
)
};
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success
:
success
,
method
:
'PUT'
});
...
...
@@ -249,18 +252,14 @@ $(document).ready(function () {
var
the_url
=
"{% url 'users:user-patch-api' pk=user_object.id %}"
;
var
checked
=
!
$
(
this
).
prop
(
'checked'
);
var
body
=
{
'is_active'
:
checked
};
var
success
=
function
()
{
toastr
.
success
(
'{% trans "Update success!" %}'
)
};
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success
:
success
});
var
success
=
'{% trans "Update Successfully!" %}'
;
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success_message
:
success
});
}).
on
(
'click'
,
'#enable_otp'
,
function
(){
var
the_url
=
"{% url 'users:user-patch-api' pk=user_object.id %}"
;
var
checked
=
!
$
(
this
).
prop
(
'checked'
);
var
body
=
{
'enable_otp'
:
checked
};
var
success
=
function
()
{
toastr
.
success
(
'{% trans "Update success!" %}'
)
};
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success
:
success
});
var
success
=
'{% trans "Update Successfully!" %}'
;
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success_message
:
success
});
}).
on
(
'click'
,
'#btn_add_user_group'
,
function
(){
if
(
Object
.
keys
(
jumpserver
.
selected_groups
).
length
===
0
)
{
return
false
;
...
...
@@ -287,6 +286,56 @@ $(document).ready(function () {
return
$
(
this
).
data
(
'gid'
);
}).
get
();
updateUserGroups
(
user_groups
)
}).
on
(
'click'
,
'#btn_reset_password'
,
function
(){
function
doReset
()
{
var
the_url
=
'{% url "users:user-reset-password-api" pk=user_object.id %}'
;
var
body
=
{};
var
success
=
function
()
{
var
msg
=
"{% trans 'E-mail sent successfully. An e-mail has been sent to the user
\
's mailbox.' %}"
;
swal
(
"{% trans 'Password-Reset' %}"
,
msg
,
"success"
);
}
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success
:
success
});
}
swal
({
title
:
"{% trans 'Are you sure?' %}"
,
text
:
"{% trans 'This will reset the user
\
's password.' %}"
,
type
:
"warning"
,
showCancelButton
:
true
,
confirmButtonColor
:
"#DD6B55"
,
confirmButtonText
:
"{% trans 'Confirm' %}"
,
closeOnConfirm
:
false
},
function
()
{
doReset
();
}
);
}).
on
(
'click'
,
'#btn_user_reset_pk'
,
function
(){
var
$this
=
$
(
this
);
var
pk
=
$
(
'#txt_pk'
).
val
();
var
the_url
=
'{% url "users:user-reset-pk-api" pk=user_object.id %}'
;
var
body
=
{
'_private_key'
:
pk
};
var
success
=
function
()
{
$
(
'#txt_pk'
).
val
(
''
);
$this
.
closest
(
'.modal'
).
modal
(
'hide'
);
var
msg
=
"{% trans 'Successfully updated the SSH private key.' %}"
;
swal
(
"{% trans 'User SSH Private Key Reset' %}"
,
msg
,
"success"
);
};
var
fail
=
function
()
{
var
msg
=
"{% trans 'Failed to update the user
\
's SSH private key.' %}"
;
swal
({
title
:
"{% trans 'User SSH Private Key Reset' %}"
,
text
:
msg
,
type
:
"error"
,
showCancelButton
:
false
,
confirmButtonColor
:
"#DD6B55"
,
confirmButtonText
:
"{% trans 'Confirm' %}"
,
closeOnConfirm
:
true
},
function
()
{
$
(
'#txt_pk'
).
focus
();
}
);
}
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success
:
success
,
error
:
fail
});
});
</script>
{% endblock %}
This diff is collapsed.
Click to expand it.
apps/users/urls.py
View file @
6751c5a6
...
...
@@ -35,6 +35,8 @@ urlpatterns += [
api
.
UserDetailDeleteUpdateApi
.
as_view
(),
name
=
'user-detail-api'
),
url
(
r'^v1/users/(?P<pk>[0-9]+)/patch$'
,
api
.
UserAttributeApi
.
as_view
(),
name
=
'user-patch-api'
),
url
(
r'^v1/users/(?P<pk>\d+)/reset-password/$'
,
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password-api'
),
url
(
r'^v1/users/(?P<pk>\d+)/reset-pk/$'
,
api
.
UserResetPKApi
.
as_view
(),
name
=
'user-reset-pk-api'
),
url
(
r'^v1/user-groups$'
,
api
.
UserGroupListAddApi
.
as_view
(),
name
=
'user-group-list-api'
),
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)$'
,
api
.
UserGroupDetailDeleteUpdateApi
.
as_view
(),
name
=
'user-group-detail-api'
),
...
...
This diff is collapsed.
Click to expand it.
apps/users/utils.py
View file @
6751c5a6
...
...
@@ -5,6 +5,7 @@ import logging
import
os
import
re
from
django.conf
import
settings
from
django.contrib.auth.mixins
import
UserPassesTestMixin
from
django.urls
import
reverse_lazy
from
django.utils.translation
import
ugettext
as
_
...
...
@@ -121,6 +122,8 @@ def send_reset_password_mail(user):
'email'
:
user
.
email
,
'login_url'
:
reverse
(
'users:login'
,
external
=
True
),
}
if
settings
.
DEBUG
:
logger
.
debug
(
message
)
send_mail_async
.
delay
(
subject
,
message
,
recipient_list
,
html_message
=
message
)
...
...
This diff is collapsed.
Click to expand it.
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