Skip to content

Commit

Permalink
Fix api authentication/authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Wisecarver committed Jul 10, 2016
1 parent bc7d47f commit 8d7e89f
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 15 deletions.
21 changes: 21 additions & 0 deletions api/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from rest_framework.authentication import SessionAuthentication


class NonCSRFSessionAuthentication(SessionAuthentication):
def authenticate(self, request):
"""
Returns a `User` if the request session currently has a logged in user.
Otherwise returns `None`.
"""

# Get the session-based user from the underlying HttpRequest object
user = getattr(request._request, 'user', None)

# Unauthenticated, CSRF validation not required
if not user or not user.is_active:
return None

# self.enforce_csrf(request)

# CSRF passed with authenticated user
return (user, None)
28 changes: 28 additions & 0 deletions api/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from oauth2_provider.ext.rest_framework import TokenHasScope
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
import logging

log = logging.getLogger(__name__)

class ReadOnlyOrTokenHasScopeOrIsAuthenticated(TokenHasScope, IsAuthenticated, BasePermission):
def has_permission(self, request, view):
if request.method in SAFE_METHODS:
return True

if request.user and request.user.is_authenticated():
return True

token = request.auth

if not token:
return False

if hasattr(token, 'scope'): # OAuth 2
required_scopes = self.get_scopes(request, view)
log.debug("Required scopes to access resource: {0}".format(required_scopes))

return token.is_valid(required_scopes)

assert False, ('TokenHasScope requires either the'
'`oauth2_provider.rest_framework.OAuth2Authentication` authentication '
'class to be used.')
6 changes: 2 additions & 4 deletions api/views/share.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from rest_framework.response import Response

from api.filters import ShareObjectFilterSet
from api.serializers import ChangeSerializer
from share import serializers
from api import serializers as api_serializers

Expand All @@ -30,14 +29,13 @@ def changes(self, request, pk=None):
changes = self.get_object().changes.all()
page = self.paginate_queryset(changes)
if page is not None:
ser = ChangeSerializer(page, many=True, context={'request': request})
ser = api_serializers.ChangeSerializer(page, many=True, context={'request': request})
return self.get_paginated_response(ser.data)
ser = ChangeSerializer(changes, many=True, context={'request': request})
ser = api_serializers.ChangeSerializer(changes, many=True, context={'request': request})
return Response(ser.data)


class ShareObjectViewSet(ChangesViewSet, VersionsViewSet, viewsets.ReadOnlyModelViewSet):
permission_classes = [permissions.IsAuthenticated, ] # TokenHasScope]
# TODO: Add in scopes once we figure out who, why, and how.
# required_scopes = ['', ]
filter_class = ShareObjectFilterSet
Expand Down
13 changes: 4 additions & 9 deletions api/views/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,36 @@
from rest_framework.response import Response

from api.filters import ChangeSetFilterSet, ChangeFilterSet
from api.permissions import ReadOnlyOrTokenHasScopeOrIsAuthenticated
from api.serializers import NormalizedDataSerializer, ChangeSetSerializer, ChangeSerializer, RawDataSerializer, \
ShareUserSerializer, ProviderSerializer
from share.models import ChangeSet, Change, RawData, ShareUser
from share.models import ChangeSet, Change, RawData, ShareUser, NormalizedData
from share.tasks import MakeJsonPatches

__all__ = ('NormalizedDataViewSet', 'ChangeSetViewSet', 'ChangeViewSet', 'RawDataViewSet', 'ShareUserViewSet', 'ProviderViewSet')


class ShareUserViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = [permissions.IsAuthenticated,]
serializer_class = ShareUserSerializer

def get_queryset(self):
return [self.request.user,]


class ProviderViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = [permissions.IsAuthenticatedOrReadOnly,]
serializer_class = ProviderSerializer

def get_queryset(self):
return ShareUser.objects.exclude(robot='')


class NormalizedDataViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated, TokenHasScope, ]
permission_classes = [ReadOnlyOrTokenHasScopeOrIsAuthenticated, ]
serializer_class = NormalizedDataSerializer
required_scopes = ['upload_normalized_manuscript', ]

def get_queryset(self):
return self.request.user.normalizeddata_set.all()
return NormalizedData.objects.all()

def create(self, request, *args, **kwargs):
prelim_data = request.data
Expand All @@ -48,19 +47,16 @@ def create(self, request, *args, **kwargs):


class ChangeSetViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated]
serializer_class = ChangeSetSerializer
# TODO: Add in scopes once we figure out who, why, and how.
# required_scopes = ['', ]
# queryset = ChangeSet.objects.all()

def get_queryset(self):
return ChangeSet.objects.all().select_related('normalized_data__source')
filter_class = ChangeSetFilterSet


class ChangeViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated]
serializer_class = ChangeSerializer
# TODO: Add in scopes once we figure out who, why, and how.
# required_scopes = ['', ]
Expand All @@ -69,7 +65,6 @@ class ChangeViewSet(viewsets.ModelViewSet):


class RawDataViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = [permissions.IsAuthenticatedOrReadOnly, ]
serializer_class = RawDataSerializer

queryset = RawData.objects.all()
5 changes: 3 additions & 2 deletions project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,11 @@
APPLICATION_USERNAME = 'system'

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticatedOrReadOnly',),
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.ext.rest_framework.OAuth2Authentication',
'rest_framework.authentication.SessionAuthentication',
# 'api.authentication.NonCSRFSessionAuthentication',
),
'PAGE_SIZE': 32,
'DEFAULT_PARSER_CLASSES': (
Expand All @@ -259,7 +260,7 @@
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
Expand Down

0 comments on commit 8d7e89f

Please sign in to comment.