Initial commit

This commit is contained in:
Dom
2026-03-05 01:20:14 +01:00
commit 2163e574c1
184 changed files with 354881 additions and 0 deletions

View File

@@ -0,0 +1,397 @@
"""
Tests unitaires pour le système de contrôle d'accès.
Ces tests vérifient l'authentification, l'autorisation RBAC,
et la gestion des sessions.
"""
import time
from datetime import datetime, timedelta
import pytest
from pipeline_mco_pmsi.security import AccessControl, Role, Permission
@pytest.fixture
def access_control():
"""Crée une instance d'AccessControl pour les tests."""
return AccessControl(session_duration_hours=1)
@pytest.fixture
def sample_users(access_control):
"""Crée des utilisateurs de test."""
tim = access_control.create_user(
username="tim_user",
password="password123",
role=Role.TIM,
email="tim@example.com",
full_name="TIM User"
)
responsable = access_control.create_user(
username="responsable_user",
password="password456",
role=Role.RESPONSABLE_DIM,
email="responsable@example.com",
full_name="Responsable DIM"
)
admin = access_control.create_user(
username="admin_user",
password="password789",
role=Role.ADMINISTRATEUR,
email="admin@example.com",
full_name="Admin User"
)
return {"tim": tim, "responsable": responsable, "admin": admin}
class TestAccessControlInit:
"""Tests d'initialisation du système de contrôle d'accès."""
def test_init_with_defaults(self):
"""Test l'initialisation avec valeurs par défaut."""
ac = AccessControl()
assert ac.session_duration_hours == 8
def test_init_with_custom_duration(self):
"""Test l'initialisation avec durée personnalisée."""
ac = AccessControl(session_duration_hours=12)
assert ac.session_duration_hours == 12
class TestCreateUser:
"""Tests de création d'utilisateurs."""
def test_create_user_success(self, access_control):
"""Test la création réussie d'un utilisateur."""
user = access_control.create_user(
username="test_user",
password="test_password",
role=Role.TIM,
email="test@example.com",
full_name="Test User"
)
assert user.username == "test_user"
assert user.role == Role.TIM
assert user.email == "test@example.com"
assert user.full_name == "Test User"
assert user.is_active is True
assert user.password_hash != "test_password" # Le mot de passe doit être hashé
assert ":" in user.password_hash # Format salt:hash
def test_create_user_duplicate_username(self, access_control):
"""Test que la création échoue si l'utilisateur existe déjà."""
access_control.create_user(
username="duplicate_user",
password="password",
role=Role.TIM
)
with pytest.raises(ValueError, match="existe déjà"):
access_control.create_user(
username="duplicate_user",
password="password2",
role=Role.RESPONSABLE_DIM
)
def test_create_user_different_roles(self, access_control):
"""Test la création d'utilisateurs avec différents rôles."""
tim = access_control.create_user("tim", "pass", Role.TIM)
responsable = access_control.create_user("resp", "pass", Role.RESPONSABLE_DIM)
admin = access_control.create_user("admin", "pass", Role.ADMINISTRATEUR)
assert tim.role == Role.TIM
assert responsable.role == Role.RESPONSABLE_DIM
assert admin.role == Role.ADMINISTRATEUR
class TestAuthenticate:
"""Tests d'authentification."""
def test_authenticate_success(self, access_control, sample_users):
"""Test l'authentification réussie."""
session = access_control.authenticate("tim_user", "password123")
assert session is not None
assert session.user_id == sample_users["tim"].user_id
assert session.session_id is not None
assert len(session.session_id) > 0
assert session.expires_at > datetime.now()
def test_authenticate_wrong_password(self, access_control, sample_users):
"""Test l'authentification avec mauvais mot de passe."""
session = access_control.authenticate("tim_user", "wrong_password")
assert session is None
def test_authenticate_unknown_user(self, access_control):
"""Test l'authentification avec utilisateur inconnu."""
session = access_control.authenticate("unknown_user", "password")
assert session is None
def test_authenticate_inactive_user(self, access_control, sample_users):
"""Test l'authentification avec compte inactif."""
# Désactiver l'utilisateur
access_control.deactivate_user(sample_users["tim"].user_id)
# Tenter de se connecter
session = access_control.authenticate("tim_user", "password123")
assert session is None
def test_authenticate_with_ip_address(self, access_control, sample_users):
"""Test l'authentification avec adresse IP."""
session = access_control.authenticate(
"tim_user",
"password123",
ip_address="192.168.1.1"
)
assert session is not None
assert session.ip_address == "192.168.1.1"
class TestGetUserFromSession:
"""Tests de récupération d'utilisateur depuis une session."""
def test_get_user_from_valid_session(self, access_control, sample_users):
"""Test la récupération avec session valide."""
session = access_control.authenticate("tim_user", "password123")
user = access_control.get_user_from_session(session.session_id)
assert user is not None
assert user.username == "tim_user"
assert user.role == Role.TIM
def test_get_user_from_invalid_session(self, access_control):
"""Test la récupération avec session invalide."""
user = access_control.get_user_from_session("invalid_session_id")
assert user is None
def test_get_user_from_expired_session(self, access_control, sample_users):
"""Test la récupération avec session expirée."""
# Créer un AccessControl avec durée très courte
ac = AccessControl(session_duration_hours=0)
ac.create_user("test", "pass", Role.TIM)
# Créer une session qui expire immédiatement
session = ac.authenticate("test", "pass")
# Attendre que la session expire
time.sleep(0.1)
# Modifier manuellement l'expiration pour simuler une session expirée
ac._sessions[session.session_id] = type(session)(
session_id=session.session_id,
user_id=session.user_id,
created_at=session.created_at,
expires_at=datetime.now() - timedelta(seconds=1),
ip_address=session.ip_address
)
user = ac.get_user_from_session(session.session_id)
assert user is None
# La session expirée devrait être supprimée
assert session.session_id not in ac._sessions
class TestHasPermission:
"""Tests de vérification des permissions."""
def test_tim_has_view_codes_permission(self, access_control, sample_users):
"""Test que TIM a la permission VIEW_CODES."""
session = access_control.authenticate("tim_user", "password123")
assert access_control.has_permission(session.session_id, Permission.VIEW_CODES) is True
def test_tim_has_correct_code_permission(self, access_control, sample_users):
"""Test que TIM a la permission CORRECT_CODE."""
session = access_control.authenticate("tim_user", "password123")
assert access_control.has_permission(session.session_id, Permission.CORRECT_CODE) is True
def test_tim_no_manage_users_permission(self, access_control, sample_users):
"""Test que TIM n'a pas la permission MANAGE_USERS."""
session = access_control.authenticate("tim_user", "password123")
assert access_control.has_permission(session.session_id, Permission.MANAGE_USERS) is False
def test_responsable_has_export_audit_permission(self, access_control, sample_users):
"""Test que Responsable DIM a la permission EXPORT_AUDIT."""
session = access_control.authenticate("responsable_user", "password456")
assert access_control.has_permission(session.session_id, Permission.EXPORT_AUDIT) is True
def test_responsable_no_manage_users_permission(self, access_control, sample_users):
"""Test que Responsable DIM n'a pas la permission MANAGE_USERS."""
session = access_control.authenticate("responsable_user", "password456")
assert access_control.has_permission(session.session_id, Permission.MANAGE_USERS) is False
def test_admin_has_all_permissions(self, access_control, sample_users):
"""Test que Admin a toutes les permissions."""
session = access_control.authenticate("admin_user", "password789")
# Tester quelques permissions
assert access_control.has_permission(session.session_id, Permission.VIEW_CODES) is True
assert access_control.has_permission(session.session_id, Permission.MANAGE_USERS) is True
assert access_control.has_permission(session.session_id, Permission.EXPORT_AUDIT) is True
assert access_control.has_permission(session.session_id, Permission.MANAGE_REFERENTIELS) is True
def test_has_permission_invalid_session(self, access_control):
"""Test la vérification avec session invalide."""
assert access_control.has_permission("invalid_session", Permission.VIEW_CODES) is False
class TestRequirePermission:
"""Tests de vérification stricte des permissions."""
def test_require_permission_success(self, access_control, sample_users):
"""Test la vérification réussie d'une permission."""
session = access_control.authenticate("tim_user", "password123")
user = access_control.require_permission(session.session_id, Permission.VIEW_CODES)
assert user is not None
assert user.username == "tim_user"
def test_require_permission_denied(self, access_control, sample_users):
"""Test la vérification échouée d'une permission."""
session = access_control.authenticate("tim_user", "password123")
with pytest.raises(PermissionError, match="Permission refusée"):
access_control.require_permission(session.session_id, Permission.MANAGE_USERS)
def test_require_permission_invalid_session(self, access_control):
"""Test la vérification avec session invalide."""
with pytest.raises(PermissionError, match="Session invalide"):
access_control.require_permission("invalid_session", Permission.VIEW_CODES)
class TestLogout:
"""Tests de déconnexion."""
def test_logout_success(self, access_control, sample_users):
"""Test la déconnexion réussie."""
session = access_control.authenticate("tim_user", "password123")
result = access_control.logout(session.session_id)
assert result is True
# La session ne devrait plus exister
user = access_control.get_user_from_session(session.session_id)
assert user is None
def test_logout_invalid_session(self, access_control):
"""Test la déconnexion avec session invalide."""
result = access_control.logout("invalid_session")
assert result is False
class TestDeactivateUser:
"""Tests de désactivation d'utilisateurs."""
def test_deactivate_user_success(self, access_control, sample_users):
"""Test la désactivation réussie d'un utilisateur."""
# Créer une session
session = access_control.authenticate("tim_user", "password123")
# Désactiver l'utilisateur
result = access_control.deactivate_user(sample_users["tim"].user_id)
assert result is True
# La session devrait être supprimée
user = access_control.get_user_from_session(session.session_id)
assert user is None
# L'utilisateur ne devrait plus pouvoir se connecter
new_session = access_control.authenticate("tim_user", "password123")
assert new_session is None
def test_deactivate_user_invalid_id(self, access_control):
"""Test la désactivation avec ID invalide."""
result = access_control.deactivate_user("invalid_user_id")
assert result is False
class TestGetUserPermissions:
"""Tests de récupération des permissions."""
def test_get_tim_permissions(self, access_control, sample_users):
"""Test la récupération des permissions TIM."""
session = access_control.authenticate("tim_user", "password123")
permissions = access_control.get_user_permissions(session.session_id)
assert Permission.VIEW_CODES in permissions
assert Permission.CORRECT_CODE in permissions
assert Permission.VALIDATE_STAY in permissions
assert Permission.MANAGE_USERS not in permissions
def test_get_responsable_permissions(self, access_control, sample_users):
"""Test la récupération des permissions Responsable DIM."""
session = access_control.authenticate("responsable_user", "password456")
permissions = access_control.get_user_permissions(session.session_id)
assert Permission.VIEW_CODES in permissions
assert Permission.EXPORT_AUDIT in permissions
assert Permission.MANAGE_RULES in permissions
assert Permission.MANAGE_USERS not in permissions
def test_get_admin_permissions(self, access_control, sample_users):
"""Test la récupération des permissions Admin."""
session = access_control.authenticate("admin_user", "password789")
permissions = access_control.get_user_permissions(session.session_id)
# Admin devrait avoir toutes les permissions
assert len(permissions) == len(Permission)
assert Permission.MANAGE_USERS in permissions
def test_get_permissions_invalid_session(self, access_control):
"""Test la récupération avec session invalide."""
permissions = access_control.get_user_permissions("invalid_session")
assert len(permissions) == 0
class TestPasswordHashing:
"""Tests de hachage des mots de passe."""
def test_password_is_hashed(self, access_control):
"""Test que le mot de passe est hashé."""
user = access_control.create_user("test", "password123", Role.TIM)
# Le hash ne devrait pas être le mot de passe en clair
assert user.password_hash != "password123"
# Le hash devrait contenir un salt
assert ":" in user.password_hash
def test_same_password_different_hashes(self, access_control):
"""Test que le même mot de passe produit des hashes différents (salt aléatoire)."""
user1 = access_control.create_user("user1", "password", Role.TIM)
user2 = access_control.create_user("user2", "password", Role.TIM)
# Les hashes devraient être différents (salt différent)
assert user1.password_hash != user2.password_hash
def test_password_verification(self, access_control):
"""Test la vérification du mot de passe."""
user = access_control.create_user("test", "password123", Role.TIM)
# Le bon mot de passe devrait fonctionner
assert access_control._verify_password("password123", user.password_hash) is True
# Un mauvais mot de passe ne devrait pas fonctionner
assert access_control._verify_password("wrong_password", user.password_hash) is False