Commit 0446f449 authored by ibuler's avatar ibuler

Add auth and permission backends

parent a62a2178
......@@ -68,7 +68,6 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ws4redis',
]
......@@ -264,12 +263,14 @@ REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAdminUser',
# 'rest_framework.permissions.IsAuthenticated',
'users.backends.IsValidUser',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
'users.backends.AppSignAuthentication',
),
}
# This setting is required to override the Django's main loop, when running in
......
......@@ -7,11 +7,12 @@ from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
from common.mixins import BulkDeleteApiMixin
from common.utils import get_logger
from .models import User, UserGroup
from .serializers import UserDetailSerializer, UserAndGroupSerializer, \
GroupDetailSerializer, UserPKUpdateSerializer, UserBulkUpdateSerializer, GroupBulkUpdateSerializer
from common.mixins import BulkDeleteApiMixin
from common.utils import get_logger
from .backends import IsSuperUser, IsAppUser, IsValidUser, IsSuperUserOrAppUser
logger = get_logger(__name__)
......@@ -84,6 +85,10 @@ class GroupDetailApi(generics.RetrieveUpdateDestroyAPIView):
class UserListUpdateApi(BulkDeleteApiMixin, ListBulkCreateUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserBulkUpdateSerializer
permission_classes = (IsSuperUserOrAppUser,)
def get(self, request, *args, **kwargs):
return super(UserListUpdateApi, self).get(request, *args, **kwargs)
class GroupListUpdateApi(BulkDeleteApiMixin, ListBulkCreateUpdateDestroyAPIView):
......
# -*- coding: utf-8 -*-
#
from rest_framework import authentication, exceptions
from rest_framework import authentication, exceptions, permissions
from rest_framework.compat import is_authenticated
from django.utils.translation import ugettext as _
from common.utils import unsign
from common.utils import unsign, get_object_or_none
from .models import User
class APPSignAuthentication(authentication.BaseAuthentication):
class AppSignAuthentication(authentication.BaseAuthentication):
keyword = 'Sign'
model = User
......@@ -30,17 +31,50 @@ class APPSignAuthentication(authentication.BaseAuthentication):
except UnicodeError:
msg = _('Invalid token header. Sign string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(sign)
def authenticate_credentials(self, key):
try:
token = self.model.objects.select_related('user').get(key=key)
except self.model.DoesNotExist:
raise exceptions.AuthenticationFailed(_('Invalid token.'))
def authenticate_credentials(self, sign):
app = unsign(sign, max_age=300)
if app:
user = get_object_or_none(self.model, username=app, role='App')
else:
raise exceptions.AuthenticationFailed(_('Invalid sign.'))
if not token.user.is_active:
if not user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
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 IsAppUser(IsValidUser, permissions.BasePermission):
"""Allows access only to app user """
def has_permission(self, request, view):
return super(IsAppUser, self).has_permission(request, view) \
and request.user.is_app_user
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 IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission):
"""Allows access between superuser and app user"""
def has_permission(self, request, view):
return super(IsSuperUserOrAppUser, self).has_permission(request, view) \
and (request.user.is_superuser or request.user.is_app_user)
if __name__ == '__main__':
......
......@@ -69,6 +69,7 @@ class User(AbstractUser):
ROLE_CHOICES = (
('Admin', _('Administrator')),
('User', _('User')),
('App', _('Application')),
)
username = models.CharField(max_length=20, unique=True, verbose_name=_('Username'))
......@@ -148,9 +149,18 @@ class User(AbstractUser):
else:
self.role = 'User'
is_admin = is_superuser
@property
def is_app_user(self):
if self.role == 'App':
return True
else:
return False
@property
def is_staff(self):
if self.is_authenticated and self.is_active and not self.is_expired and self.is_superuser:
if self.is_authenticated and self.is_valid:
return True
else:
return False
......@@ -185,14 +195,14 @@ class User(AbstractUser):
Token.objects.filter(user=self).delete()
return Token.objects.create(user=self)
def generate_reset_token(self):
return signing.dumps({'reset': self.id, 'email': self.email})
def is_member_of(self, user_group):
if user_group in self.groups.all():
return True
return False
def generate_reset_token(self):
return signing.dumps({'reset': self.id, 'email': self.email})
@classmethod
def validate_reset_token(cls, token, max_age=3600):
try:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment