diff --git a/java/roomBooking/pom.xml b/java/roomBooking/pom.xml index 476f735b695a459292a258d72d89261c89dca993..07747352ee836f269490419f4944847975717ff0 100644 --- a/java/roomBooking/pom.xml +++ b/java/roomBooking/pom.xml @@ -49,6 +49,32 @@ <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-api</artifactId> + <version>0.11.5</version> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-impl</artifactId> + <version>0.11.5</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-jackson</artifactId> + <version>0.11.5</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <scope>provided</scope> + </dependency> </dependencies> <build> diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/auth/AuthController.java b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/AuthController.java new file mode 100644 index 0000000000000000000000000000000000000000..c47ba890b6d67fd87fb23f809ffa5ea3c69fc99a --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/AuthController.java @@ -0,0 +1,47 @@ +package com.uva.monolith.services.auth; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import com.uva.monolith.services.users.controllers.UserService; +import com.uva.monolith.services.users.models.User; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +@RestController +@RequestMapping("/api/auth") +public class AuthController { + + private final String SECRET_KEY = "clave_secreta"; + + @Autowired + private UserService userService; + + @PostMapping("/login") + public Map<String, String> login(@RequestBody LoginRequest loginRequest) { + User user = userService.findByEmail(loginRequest.getEmail()); + + if (user != null && userService.verifyPassword(loginRequest.getPassword(), user.getPassword())) { + String token = Jwts.builder() + .setSubject(user.getEmail()) + .signWith(new SecretKeySpec(SECRET_KEY.getBytes(), SignatureAlgorithm.HS256.getJcaName())) + .claim("email", user.getEmail()) + .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hora + .compact(); + + Map<String, String> response = new HashMap<>(); + response.put("token", token); + return response; + } + + throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Credenciales inválidas"); + } +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/auth/JwtAuthenticationFilter.java b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/JwtAuthenticationFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..2d33e24c716c5c5c87574da3234e9f7298023694 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/JwtAuthenticationFilter.java @@ -0,0 +1,48 @@ +package com.uva.monolith.services.auth; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.Filter; +import java.io.IOException; + +@Component +public class JwtAuthenticationFilter implements Filter { + + private final String SECRET_KEY = "clave_secreta"; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + String authHeader = httpRequest.getHeader("Authorization"); + + if (authHeader != null && authHeader.startsWith("Bearer ")) { + String token = authHeader.substring(7); + Claims claims = Jwts.parserBuilder() + .setSigningKey(SECRET_KEY.getBytes()) + .build() + .parseClaimsJws(token) + .getBody(); + + String username = claims.getSubject(); + if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + username, null, null); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + + chain.doFilter(request, response); + } + +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/auth/LoginRequest.java b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/LoginRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..62f9cb9e8bbb6a8b05489e4e3ec3024a7aff51b2 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/LoginRequest.java @@ -0,0 +1,23 @@ +package com.uva.monolith.services.auth; + +public class LoginRequest { + + private String email; + private String password; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/auth/SecurityConfig.java b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/SecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..4c4b89212472d596cd0ebd12933013e17ba68954 --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/auth/SecurityConfig.java @@ -0,0 +1,32 @@ +package com.uva.monolith.services.auth; + +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; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + private final JwtAuthenticationFilter jwtAuthenticationFilter; + + public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) { + this.jwtAuthenticationFilter = jwtAuthenticationFilter; + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.csrf(csrf -> csrf.disable()) + .authorizeHttpRequests(authorize -> authorize + .requestMatchers("/api/auth/login", "/api/auth/register").permitAll() // Rutas públicas + .requestMatchers("/api/users/**", "/api/hotels/**", "/api/reservas/**").authenticated() // Protegidas + ) + // Registra el filtro antes del filtro estándar de autenticación + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java index c097ef7d7c26443ff82da3860e1cf54362df94d2..eb71920dc9fdca9beb383e34110caf343f14b2e4 100644 --- a/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import com.uva.monolith.services.bookings.models.Booking; import com.uva.monolith.services.users.models.User; @@ -128,4 +129,6 @@ public class UserController { User user = userRepository.findById(id).orElseThrow(); return user.getBookings(); } + + } diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserService.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserService.java new file mode 100644 index 0000000000000000000000000000000000000000..136875b5f6ad32296af1ea8d960be2ae499d8dfc --- /dev/null +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserService.java @@ -0,0 +1,37 @@ +package com.uva.monolith.services.users.controllers; + +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.server.ResponseStatusException; + +import com.uva.monolith.services.users.models.User; + +import org.springframework.http.HttpStatus; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +import org.springframework.beans.factory.annotation.Autowired; +import com.uva.monolith.services.users.repositories.UserRepository; + +@Service +public class UserService { + + @Autowired + private UserRepository userRepository; + + private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + public boolean verifyPassword(String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + public String encodePassword(String password) { + return passwordEncoder.encode(password); + } + + @GetMapping("/users") + public User findByEmail(@RequestParam String email) { + return userRepository.findByEmail(email) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Usuario no encontrado")); +} +} diff --git a/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/User.java b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/User.java index 5c1f928c0bf0f273f27d890739801c89bdd9c9be..37d2eeab386dc694a10793c6d21a460aba3545df 100644 --- a/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/User.java +++ b/java/roomBooking/src/main/java/com/uva/monolith/services/users/models/User.java @@ -3,6 +3,8 @@ package com.uva.monolith.services.users.models; import java.time.LocalDate; import java.util.List; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.uva.monolith.services.bookings.models.Booking; @@ -89,8 +91,9 @@ public class User { return password; } - public void setPassword(String password) { - this.password = password; + public void setPassword(String rawPassword) { + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + this.password = encoder.encode(rawPassword); } public UserRol getRol() { @@ -120,4 +123,5 @@ public class User { public void setBookings(List<Booking> bookings) { this.bookings = bookings; } + }