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
27070123
Commit
27070123
authored
Dec 25, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Finish access key auth
parent
c5ab49c5
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
192 additions
and
37 deletions
+192
-37
api.py
apps/assets/api.py
+3
-2
hands.py
apps/assets/hands.py
+1
-1
api.py
apps/audits/api.py
+3
-3
hands.py
apps/audits/hands.py
+1
-1
compat.py
apps/common/compat.py
+77
-2
utils.py
apps/common/utils.py
+68
-2
settings.py
apps/jumpserver/settings.py
+2
-3
api.py
apps/terminal/api.py
+3
-3
hands.py
apps/terminal/hands.py
+3
-2
api.py
apps/users/api.py
+1
-1
authentication.py
apps/users/authentication.py
+22
-9
user.py
apps/users/models/user.py
+2
-2
permissions.py
apps/users/permissions.py
+6
-6
No files found.
apps/assets/api.py
View file @
27070123
...
...
@@ -8,7 +8,7 @@ from django.shortcuts import get_object_or_404
from
common.mixins
import
IDInFilterMixin
from
common.utils
import
get_object_or_none
,
signer
from
.hands
import
IsSuperUserOr
Terminal
User
,
IsSuperUser
from
.hands
import
IsSuperUserOr
App
User
,
IsSuperUser
from
.models
import
AssetGroup
,
Asset
,
IDC
,
SystemUser
,
AdminUser
from
.
import
serializers
...
...
@@ -18,6 +18,7 @@ class AssetViewSet(IDInFilterMixin, viewsets.ModelViewSet):
queryset
=
Asset
.
objects
.
all
()
serializer_class
=
serializers
.
AssetSerializer
filter_fields
=
(
'id'
,
'ip'
,
'hostname'
)
permission_classes
=
(
IsSuperUserOrAppUser
,)
def
get_queryset
(
self
):
queryset
=
super
(
AssetViewSet
,
self
)
.
get_queryset
()
...
...
@@ -90,7 +91,7 @@ class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
class
SystemUserAuthApi
(
APIView
):
permission_classes
=
(
IsSuperUserOr
Terminal
User
,)
permission_classes
=
(
IsSuperUserOr
App
User
,)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
system_user_id
=
request
.
query_params
.
get
(
'system_user_id'
,
-
1
)
...
...
apps/assets/hands.py
View file @
27070123
...
...
@@ -12,5 +12,5 @@
from
users.utils
import
AdminUserRequiredMixin
from
users.permissions
import
IsSuperUserOr
Terminal
User
,
IsSuperUser
from
users.permissions
import
IsSuperUserOr
App
User
,
IsSuperUser
from
users.models
import
User
,
UserGroup
apps/audits/api.py
View file @
27070123
...
...
@@ -7,7 +7,7 @@ from rest_framework import generics, viewsets
from
rest_framework.views
import
APIView
,
Response
from
.
import
models
,
serializers
from
.hands
import
IsSuperUserOr
Terminal
User
,
Terminal
from
.hands
import
IsSuperUserOr
App
User
,
Terminal
class
ProxyLogViewSet
(
viewsets
.
ModelViewSet
):
...
...
@@ -32,13 +32,13 @@ class ProxyLogViewSet(viewsets.ModelViewSet):
queryset
=
models
.
ProxyLog
.
objects
.
all
()
serializer_class
=
serializers
.
ProxyLogSerializer
permission_classes
=
(
IsSuperUserOr
Terminal
User
,)
permission_classes
=
(
IsSuperUserOr
App
User
,)
class
CommandLogViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
models
.
CommandLog
.
objects
.
all
()
serializer_class
=
serializers
.
CommandLogSerializer
permission_classes
=
(
IsSuperUserOr
Terminal
User
,)
permission_classes
=
(
IsSuperUserOr
App
User
,)
# class CommandLogTitleApi(APIView):
...
...
apps/audits/hands.py
View file @
27070123
...
...
@@ -4,5 +4,5 @@
from
users.utils
import
AdminUserRequiredMixin
from
users.models
import
User
from
assets.models
import
Asset
,
SystemUser
from
users.permissions
import
IsSuperUserOr
Terminal
User
from
users.permissions
import
IsSuperUserOr
App
User
from
terminal.models
import
Terminal
apps/common/compat.py
View file @
27070123
...
...
@@ -2,6 +2,81 @@
# -*- coding: utf-8 -*-
#
"""
兼容Python版本
"""
import
sys
is_py2
=
(
sys
.
version_info
[
0
]
==
2
)
is_py3
=
(
sys
.
version_info
[
0
]
==
3
)
try
:
import
simplejson
as
json
except
(
ImportError
,
SyntaxError
):
import
json
if
is_py2
:
def
to_bytes
(
data
):
"""若输入为unicode, 则转为utf-8编码的bytes;其他则原样返回。"""
if
isinstance
(
data
,
unicode
):
return
data
.
encode
(
'utf-8'
)
else
:
return
data
def
to_string
(
data
):
"""把输入转换为str对象"""
return
to_bytes
(
data
)
def
to_unicode
(
data
):
"""把输入转换为unicode,要求输入是unicode或者utf-8编码的bytes。"""
if
isinstance
(
data
,
bytes
):
return
data
.
decode
(
'utf-8'
)
else
:
return
data
def
stringify
(
input
):
if
isinstance
(
input
,
dict
):
return
dict
([(
stringify
(
key
),
stringify
(
value
))
for
key
,
value
in
input
.
iteritems
()])
elif
isinstance
(
input
,
list
):
return
[
stringify
(
element
)
for
element
in
input
]
elif
isinstance
(
input
,
unicode
):
return
input
.
encode
(
'utf-8'
)
else
:
return
input
builtin_str
=
str
bytes
=
str
str
=
unicode
elif
is_py3
:
def
to_bytes
(
data
):
"""若输入为str(即unicode),则转为utf-8编码的bytes;其他则原样返回"""
if
isinstance
(
data
,
str
):
return
data
.
encode
(
encoding
=
'utf-8'
)
else
:
return
data
def
to_string
(
data
):
"""若输入为bytes,则认为是utf-8编码,并返回str"""
if
isinstance
(
data
,
bytes
):
return
data
.
decode
(
'utf-8'
)
else
:
return
data
def
to_unicode
(
data
):
"""把输入转换为unicode,要求输入是unicode或者utf-8编码的bytes。"""
return
to_string
(
data
)
def
stringify
(
input
):
return
input
builtin_str
=
str
bytes
=
bytes
str
=
str
if
__name__
==
'__main__'
:
pass
apps/common/utils.py
View file @
27070123
...
...
@@ -3,12 +3,17 @@
from
__future__
import
unicode_literals
from
six
import
string_types
import
base64
import
os
from
itertools
import
chain
import
string
import
logging
import
datetime
import
paramiko
import
time
import
hashlib
from
email.utils
import
formatdate
import
calendar
import
threading
import
paramiko
import
sshpubkeys
...
...
@@ -16,7 +21,6 @@ from itsdangerous import TimedJSONWebSignatureSerializer, JSONWebSignatureSerial
BadSignature
,
SignatureExpired
from
django.shortcuts
import
reverse
as
dj_reverse
from
django.conf
import
settings
from
django.core
import
signing
from
django.utils
import
timezone
try
:
...
...
@@ -24,6 +28,8 @@ try:
except
ImportError
:
import
StringIO
from
.compat
import
to_bytes
,
to_string
SECRET_KEY
=
settings
.
SECRET_KEY
...
...
@@ -255,4 +261,63 @@ def setattr_bulk(seq, key, value):
return
map
(
set_attr
,
seq
)
def
content_md5
(
data
):
"""计算data的MD5值,经过Base64编码并返回str类型。
返回值可以直接作为HTTP Content-Type头部的值
"""
m
=
hashlib
.
md5
(
to_bytes
(
data
))
return
to_string
(
base64
.
b64encode
(
m
.
digest
()))
_STRPTIME_LOCK
=
threading
.
Lock
()
_GMT_FORMAT
=
"
%
a,
%
d
%
b
%
Y
%
H:
%
M:
%
S GMT"
_ISO8601_FORMAT
=
"
%
Y-
%
m-
%
dT
%
H:
%
M:
%
S.000Z"
def
to_unixtime
(
time_string
,
format_string
):
with
_STRPTIME_LOCK
:
return
int
(
calendar
.
timegm
(
time
.
strptime
(
time_string
,
format_string
)))
def
http_date
(
timeval
=
None
):
"""返回符合HTTP标准的GMT时间字符串,用strftime的格式表示就是"
%
a,
%
d
%
b
%
Y
%
H:
%
M:
%
S GMT"。
但不能使用strftime,因为strftime的结果是和locale相关的。
"""
return
formatdate
(
timeval
,
usegmt
=
True
)
def
http_to_unixtime
(
time_string
):
"""把HTTP Date格式的字符串转换为UNIX时间(自1970年1月1日UTC零点的秒数)。
HTTP Date形如 `Sat, 05 Dec 2015 11:10:29 GMT` 。
"""
return
to_unixtime
(
time_string
,
_GMT_FORMAT
)
def
iso8601_to_unixtime
(
time_string
):
"""把ISO8601时间字符串(形如,2012-02-24T06:07:48.000Z)转换为UNIX时间,精确到秒。"""
return
to_unixtime
(
time_string
,
_ISO8601_FORMAT
)
def
http_to_unixtime
(
time_string
):
"""把HTTP Date格式的字符串转换为UNIX时间(自1970年1月1日UTC零点的秒数)。
HTTP Date形如 `Sat, 05 Dec 2015 11:10:29 GMT` 。
"""
return
to_unixtime
(
time_string
,
"
%
a,
%
d
%
b
%
Y
%
H:
%
M:
%
S GMT"
)
def
make_signature
(
access_key_secret
,
date
=
None
):
if
isinstance
(
date
,
int
):
date_gmt
=
http_date
(
date
)
elif
date
is
None
:
date_gmt
=
http_date
(
int
(
time
.
time
()))
else
:
date_gmt
=
date
data
=
str
(
access_key_secret
)
+
"
\n
"
+
date_gmt
return
content_md5
(
data
)
signer
=
Signer
()
\ No newline at end of file
apps/jumpserver/settings.py
View file @
27070123
...
...
@@ -272,13 +272,12 @@ REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES'
:
(
'users.permissions.Is
Valid
User'
,
'users.permissions.Is
Super
User'
,
),
'DEFAULT_AUTHENTICATION_CLASSES'
:
(
'users.authentication.
Terminal
Authentication'
,
'users.authentication.
AccessKey
Authentication'
,
'users.authentication.AccessTokenAuthentication'
,
'rest_framework.authentication.TokenAuthentication'
,
'rest_framework.authentication.BasicAuthentication'
,
'rest_framework.authentication.SessionAuthentication'
,
),
'DEFAULT_FILTER_BACKENDS'
:
(
'django_filters.rest_framework.DjangoFilterBackend'
,),
...
...
apps/terminal/api.py
View file @
27070123
...
...
@@ -11,7 +11,7 @@ from rest_framework.permissions import AllowAny
from
common.utils
import
signer
,
get_object_or_none
from
.models
import
Terminal
,
TerminalHeatbeat
from
.serializers
import
TerminalSerializer
,
TerminalHeatbeatSerializer
from
.hands
import
IsSuperUserOr
Terminal
User
,
User
from
.hands
import
IsSuperUserOr
App
User
,
User
class
TerminalRegister
(
ListCreateAPIView
):
...
...
@@ -62,13 +62,13 @@ class TerminalViewSet(viewsets.ModelViewSet):
class
TerminalHeatbeatApi
(
ListCreateAPIView
):
queryset
=
TerminalHeatbeat
.
objects
.
all
()
serializer_class
=
TerminalHeatbeatSerializer
permission_classes
=
(
IsSuperUserOr
Terminal
User
,)
permission_classes
=
(
IsSuperUserOr
App
User
,)
class
TerminalHeatbeatViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
TerminalHeatbeat
.
objects
.
all
()
serializer_class
=
TerminalHeatbeatSerializer
permission_classes
=
(
IsSuperUserOr
Terminal
User
,)
permission_classes
=
(
IsSuperUserOr
App
User
,)
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
terminal
=
request
.
user
...
...
apps/terminal/hands.py
View file @
27070123
...
...
@@ -2,5 +2,5 @@
#
from
users.models
import
User
from
users.permissions
import
IsSuperUserOr
Terminal
User
from
audits.models
import
ProxyLog
from
users.permissions
import
IsSuperUserOr
App
User
from
audits.models
import
ProxyLog
\ No newline at end of file
apps/users/api.py
View file @
27070123
...
...
@@ -16,7 +16,7 @@ from common.utils import get_logger
from
.utils
import
check_user_valid
,
get_or_refresh_token
from
.models
import
User
,
UserGroup
from
.hands
import
write_login_log_async
from
.permissions
import
IsSuperUser
,
Is
TerminalUser
,
IsValidUser
,
IsSuperUserOrTerminal
User
from
.permissions
import
IsSuperUser
,
Is
AppUser
,
IsValidUser
,
IsSuperUserOrApp
User
from
.
import
serializers
...
...
apps/users/authentication.py
View file @
27070123
...
...
@@ -2,6 +2,8 @@
#
import
base64
import
hashlib
import
time
from
django.core.cache
import
cache
from
django.conf
import
settings
...
...
@@ -12,7 +14,7 @@ from django.utils.six import text_type
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework
import
HTTP_HEADER_ENCODING
from
common.utils
import
get_object_or_none
from
common.utils
import
get_object_or_none
,
make_signature
,
http_to_unixtime
from
.utils
import
get_or_refresh_token
from
.models
import
User
,
AccessKey
...
...
@@ -22,7 +24,6 @@ def get_request_date_header(request):
if
isinstance
(
date
,
text_type
):
# Work around django test client oddness
date
=
date
.
encode
(
HTTP_HEADER_ENCODING
)
return
date
...
...
@@ -54,18 +55,30 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
raise
exceptions
.
AuthenticationFailed
(
msg
)
access_key_id
=
sign
[
0
]
secret
=
sign
[
1
]
date
=
return
self
.
authenticate_credentials
(
sign
)
request_signature
=
sign
[
1
]
def
authenticate_credentials
(
self
,
access_key_id
,
secret
,
datetime
):
access_key_id
=
sign
[
0
]
secret
=
sign
[
1
]
return
self
.
authenticate_credentials
(
request
,
access_key_id
,
request_signature
)
def
authenticate_credentials
(
self
,
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
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Invalid signature.'
))
access_key_secret
=
access_key
.
secret
print
(
request_date
)
try
:
request_unix_time
=
http_to_unixtime
(
request_date
)
except
ValueError
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'HTTP header: Date not provide or not
%
a,
%
d
%
b
%
Y
%
H:
%
M:
%
S GMT'
))
if
int
(
time
.
time
())
-
request_unix_time
>
15
*
60
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Expired, more than 15 minutes'
))
signature
=
make_signature
(
access_key_secret
,
request_date
)
if
not
signature
==
request_signature
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Invalid signature.
%
s:
%
s'
%
(
signature
,
request_signature
)))
if
not
access_key
.
user
.
is_active
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'User disabled.'
))
...
...
apps/users/models/user.py
View file @
27070123
...
...
@@ -101,8 +101,8 @@ class User(AbstractUser):
return
False
@property
def
is_
terminal
(
self
):
return
False
def
is_
app
(
self
):
return
self
.
role
==
'App'
@is_superuser.setter
def
is_superuser
(
self
,
value
):
...
...
apps/users/permissions.py
View file @
27070123
...
...
@@ -23,12 +23,12 @@ class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
and
request
.
user
.
is_valid
class
Is
Terminal
User
(
IsValidUser
,
permissions
.
BasePermission
):
class
Is
App
User
(
IsValidUser
,
permissions
.
BasePermission
):
"""Allows access only to app user """
def
has_permission
(
self
,
request
,
view
):
return
super
(
Is
Terminal
User
,
self
)
.
has_permission
(
request
,
view
)
\
and
isinstance
(
request
.
user
,
Terminal
)
return
super
(
Is
App
User
,
self
)
.
has_permission
(
request
,
view
)
\
and
request
.
user
.
is_app
(
)
class
IsSuperUser
(
IsValidUser
,
permissions
.
BasePermission
):
...
...
@@ -39,12 +39,12 @@ class IsSuperUser(IsValidUser, permissions.BasePermission):
and
request
.
user
.
is_superuser
class
IsSuperUserOr
Terminal
User
(
IsValidUser
,
permissions
.
BasePermission
):
class
IsSuperUserOr
App
User
(
IsValidUser
,
permissions
.
BasePermission
):
"""Allows access between superuser and app user"""
def
has_permission
(
self
,
request
,
view
):
return
super
(
IsSuperUserOr
Terminal
User
,
self
)
.
has_permission
(
request
,
view
)
\
and
(
request
.
user
.
is_superuser
or
request
.
user
.
is_
terminal
)
return
super
(
IsSuperUserOr
App
User
,
self
)
.
has_permission
(
request
,
view
)
\
and
(
request
.
user
.
is_superuser
or
request
.
user
.
is_
app
)
if
__name__
==
'__main__'
:
...
...
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