diff --git a/pom.xml b/pom.xml
index c5f4dd4..40078d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -185,8 +185,10 @@
dotenv-java
2.3.1
-
-
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
diff --git a/src/main/java/edu/eci/cvds/prometeo/config/JwtRequestFilter.java b/src/main/java/edu/eci/cvds/prometeo/config/JwtRequestFilter.java
new file mode 100644
index 0000000..1f8e10d
--- /dev/null
+++ b/src/main/java/edu/eci/cvds/prometeo/config/JwtRequestFilter.java
@@ -0,0 +1,75 @@
+package edu.eci.cvds.prometeo.config;
+
+import edu.eci.cvds.prometeo.util.JwtUtil;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+import java.util.List;
+
+@Component
+public class JwtRequestFilter extends OncePerRequestFilter {
+
+ private final JwtUtil jwtUtil;
+
+ public JwtRequestFilter(JwtUtil jwtUtil) {
+ this.jwtUtil = jwtUtil;
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain chain)
+ throws ServletException, IOException {
+ final String authHeader = request.getHeader("Authorization");
+
+ System.out.println("🔍 Checking Authorization header...");
+ if (authHeader != null && authHeader.startsWith("Bearer ")) {
+ System.out.println("✅ Authorization header found: " + authHeader);
+
+ try {
+ var claims = jwtUtil.extractClaims(authHeader);
+
+ String username = claims.get("userName", String.class);
+ String role = claims.get("role", String.class).toUpperCase();
+ String name = claims.get("name", String.class);
+ String idCard = claims.get("id", String.class);
+
+ // Log extracted claims
+ System.out.println("✅ JWT Claims extracted:");
+ System.out.println("username = " + username);
+ System.out.println("role = " + role);
+ System.out.println("name = " + name);
+ System.out.println("idCard = " + idCard);
+
+ // Save attributes in the request
+ request.setAttribute("username", username);
+ request.setAttribute("role", role);
+ request.setAttribute("name", name);
+ request.setAttribute("institutionalId", idCard);
+
+ // Set authentication in SecurityContext
+ var authorities = List.of(new SimpleGrantedAuthority("ROLE_" + role));
+ var auth = new UsernamePasswordAuthenticationToken(username, null, authorities);
+ SecurityContextHolder.getContext().setAuthentication(auth);
+
+ } catch (Exception e) {
+ System.out.println("❌ Error extracting JWT claims: " + e.getMessage());
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
+ return;
+ }
+ } else {
+ System.out.println("⚠️ Authorization header is missing or does not start with 'Bearer '");
+ }
+
+ chain.doFilter(request, response);
+ System.out.println("🔍 Post-filter role: " + request.getAttribute("role"));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/eci/cvds/prometeo/config/LoggingFilter.java b/src/main/java/edu/eci/cvds/prometeo/config/LoggingFilter.java
new file mode 100644
index 0000000..84fb9e6
--- /dev/null
+++ b/src/main/java/edu/eci/cvds/prometeo/config/LoggingFilter.java
@@ -0,0 +1,24 @@
+package edu.eci.cvds.prometeo.config;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+public class LoggingFilter extends OncePerRequestFilter {
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain)
+ throws ServletException, IOException {
+ System.out.println("🔍 Request URI: " + request.getRequestURI());
+ System.out.println("🔍 Method: " + request.getMethod());
+ System.out.println("🔍 All Attributes: ");
+ request.getAttributeNames().asIterator().forEachRemaining(attr ->
+ System.out.println(attr + " = " + request.getAttribute(attr))
+ );
+ filterChain.doFilter(request, response);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/eci/cvds/prometeo/config/SecurityConfig.java b/src/main/java/edu/eci/cvds/prometeo/config/SecurityConfig.java
index ba9a8af..b28a9b2 100644
--- a/src/main/java/edu/eci/cvds/prometeo/config/SecurityConfig.java
+++ b/src/main/java/edu/eci/cvds/prometeo/config/SecurityConfig.java
@@ -1,26 +1,40 @@
package edu.eci.cvds.prometeo.config;
+import lombok.extern.slf4j.Slf4j;
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.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfig {
-
+
+ private final JwtRequestFilter jwtRequestFilter;
+
+ public SecurityConfig(JwtRequestFilter jwtRequestFilter) {
+ this.jwtRequestFilter = jwtRequestFilter;
+ }
+
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- // Configuración que desactiva toda la seguridad
http
- .csrf(csrf -> csrf.disable())
- .authorizeHttpRequests(authorize -> authorize
- .requestMatchers("/**").permitAll()
- )
- .formLogin(form -> form.disable())
- .httpBasic(basic -> basic.disable());
-
+ .csrf(csrf -> csrf.disable())
+ .authorizeHttpRequests(auth -> auth
+
+ .requestMatchers("/api/users/create").authenticated()
+
+ .requestMatchers("/api/users/trainer/**").hasRole("TRAINER")
+
+ .anyRequest().hasAnyRole("TRAINER", "STUDENT", "ADMIN")
+ )
+ .formLogin(form -> form.disable())
+ .httpBasic(basic -> basic.disable())
+ .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
+ .addFilterBefore(new LoggingFilter(), JwtRequestFilter.class);
return http.build();
}
}
\ No newline at end of file
diff --git a/src/main/java/edu/eci/cvds/prometeo/controller/UserController.java b/src/main/java/edu/eci/cvds/prometeo/controller/UserController.java
index 0edda18..20d581e 100644
--- a/src/main/java/edu/eci/cvds/prometeo/controller/UserController.java
+++ b/src/main/java/edu/eci/cvds/prometeo/controller/UserController.java
@@ -6,6 +6,7 @@
import edu.eci.cvds.prometeo.repository.RoutineRepository;
import edu.eci.cvds.prometeo.service.*;
import edu.eci.cvds.prometeo.dto.*;
+import jakarta.servlet.http.HttpServletRequest;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
@@ -116,6 +117,53 @@ public ResponseEntity> getUsersByRole(
@Parameter(description = "Role name") @PathVariable String role) {
return ResponseEntity.ok(userService.getUsersByRole(role));
}
+
+ @PostMapping("/create")
+ @Operation(summary = "Create user from JWT", description = "Creates a new user using data from the JWT token")
+ @ApiResponse(responseCode = "201", description = "User created successfully",
+ content = @Content(schema = @Schema(implementation = User.class)))
+ @ApiResponse(responseCode = "400", description = "Invalid input data")
+ @ApiResponse(responseCode = "409", description = "User already exists")
+ public ResponseEntity createUser(HttpServletRequest request) {
+ try {
+ String institutionalId = (String) request.getAttribute("institutionalId");
+ String username = (String) request.getAttribute("username");
+ String name = (String) request.getAttribute("name");
+ String role = (String) request.getAttribute("role");
+
+ // Log extracted attributes
+ System.out.println("🔍 Extracted attributes:");
+ System.out.println("institutionalId = " + institutionalId);
+ System.out.println("username = " + username);
+ System.out.println("name = " + name);
+ System.out.println("role = " + role);
+
+ // Validate attributes
+ if (institutionalId == null || name == null || role == null) {
+ System.out.println("❌ Missing required attributes");
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
+ }
+
+ // Check if user already exists
+ if (userService.userExistsByInstitutionalId(institutionalId)) {
+ System.out.println("⚠️ User with institutionalId " + institutionalId + " already exists");
+ return ResponseEntity.status(HttpStatus.CONFLICT).body(null);
+ }
+
+ // Create user
+ UserDTO userDTO = new UserDTO();
+ userDTO.setInstitutionalId(institutionalId);
+ userDTO.setName(name);
+ userDTO.setRole(role);
+
+ User createdUser = userService.createUser(userDTO);
+ return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
+
+ } catch (Exception e) {
+ System.out.println("❌ Error creating user: " + e.getMessage());
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
+ }
+}
@PutMapping("/{id}")
@Operation(summary = "Update user", description = "Updates a user's basic information")
@@ -127,15 +175,6 @@ public ResponseEntity updateUser(
return ResponseEntity.ok(userService.updateUser(id, userDTO));
}
- @PostMapping
- @Operation(summary = "Create user", description = "Creates a new user in the system")
- @ApiResponse(responseCode = "201", description = "User created successfully", content = @Content(schema = @Schema(implementation = User.class)))
- public ResponseEntity createUser(
- @Parameter(description = "User data") @RequestBody UserDTO userDTO) {
- User createdUser = userService.createUser(userDTO);
- return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
- }
-
@DeleteMapping("/{id}")
@Operation(summary = "Delete user", description = "Deletes a user from the system")
@ApiResponse(responseCode = "200", description = "User deleted successfully")
@@ -835,6 +874,8 @@ public ResponseEntity> getTrainerSessions(
@Parameter(description = "Trainer ID") @PathVariable UUID trainerId) {
List