Skip to content
Snippets Groups Projects
Commit 403eec11 authored by Fatima Ezzahra Majidi's avatar Fatima Ezzahra Majidi
Browse files

Merge branch 'master' into 'main'

Ajout de sécurité

See merge request !6
parents 464a26d1 9a1bfece
Branches
No related tags found
1 merge request!6Ajout de sécurité
Showing
with 242 additions and 7 deletions
......@@ -87,6 +87,26 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
......
......@@ -2,18 +2,46 @@ package com.example.gestionstagesbackend.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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()) // ✅ Disable CSRF protection
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll() // ✅ Allow all requests (for testing)
);
.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();
}
}
package com.example.gestionstagesbackend.controllers;
import com.example.gestionstagesbackend.model.User;
import com.example.gestionstagesbackend.services.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.Map;
@RestController
@RequestMapping("/api/auth")
@CrossOrigin(origins = "*")
public class AuthController {
private final UserService userService;
private final AuthenticationManager authenticationManager;
public AuthController(UserService userService, AuthenticationManager authenticationManager) {
this.userService = userService;
this.authenticationManager = authenticationManager;
}
@PostMapping("/register")
public ResponseEntity<?> registerUser(@RequestBody User user) {
if (userService.findByUsername(user.getUsername()).isPresent()) {
return ResponseEntity.badRequest().body(Map.of("message", "Username is already taken"));
}
if (user.getRoles() == null || user.getRoles().isEmpty()) {
user.setRoles(Collections.singleton("ROLE_ETUDIANT")); // Default role
}
User newUser = userService.registerUser(user);
return ResponseEntity.ok(newUser);
}
@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)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
return ResponseEntity.ok(Map.of("message", "Login successful"));
}
}
......@@ -105,19 +105,38 @@ public class CandidacyController {
}
Candidacy candidacy = existingCandidacy.get();
// Update Student
if (updatedCandidacy.getStudent() != null && updatedCandidacy.getStudent().getId() != null) {
candidacy.setStudent(updatedCandidacy.getStudent());
}
// Update Stage
if (updatedCandidacy.getStage() != null && updatedCandidacy.getStage().getId() != null) {
candidacy.setStage(updatedCandidacy.getStage());
}
// Update UnivSupervisor
if (updatedCandidacy.getUnivSupervisor() != null) {
candidacy.setUnivSupervisor(updatedCandidacy.getUnivSupervisor());
}
// Update Request State (FirstRequest, Accepted, Declined)
if (updatedCandidacy.getRequestState() != null) {
candidacy.setRequestState(updatedCandidacy.getRequestState());
}
// Update Accepted State (wait, inProgress, terminated)
if (updatedCandidacy.getAcceptedState() != null) {
candidacy.setAcceptedState(updatedCandidacy.getAcceptedState());
}
// Save the updated candidacy
Candidacy savedCandidacy = candidacyService.saveCandidacy(candidacy);
return ResponseEntity.ok(savedCandidacy);
}
}
package com.example.gestionstagesbackend.enums;
public enum Role {
ROLE_ETUDIANT, // voir liste étudiant, voir liste stages
ROLE_ENTREPRISE, // CRUD stage
ROLE_SUPERVISEUR, // CRUD étudiant, voir liste stages
ROLE_ADMIN // Tous les droits
}
package com.example.gestionstagesbackend.model;
import com.example.gestionstagesbackend.enums.AcceptedCandidacyStateKind;
import com.example.gestionstagesbackend.enums.CandidacyRequestState;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.*;
......@@ -17,7 +19,7 @@ public class Candidacy {
@ManyToOne
@JoinColumn(name = "stage_id", nullable = false)
@JsonIgnoreProperties({"candidacies", "enterprise"}) // Ensures that Candidacy includes Stage but avoids loops
@JsonIgnoreProperties({"candidacies"}) // Ensures that Candidacy includes Stage but avoids loops
private Stage stage;
// suppression de @JsonIgnoreProperties pour inclure Stage in response
......@@ -27,12 +29,22 @@ public class Candidacy {
@JsonIgnoreProperties({"supervisedStages"}) // Prevents recursion
private UnivSupervisor univSupervisor;
// Enum to store the request state (FirstRequest, Accepted, Declined)
@Enumerated(EnumType.STRING)
private CandidacyRequestState requestState = CandidacyRequestState.FirstRequest;
// Enum to store the accepted candidacy state (wait, inProgress, terminated)
@Enumerated(EnumType.STRING)
private AcceptedCandidacyStateKind acceptedState = AcceptedCandidacyStateKind.wait;
public Candidacy() {}
public Candidacy(Student student, Stage stage, UnivSupervisor univSupervisor) {
this.student = student;
this.stage = stage;
this.univSupervisor = univSupervisor;
this.requestState = CandidacyRequestState.FirstRequest; // Default state
this.acceptedState = AcceptedCandidacyStateKind.wait; // Default state
}
public Long getId() { return id; }
......@@ -46,4 +58,11 @@ public class Candidacy {
public UnivSupervisor getUnivSupervisor() { return univSupervisor; }
public void setUnivSupervisor(UnivSupervisor univSupervisor) { this.univSupervisor = univSupervisor; }
public CandidacyRequestState getRequestState() { return requestState; }
public void setRequestState(CandidacyRequestState requestState) { this.requestState = requestState; }
public AcceptedCandidacyStateKind getAcceptedState() { return acceptedState; }
public void setAcceptedState(AcceptedCandidacyStateKind acceptedState) { this.acceptedState = acceptedState; }
}
......@@ -3,7 +3,7 @@ package com.example.gestionstagesbackend.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.*;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.util.stream.Collectors;
@Entity
public class Enterprise {
......@@ -14,9 +14,18 @@ public class Enterprise {
private String address;
@OneToMany(mappedBy = "enterprise", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
//@JsonManagedReference // Ensures that stages are included in Enterprise JSON responses
@JsonIgnoreProperties({"enterprise"}) // Avoid infinite recursion
private List<Stage> stages;
/*@Transient // This field is not stored in the database
public List<Candidacy> getCandidacies() {
if (stages != null) {
return stages.stream()
.flatMap(stage -> stage.getCandidacies().stream()) // Collect all candidacies
.collect(Collectors.toList());
}
return List.of(); // Return an empty list if no stages
}*/
public Enterprise() {}
......
package com.example.gestionstagesbackend.model;
import jakarta.persistence.*;
import java.util.Set;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
private String password;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> roles; // ["ROLE_ETUDIANT", "ROLE_ENTREPRISE", "ROLE_SUPERVISEUR", "ROLE_ADMIN"]
public User() {}
public User(String username, String email, 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 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; }
}
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);
}
package com.example.gestionstagesbackend.services;
import com.example.gestionstagesbackend.model.User;
import com.example.gestionstagesbackend.repositories.UserRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public User registerUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword())); // Hash password
return userRepository.save(user);
}
public Optional<User> findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment