mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-03 16:51:26 +00:00
117 lines
4.3 KiB
Python
117 lines
4.3 KiB
Python
"""
|
|
Tests de sécurité — Settings (SMTP)
|
|
Vérifie :
|
|
- Le mot de passe SMTP est absent des réponses GET (write_only)
|
|
- Authentification requise
|
|
"""
|
|
|
|
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, ProfileRole
|
|
from Establishment.models import Establishment
|
|
from Settings.models import SMTPSettings
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def create_user_with_role(email):
|
|
user = Profile.objects.create_user(
|
|
username=email, email=email, password="TestPass!123"
|
|
)
|
|
est = Establishment.objects.create(
|
|
name=f"Ecole {email}", address="1 rue Test",
|
|
total_capacity=50, establishment_type=[1]
|
|
)
|
|
ProfileRole.objects.create(
|
|
profile=user, role_type=ProfileRole.RoleType.PROFIL_ADMIN,
|
|
establishment=est, is_active=True
|
|
)
|
|
return user, est
|
|
|
|
|
|
OVERRIDE = dict(
|
|
CACHES={'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}},
|
|
SESSION_ENGINE='django.contrib.sessions.backends.db',
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tests
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@override_settings(**OVERRIDE)
|
|
class SMTPSettingsAuthTest(TestCase):
|
|
"""Authentification requise sur l'endpoint SMTP."""
|
|
|
|
def setUp(self):
|
|
self.client = APIClient()
|
|
self.url = reverse('Settings:smtp_settings')
|
|
|
|
def test_sans_auth_retourne_401(self):
|
|
response = self.client.get(self.url)
|
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
|
|
|
|
|
@override_settings(**OVERRIDE)
|
|
class SMTPPasswordNotExposedTest(TestCase):
|
|
"""
|
|
Le mot de passe SMTP ne doit jamais apparaître dans les réponses GET.
|
|
Avant la correction, smtp_password était retourné en clair à tout
|
|
utilisateur authentifié (incluant les parents).
|
|
"""
|
|
|
|
def setUp(self):
|
|
self.client = APIClient()
|
|
self.url = reverse('Settings:smtp_settings')
|
|
self.user, self.est = create_user_with_role('smtp_test@test.com')
|
|
SMTPSettings.objects.create(
|
|
establishment=self.est,
|
|
smtp_server='smtp.example.com',
|
|
smtp_port=587,
|
|
smtp_user='user@example.com',
|
|
smtp_password='super_secret_password_123',
|
|
use_tls=True,
|
|
)
|
|
|
|
def test_smtp_password_absent_de_la_reponse(self):
|
|
"""
|
|
GET /settings/smtp/ ne doit pas retourner smtp_password.
|
|
"""
|
|
token = str(RefreshToken.for_user(self.user).access_token)
|
|
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token}')
|
|
response = self.client.get(self.url, {'establishment_id': self.est.id})
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
data = response.json()
|
|
# Le mot de passe ne doit pas être dans la réponse (write_only)
|
|
self.assertNotIn(
|
|
'smtp_password', data,
|
|
"smtp_password ne doit pas être exposé dans les réponses API (OWASP A02 - Cryptographic Failures)"
|
|
)
|
|
# Vérification supplémentaire : la valeur secrète n'est pas dans la réponse brute
|
|
self.assertNotIn('super_secret_password_123', response.content.decode())
|
|
|
|
def test_smtp_password_accepte_en_ecriture(self):
|
|
"""
|
|
POST /settings/smtp/ doit accepter smtp_password (write_only ne bloque pas l'écriture).
|
|
"""
|
|
token = str(RefreshToken.for_user(self.user).access_token)
|
|
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token}')
|
|
payload = {
|
|
'establishment': self.est.id,
|
|
'smtp_server': 'smtp.newserver.com',
|
|
'smtp_port': 465,
|
|
'smtp_user': 'new@example.com',
|
|
'smtp_password': 'nouveau_mot_de_passe',
|
|
'use_tls': False,
|
|
'use_ssl': True,
|
|
}
|
|
from rest_framework.test import APIRequestFactory
|
|
response = self.client.post(self.url, data=payload, format='json')
|
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_201_CREATED])
|