From cc421481294fd460892a5f271753c2b1cb01f078 Mon Sep 17 00:00:00 2001
From: fatima ezzahra majidi <fatima-ezzahra.majidi.etu@univ-lille.fr>
Date: Fri, 7 Mar 2025 04:34:57 +0000
Subject: [PATCH] =?UTF-8?q?renforcement=20de=20s=C3=A9curit=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Config/SecurityConfig.java                | 47 ----------
 .../GestionStagesBackendApplication.java      |  5 +-
 .../config/SecurityConfig.java                | 80 ++++++++++++++++
 .../controllers/AdminController.java          | 17 ++++
 .../controllers/AuthController.java           | 67 ++++++++++++--
 .../controllers/CandidacyController.java      | 10 +-
 .../controllers/EnterpriseController.java     |  8 +-
 .../controllers/StageController.java          | 15 +--
 .../controllers/StudentController.java        | 14 ++-
 .../controllers/UnivSupervisorController.java |  8 +-
 .../gestionstagesbackend/model/User.java      | 91 ++++++++++++++++---
 .../repositories/UserRepository.java          |  3 +-
 .../services/UserService.java                 | 50 +++++++++-
 13 files changed, 316 insertions(+), 99 deletions(-)
 delete mode 100644 src/main/java/com/example/gestionstagesbackend/Config/SecurityConfig.java
 create mode 100644 src/main/java/com/example/gestionstagesbackend/config/SecurityConfig.java
 create mode 100644 src/main/java/com/example/gestionstagesbackend/controllers/AdminController.java

diff --git a/src/main/java/com/example/gestionstagesbackend/Config/SecurityConfig.java b/src/main/java/com/example/gestionstagesbackend/Config/SecurityConfig.java
deleted file mode 100644
index 781796f..0000000
--- a/src/main/java/com/example/gestionstagesbackend/Config/SecurityConfig.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.example.gestionstagesbackend.Config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.web.SecurityFilterChain;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
-import org.springframework.security.authentication.AuthenticationManager;
-
-@Configuration
-@EnableWebSecurity
-@EnableMethodSecurity(prePostEnabled = true) // Enables @PreAuthorize
-public class SecurityConfig {
-
-    @Bean
-    public PasswordEncoder passwordEncoder() {
-        return new BCryptPasswordEncoder();
-    }
-
-    @Bean
-    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
-        return authenticationConfiguration.getAuthenticationManager();
-    }
-
-    @Bean
-    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-        http
-                .csrf(csrf -> csrf.disable())
-                .authorizeHttpRequests(auth -> auth
-                        .requestMatchers("/api/auth/**").permitAll() // Public routes
-                        .requestMatchers("/api/students/**").hasAnyRole("SUPERVISEUR", "ADMIN")
-                        .requestMatchers("/api/stages/**").hasAnyRole("ENTREPRISE", "ADMIN")
-                        .requestMatchers("/api/enterprises/**").hasRole("ADMIN")
-                        .requestMatchers("/api/candidacies/**").hasAnyRole("ETUDIANT", "ADMIN")
-                        .anyRequest().authenticated()
-                )
-                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
-
-        return http.build();
-    }
-}
diff --git a/src/main/java/com/example/gestionstagesbackend/GestionStagesBackendApplication.java b/src/main/java/com/example/gestionstagesbackend/GestionStagesBackendApplication.java
index 23df20b..d7f85ea 100644
--- a/src/main/java/com/example/gestionstagesbackend/GestionStagesBackendApplication.java
+++ b/src/main/java/com/example/gestionstagesbackend/GestionStagesBackendApplication.java
@@ -12,8 +12,5 @@ public class GestionStagesBackendApplication {
         SpringApplication.run(GestionStagesBackendApplication.class, args);
     }
 
-    @Bean
-    public BCryptPasswordEncoder passwordEncoder() {
-        return new BCryptPasswordEncoder();
-    }
+
 }
diff --git a/src/main/java/com/example/gestionstagesbackend/config/SecurityConfig.java b/src/main/java/com/example/gestionstagesbackend/config/SecurityConfig.java
new file mode 100644
index 0000000..26b1c00
--- /dev/null
+++ b/src/main/java/com/example/gestionstagesbackend/config/SecurityConfig.java
@@ -0,0 +1,80 @@
+package com.example.gestionstagesbackend.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+@Configuration
+public class SecurityConfig {
+
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
+    @Bean
+    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
+        return authenticationConfiguration.getAuthenticationManager();
+    }
+
+    @Bean
+    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+        http
+                .cors(cors -> cors.configurationSource(corsConfigurationSource()))  // Enable CORS
+                .csrf(csrf -> csrf.disable())  // Disable CSRF for APIs
+                .authorizeHttpRequests(auth -> auth
+                        // Allow everyone to access login, register, and logout
+                        .requestMatchers("/api/auth/login", "/api/auth/logout", "/api/auth/register").permitAll()
+
+                        // Allow OPTIONS requests for CORS preflight
+                        .requestMatchers("/**").permitAll()
+
+                        // Role-based access
+                        .requestMatchers("/api/students").hasRole("ETUDIANT")
+                        .requestMatchers("/api/students/**").hasRole("ETUDIANT")
+                        .requestMatchers("/api/stages").hasRole("ETUDIANT")
+                        .requestMatchers("/api/stages/**").hasRole("ENTREPRISE")
+                        .requestMatchers("/api/students").hasRole("SUPERVISEUR")
+                        .requestMatchers("/api/students/**").hasRole("SUPERVISEUR")
+                        .requestMatchers("/api/stages").hasRole("SUPERVISEUR")
+                        .requestMatchers("/api/stages/**").hasRole("SUPERVISEUR")
+                        .requestMatchers("/api/enterprises/add").hasRole("ENTREPRISE")
+                        .requestMatchers("/api/enterprises/update").hasRole("ENTREPRISE")
+                        .requestMatchers("/api/enterprises/delete").hasRole("ENTREPRISE")
+                        .requestMatchers("/**").hasRole("ADMIN")
+
+                        // Any other request requires authentication
+                        .anyRequest().authenticated()
+                )
+                .formLogin()
+                .and()
+                .httpBasic();
+
+        return http.build();
+    }
+
+    @Bean
+    public CorsConfigurationSource corsConfigurationSource() {
+        CorsConfiguration configuration = new CorsConfiguration();
+        configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // Frontend URL
+        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); // Allow these HTTP methods
+        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); // Allow these headers
+        configuration.setAllowCredentials(true); // Allow cookies/auth headers
+
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", configuration);
+        return source;
+    }
+}
diff --git a/src/main/java/com/example/gestionstagesbackend/controllers/AdminController.java b/src/main/java/com/example/gestionstagesbackend/controllers/AdminController.java
new file mode 100644
index 0000000..4603fb9
--- /dev/null
+++ b/src/main/java/com/example/gestionstagesbackend/controllers/AdminController.java
@@ -0,0 +1,17 @@
+package com.example.gestionstagesbackend.controllers;
+
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
+@RequestMapping("/admin")
+public class AdminController {
+
+    @GetMapping("/dashboard")
+    public String adminDashboard() {
+        return "Welcome, Admin!";
+    }
+}
diff --git a/src/main/java/com/example/gestionstagesbackend/controllers/AuthController.java b/src/main/java/com/example/gestionstagesbackend/controllers/AuthController.java
index 19f6cd7..04135e8 100644
--- a/src/main/java/com/example/gestionstagesbackend/controllers/AuthController.java
+++ b/src/main/java/com/example/gestionstagesbackend/controllers/AuthController.java
@@ -2,6 +2,9 @@ package com.example.gestionstagesbackend.controllers;
 
 import com.example.gestionstagesbackend.model.User;
 import com.example.gestionstagesbackend.services.UserService;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -11,11 +14,13 @@ import org.springframework.web.bind.annotation.*;
 
 import java.util.Collections;
 import java.util.Map;
+import java.util.Optional;
 
 @RestController
 @RequestMapping("/api/auth")
-@CrossOrigin(origins = "*")
+@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
 public class AuthController {
+
     private final UserService userService;
     private final AuthenticationManager authenticationManager;
 
@@ -24,31 +29,77 @@ public class AuthController {
         this.authenticationManager = authenticationManager;
     }
 
+    /** REGISTER NEW USER **/
     @PostMapping("/register")
     public ResponseEntity<?> registerUser(@RequestBody User user) {
         if (userService.findByUsername(user.getUsername()).isPresent()) {
+            System.out.println("❌ Registration failed: Username " + user.getUsername() + " is already taken.");
             return ResponseEntity.badRequest().body(Map.of("message", "Username is already taken"));
         }
 
+        // Assign default role if none is provided
         if (user.getRoles() == null || user.getRoles().isEmpty()) {
             user.setRoles(Collections.singleton("ROLE_ETUDIANT")); // Default role
         }
 
+        // Save user with hashed password
         User newUser = userService.registerUser(user);
-        return ResponseEntity.ok(newUser);
+        System.out.println("✅ User registered successfully: " + newUser.getUsername());
+        return ResponseEntity.ok("User registered successfully");
     }
 
-
+    /** LOGIN USER (No JWT, Just Plain Text Response) **/
     @PostMapping("/login")
     public ResponseEntity<?> loginUser(@RequestBody Map<String, String> loginRequest) {
         String username = loginRequest.get("username");
         String password = loginRequest.get("password");
 
-        Authentication authentication = authenticationManager.authenticate(
-                new UsernamePasswordAuthenticationToken(username, password)
-        );
+        System.out.println("🔍 Attempting login for: " + username);
+
+        if (username == null || password == null) {
+            System.out.println("❌ Username or password is missing in the request.");
+            return ResponseEntity.status(400).body("Username and password are required");
+        }
+
+        Optional<User> user = userService.findByUsername(username);
+        if (user.isEmpty()) {
+            System.out.println("❌ User not found!");
+            return ResponseEntity.status(401).body("Invalid credentials");
+        }
+
+        System.out.println("✅ User found: " + username);
+
+        try {
+            Authentication authentication = authenticationManager.authenticate(
+                    new UsernamePasswordAuthenticationToken(username, password)
+            );
 
-        SecurityContextHolder.getContext().setAuthentication(authentication);
-        return ResponseEntity.ok(Map.of("message", "Login successful"));
+            // Update security context on successful authentication
+            SecurityContextHolder.getContext().setAuthentication(authentication);
+            System.out.println("✅ Login successful for user: " + username);
+            return ResponseEntity.ok("Login successful");
+        } catch (Exception e) {
+            System.out.println("❌ Authentication failed for user " + username + ": " + e.getMessage());
+            return ResponseEntity.status(401).body("Invalid username or password");
+        }
+
+    }
+    /** LOGOUT USER **/
+    @PostMapping("/logout")
+    public ResponseEntity<?> logoutUser(HttpServletRequest request, HttpServletResponse response) {
+        System.out.println("🔓 Logging out user: " + SecurityContextHolder.getContext().getAuthentication());
+
+        // Invalidate session
+        HttpSession session = request.getSession(false);
+        if (session != null) {
+            session.invalidate();
+        }
+
+        // Clear authentication
+        SecurityContextHolder.clearContext();
+
+        System.out.println("✅ Logout successful.");
+        return ResponseEntity.ok("Logout successful");
     }
+
 }
diff --git a/src/main/java/com/example/gestionstagesbackend/controllers/CandidacyController.java b/src/main/java/com/example/gestionstagesbackend/controllers/CandidacyController.java
index 94a5746..99034d7 100644
--- a/src/main/java/com/example/gestionstagesbackend/controllers/CandidacyController.java
+++ b/src/main/java/com/example/gestionstagesbackend/controllers/CandidacyController.java
@@ -9,6 +9,7 @@ import com.example.gestionstagesbackend.services.StudentService;
 import com.example.gestionstagesbackend.services.StageService;
 import com.example.gestionstagesbackend.services.UnivSupervisorService;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -16,7 +17,7 @@ import java.util.Optional;
 
 @RestController
 @RequestMapping("/api/candidacies")
-@CrossOrigin(origins = "*")
+@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
 public class CandidacyController {
     private final CandidacyService candidacyService;
     private final StudentService studentService;
@@ -31,7 +32,8 @@ public class CandidacyController {
         this.univSupervisorService = univSupervisorService;
     }
 
-    @PostMapping
+    //@PreAuthorize("hasRole('ETUDIANT') or hasRole('ADMIN')")
+    @PostMapping("/add")
     public ResponseEntity<?> createCandidacy(@RequestBody Candidacy candidacy) {
         if (candidacy.getStudent() == null || candidacy.getStudent().getId() == null) {
             return ResponseEntity.badRequest().body("Student ID is required");
@@ -69,11 +71,13 @@ public class CandidacyController {
         return ResponseEntity.ok(savedCandidacy);
     }
 
+    //@PreAuthorize("hasRole('ETUDIANT') or hasRole('ADMIN')")
     @GetMapping
     public ResponseEntity<List<Candidacy>> getAllCandidacies() {
         return ResponseEntity.ok(candidacyService.getAllCandidacies());
     }
 
+    //@PreAuthorize("hasRole('ETUDIANT') or hasRole('ADMIN')")
     @GetMapping("/{id}")
     public ResponseEntity<Candidacy> getCandidacyById(@PathVariable Long id) {
         Optional<Candidacy> optionalCandidacy = candidacyService.getCandidacyById(id);
@@ -87,6 +91,7 @@ public class CandidacyController {
         }
     }
 
+    //@PreAuthorize("hasRole('ETUDIANT') or hasRole('ADMIN')")
     @DeleteMapping("/{id}")
     public ResponseEntity<Void> deleteCandidacy(@PathVariable Long id) {
         if (!candidacyService.existsById(id)) {
@@ -96,6 +101,7 @@ public class CandidacyController {
         return ResponseEntity.noContent().build();
     }
 
+    //@PreAuthorize("hasRole('ETUDIANT') or hasRole('ADMIN')")
     @PutMapping("/{id}")
     public ResponseEntity<?> updateCandidacy(@PathVariable Long id, @RequestBody Candidacy updatedCandidacy) {
         Optional<Candidacy> existingCandidacy = candidacyService.getCandidacyById(id);
diff --git a/src/main/java/com/example/gestionstagesbackend/controllers/EnterpriseController.java b/src/main/java/com/example/gestionstagesbackend/controllers/EnterpriseController.java
index 4ac9c60..abd889e 100644
--- a/src/main/java/com/example/gestionstagesbackend/controllers/EnterpriseController.java
+++ b/src/main/java/com/example/gestionstagesbackend/controllers/EnterpriseController.java
@@ -10,7 +10,7 @@ import java.util.Optional;
 
 @RestController
 @RequestMapping("/api/enterprises")
-@CrossOrigin(origins = "*")
+@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
 public class EnterpriseController {
 
     private final EnterpriseService enterpriseService;
@@ -19,7 +19,7 @@ public class EnterpriseController {
         this.enterpriseService = enterpriseService;
     }
 
-    @PostMapping
+    @PostMapping("/add")
     public ResponseEntity<Enterprise> createEnterprise(@RequestBody Enterprise enterprise) {
         System.out.println("Received POST request: " + enterprise.getName() + ", " + enterprise.getAddress());
 
@@ -44,14 +44,14 @@ public class EnterpriseController {
                 .orElse(ResponseEntity.notFound().build());
     }
 
-    @DeleteMapping("/{id}")
+    @DeleteMapping("/delete/{id}")
     public ResponseEntity<Void> deleteEnterprise(@PathVariable Long id) {
         System.out.println("Deleting enterprise with ID: " + id);
         enterpriseService.deleteEnterprise(id);
         return ResponseEntity.noContent().build();
     }
 
-    @PutMapping("/{id}")
+    @PutMapping("/update/{id}")
     public ResponseEntity<?> updateEnterprise(@PathVariable Long id, @RequestBody Enterprise updatedEnterprise) {
         Optional<Enterprise> optionalEnterprise = enterpriseService.getEnterpriseById(id);
 
diff --git a/src/main/java/com/example/gestionstagesbackend/controllers/StageController.java b/src/main/java/com/example/gestionstagesbackend/controllers/StageController.java
index a3155a8..cb4ef17 100644
--- a/src/main/java/com/example/gestionstagesbackend/controllers/StageController.java
+++ b/src/main/java/com/example/gestionstagesbackend/controllers/StageController.java
@@ -5,6 +5,7 @@ import com.example.gestionstagesbackend.model.Enterprise;
 import com.example.gestionstagesbackend.services.StageService;
 import com.example.gestionstagesbackend.services.EnterpriseService;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -12,7 +13,7 @@ import java.util.Optional;
 
 @RestController
 @RequestMapping("/api/stages")
-@CrossOrigin(origins = "*")
+@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
 public class StageController {
     private final StageService stageService;
     private final EnterpriseService enterpriseService;
@@ -22,7 +23,8 @@ public class StageController {
         this.enterpriseService = enterpriseService;
     }
 
-    @PostMapping
+    //@PreAuthorize("hasRole('ROLE_ENTREPRISE') or hasRole('ROLE_ADMIN')")
+    @PostMapping("/add")
     public ResponseEntity<?> createStage(@RequestBody Stage stage) {
         if (stage.getEnterprise() == null || stage.getEnterprise().getId() == null) {
             return ResponseEntity.badRequest().body("Enterprise ID is required");
@@ -43,8 +45,7 @@ public class StageController {
         return fullStage.map(ResponseEntity::ok).orElse(ResponseEntity.ok(savedStage));
     }
 
-
-
+    //@PreAuthorize("hasRole('ROLE_SUPERVISEUR') or hasRole('ROLE_ETUDIANT') or hasRole('ROLE_ADMIN')")
     @GetMapping
     public ResponseEntity<List<Stage>> getAllStages() {
         return ResponseEntity.ok(stageService.getAllStages());
@@ -63,7 +64,8 @@ public class StageController {
     }
 
 
-    @PutMapping("/{id}")
+    //@PreAuthorize("hasRole('ROLE_ENTREPRISE') or hasRole('ROLE_ADMIN')")
+    @PutMapping("/update/{id}")
     public ResponseEntity<?> updateStage(@PathVariable Long id, @RequestBody Stage updatedStage) {
         Optional<Stage> optionalStage = stageService.getStageById(id);
 
@@ -86,7 +88,8 @@ public class StageController {
             return ResponseEntity.notFound().build();
         }
     }
-    @DeleteMapping("/{id}")
+    //@PreAuthorize("hasRole('ROLE_ENTREPRISE') or hasRole('ROLE_ADMIN')")
+    @DeleteMapping("/delete/{id}")
     public ResponseEntity<?> deleteStage(@PathVariable Long id) {
         Optional<Stage> optionalStage = stageService.getStageById(id);
 
diff --git a/src/main/java/com/example/gestionstagesbackend/controllers/StudentController.java b/src/main/java/com/example/gestionstagesbackend/controllers/StudentController.java
index f07a8ce..45f172d 100644
--- a/src/main/java/com/example/gestionstagesbackend/controllers/StudentController.java
+++ b/src/main/java/com/example/gestionstagesbackend/controllers/StudentController.java
@@ -5,6 +5,7 @@ import com.example.gestionstagesbackend.model.Student;
 import com.example.gestionstagesbackend.services.CandidacyService;
 import com.example.gestionstagesbackend.services.StudentService;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -12,7 +13,7 @@ import java.util.Optional;
 
 @RestController
 @RequestMapping("/api/students")
-@CrossOrigin(origins = "*")
+@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
 public class StudentController {
     private final StudentService studentService;
     private final CandidacyService candidacyService;
@@ -22,17 +23,20 @@ public class StudentController {
         this.candidacyService = candidacyService;
     }
 
-    @PostMapping
+    //@PreAuthorize("hasRole('ROLE_SUPERVISEUR') or hasRole('ROLE_ADMIN')")
+    @PostMapping("/add")
     public ResponseEntity<Student> createStudent(@RequestBody Student student) {
         Student savedStudent = studentService.saveStudent(student);
         return ResponseEntity.ok(savedStudent);
     }
 
+    //@PreAuthorize("hasRole('ROLE_SUPERVISEUR') or hasRole('ROLE_ETUDIANT') or hasRole('ROLE_ADMIN')")
     @GetMapping
     public ResponseEntity<List<Student>> getAllStudents() {
         return ResponseEntity.ok(studentService.getAllStudents());
     }
 
+    //@PreAuthorize("hasRole('ROLE_SUPERVISEUR') or hasRole('ROLE_ETUDIANT') or hasRole('ROLE_ADMIN')")
     @GetMapping("/{id}")
     public ResponseEntity<Student> getStudentById(@PathVariable Long id) {
         return studentService.getStudentById(id)
@@ -47,8 +51,8 @@ public class StudentController {
         return ResponseEntity.ok(candidacies);
     }
 
-    // ✅ PUT - Update student by ID
-    @PutMapping("/{id}")
+    //@PreAuthorize("hasRole('ROLE_SUPERVISEUR') or hasRole('ROLE_ADMIN')")
+    @PutMapping("/update/{id}")
     public ResponseEntity<Student> updateStudent(@PathVariable Long id, @RequestBody Student updatedStudent) {
         Optional<Student> optionalStudent = studentService.getStudentById(id);
 
@@ -65,7 +69,7 @@ public class StudentController {
     }
 
     // ✅ DELETE - Remove student by ID
-    @DeleteMapping("/{id}")
+    @DeleteMapping("/delete/{id}")
     public ResponseEntity<Void> deleteStudent(@PathVariable Long id) {
         studentService.deleteStudent(id);
         return ResponseEntity.noContent().build();
diff --git a/src/main/java/com/example/gestionstagesbackend/controllers/UnivSupervisorController.java b/src/main/java/com/example/gestionstagesbackend/controllers/UnivSupervisorController.java
index 186c6e0..2973a23 100644
--- a/src/main/java/com/example/gestionstagesbackend/controllers/UnivSupervisorController.java
+++ b/src/main/java/com/example/gestionstagesbackend/controllers/UnivSupervisorController.java
@@ -10,7 +10,7 @@ import java.util.Optional;
 
 @RestController
 @RequestMapping("/api/univsupervisors")
-@CrossOrigin(origins = "*")
+@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
 public class UnivSupervisorController {
     private final UnivSupervisorService univSupervisorService;
 
@@ -18,7 +18,7 @@ public class UnivSupervisorController {
         this.univSupervisorService = univSupervisorService;
     }
 
-    @PostMapping
+    @PostMapping("/add")
     public ResponseEntity<UnivSupervisor> createUnivSupervisor(@RequestBody UnivSupervisor univSupervisor) {
         UnivSupervisor savedUnivSupervisor = univSupervisorService.saveUnivSupervisor(univSupervisor);
         return ResponseEntity.ok(savedUnivSupervisor);
@@ -37,7 +37,7 @@ public class UnivSupervisorController {
     }
 
     // ✅ PUT - Update UnivSupervisor by ID
-    @PutMapping("/{id}")
+    @PutMapping("/update/{id}")
     public ResponseEntity<UnivSupervisor> updateUnivSupervisor(@PathVariable Long id, @RequestBody UnivSupervisor updatedSupervisor) {
         Optional<UnivSupervisor> optionalSupervisor = univSupervisorService.getUnivSupervisorById(id);
 
@@ -53,7 +53,7 @@ public class UnivSupervisorController {
     }
 
     // ✅ DELETE - Remove UnivSupervisor by ID
-    @DeleteMapping("/{id}")
+    @DeleteMapping("/delete/{id}")
     public ResponseEntity<Void> deleteUnivSupervisor(@PathVariable Long id) {
         univSupervisorService.deleteUnivSupervisor(id);
         return ResponseEntity.noContent().build();
diff --git a/src/main/java/com/example/gestionstagesbackend/model/User.java b/src/main/java/com/example/gestionstagesbackend/model/User.java
index 085a592..14ba595 100644
--- a/src/main/java/com/example/gestionstagesbackend/model/User.java
+++ b/src/main/java/com/example/gestionstagesbackend/model/User.java
@@ -1,40 +1,101 @@
 package com.example.gestionstagesbackend.model;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import jakarta.persistence.*;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 @Entity
 @Table(name = "users")
-public class User {
+public class User implements UserDetails { // ✅ Implements UserDetails
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Column(unique = true, nullable = false)
     private String username;
-    private String email;
+
+    @JsonIgnore
+    @Column(nullable = false)
     private String password;
 
     @ElementCollection(fetch = FetchType.EAGER)
-    private Set<String> roles; // ["ROLE_ETUDIANT", "ROLE_ENTREPRISE", "ROLE_SUPERVISEUR", "ROLE_ADMIN"]
+    @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"))
+    @Column(name = "role")
+    private Set<String> roles; // ✅ Roles stored in a separate table
 
     public User() {}
 
-    public User(String username, String email, String password, Set<String> roles) {
+    public User(String username, String password, Set<String> roles) {
         this.username = username;
-        this.email = email;
         this.password = password;
         this.roles = roles;
     }
 
-    public Long getId() { return id; }
-    public String getUsername() { return username; }
-    public String getEmail() { return email; }
-    public String getPassword() { return password; }
-    public Set<String> getRoles() { return roles; }
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
 
-    public void setId(Long id) { this.id = id; }
-    public void setUsername(String username) { this.username = username; }
-    public void setEmail(String email) { this.email = email; }
-    public void setPassword(String password) { this.password = password; }
-    public void setRoles(Set<String> roles) { this.roles = roles; }
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public Set<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(Set<String> roles) {
+        this.roles = roles;
+    }
+
+    // ✅ Implementing UserDetails methods
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return roles.stream().map(role -> (GrantedAuthority) () -> role).collect(Collectors.toSet());
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "User{id=" + id + ", username='" + username + "', roles=" + roles + "}";
+    }
 }
diff --git a/src/main/java/com/example/gestionstagesbackend/repositories/UserRepository.java b/src/main/java/com/example/gestionstagesbackend/repositories/UserRepository.java
index 80e7e38..ce9ec7d 100644
--- a/src/main/java/com/example/gestionstagesbackend/repositories/UserRepository.java
+++ b/src/main/java/com/example/gestionstagesbackend/repositories/UserRepository.java
@@ -2,10 +2,9 @@ package com.example.gestionstagesbackend.repositories;
 
 import com.example.gestionstagesbackend.model.User;
 import org.springframework.data.jpa.repository.JpaRepository;
+
 import java.util.Optional;
 
 public interface UserRepository extends JpaRepository<User, Long> {
     Optional<User> findByUsername(String username);
-    boolean existsByUsername(String username);
-    boolean existsByEmail(String email);
 }
diff --git a/src/main/java/com/example/gestionstagesbackend/services/UserService.java b/src/main/java/com/example/gestionstagesbackend/services/UserService.java
index 8617474..394867c 100644
--- a/src/main/java/com/example/gestionstagesbackend/services/UserService.java
+++ b/src/main/java/com/example/gestionstagesbackend/services/UserService.java
@@ -2,12 +2,18 @@ package com.example.gestionstagesbackend.services;
 
 import com.example.gestionstagesbackend.model.User;
 import com.example.gestionstagesbackend.repositories.UserRepository;
+import jakarta.annotation.PostConstruct;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
+
 import java.util.Optional;
+import java.util.Set;
 
 @Service
-public class UserService {
+public class UserService implements UserDetailsService {
     private final UserRepository userRepository;
     private final PasswordEncoder passwordEncoder;
 
@@ -16,12 +22,52 @@ public class UserService {
         this.passwordEncoder = passwordEncoder;
     }
 
+    public boolean checkPassword(String rawPassword, String encodedPassword) {
+        return passwordEncoder.matches(rawPassword, encodedPassword);
+    }
+
     public User registerUser(User user) {
-        user.setPassword(passwordEncoder.encode(user.getPassword())); // Hash password
+        if (user.getPassword() == null || user.getPassword().trim().isEmpty()) {
+            throw new IllegalArgumentException("Password cannot be null or empty");
+        }
+        user.setPassword(passwordEncoder.encode(user.getPassword())); // Hash password before saving
         return userRepository.save(user);
     }
 
+
     public Optional<User> findByUsername(String username) {
         return userRepository.findByUsername(username);
     }
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        User user = userRepository.findByUsername(username)
+                .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
+
+        // Convert to UserDetails for Spring Security
+        return org.springframework.security.core.userdetails.User
+                .withUsername(user.getUsername())
+                .password(user.getPassword())
+                .authorities(user.getRoles().toArray(new String[0])) // Convert roles to authorities
+                .build();
+    }
+
+    @PostConstruct
+    public void createDefaultUsers() {
+        createUserIfNotExists("admin", "admin123", Set.of("ROLE_ADMIN"));
+        createUserIfNotExists("etudiant", "etudiant123", Set.of("ROLE_ETUDIANT"));
+        createUserIfNotExists("entreprise", "entreprise123", Set.of("ROLE_ENTREPRISE"));
+        createUserIfNotExists("superviseur", "superviseur123", Set.of("ROLE_SUPERVISEUR"));
+    }
+
+    private void createUserIfNotExists(String username, String password, Set<String> roles) {
+        if (userRepository.findByUsername(username).isEmpty()) {
+            User user = new User();
+            user.setUsername(username);
+            user.setPassword(passwordEncoder.encode(password));
+            user.setRoles(roles);
+            userRepository.save(user);
+            System.out.println("✅ Created user: " + username + " with roles " + roles);
+        }
+    }
 }
-- 
GitLab