diff --git a/java/services/bookings/src/main/java/com/uva/api/bookings/config/SecurityConfig.java b/java/services/bookings/src/main/java/com/uva/api/bookings/config/SecurityConfig.java index 9bd46e972889c4cd425281a2308c80e08c85ef12..dbc66924e5e70689f66bc0b90c4e33ef4b08e18c 100644 --- a/java/services/bookings/src/main/java/com/uva/api/bookings/config/SecurityConfig.java +++ b/java/services/bookings/src/main/java/com/uva/api/bookings/config/SecurityConfig.java @@ -60,6 +60,7 @@ public class SecurityConfig { .authorizeHttpRequests(authorize -> authorize // Permitir OPTIONS sin autenticación .requestMatchers(OPTIONS, "/**").permitAll() + // Restring acceso .requestMatchers(GET, "/bookings*").authenticated() diff --git a/java/services/bookings/src/main/java/com/uva/api/bookings/models/external/users/UserRol.java b/java/services/bookings/src/main/java/com/uva/api/bookings/models/external/users/UserRol.java index 08f1f40dbed9870b29703925495b3b58d77403eb..6fe25fd2dab50a65d630728f35d4165e75958bcc 100644 --- a/java/services/bookings/src/main/java/com/uva/api/bookings/models/external/users/UserRol.java +++ b/java/services/bookings/src/main/java/com/uva/api/bookings/models/external/users/UserRol.java @@ -1,5 +1,5 @@ package com.uva.api.bookings.models.external.users; public enum UserRol { - ADMIN, HOTEL_ADMIN, CLIENT + ADMIN, MANAGER, CLIENT } diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/apis/TokenAPI.java b/java/services/hotels/src/main/java/com/uva/api/hotels/apis/TokenAPI.java index 4e5c5dc2cc9f4f0168a5f98aac469bd9b09e8f50..9fbad4321bf13778b77a152bba94c7155d8926be 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/apis/TokenAPI.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/apis/TokenAPI.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.JsonNode; -import com.uva.api.hotels.models.external.JwtData; +import com.uva.api.hotels.models.external.jwt.JwtData; @Component public class TokenAPI { diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/config/SecurityConfig.java b/java/services/hotels/src/main/java/com/uva/api/hotels/config/SecurityConfig.java index 17bb9475d5e8d654f333b654c1e991476a471d0e..800461c93bb53192077ed9dc5d2b897ed644da14 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/config/SecurityConfig.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/config/SecurityConfig.java @@ -3,49 +3,83 @@ package com.uva.api.hotels.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import static org.springframework.http.HttpMethod.*; 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; import com.uva.api.hotels.filter.JwtAuthenticationFilter; +import com.uva.api.hotels.models.external.jwt.Service; +import com.uva.api.hotels.models.external.users.UserRol; +import static com.uva.api.hotels.models.external.users.UserRol.*; @Configuration @EnableWebSecurity public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; + private final String[] SERVICES = flat(Service.values()); public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) { this.jwtAuthenticationFilter = jwtAuthenticationFilter; } + private String[] flat(UserRol... roles) { + return java.util.Arrays.stream(roles) + .map(Enum::toString) + .map(role -> String.format("ROLE_%s", role)) + .toArray(String[]::new); + } + + private String[] flat(Service... services) { + return java.util.Arrays.stream(services) + .map(Enum::toString) + .toArray(String[]::new); + } + + private String[] join(String[]... authority) { + return java.util.Arrays.stream(authority) + .flatMap(java.util.Arrays::stream) + .toArray(String[]::new); + } + + /** + * All services and specified roles + * + * @param roles + * @return + */ + private String[] anyService(UserRol... roles) { + return join(flat(roles), SERVICES); + } + @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http.csrf(csrf -> csrf.disable()); - // .authorizeHttpRequests(authorize -> authorize - // // Permitir OPTIONS sin autenticación - // .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() - // // Acceso restringido a usuarios y administradores - // .requestMatchers("users", "users/**").hasAnyRole( - // UserRol.CLIENT.toString(), UserRol.HOTEL_ADMIN.toString(), - // UserRol.ADMIN.toString()) - // // Acceso restringido a gestores de hoteles y administradores - // .requestMatchers(HttpMethod.GET, "hotels", "hotels/*").hasAnyRole( - // UserRol.CLIENT.toString(), UserRol.HOTEL_ADMIN.toString(), - // UserRol.ADMIN.toString()) - - // .requestMatchers("hotels", "hotels/**") - // .hasAnyRole(UserRol.ADMIN.toString(), UserRol.HOTEL_ADMIN.toString()) - // // Acceso restringido a cualquier usuario del sistema - // .requestMatchers("bookings", "bookings/**") - // .hasAnyRole(UserRol.ADMIN.toString(), UserRol.HOTEL_ADMIN.toString(), - // UserRol.CLIENT.toString()) - // // Rechazar el resto - // .anyRequest().denyAll()) - // // Registra el filtro antes del filtro estándar de autenticación - // .addFilterBefore(jwtAuthenticationFilter, - // UsernamePasswordAuthenticationFilter.class); + http.csrf(csrf -> csrf.disable()) + .authorizeHttpRequests(authorize -> authorize + // Permitir OPTIONS sin autenticación + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() + // Acceso restringido + .requestMatchers(GET, "/hotels*", "/hotels/**").authenticated() + + .requestMatchers(POST, "/hotels*") + .hasAnyAuthority(flat(ADMIN, MANAGER)) + + .requestMatchers(DELETE, "/hotels*") + .hasAnyAuthority(anyService(ADMIN)) + + .requestMatchers(DELETE, "/hotels/{id}") + .hasAnyAuthority(flat(ADMIN, MANAGER)) + + .requestMatchers(PATCH, "/hotels/{id}/rooms/{rid}") + .hasAnyAuthority(flat(ADMIN, MANAGER)) + + // Rechazar el resto + .anyRequest().denyAll()) + // Registra el filtro antes del filtro estándar de autenticación + .addFilterBefore(jwtAuthenticationFilter, + UsernamePasswordAuthenticationFilter.class); return http.build(); } diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/controllers/HotelController.java b/java/services/hotels/src/main/java/com/uva/api/hotels/controllers/HotelController.java index a23e50106d223fe78b9ac4a40c01320f204d5fa9..b60bf510d446f8cc2e91a18e13f009018235288d 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/controllers/HotelController.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/controllers/HotelController.java @@ -1,19 +1,17 @@ package com.uva.api.hotels.controllers; -import java.util.List; import java.util.Map; import java.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import com.uva.api.hotels.exceptions.InvalidRequestException; import com.uva.api.hotels.models.Hotel; -import com.uva.api.hotels.models.Room; import com.uva.api.hotels.services.HotelService; +import com.uva.api.hotels.utils.Utils; @RestController @RequestMapping("hotels") @@ -23,63 +21,68 @@ public class HotelController { private HotelService hotelService; @GetMapping - public List<Hotel> getAllHotels( + public ResponseEntity<?> getAllHotels( + @RequestHeader(value = "Authorization", required = true) String authorization, @RequestParam(required = false) Integer managerId, @RequestParam(required = false) LocalDate start, @RequestParam(required = false) LocalDate end) { - return hotelService.getAllHotels(managerId, start, end); + String token = Utils.getToken(authorization); + return hotelService.getAllHotels(token, managerId, start, end); } @PostMapping public ResponseEntity<?> addHotel(@RequestBody Hotel hotel) { - System.out.println(hotel.toString()); - Hotel savedHotel = hotelService.addHotel(hotel); - return new ResponseEntity<>(savedHotel, HttpStatus.CREATED); + return hotelService.addHotel(hotel); } @GetMapping("/{id}") - public Hotel getHotelById(@PathVariable int id) { - return hotelService.getHotelById(id); + public ResponseEntity<?> getHotelById( + @RequestHeader(value = "Authorization", required = true) String authorization, + @PathVariable int id) { + String token = Utils.getToken(authorization); + return hotelService.getHotelById(token, id); } @DeleteMapping public ResponseEntity<?> deleteHotelsByManagerId( + @RequestHeader(value = "Authorization", required = true) String authorization, @RequestParam(required = true) Integer managerId) { - List<Hotel> hotels = hotelService.deleteHotelsByManagerId(managerId); - return new ResponseEntity<>(hotels, HttpStatus.OK); + String token = Utils.getToken(authorization); + return hotelService.deleteHotelsByManagerId(token, managerId); } @DeleteMapping("/{id}") @Transactional - public ResponseEntity<?> deleteHotel(@PathVariable Integer id) { - hotelService.deleteHotel(id); - return ResponseEntity.ok().build(); + public ResponseEntity<?> deleteHotel( + @RequestHeader(value = "Authorization", required = true) String authorization, + @PathVariable Integer id) { + String token = Utils.getToken(authorization); + return hotelService.deleteHotel(token, id); } @GetMapping("/{hotelId}/rooms") - public ResponseEntity<List<Room>> getRoomsFromHotel( + public ResponseEntity<?> getRoomsFromHotel( @PathVariable int hotelId, @RequestParam(required = false) LocalDate start, @RequestParam(required = false) LocalDate end) { - List<Room> rooms = hotelService.getRoomsFromHotel(hotelId, start, end); - return new ResponseEntity<>(rooms, HttpStatus.OK); + return hotelService.getRoomsFromHotel(hotelId, start, end); } @PatchMapping("/{hotelId}/rooms/{roomId}") - public ResponseEntity<Room> updateRoomAvailability( + public ResponseEntity<?> updateRoomAvailability( + @RequestHeader(value = "Authorization", required = true) String authorization, @PathVariable int hotelId, @PathVariable int roomId, @RequestBody Map<String, Boolean> body) { + String token = Utils.getToken(authorization); if (!body.containsKey("available")) { throw new InvalidRequestException("El campo 'available' es obligatorio"); } - Room updatedRoom = hotelService.updateRoomAvailability(hotelId, roomId, body.get("available")); - return new ResponseEntity<>(updatedRoom, HttpStatus.OK); + return hotelService.updateRoomAvailability(token, hotelId, roomId, body.get("available")); } @GetMapping("/{hotelId}/rooms/{roomId}") - public Room getRoomByIdFromHotel( - @PathVariable int hotelId, @PathVariable int roomId) { + public ResponseEntity<?> getRoomByIdFromHotel(@PathVariable int hotelId, @PathVariable int roomId) { return hotelService.getRoomByIdFromHotel(hotelId, roomId); } } diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/filter/JwtAuthenticationFilter.java b/java/services/hotels/src/main/java/com/uva/api/hotels/filter/JwtAuthenticationFilter.java index 8f1c296e127da4191970f99fe379ec0d701add00..05bc768cdd2a7c98fbc0b508fb228b4c0506cf58 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/filter/JwtAuthenticationFilter.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/filter/JwtAuthenticationFilter.java @@ -1,14 +1,14 @@ package com.uva.api.hotels.filter; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; -import com.uva.api.hotels.models.external.JwtData; +import com.uva.api.hotels.models.external.jwt.JwtData; +import com.uva.api.hotels.models.external.jwt.Service; import com.uva.api.hotels.models.external.users.UserRol; import com.uva.api.hotels.services.TokenService; @@ -42,16 +42,12 @@ public class JwtAuthenticationFilter implements Filter { return service.decodeToken(token); } catch (Exception ex) { System.err.println( - "[" + LocalDateTime.now().toString() + "] Error de verificación del token"); + "[" + LocalDateTime.now().toString() + "] Error de verificación del token\n"); ex.printStackTrace(System.err); return null; } } - private String formatRole(UserRol rol) { - return String.format("ROLE_%s", rol.toString()); - } - @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @@ -59,38 +55,47 @@ public class JwtAuthenticationFilter implements Filter { HttpServletRequest httpRequest = (HttpServletRequest) request; String token = getTokenFromRequest(httpRequest); - System.out.println("[" + LocalDateTime.now().toString() + "] TOKEN: " + token); + System.out.println("[" + LocalDateTime.now().toString() + "] TOKEN: " + token + "\n"); if (token != null) { JwtData jwt = validateAndDecodeToken(token); if (jwt != null) { - System.out.println("-->" + jwt + "<--"); + String email = jwt.getEmail(); + UserRol role = jwt.getRol(); + Service service = jwt.getService(); + String audience = jwt.getAudience(); + + System.out.println("[" + LocalDateTime.now().toString() + "] email=" + email + " role=" + role + + " service=" + service + " audience=" + audience + "\n"); + + if (audience != null) { + // Definimos la autoridad + String authorityValue = null; + if (audience.equals("INTERNAL") && service != null) { + authorityValue = service.toString(); + } else if (audience.equals("EXTERNAL") && role != null) { + authorityValue = String.format("ROLE_%s", role); + } + + if (authorityValue != null && + SecurityContextHolder.getContext().getAuthentication() == null) { + + // Crear la autoridad con la autoridad oportuna + SimpleGrantedAuthority authority = new SimpleGrantedAuthority(authorityValue); + + // Crear autenticación + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + email, + null, Collections.singletonList(authority)); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest)); + + // Establecer autenticación en el contexto de seguridad + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } } } - // String email = getEmailFromToken(jwt); - // UserRol role = getRoleFromToken(jwt); - // System.out.print(" email=" + email + " role=" + role + " "); - - // if (email != null && role != null && - // SecurityContextHolder.getContext().getAuthentication() == null) { - // // Crear la autoridad con el rol del token - // SimpleGrantedAuthority authority = new - // SimpleGrantedAuthority(formatRole(role)); - - // // Crear autenticación - // UsernamePasswordAuthenticationToken authentication = new - // UsernamePasswordAuthenticationToken(email, - // null, Collections.singletonList(authority)); - // authentication.setDetails(new - // WebAuthenticationDetailsSource().buildDetails(httpRequest)); - - // // Establecer autenticación en el contexto de seguridad - // SecurityContextHolder.getContext().setAuthentication(authentication); - // } - // } - // } - // Continuar con el resto de filtros chain.doFilter(request, response); } diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/models/Hotel.java b/java/services/hotels/src/main/java/com/uva/api/hotels/models/Hotel.java index a4be31035e2635163d684fe87fbc36e4067d2159..3d3f1ebc05c4ac14ee6d3bec2ed99541d480a022 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/models/Hotel.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/models/Hotel.java @@ -47,7 +47,7 @@ public class Hotel { private List<Room> rooms; @Column(name = "manager_id") - private int managerId; + private Integer managerId; public void setRooms(List<Room> rooms) { this.rooms = rooms; diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/JwtData.java b/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/jwt/JwtData.java similarity index 88% rename from java/services/hotels/src/main/java/com/uva/api/hotels/models/external/JwtData.java rename to java/services/hotels/src/main/java/com/uva/api/hotels/models/external/jwt/JwtData.java index 7041acc775b48282a84e1c6fac18ad536096e2c5..03f09ad65097861d031a5395fd752c2b0814aa93 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/JwtData.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/jwt/JwtData.java @@ -1,4 +1,4 @@ -package com.uva.api.hotels.models.external; +package com.uva.api.hotels.models.external.jwt; import java.util.Date; @@ -21,7 +21,7 @@ public class JwtData { private String name; private String email; private UserRol rol; - private String service; + private Service service; private String subject; private String audience; diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/jwt/Service.java b/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/jwt/Service.java new file mode 100644 index 0000000000000000000000000000000000000000..1a0e269b317e3cad56adc2fbc45676e612113fdd --- /dev/null +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/jwt/Service.java @@ -0,0 +1,8 @@ +package com.uva.api.hotels.models.external.jwt; + +public enum Service { + USERS, + HOTELS, + BOOKINGS, + AUTHENTICATION +} diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/users/UserRol.java b/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/users/UserRol.java index 2b5cdedbca232064015ed24a7f5154a4352a9365..9fd5e8be27352e34f1ffbfbd3173dfa9b556588e 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/users/UserRol.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/models/external/users/UserRol.java @@ -1,5 +1,5 @@ package com.uva.api.hotels.models.external.users; public enum UserRol { - ADMIN, CLIENT, HOTEL_ADMIN + ADMIN, CLIENT, MANAGER } diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/services/HotelService.java b/java/services/hotels/src/main/java/com/uva/api/hotels/services/HotelService.java index 4b736e1f8436687118c1ccdb80250846b8dcfb88..74ccea8586d7bb1723af43073ab6c295b5a035f8 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/services/HotelService.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/services/HotelService.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import com.uva.api.hotels.apis.BookingAPI; @@ -14,11 +16,14 @@ import com.uva.api.hotels.exceptions.InvalidDateRangeException; import com.uva.api.hotels.exceptions.InvalidRequestException; import com.uva.api.hotels.models.Hotel; import com.uva.api.hotels.models.Room; +import com.uva.api.hotels.models.external.users.UserRol; import com.uva.api.hotels.repositories.HotelRepository; import com.uva.api.hotels.repositories.RoomRepository; @Service public class HotelService { + @Autowired + private TokenService tokenService; @Autowired private HotelRepository hotelRepository; @Autowired @@ -28,7 +33,11 @@ public class HotelService { @Autowired private ManagerAPI managerAPI; - public List<Hotel> getAllHotels(Integer managerId, LocalDate start, LocalDate end) { + public ResponseEntity<List<Hotel>> getAllHotels(String token, Integer managerId, LocalDate start, LocalDate end) { + + if (managerId != null) + tokenService.assertPermission(token, managerId); + List<Hotel> hotels = (managerId != null) ? hotelRepository.findAllByManagerId(managerId) : hotelRepository.findAll(); @@ -37,7 +46,7 @@ public class HotelService { throw new InvalidDateRangeException("La fecha de inicio debe ser anterior a la fecha de fin"); Set<Integer> notAvailableRoomsId = bookingAPI.getNotAvailableRooms(start, end); - notAvailableRoomsId.forEach(k -> System.err.println(k)); + hotels = hotels.stream().map(h -> { List<Room> rooms = h.getRooms().stream() .filter(r -> !notAvailableRoomsId.contains(r.getId()) && r.isAvailable()) @@ -46,41 +55,55 @@ public class HotelService { return h; }).filter(h -> !h.getRooms().isEmpty()).toList(); } - return hotels; + if (hotels.isEmpty()) + throw new InvalidRequestException("No hotels"); + + if (!tokenService.hasAnyRole(token, UserRol.ADMIN, UserRol.MANAGER)) + hotels = hotels.stream().map(h -> { + h.setManagerId(null); + return h; + }).toList(); + return ResponseEntity.ok(hotels); } - public Hotel addHotel(Hotel hotel) { + public ResponseEntity<Hotel> addHotel(Hotel hotel) { boolean exist = managerAPI.existsManagerById(hotel.getManagerId()); System.out.println("Id del manager" + hotel.getManagerId()); if (!exist) { throw new InvalidRequestException("No existe el manager con id " + hotel.getManagerId()); } - return hotelRepository.save(hotel); + hotel = hotelRepository.save(hotel); + return new ResponseEntity<>(hotel, HttpStatus.CREATED); } - public Hotel getHotelById(int id) { - return hotelRepository.findById(id) + public ResponseEntity<Hotel> getHotelById(String token, int id) { + Hotel h = hotelRepository.findById(id) .orElseThrow(() -> new HotelNotFoundException(id)); + tokenService.assertPermission(token, h.getManagerId()); + return ResponseEntity.ok(h); } - public List<Hotel> deleteHotelsByManagerId(int managerId) { + public ResponseEntity<List<Hotel>> deleteHotelsByManagerId(String token, int managerId) { + tokenService.assertPermission(token, managerId); List<Hotel> hotels = hotelRepository.findAllByManagerId(managerId); - if (hotels.isEmpty()) { + if (hotels.isEmpty()) throw new InvalidRequestException("No hay hoteles para el manager con id " + managerId); - } + bookingAPI.deleteAllByManagerId(managerId); hotelRepository.deleteAll(hotels); - return hotels; + return ResponseEntity.ok(hotels); } - public void deleteHotel(int id) { + public ResponseEntity<Hotel> deleteHotel(String token, int id) { Hotel target = hotelRepository.findById(id) .orElseThrow(() -> new HotelNotFoundException(id)); + tokenService.assertPermission(token, target.getManagerId()); bookingAPI.deleteAllByHotelId(id); hotelRepository.delete(target); + return ResponseEntity.ok(target); } - public List<Room> getRoomsFromHotel(int hotelId, LocalDate start, LocalDate end) { + public ResponseEntity<List<Room>> getRoomsFromHotel(int hotelId, LocalDate start, LocalDate end) { List<Room> rooms = roomRepository.findAllByHotelId(hotelId); if (start != null && end != null) { if (!start.isBefore(end)) { @@ -91,18 +114,22 @@ public class HotelService { .filter(r -> !notAvailableRoomsId.contains(r.getId()) && r.isAvailable()) .toList(); } - return rooms; + return ResponseEntity.ok(rooms); } - public Room updateRoomAvailability(int hotelId, int roomId, boolean available) { + public ResponseEntity<Room> updateRoomAvailability(String token, int hotelId, int roomId, boolean available) { + Hotel hotel = hotelRepository.findById(hotelId).orElseThrow(() -> new HotelNotFoundException(roomId)); Room targetRoom = roomRepository.findByIdAndHotelId(roomId, hotelId) .orElseThrow(() -> new InvalidRequestException("Habitación no encontrada")); + tokenService.assertPermission(token, hotel.getManagerId()); targetRoom.setAvailable(available); - return roomRepository.save(targetRoom); + targetRoom = roomRepository.save(targetRoom); + return ResponseEntity.ok(targetRoom); } - public Room getRoomByIdFromHotel(int hotelId, int roomId) { - return roomRepository.findByIdAndHotelId(roomId, hotelId) + public ResponseEntity<Room> getRoomByIdFromHotel(int hotelId, int roomId) { + Room r = roomRepository.findByIdAndHotelId(roomId, hotelId) .orElseThrow(() -> new HotelNotFoundException(hotelId)); + return ResponseEntity.ok(r); } } diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/services/TokenService.java b/java/services/hotels/src/main/java/com/uva/api/hotels/services/TokenService.java index d5ebdc3a85a13137c249bdde73b979a6a67d2e5e..bed994702b11475f821dca0b001dd26f62c75ead 100644 --- a/java/services/hotels/src/main/java/com/uva/api/hotels/services/TokenService.java +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/services/TokenService.java @@ -4,10 +4,13 @@ import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; import com.uva.api.hotels.apis.TokenAPI; -import com.uva.api.hotels.models.external.JwtData; +import com.uva.api.hotels.models.external.jwt.JwtData; +import com.uva.api.hotels.models.external.users.UserRol; @Service public class TokenService { @@ -24,25 +27,65 @@ public class TokenService { public String getServiceToken() { if (ownToken == null || expireSoon(ownToken)) { - System.out.println("Generando token"); + System.out.println("\nGenerando token"); long s = System.currentTimeMillis(); ownToken = api.getServiceToken(); long t = System.currentTimeMillis() - s; - System.out.println("Token Generando en " + t + " ms"); + System.out.println("Token Generando en " + t + " ms\n"); } return ownToken.getToken(); } public JwtData decodeToken(String token) { - if (cache.containsKey(token)) - return cache.get(token); - System.out.println("Actualizando token"); + JwtData decoded; + if (cache.containsKey(token)) { + decoded = cache.get(token); + if (!expireSoon(decoded)) + return cache.get(token); + } + System.out.println("\nActualizando token"); long s = System.currentTimeMillis(); - JwtData decoded = api.decodeToken(token); + decoded = api.decodeToken(token); long t = System.currentTimeMillis() - s; - System.out.println("Actualizando token en " + t + " ms"); + System.out.println("Actualizando token en " + t + " ms\n"); cache.put(token, decoded); return decoded; } + /** + * Valida que la entidad representada con el token tenga permisos de + * administrador, sea un servicio o sea el dueño del recurso (idExpected) + * + * @param token + * @param idExpected + */ + public void assertPermission(String token, int idExpected) { + JwtData decoded = decodeToken(token); + boolean isOwner = decoded.getId() == idExpected; + if (!isOwner) + assertPermission(token); + } + + /** + * Valida que la entidad representada con el token tenga permisos de + * administrador o sea un servicio + * + * @param token + */ + public void assertPermission(String token) { + JwtData decoded = decodeToken(token); + boolean isAdmin = decoded.isAdmin(); + boolean isService = decoded.getService() != null && decoded.getAudience().equals("INTERNAL"); + if (!isAdmin && !isService) + throw new HttpClientErrorException(HttpStatus.FORBIDDEN); + } + + public boolean hasAnyRole(String token, UserRol... roles) { + JwtData decoded = decodeToken(token); + for (UserRol role : roles) + if (decoded.getRol() == role) + return true; + return false; + } + } diff --git a/java/services/hotels/src/main/java/com/uva/api/hotels/utils/Utils.java b/java/services/hotels/src/main/java/com/uva/api/hotels/utils/Utils.java new file mode 100644 index 0000000000000000000000000000000000000000..2a54d3f23cc4ca913b0cdd81c0cd94cb2cd5c5e6 --- /dev/null +++ b/java/services/hotels/src/main/java/com/uva/api/hotels/utils/Utils.java @@ -0,0 +1,13 @@ +package com.uva.api.hotels.utils; + +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpClientErrorException; + +public class Utils { + public static String getToken(String authorization) { + String prefix = "Bearer "; + if (!authorization.startsWith(prefix)) + throw new HttpClientErrorException(HttpStatus.FORBIDDEN); + return authorization.substring(prefix.length()); + } +}