Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions exodus/restful_api/permissions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
from rest_framework import permissions


class IsAuthenticatedOrOptions(permissions.IsAuthenticated):
"""
Allow unauthenticated OPTIONS requests through.

CORS preflight requests always omit credentials, so they must be
answered without requiring authentication (see the Fetch spec).
"""

def has_permission(self, request, view):
if request.method == 'OPTIONS':
return True
return super().has_permission(request, view)


class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
Expand Down
5 changes: 5 additions & 0 deletions exodus/restful_api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ def test_returns_unauthorized_when_no_auth(self):
response = self.client.get(self.PATH)
self.assertEqual(response.status_code, 401)

def test_options_preflight_does_not_require_auth(self):
response = self.client.options(self.PATH)

self.assertEqual(response.status_code, 200)

def test_returns_empty_json_when_no_applications(self):
self._force_authentication()
response = self.client.get(self.PATH)
Expand Down
23 changes: 12 additions & 11 deletions exodus/restful_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.permissions import IsAdminUser

from reports.models import Application, Report, Certificate
from trackers.models import Tracker
from restful_api.permissions import IsAuthenticatedOrOptions
from restful_api.serializers import ApplicationSerializer, TrackerSerializer, \
ReportInfosSerializer, ReportSerializer, SearchQuerySerializer, \
SearchApplicationSerializer, ApplicationShortSerializer
Expand All @@ -23,7 +24,7 @@
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def get_report_infos(request, r_id):
try:
report = Report.objects.get(pk=r_id)
Expand Down Expand Up @@ -52,7 +53,7 @@ def get_report_infos(request, r_id):
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated, IsAdminUser))
@permission_classes((IsAuthenticatedOrOptions, IsAdminUser))
def get_apk(request, r_id):
try:
report = Report.objects.get(pk=r_id)
Expand Down Expand Up @@ -123,7 +124,7 @@ def _get_tracker_list():
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def get_all_reports(request):
report_list = Report.objects.order_by('-creation_date')[:500]
applications = _get_reports_list(report_list)
Expand All @@ -148,7 +149,7 @@ def get_all_trackers(request):
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def get_all_applications(request):
try:
if request.GET.get('tracker'):
Expand All @@ -168,7 +169,7 @@ def get_all_applications(request):
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def search_strict_handle(request, handle):
try:
reports = Report.objects.filter(application__handle=handle).order_by('-creation_date')
Expand Down Expand Up @@ -199,7 +200,7 @@ def search_latest_report(request, handle):
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def get_report_details(request, r_id):
try:
report = Report.objects.get(pk=r_id)
Expand Down Expand Up @@ -258,7 +259,7 @@ def search(request):
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def search_strict_handle_details(request, handle):
try:
reports = Report.objects.filter(application__handle=handle)
Expand Down Expand Up @@ -290,22 +291,22 @@ def search_strict_handle_details(request, handle):
@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def get_trackers_count(request):
return JsonResponse({'count': Tracker.objects.count()})


@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def get_reports_count(request):
return JsonResponse({'count': Report.objects.count()})


@csrf_exempt
@api_view(['GET'])
@authentication_classes((TokenAuthentication,))
@permission_classes((IsAuthenticated,))
@permission_classes((IsAuthenticatedOrOptions,))
def get_applications_count(request):
return JsonResponse({'count': Application.objects.distinct('handle').count()})