🔧 Sécurisation des contrôleurs : gestion des accès par rôles (admin, secrétaire, chauffagiste)

This commit is contained in:
sermandm 2025-04-25 15:40:06 +02:00
parent 28f63a5363
commit b20dc2e00f
9 changed files with 159 additions and 43 deletions

View File

@ -12,10 +12,10 @@ class AuthenticationController extends AbstractController
#[Route(path: '/', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response
{
// get the login error if there is one
// Get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
// Last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('login/index.html.twig', [
@ -29,4 +29,4 @@ class AuthenticationController extends AbstractController
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
}

View File

@ -20,6 +20,9 @@ class CalendrierController extends AbstractController
#[Route('/secretaire', name: 'app_calendrier_indexSecretaire')]
public function indexSecretaire(): Response
{
// Check that only admins and secretaries can view this page
$this->denyAccessUnlessGranted('ROLE_SECRETAIRE');
return $this->render('calendrier/indexSecretaire.html.twig', [
'controller_name' => 'CalendrierController',
]);
@ -28,20 +31,13 @@ class CalendrierController extends AbstractController
#[Route('/chauffagiste', name: 'app_calendrier_indexChauffagiste')]
public function indexChauffagiste(): Response
{
// Ensure chauffagiste only sees their own calendar
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
// filter logic for individual chauffagiste calendar
}
return $this->render('calendrier/indexChauffagiste.html.twig', [
'controller_name' => 'CalendrierController',
]); }
// créer intervention : secretaire + admin
// créer un nouveau rdv
// modifier un rdv
// supprimer un rdv
// choisir un chauffagiste
// deconnexion
// créer intervention : chauffagiste
// modifier un rdv
// deconnexion
// quand on créer une rdv, alors cela nous redirige vers la page intervention
]);
}
}

View File

@ -4,26 +4,28 @@ namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
class DashboardController extends AbstractController
{
#[Route('/admin/dashboard', name: 'admin_dashboard')]
public function admin(): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
return $this->render('dashboard/admin.html.twig');
}
#[Route('/secretaire/dashboard', name: 'secretaire_dashboard')]
public function secretaire(): Response
{
$this->denyAccessUnlessGranted('ROLE_SECRETAIRE');
return $this->render('dashboard/secretaire.html.twig');
}
#[Route('/chauffagiste/dashboard', name: 'chauffagiste_dashboard')]
public function chauffagiste(): Response
{
$this->denyAccessUnlessGranted('ROLE_CHAUFFAGISTE');
return $this->render('dashboard/chauffagiste.html.twig');
}
}

View File

@ -17,8 +17,13 @@ final class FaultController extends AbstractController
#[Route(name: 'app_fault_index', methods: ['GET'])]
public function index(FaultRepository $faultRepository): Response
{
// Filtrage des pannes : un chauffagiste ne peut voir que ses pannes
$faults = $this->isGranted('ROLE_CHAUFFAGISTE')
? $faultRepository->findByUser($this->getUser()) // Filtre les pannes par utilisateur
: $faultRepository->findAll(); // Admins voient toutes les pannes
return $this->render('fault/index.html.twig', [
'faults' => $faultRepository->findAll(),
'faults' => $faults,
]);
}
@ -30,6 +35,11 @@ final class FaultController extends AbstractController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Associe la panne à un chauffagiste si c'est un chauffagiste
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
$fault->setUser($this->getUser());
}
$entityManager->persist($fault);
$entityManager->flush();
@ -45,6 +55,11 @@ final class FaultController extends AbstractController
#[Route('/{id}', name: 'app_fault_show', methods: ['GET'])]
public function show(Fault $fault): Response
{
// Un chauffagiste ne peut voir que ses pannes
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $fault->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas voir cette panne.');
}
return $this->render('fault/show.html.twig', [
'fault' => $fault,
]);
@ -53,6 +68,11 @@ final class FaultController extends AbstractController
#[Route('/{id}/edit', name: 'app_fault_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Fault $fault, EntityManagerInterface $entityManager): Response
{
// Un chauffagiste ne peut modifier que ses propres pannes
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $fault->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier cette panne.');
}
$form = $this->createForm(FaultType::class, $fault);
$form->handleRequest($request);
@ -71,7 +91,12 @@ final class FaultController extends AbstractController
#[Route('/{id}', name: 'app_fault_delete', methods: ['POST'])]
public function delete(Request $request, Fault $fault, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete'.$fault->getId(), $request->getPayload()->getString('_token'))) {
// Un chauffagiste ne peut supprimer que ses propres pannes
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $fault->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer cette panne.');
}
if ($this->isCsrfTokenValid('delete'.$fault->getId(), $request->get('csrf_token'))) {
$entityManager->remove($fault);
$entityManager->flush();
}

View File

@ -17,8 +17,16 @@ final class InterventionController extends AbstractController
#[Route(name: 'app_intervention_index', methods: ['GET'])]
public function index(InterventionRepository $interventionRepository): Response
{
// Vérifier si l'utilisateur est un chauffagiste, pour filtrer ses interventions
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
$interventions = $interventionRepository->findByUser($this->getUser()); // On filtre par utilisateur connecté
} else {
// Les autres rôles (admin) peuvent voir toutes les interventions
$interventions = $interventionRepository->findAll();
}
return $this->render('intervention/index.html.twig', [
'interventions' => $interventionRepository->findAll(),
'interventions' => $interventions,
]);
}
@ -30,6 +38,11 @@ final class InterventionController extends AbstractController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Si l'utilisateur est un chauffagiste, on associe l'intervention à lui
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
$intervention->setUser($this->getUser());
}
$entityManager->persist($intervention);
$entityManager->flush();
@ -45,6 +58,11 @@ final class InterventionController extends AbstractController
#[Route('/{id}', name: 'app_intervention_show', methods: ['GET'])]
public function show(Intervention $intervention): Response
{
// Vérifier si l'utilisateur peut voir cette intervention (chauffagiste ne voit que ses interventions)
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $intervention->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas voir cette intervention.');
}
return $this->render('intervention/show.html.twig', [
'intervention' => $intervention,
]);
@ -53,6 +71,11 @@ final class InterventionController extends AbstractController
#[Route('/{id}/edit', name: 'app_intervention_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Intervention $intervention, EntityManagerInterface $entityManager): Response
{
// Vérification de sécurité : un chauffagiste ne peut modifier que ses propres interventions
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $intervention->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier cette intervention.');
}
$form = $this->createForm(InterventionType::class, $intervention);
$form->handleRequest($request);
@ -71,7 +94,12 @@ final class InterventionController extends AbstractController
#[Route('/{id}', name: 'app_intervention_delete', methods: ['POST'])]
public function delete(Request $request, Intervention $intervention, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete'.$intervention->getId(), $request->getPayload()->getString('_token'))) {
// Vérification de sécurité : un chauffagiste ne peut supprimer que ses propres interventions
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $intervention->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer cette intervention.');
}
if ($this->isCsrfTokenValid('delete'.$intervention->getId(), $request->get('csrf_token'))) {
$entityManager->remove($intervention);
$entityManager->flush();
}

View File

@ -17,6 +17,7 @@ final class SkillController extends AbstractController
#[Route(name: 'app_skill_index', methods: ['GET'])]
public function index(SkillRepository $skillRepository): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
return $this->render('skill/admin.html.twig', [
'skills' => $skillRepository->findAll(),
]);
@ -25,6 +26,7 @@ final class SkillController extends AbstractController
#[Route('/new', name: 'app_skill_new', methods: ['GET', 'POST'])]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$skill = new Skill();
$form = $this->createForm(SkillType::class, $skill);
$form->handleRequest($request);
@ -53,6 +55,7 @@ final class SkillController extends AbstractController
#[Route('/{id}/edit', name: 'app_skill_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Skill $skill, EntityManagerInterface $entityManager): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$form = $this->createForm(SkillType::class, $skill);
$form->handleRequest($request);
@ -71,7 +74,8 @@ final class SkillController extends AbstractController
#[Route('/{id}', name: 'app_skill_delete', methods: ['POST'])]
public function delete(Request $request, Skill $skill, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete'.$skill->getId(), $request->getPayload()->getString('_token'))) {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
if ($this->isCsrfTokenValid('delete'.$skill->getId(), $request->get('csrf_token'))) {
$entityManager->remove($skill);
$entityManager->flush();
}

View File

@ -53,6 +53,11 @@ final class StockController extends AbstractController
#[Route('/{id}/edit', name: 'app_stock_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Stock $stock, EntityManagerInterface $entityManager): Response
{
// Si un chauffagiste essaie de modifier un stock d'admin
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier ce stock.');
}
$form = $this->createForm(StockType::class, $stock);
$form->handleRequest($request);
@ -71,7 +76,7 @@ final class StockController extends AbstractController
#[Route('/{id}', name: 'app_stock_delete', methods: ['POST'])]
public function delete(Request $request, Stock $stock, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete'.$stock->getId(), $request->getPayload()->getString('_token'))) {
if ($this->isCsrfTokenValid('delete'.$stock->getId(), $request->get('csrf_token'))) {
$entityManager->remove($stock);
$entityManager->flush();
}

View File

@ -9,13 +9,15 @@ use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
#[Route('/user')]
final class UserController extends AbstractController
/**
* @Route("/user")
*/
class UserController extends AbstractController
{
#[Route(name: 'app_user_index', methods: ['GET'])]
/**
* @Route("/", name="app_user_index", methods={"GET"})
*/
public function index(UserRepository $userRepository): Response
{
return $this->render('user/index.html.twig', [
@ -23,19 +25,16 @@ final class UserController extends AbstractController
]);
}
#[Route('/new', name: 'app_user_new', methods: ['GET', 'POST'])]
public function new(Request $request, EntityManagerInterface $entityManager, UserPasswordHasherInterface $passwordHasher): Response
/**
* @Route("/new", name="app_user_new", methods={"GET", "POST"})
*/
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$user = new Utilisateur();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Hash du mot de passe
$plainPassword = $form->get('plainPassword')->getData();
$hashedPassword = $passwordHasher->hashPassword($user, $plainPassword);
$user->setPassword($hashedPassword);
$entityManager->persist($user);
$entityManager->flush();
@ -48,7 +47,9 @@ final class UserController extends AbstractController
]);
}
#[Route('/{id}', name: 'app_user_show', methods: ['GET'])]
/**
* @Route("/{id}", name="app_user_show", methods={"GET"})
*/
public function show(Utilisateur $user): Response
{
return $this->render('user/show.html.twig', [
@ -56,9 +57,24 @@ final class UserController extends AbstractController
]);
}
#[Route('/{id}/edit', name: 'app_user_edit', methods: ['GET', 'POST'])]
/**
* @Route("/{id}/edit", name="app_user_edit", methods={"GET", "POST"})
*/
public function edit(Request $request, Utilisateur $user, EntityManagerInterface $entityManager): Response
{
// Si l'utilisateur est un secrétaire et qu'il essaie de modifier un autre secrétaire
if ($this->isGranted('ROLE_SECRETAIRE') && $user->hasRole('ROLE_SECRETAIRE')) {
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier un autre secrétaire.');
}
// Si l'utilisateur est un chauffagiste et qu'il essaie de modifier un admin
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $user->hasRole('ROLE_ADMIN')) {
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier un admin.');
}
// On s'assure que seul un admin peut éditer un autre admin
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
@ -74,10 +90,25 @@ final class UserController extends AbstractController
]);
}
#[Route('/{id}', name: 'app_user_delete', methods: ['POST'])]
/**
* @Route("/{id}", name="app_user_delete", methods={"POST"})
*/
public function delete(Request $request, Utilisateur $user, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete'.$user->getId(), $request->getPayload()->getString('_token'))) {
// Si l'utilisateur est un secrétaire et qu'il essaie de supprimer un autre secrétaire
if ($this->isGranted('ROLE_SECRETAIRE') && $user->hasRole('ROLE_SECRETAIRE')) {
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer un autre secrétaire.');
}
// Si l'utilisateur est un chauffagiste et qu'il essaie de supprimer un admin
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $user->hasRole('ROLE_ADMIN')) {
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer un admin.');
}
// On s'assure que seul un admin peut supprimer un autre admin
$this->denyAccessUnlessGranted('ROLE_ADMIN');
if ($this->isCsrfTokenValid('delete' . $user->getId(), $request->get('csrf_token'))) {
$entityManager->remove($user);
$entityManager->flush();
}

View File

@ -17,8 +17,13 @@ final class VehicleController extends AbstractController
#[Route(name: 'app_vehicle_index', methods: ['GET'])]
public function index(VehicleRepository $vehicleRepository): Response
{
// Admin peut voir tous les véhicules, chauffagiste ne peut voir que ses véhicules
$vehicles = $this->isGranted('ROLE_CHAUFFAGISTE')
? $vehicleRepository->findByUser($this->getUser()) // Filtre les véhicules par utilisateur
: $vehicleRepository->findAll(); // Les admins voient tout
return $this->render('vehicle/index.html.twig', [
'vehicles' => $vehicleRepository->findAll(),
'vehicles' => $vehicles,
]);
}
@ -30,6 +35,11 @@ final class VehicleController extends AbstractController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Si l'utilisateur est un chauffagiste, on associe le véhicule à lui
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
$vehicle->setUser($this->getUser());
}
$entityManager->persist($vehicle);
$entityManager->flush();
@ -45,6 +55,11 @@ final class VehicleController extends AbstractController
#[Route('/{id}', name: 'app_vehicle_show', methods: ['GET'])]
public function show(Vehicle $vehicle): Response
{
// Si l'utilisateur est un chauffagiste et essaie de voir un véhicule d'un autre chauffagiste, on bloque
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $vehicle->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas voir ce véhicule.');
}
return $this->render('vehicle/show.html.twig', [
'vehicle' => $vehicle,
]);
@ -53,6 +68,11 @@ final class VehicleController extends AbstractController
#[Route('/{id}/edit', name: 'app_vehicle_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Vehicle $vehicle, EntityManagerInterface $entityManager): Response
{
// Vérifier si un chauffagiste essaie de modifier un véhicule d'un autre chauffagiste
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $vehicle->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier ce véhicule.');
}
$form = $this->createForm(VehicleType::class, $vehicle);
$form->handleRequest($request);
@ -71,7 +91,12 @@ final class VehicleController extends AbstractController
#[Route('/{id}', name: 'app_vehicle_delete', methods: ['POST'])]
public function delete(Request $request, Vehicle $vehicle, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete'.$vehicle->getId(), $request->getPayload()->getString('_token'))) {
// Vérification de sécurité : un chauffagiste ne peut supprimer un véhicule d'un autre chauffagiste
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $vehicle->getUser() !== $this->getUser()) {
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer ce véhicule.');
}
if ($this->isCsrfTokenValid('delete'.$vehicle->getId(), $request->get('csrf_token'))) {
$entityManager->remove($vehicle);
$entityManager->flush();
}