From 4d71c2d1ff3d59f8ff7606f8a7ec809ec059f2f4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 20 Dec 2016 01:19:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9token=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=EF=BC=8C=E6=8B=86=E5=88=86=E8=AE=A4=E8=AF=81=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=92=8C=E6=9D=83=E9=99=90=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/hands.py | 2 +- apps/assets/urls/api_urls.py | 4 +- apps/audits/hands.py | 2 +- apps/jumpserver/settings.py | 6 +-- apps/perms/api.py | 2 +- apps/terminal/api.py | 3 +- apps/terminal/hands.py | 4 +- apps/users/api.py | 14 ++--- apps/users/{backends.py => authentication.py} | 43 +--------------- apps/users/hands.py | 1 + apps/users/models.py | 1 + apps/users/permissions.py | 51 +++++++++++++++++++ apps/users/urls/api_urls.py | 14 ++--- apps/users/utils.py | 13 ++++- 14 files changed, 88 insertions(+), 72 deletions(-) rename apps/users/{backends.py => authentication.py} (66%) create mode 100644 apps/users/permissions.py diff --git a/apps/assets/hands.py b/apps/assets/hands.py index acf0db52e..94e4a3d77 100644 --- a/apps/assets/hands.py +++ b/apps/assets/hands.py @@ -12,5 +12,5 @@ from users.utils import AdminUserRequiredMixin -from users.backends import IsSuperUserOrTerminalUser, IsSuperUser +from users.permissions import IsSuperUserOrTerminalUser, IsSuperUser from users.models import User, UserGroup diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index ca1760404..f7370962f 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -14,9 +14,9 @@ router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user') 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/assets_bulk$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), # url(r'^v1/idc/(?P[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/auth', api.SystemUserAuthApi.as_view(), name='system-user-auth'), ] urlpatterns += router.urls diff --git a/apps/audits/hands.py b/apps/audits/hands.py index 281440780..889ec6940 100644 --- a/apps/audits/hands.py +++ b/apps/audits/hands.py @@ -4,5 +4,5 @@ from users.utils import AdminUserRequiredMixin from users.models import User from assets.models import Asset, SystemUser -from users.backends import IsSuperUserOrTerminalUser +from users.permissions import IsSuperUserOrTerminalUser from terminal.models import Terminal diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index e9e73b15c..ca3beb996 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -263,11 +263,11 @@ REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. 'DEFAULT_PERMISSION_CLASSES': ( - 'users.backends.IsValidUser', + 'users.permissions.IsValidUser', ), 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'users.backends.TerminalAuthentication', - 'users.backends.AccessTokenAuthentication', + 'users.authentication.TerminalAuthentication', + 'users.authentication.AccessTokenAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', diff --git a/apps/perms/api.py b/apps/perms/api.py index a2522f44b..b80e351ef 100644 --- a/apps/perms/api.py +++ b/apps/perms/api.py @@ -4,7 +4,7 @@ from rest_framework.views import APIView, Response from rest_framework.generics import ListAPIView, get_object_or_404 from rest_framework import viewsets -from users.backends import IsValidUser, IsSuperUser +from users.permissions import IsValidUser, IsSuperUser from common.utils import get_object_or_none from .utils import get_user_granted_assets, get_user_granted_asset_groups, get_user_asset_permissions, \ get_user_group_asset_permissions, get_user_group_granted_assets, get_user_group_granted_asset_groups diff --git a/apps/terminal/api.py b/apps/terminal/api.py index 224dac98b..e3113d0b0 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -11,7 +11,8 @@ 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 IsSuperUserOrTerminalUser +from .hands import IsSuperUserOrTerminalUser, User + class TerminalViewSet(viewsets.ModelViewSet): diff --git a/apps/terminal/hands.py b/apps/terminal/hands.py index bf513c03a..7cff4eefd 100644 --- a/apps/terminal/hands.py +++ b/apps/terminal/hands.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -from users.backends import IsSuperUserOrTerminalUser +from users.models import User +from users.permissions import IsSuperUserOrTerminalUser from audits.models import ProxyLog - diff --git a/apps/users/api.py b/apps/users/api.py index ba8af72b3..5c1988242 100644 --- a/apps/users/api.py +++ b/apps/users/api.py @@ -13,10 +13,10 @@ from django_filters.rest_framework import DjangoFilterBackend from common.mixins import IDInFilterMixin from common.utils import get_logger -from .utils import check_user_valid, token_gen +from .utils import check_user_valid, get_or_refresh_token from .models import User, UserGroup from .hands import write_login_log_async -from .backends import IsSuperUser, IsTerminalUser, IsValidUser, IsSuperUserOrTerminalUser +from .permissions import IsSuperUser, IsTerminalUser, IsValidUser, IsSuperUserOrTerminalUser from . import serializers @@ -87,19 +87,11 @@ class UserGroupUpdateUserApi(generics.RetrieveUpdateAPIView): class UserToken(APIView): permission_classes = (IsValidUser,) - expiration = settings.CONFIG.TOKEN_EXPIRATION or 3600 def get(self, request): if not request.user: return Response({'error': 'unauthorized'}) - - remote_addr = request.META.get('REMOTE_ADDR', '') - remote_addr = base64.b16encode(remote_addr).replace('=', '') - token = cache.get('%s_%s' % (request.user.id, remote_addr)) - if not token: - token = token_gen(request.user) - cache.set(token, request.user.id, self.expiration) - cache.set('%s_%s' % (request.user.id, remote_addr), token, self.expiration) + token = get_token(request) return Response({'token': token}) diff --git a/apps/users/backends.py b/apps/users/authentication.py similarity index 66% rename from apps/users/backends.py rename to apps/users/authentication.py index aad173ff4..51405b351 100644 --- a/apps/users/backends.py +++ b/apps/users/authentication.py @@ -11,6 +11,7 @@ from rest_framework.compat import is_authenticated from common.utils import signer, get_object_or_none from .hands import Terminal +from .utils import get_or_refresh_token from .models import User @@ -83,45 +84,5 @@ class AccessTokenAuthentication(authentication.BaseAuthentication): if not user: return None - - remote_addr = request.META.get('REMOTE_ADDR', '') - remote_addr = base64.b16encode(remote_addr).replace('=', '') - cache.set(token, user_id, self.expiration) - cache.set('%s_%s' % (user.id, remote_addr), token, self.expiration) + get_or_refresh_token(request, user) return user, None - - -class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission): - """Allows access to valid user, is active and not expired""" - - def has_permission(self, request, view): - return super(IsValidUser, self).has_permission(request, view) \ - and request.user.is_valid - - -class IsTerminalUser(IsValidUser, permissions.BasePermission): - """Allows access only to app user """ - - def has_permission(self, request, view): - return super(IsTerminalUser, self).has_permission(request, view) \ - and isinstance(request.user, Terminal) - - -class IsSuperUser(IsValidUser, permissions.BasePermission): - """Allows access only to superuser""" - - def has_permission(self, request, view): - return super(IsSuperUser, self).has_permission(request, view) \ - and request.user.is_superuser - - -class IsSuperUserOrTerminalUser(IsValidUser, permissions.BasePermission): - """Allows access between superuser and app user""" - - def has_permission(self, request, view): - return super(IsSuperUserOrTerminalUser, self).has_permission(request, view) \ - and (request.user.is_superuser or request.user.is_terminal) - - -if __name__ == '__main__': - pass diff --git a/apps/users/hands.py b/apps/users/hands.py index e423ebe81..57832f35f 100644 --- a/apps/users/hands.py +++ b/apps/users/hands.py @@ -12,5 +12,6 @@ from terminal.models import Terminal from audits.tasks import write_login_log_async +from users.models import User # from perms.models import AssetPermission # from perms.utils import get_user_granted_assets, get_user_granted_asset_groups diff --git a/apps/users/models.py b/apps/users/models.py index ede813e83..35178003e 100644 --- a/apps/users/models.py +++ b/apps/users/models.py @@ -67,6 +67,7 @@ class User(AbstractUser): ROLE_CHOICES = ( ('Admin', _('Administrator')), ('User', _('User')), + ('APP', _('Application')) ) username = models.CharField(max_length=20, unique=True, verbose_name=_('Username')) diff --git a/apps/users/permissions.py b/apps/users/permissions.py new file mode 100644 index 000000000..7ec7ad1ee --- /dev/null +++ b/apps/users/permissions.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +import base64 + +from django.core.cache import cache +from django.conf import settings +from django.utils.translation import ugettext as _ +from rest_framework import authentication, exceptions, permissions +from rest_framework.compat import is_authenticated + +from common.utils import signer, get_object_or_none +from .hands import Terminal +from .models import User + + +class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission): + """Allows access to valid user, is active and not expired""" + + def has_permission(self, request, view): + return super(IsValidUser, self).has_permission(request, view) \ + and request.user.is_valid + + +class IsTerminalUser(IsValidUser, permissions.BasePermission): + """Allows access only to app user """ + + def has_permission(self, request, view): + return super(IsTerminalUser, self).has_permission(request, view) \ + and isinstance(request.user, Terminal) + + +class IsSuperUser(IsValidUser, permissions.BasePermission): + """Allows access only to superuser""" + + def has_permission(self, request, view): + return super(IsSuperUser, self).has_permission(request, view) \ + and request.user.is_superuser + + +class IsSuperUserOrTerminalUser(IsValidUser, permissions.BasePermission): + """Allows access between superuser and app user""" + + def has_permission(self, request, view): + return super(IsSuperUserOrTerminalUser, self).has_permission(request, view) \ + and (request.user.is_superuser or request.user.is_terminal) + + +if __name__ == '__main__': + pass diff --git a/apps/users/urls/api_urls.py b/apps/users/urls/api_urls.py index e0fafeebb..3964a5030 100644 --- a/apps/users/urls/api_urls.py +++ b/apps/users/urls/api_urls.py @@ -16,14 +16,14 @@ router.register(r'v1/user-groups', api.UserGroupViewSet, 'user-group') urlpatterns = [ - url(r'^v1/users/token/$', api.UserToken.as_view(), name='user-token'), - url(r'^v1/users/profile/$', api.UserProfile.as_view(), name='user-profile'), - url(r'^v1/users/(?P\d+)/reset-password/$', api.UserResetPasswordApi.as_view(), name='user-reset-password'), - url(r'^v1/users/(?P\d+)/reset-pk/$', api.UserResetPKApi.as_view(), name='user-reset-pk'), - url(r'^v1/users/(?P\d+)/update-pk/$', api.UserUpdatePKApi.as_view(), name='user-update-pk'), - url(r'^v1/users/(?P\d+)/groups/$', + 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/users/(?P\d+)/reset-password$', api.UserResetPasswordApi.as_view(), name='user-reset-password'), + url(r'^v1/users/(?P\d+)/reset-pk$', api.UserResetPKApi.as_view(), name='user-reset-pk'), + url(r'^v1/users/(?P\d+)/update-pk$', api.UserUpdatePKApi.as_view(), name='user-update-pk'), + url(r'^v1/users/(?P\d+)/groups$', api.UserUpdateGroupApi.as_view(), name='user-update-group'), - url(r'^v1/user-groups/(?P\d+)/users/$', + url(r'^v1/user-groups/(?P\d+)/users$', api.UserGroupUpdateUserApi.as_view(), name='user-group-update-user'), ] diff --git a/apps/users/utils.py b/apps/users/utils.py index 9797b5fe4..ace4ebfe6 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -1,6 +1,7 @@ # ~*~ coding: utf-8 ~*~ # from __future__ import unicode_literals +import base64 import logging import os import re @@ -10,6 +11,7 @@ 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 _ +from django.core.cache import cache from paramiko.rsakey import RSAKey @@ -195,6 +197,13 @@ def check_user_valid(**kwargs): return None -def token_gen(*args, **kwargs): +def get_or_refresh_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' % (user.id, remote_addr)) + if not token: + token = uuid.uuid4().get_hex() + cache.set(token, request.user.id, expiration) + cache.set('%s_%s' % (request.user.id, remote_addr), token, expiration) return uuid.uuid4().get_hex() -