mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-04 03:31:28 +00:00
feat: Securisation du Backend
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.3 on 2025-11-30 11:02
|
||||
# Generated by Django 5.1.3 on 2026-03-14 13:23
|
||||
|
||||
import Establishment.models
|
||||
import django.contrib.postgres.fields
|
||||
|
||||
92
Back-End/Establishment/tests.py
Normal file
92
Back-End/Establishment/tests.py
Normal file
@ -0,0 +1,92 @@
|
||||
"""
|
||||
Tests unitaires pour le module Establishment.
|
||||
Vérifie que les endpoints requièrent une authentification JWT.
|
||||
"""
|
||||
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from Auth.models import Profile
|
||||
|
||||
|
||||
def create_user(email="establishment_test@example.com", password="testpassword123"):
|
||||
return Profile.objects.create_user(username=email, email=email, password=password)
|
||||
|
||||
|
||||
def get_jwt_token(user):
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return str(refresh.access_token)
|
||||
|
||||
|
||||
TEST_REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
),
|
||||
}
|
||||
|
||||
TEST_CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
|
||||
|
||||
|
||||
@override_settings(
|
||||
CACHES=TEST_CACHES,
|
||||
SESSION_ENGINE='django.contrib.sessions.backends.db',
|
||||
REST_FRAMEWORK=TEST_REST_FRAMEWORK,
|
||||
)
|
||||
class EstablishmentEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints Establishment."""
|
||||
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.list_url = reverse("Establishment:establishment_list_create")
|
||||
self.user = create_user()
|
||||
|
||||
def test_get_establishments_sans_auth_retourne_401(self):
|
||||
"""GET /Establishment/establishments sans token doit retourner 401."""
|
||||
response = self.client.get(self.list_url)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
def test_post_establishment_sans_auth_retourne_401(self):
|
||||
"""POST /Establishment/establishments sans token doit retourner 401."""
|
||||
import json
|
||||
response = self.client.post(
|
||||
self.list_url,
|
||||
data=json.dumps({"name": "Ecole Alpha"}),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
def test_get_establishment_detail_sans_auth_retourne_401(self):
|
||||
"""GET /Establishment/establishments/{id} sans token doit retourner 401."""
|
||||
url = reverse("Establishment:establishment_detail", kwargs={"id": 1})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
def test_put_establishment_sans_auth_retourne_401(self):
|
||||
"""PUT /Establishment/establishments/{id} sans token doit retourner 401."""
|
||||
import json
|
||||
url = reverse("Establishment:establishment_detail", kwargs={"id": 1})
|
||||
response = self.client.put(
|
||||
url,
|
||||
data=json.dumps({"name": "Ecole Beta"}),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
def test_delete_establishment_sans_auth_retourne_401(self):
|
||||
"""DELETE /Establishment/establishments/{id} sans token doit retourner 401."""
|
||||
url = reverse("Establishment:establishment_detail", kwargs={"id": 1})
|
||||
response = self.client.delete(url)
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
def test_get_establishments_avec_auth_retourne_200(self):
|
||||
"""GET /Establishment/establishments avec token valide doit retourner 200."""
|
||||
token = get_jwt_token(self.user)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = self.client.get(self.list_url)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
@ -4,6 +4,7 @@ from django.utils.decorators import method_decorator
|
||||
from rest_framework.parsers import JSONParser, MultiPartParser, FormParser
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated, BasePermission
|
||||
from .models import Establishment
|
||||
from .serializers import EstablishmentSerializer
|
||||
from N3wtSchool.bdd import delete_object, getAllObjects, getObject
|
||||
@ -15,9 +16,29 @@ import N3wtSchool.mailManager as mailer
|
||||
import os
|
||||
from N3wtSchool import settings
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
|
||||
class IsWebhookApiKey(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
api_key = settings.WEBHOOK_API_KEY
|
||||
if not api_key:
|
||||
return False
|
||||
return request.headers.get('X-API-Key') == api_key
|
||||
|
||||
|
||||
class IsAuthenticatedOrWebhookApiKey(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
if request.user and request.user.is_authenticated:
|
||||
return True
|
||||
return IsWebhookApiKey().has_permission(request, view)
|
||||
|
||||
|
||||
class EstablishmentListCreateView(APIView):
|
||||
|
||||
def get_permissions(self):
|
||||
if self.request.method == 'POST':
|
||||
return [IsAuthenticatedOrWebhookApiKey()]
|
||||
return [IsAuthenticated()]
|
||||
|
||||
def get(self, request):
|
||||
establishments = getAllObjects(Establishment)
|
||||
establishments_serializer = EstablishmentSerializer(establishments, many=True)
|
||||
@ -44,6 +65,7 @@ class EstablishmentListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class EstablishmentDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
parser_classes = [MultiPartParser, FormParser]
|
||||
|
||||
def get(self, request, id=None):
|
||||
@ -87,7 +109,9 @@ def create_establishment_with_directeur(establishment_data):
|
||||
directeur_email = directeur_data.get("email")
|
||||
last_name = directeur_data.get("last_name", "")
|
||||
first_name = directeur_data.get("first_name", "")
|
||||
password = directeur_data.get("password", "Provisoire01!")
|
||||
password = directeur_data.get("password")
|
||||
if not password:
|
||||
raise ValueError("Le champ 'directeur.password' est obligatoire pour créer un établissement.")
|
||||
|
||||
# Création ou récupération du profil utilisateur
|
||||
profile, created = Profile.objects.get_or_create(
|
||||
|
||||
Reference in New Issue
Block a user