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
70da177e
Commit
70da177e
authored
Dec 29, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update api
parent
92d854b9
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
69 additions
and
71 deletions
+69
-71
api.py
apps/assets/api.py
+12
-26
forms.py
apps/assets/forms.py
+3
-3
user.py
apps/assets/models/user.py
+6
-1
serializers.py
apps/assets/serializers.py
+10
-1
api_urls.py
apps/assets/urls/api_urls.py
+3
-2
models.py
apps/audits/models.py
+0
-1
utils.py
apps/audits/utils.py
+10
-7
api.py
apps/users/api.py
+12
-18
authentication.py
apps/users/authentication.py
+4
-3
api_urls.py
apps/users/urls/api_urls.py
+1
-0
utils.py
apps/users/utils.py
+8
-9
No files found.
apps/assets/api.py
View file @
70da177e
# ~*~ coding: utf-8 ~*~
from
rest_framework
import
viewsets
,
generics
,
mixins
from
rest_framework.response
import
Response
from
rest_framework.views
import
APIView
from
rest_framework_bulk
import
BulkListSerializer
,
BulkSerializerMixin
,
ListBulkCreateUpdateDestroyAPIView
...
...
@@ -90,34 +91,19 @@ class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
permission_classes
=
(
IsSuperUser
,)
class
SystemUserAuthApi
(
APIView
):
class
SystemUserAuthInfoApi
(
generics
.
RetrieveAPIView
):
queryset
=
SystemUser
.
objects
.
all
()
permission_classes
=
(
IsSuperUserOrAppUser
,)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
system_user_id
=
request
.
query_params
.
get
(
'system_user_id'
,
-
1
)
system_user_username
=
request
.
query_params
.
get
(
'system_user_username'
,
''
)
system_user
=
get_object_or_none
(
SystemUser
,
id
=
system_user_id
,
username
=
system_user_username
)
if
system_user
:
if
system_user
.
password
:
password
=
signer
.
sign
(
system_user
.
password
)
else
:
password
=
signer
.
sign
(
''
)
if
system_user
.
private_key
:
private_key
=
signer
.
sign
(
system_user
.
private_key
)
else
:
private_key
=
signer
.
sign
(
None
)
response
=
{
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
system_user
=
self
.
get_object
()
data
=
{
'id'
:
system_user
.
id
,
'password'
:
password
,
'private_key'
:
private_key
,
'name'
:
system_user
.
name
,
'username'
:
system_user
.
username
,
'password'
:
system_user
.
password
,
'private_key'
:
system_user
.
private_key
,
'auth_method'
:
system_user
.
auth_method
,
}
return
Response
(
response
)
else
:
return
Response
({
'msg'
:
'error system user id or username'
},
status
=
401
)
return
Response
(
data
)
apps/assets/forms.py
View file @
70da177e
...
...
@@ -263,7 +263,7 @@ class SystemUserForm(forms.ModelForm):
class
Meta
:
model
=
SystemUser
fields
=
[
'name'
,
'username'
,
'protocol'
,
'auto_generate_key'
,
'password'
,
'private_key_file'
,
'a
s_default
'
,
'name'
,
'username'
,
'protocol'
,
'auto_generate_key'
,
'password'
,
'private_key_file'
,
'a
uth_method
'
,
'auto_push'
,
'auto_update'
,
'sudo'
,
'comment'
,
'shell'
,
'home'
,
'uid'
,
]
widgets
=
{
...
...
@@ -273,8 +273,8 @@ class SystemUserForm(forms.ModelForm):
help_texts
=
{
'name'
:
'* required'
,
'username'
:
'* required'
,
'aut
h
_push'
:
'Auto push system user to asset'
,
'aut
h
_update'
:
'Auto update system user ssh key'
,
'aut
o
_push'
:
'Auto push system user to asset'
,
'aut
o
_update'
:
'Auto update system user ssh key'
,
}
...
...
apps/assets/models/user.py
View file @
70da177e
...
...
@@ -95,13 +95,18 @@ class SystemUser(models.Model):
PROTOCOL_CHOICES
=
(
(
'ssh'
,
'ssh'
),
)
AUTH_METHOD_CHOICES
=
(
(
'P'
,
'Password'
),
(
'K'
,
'Public key'
),
)
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
username
=
models
.
CharField
(
max_length
=
16
,
verbose_name
=
_
(
'Username'
))
_password
=
models
.
CharField
(
max_length
=
256
,
blank
=
True
,
verbose_name
=
_
(
'Password'
))
protocol
=
models
.
CharField
(
max_length
=
16
,
choices
=
PROTOCOL_CHOICES
,
default
=
'ssh'
,
verbose_name
=
_
(
'Protocol'
))
_private_key
=
models
.
CharField
(
max_length
=
4096
,
blank
=
True
,
verbose_name
=
_
(
'SSH private key'
))
_public_key
=
models
.
CharField
(
max_length
=
4096
,
blank
=
True
,
verbose_name
=
_
(
'SSH public key'
))
as_default
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'As default'
))
auth_method
=
models
.
CharField
(
choices
=
AUTH_METHOD_CHOICES
,
default
=
'K'
,
max_length
=
1
,
verbose_name
=
_
(
'Auth method'
))
auto_push
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Auto push'
))
auto_update
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Auto update pass/key'
))
sudo
=
models
.
TextField
(
max_length
=
4096
,
default
=
'/user/bin/whoami'
,
verbose_name
=
_
(
'Sudo'
))
...
...
apps/assets/serializers.py
View file @
70da177e
...
...
@@ -17,6 +17,7 @@ class AssetGroupSerializer(serializers.ModelSerializer):
def
get_assets_amount
(
obj
):
return
obj
.
assets
.
count
()
class
AssetUpdateGroupSerializer
(
serializers
.
ModelSerializer
):
groups
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
AssetGroup
.
objects
.
all
())
...
...
@@ -24,6 +25,7 @@ class AssetUpdateGroupSerializer(serializers.ModelSerializer):
model
=
Asset
fields
=
[
'id'
,
'groups'
]
class
AssetUpdateSystemUserSerializer
(
serializers
.
ModelSerializer
):
system_users
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
SystemUser
.
objects
.
all
())
...
...
@@ -31,6 +33,7 @@ class AssetUpdateSystemUserSerializer(serializers.ModelSerializer):
model
=
Asset
fields
=
[
'id'
,
'system_users'
]
class
AdminUserSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
AdminUser
...
...
@@ -52,6 +55,12 @@ class SystemUserSerializer(serializers.ModelSerializer):
return
fields
class
SystemUserSimpleSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
SystemUser
fields
=
(
'id'
,
'name'
,
'username'
)
class
AssetSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
# system_users = SystemUserSerializer(many=True, read_only=True)
# admin_user = AdminUserSerializer(many=False, read_only=True)
...
...
@@ -75,7 +84,7 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
system_users
=
SystemUserSerializer
(
many
=
True
,
read_only
=
True
)
system_users
=
SystemUserS
impleS
erializer
(
many
=
True
,
read_only
=
True
)
is_inherited
=
serializers
.
SerializerMethodField
()
system_users_join
=
serializers
.
SerializerMethodField
()
...
...
apps/assets/urls/api_urls.py
View file @
70da177e
...
...
@@ -16,11 +16,12 @@ router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user')
urlpatterns
=
[
url
(
r'^v1/assets_bulk/$'
,
api
.
AssetListUpdateApi
.
as_view
(),
name
=
'asset-bulk-update'
),
# url(r'^v1/idc/(?P<pk>[0-9]+)/assets/$', api.IDCAssetsApi.as_view(), name='api-idc-assets'),
url
(
r'^v1/system-user/auth/'
,
api
.
SystemUserAuthApi
.
as_view
(),
name
=
'system-user-auth'
),
url
(
r'^v1/system-user/(?P<pk>[0-9]+)/auth-info/'
,
api
.
SystemUserAuthInfoApi
.
as_view
(),
name
=
'system-user-auth-info'
),
url
(
r'^v1/assets/(?P<pk>\d+)/groups/$'
,
api
.
AssetUpdateGroupApi
.
as_view
(),
name
=
'asset-update-group'
),
url
(
r'^v1/assets/(?P<pk>\d+)/system-users/$'
,
api
.
SystemUserUpdateApi
.
as_view
(),
name
=
'asset-update-systemusers'
),
api
.
SystemUserUpdateApi
.
as_view
(),
name
=
'asset-update-system
-
users'
),
]
urlpatterns
+=
router
.
urls
...
...
apps/audits/models.py
View file @
70da177e
...
...
@@ -18,7 +18,6 @@ class LoginLog(models.Model):
username
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username'
))
name
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
_
(
'Name'
))
login_type
=
models
.
CharField
(
choices
=
LOGIN_TYPE_CHOICE
,
max_length
=
2
,
verbose_name
=
_
(
'Login type'
))
terminal
=
models
.
CharField
(
max_length
=
32
,
verbose_name
=
_
(
'Terminal'
))
login_ip
=
models
.
GenericIPAddressField
(
verbose_name
=
_
(
'Login ip'
))
login_city
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Login city'
))
user_agent
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'User agent'
))
...
...
apps/audits/utils.py
View file @
70da177e
...
...
@@ -17,25 +17,28 @@ def validate_ip(ip):
return
False
def
write_login_log
(
username
,
name
=
''
,
login_type
=
'
W
'
,
terminal
=
''
,
login_ip
=
''
,
user_agent
=
''
):
def
write_login_log
(
username
,
name
=
''
,
login_type
=
''
,
login_ip
=
''
,
user_agent
=
''
):
if
not
(
login_ip
and
validate_ip
(
login_ip
)):
login_ip
=
'0.0.0.0'
if
not
name
:
name
=
username
login_city
=
get_ip_city
(
login_ip
)
LoginLog
.
objects
.
create
(
username
=
username
,
name
=
name
,
login_type
=
login_type
,
login_ip
=
login_ip
,
terminal
=
terminal
,
login_city
=
login_city
,
user_agent
=
user_agent
)
LoginLog
.
objects
.
create
(
username
=
username
,
name
=
name
,
login_type
=
login_type
,
login_ip
=
login_ip
,
login_city
=
login_city
,
user_agent
=
user_agent
)
def
get_ip_city
(
ip
,
timeout
=
10
):
# Taobao ip api: http://ip.taobao.com//service/getIpInfo.php?ip=8.8.8.8
# Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=js
# Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=js
on
url
=
'http://ip.taobao.com/service/getIpInfo.php?ip='
+
ip
url
=
'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=
%
s&format=json'
%
ip
try
:
r
=
requests
.
get
(
url
,
timeout
=
timeout
)
except
requests
.
Timeout
:
r
=
None
city
=
'Unknown'
if
r
.
status_code
==
200
:
if
r
and
r
.
status_code
==
200
:
try
:
data
=
r
.
json
()
if
data
[
'code'
]
==
0
:
...
...
apps/users/api.py
View file @
70da177e
...
...
@@ -100,7 +100,7 @@ class UserToken(APIView):
user
,
msg
=
check_user_valid
(
username
=
username
,
email
=
email
,
password
=
password
,
public_key
=
public_key
)
if
user
:
token
=
generate_token
(
request
)
token
=
generate_token
(
request
,
user
)
return
Response
({
'Token'
:
token
,
'key'
:
'Bearer'
},
status
=
200
)
else
:
return
Response
({
'error'
:
msg
},
status
=
406
)
...
...
@@ -114,28 +114,22 @@ class UserProfile(APIView):
class
UserAuthApi
(
APIView
):
permission_classes
=
()
expiration
=
settings
.
CONFIG
.
TOKEN_EXPIRATION
or
3600
permission_classes
=
(
AllowAny
,)
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
username
=
request
.
data
.
get
(
'username'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
remote_addr
=
request
.
data
.
get
(
'remote_addr'
,
''
)
terminal
=
request
.
data
.
get
(
'applications'
,
''
)
login_type
=
request
.
data
.
get
(
'login_type'
,
'T'
)
user
=
check_user_valid
(
username
=
username
,
password
=
password
,
public_key
=
public_key
)
login_type
=
request
.
data
.
get
(
'login_type'
,
''
)
login_ip
=
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
user_agent
=
request
.
data
.
get
(
'HTTP_USER_AGENT'
,
''
)
user
,
msg
=
check_user_valid
(
username
=
username
,
password
=
password
,
public_key
=
public_key
)
if
user
:
token
=
cache
.
get
(
'
%
s_
%
s'
%
(
user
.
id
,
remote_addr
))
if
not
token
:
token
=
generate_token
(
request
)
cache
.
set
(
token
,
user
.
id
,
self
.
expiration
)
cache
.
set
(
'
%
s_
%
s'
%
(
user
.
id
,
remote_addr
),
token
,
self
.
expiration
)
write_login_log_async
.
delay
(
user
.
username
,
name
=
user
.
name
,
terminal
=
terminal
,
login_ip
=
remote_addr
,
login_type
=
login_type
)
return
Response
({
'token'
:
token
,
'id'
:
user
.
id
,
'username'
:
user
.
username
,
'name'
:
user
.
name
,
'is_active'
:
user
.
is_active
})
token
=
generate_token
(
request
,
user
)
write_login_log_async
.
delay
(
user
.
username
,
name
=
user
.
name
,
user_agent
=
user_agent
,
login_ip
=
login_ip
,
login_type
=
login_type
)
return
Response
({
'token'
:
token
,
'user'
:
user
.
to_json
()})
else
:
return
Response
({
'msg'
:
'Invalid password or public key or user is not active or expired'
},
status
=
401
)
return
Response
({
'msg'
:
msg
},
status
=
401
)
apps/users/authentication.py
View file @
70da177e
...
...
@@ -43,7 +43,6 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
msg
=
_
(
'Invalid signature header. Signature string should not contain spaces.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
try
:
sign
=
auth
[
1
]
.
decode
()
.
split
(
':'
)
if
len
(
sign
)
!=
2
:
...
...
@@ -58,7 +57,8 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
return
self
.
authenticate_credentials
(
request
,
access_key_id
,
request_signature
)
def
authenticate_credentials
(
self
,
request
,
access_key_id
,
request_signature
):
@staticmethod
def
authenticate_credentials
(
request
,
access_key_id
,
request_signature
):
access_key
=
get_object_or_none
(
AccessKey
,
id
=
access_key_id
)
request_date
=
get_request_date_header
(
request
)
if
access_key
is
None
or
not
access_key
.
user
:
...
...
@@ -109,7 +109,8 @@ class AccessTokenAuthentication(authentication.BaseAuthentication):
raise
exceptions
.
AuthenticationFailed
(
msg
)
return
self
.
authenticate_credentials
(
token
)
def
authenticate_credentials
(
self
,
token
):
@staticmethod
def
authenticate_credentials
(
token
):
user_id
=
cache
.
get
(
token
)
user
=
get_object_or_none
(
User
,
id
=
user_id
)
...
...
apps/users/urls/api_urls.py
View file @
70da177e
...
...
@@ -17,6 +17,7 @@ router.register(r'v1/user-groups', api.UserGroupViewSet, 'user-group')
urlpatterns
=
[
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/auth/$'
,
api
.
UserAuthApi
.
as_view
(),
name
=
'user-auth'
),
url
(
r'^v1/users/(?P<pk>\d+)/password/reset/$'
,
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password'
),
url
(
r'^v1/users/(?P<pk>\d+)/public-key/reset/$'
,
api
.
UserResetPKApi
.
as_view
(),
name
=
'user-public-key-reset'
),
url
(
r'^v1/users/(?P<pk>\d+)/public-key/update/$'
,
api
.
UserUpdatePKApi
.
as_view
(),
name
=
'user-public-key-update'
),
...
...
apps/users/utils.py
View file @
70da177e
...
...
@@ -180,8 +180,8 @@ def send_reset_ssh_key_mail(user):
def
check_user_valid
(
**
kwargs
):
password
=
kwargs
.
pop
(
'password'
,
None
)
public_key
=
kwargs
.
pop
(
'public_key'
,
None
)
email
=
kwargs
.
pop
(
'email'
)
username
=
kwargs
.
pop
(
'username'
)
email
=
kwargs
.
pop
(
'email'
,
None
)
username
=
kwargs
.
pop
(
'username'
,
None
)
if
username
:
user
=
get_object_or_none
(
User
,
username
=
username
)
...
...
@@ -206,24 +206,23 @@ def check_user_valid(**kwargs):
elif
len
(
public_key_saved
)
>
1
:
if
public_key
==
public_key_saved
[
1
]:
return
user
,
''
return
None
,
_
(
'Pass
ow
rd or SSH public key invalid'
)
return
None
,
_
(
'Pass
wo
rd or SSH public key invalid'
)
def
refresh_token
(
token
,
user
):
expiration
=
settings
.
CONFIG
.
TOKEN_EXPIRATION
or
3600
def
refresh_token
(
token
,
user
,
expiration
=
3600
):
cache
.
set
(
token
,
user
.
id
,
expiration
)
def
generate_token
(
request
):
def
generate_token
(
request
,
user
):
expiration
=
settings
.
CONFIG
.
TOKEN_EXPIRATION
or
3600
remote_addr
=
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
remote_addr
=
base64
.
b16encode
(
remote_addr
)
.
replace
(
'='
,
''
)
token
=
cache
.
get
(
'
%
s_
%
s'
%
(
request
.
user
.
id
,
remote_addr
))
token
=
cache
.
get
(
'
%
s_
%
s'
%
(
user
.
id
,
remote_addr
))
if
not
token
:
token
=
uuid
.
uuid4
()
.
get_hex
()
print
(
'Set cache:
%
s'
%
token
)
cache
.
set
(
token
,
request
.
user
.
id
,
expiration
)
cache
.
set
(
'
%
s_
%
s'
%
(
request
.
user
.
id
,
remote_addr
),
token
,
expiration
)
cache
.
set
(
token
,
user
.
id
,
expiration
)
cache
.
set
(
'
%
s_
%
s'
%
(
user
.
id
,
remote_addr
),
token
,
expiration
)
return
token
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