Commit c2c2f7d4 authored by Florent Chehab's avatar Florent Chehab

enhance(request security):

* Updated all DRF custom permissions to make sure they have has_permission and has_object_permission
* Changed default permission
* Updated middleware to filter incomming request based on their type
* Added test for this

Closes #118
parent 7dc6e615
Pipeline #40469 passed with stages
in 3 minutes and 30 seconds
......@@ -9,19 +9,24 @@ from backend_app.utils import is_member
class IsAuthenticated(rf_IsAuthenticated):
pass
def has_object_permission(self, request, view, obj):
return self.has_permission(request, view)
class IsStaff(IsAdminUser):
pass
def has_object_permission(self, request, view, obj):
return self.has_permission(request, view)
class IsDri(permissions.BasePermission):
class IsDri(BasePermission):
"""
Permission to make a viewset readonly unless the request user
is a member of the DRI group.
"""
def has_object_permission(self, request, view, obj):
return self.has_permission(request, view)
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
......@@ -44,29 +49,35 @@ class IsOwner(BasePermission):
# For the user model
return request.user == obj
def has_permission(self, request, view):
return True
class NoDelete(BasePermission):
"""
Permission to prevent the use of the DELETE method.
"""
def has_permission(self, request, view):
if request.method == "DELETE":
return False
def has_object_permission(self, request, view, obj):
return self.has_permission(request, view)
return True
def has_permission(self, request, view):
return request.method != "DELETE"
class NoPost(permissions.BasePermission):
class NoPost(BasePermission):
"""
Permission to disallow POST request
"""
def has_object_permission(self, request, view, obj):
return self.has_permission(request, view)
def has_permission(self, request, view):
return request.method != "POST"
class ReadOnly(permissions.BasePermission):
class ReadOnly(BasePermission):
"""
Permission to make a viewset read-only.
"""
......
from backend_app.permissions.app_permissions import NoDelete, IsAuthenticated, IsStaff
from backend_app.permissions.app_permissions import IsAuthenticated
DEFAULT_VIEWSET_PERMISSIONS = IsAuthenticated & (IsStaff | NoDelete)
DEFAULT_VIEWSET_PERMISSIONS = IsAuthenticated
from django.utils.deprecation import MiddlewareMixin
from re import compile
from django.http import HttpResponseRedirect
from django.conf import settings
from re import compile
from django.http import HttpResponseRedirect, HttpResponse
from django.utils.deprecation import MiddlewareMixin
from rest_framework import permissions
EXEMPT_URLS = []
if hasattr(settings, "LOGIN_EXEMPT_URLS"):
EXEMPT_URLS += [compile(str.lstrip("/")) for str in settings.LOGIN_EXEMPT_URLS]
AUTHORIZED_REQUEST_METHODS = list(permissions.SAFE_METHODS) + ["POST", "PUT", "DELETE"]
class LoginRequiredMiddleware(MiddlewareMixin):
class RexDriRequestMiddleware(MiddlewareMixin):
"""
Middleware that requires a user to be authenticated to view any page other
This middleware performs different actions.
- It checks that the HTTP request method is authorized on the plateform.
- It requires a user to be authenticated to view any page other
than LOGIN_URL. Exemptions to this requirement can optionally be specified
in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which
you can copy from your urls.py).
......@@ -21,14 +29,20 @@ class LoginRequiredMiddleware(MiddlewareMixin):
"""
def process_request(self, request):
# Check that the request.method is authorized on the site
if request.method not in AUTHORIZED_REQUEST_METHODS:
return HttpResponse("Unauthorized", status=401)
assert hasattr(
request, "user"
), "The Login Required middleware\
), "The RexDriRequestMiddleware\
requires authentication middleware to be installed. Edit your\
MIDDLEWARE_CLASSES setting to insert\
'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\
work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\
'django.core.context_processors.auth'."
# If the user is not authenticated redirect him/her to the login page
if not request.user.is_authenticated:
path = request.path_info.lstrip("/")
if not any(m.match(path) for m in EXEMPT_URLS):
......
......@@ -121,7 +121,7 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"base_app.middleware.LoginRequiredMiddleware",
"base_app.middleware.RexDriRequestMiddleware",
]
#
......
from django.test import TestCase
from rest_framework.test import APIClient
class MiddlewareAuthorizedMethodsTestCase(TestCase):
"""
Test of REX-DRI middleware.
Part regarding authorized HTTP methods
"""
url = "/admin/login/"
def test_get_allowed(self):
client = APIClient()
response = client.get(self.url)
self.assertNotEqual(response.status_code, 201)
def test_patch_not_allowed(self):
client = APIClient()
response = client.patch(self.url)
self.assertEqual(response.status_code, 401)
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