diff --git a/data/hotel.sqlite b/data/hotel.sqlite index d841a55..edcf485 100644 Binary files a/data/hotel.sqlite and b/data/hotel.sqlite differ diff --git a/data/hotel.sqlite-shm b/data/hotel.sqlite-shm deleted file mode 100644 index f69a215..0000000 Binary files a/data/hotel.sqlite-shm and /dev/null differ diff --git a/data/hotel.sqlite-wal b/data/hotel.sqlite-wal deleted file mode 100644 index b88b146..0000000 Binary files a/data/hotel.sqlite-wal and /dev/null differ diff --git a/pom.xml b/pom.xml index fdac999..a0c4b5a 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,32 @@ hibernate-community-dialects + + org.springframework.boot + spring-boot-starter-security + + + + + io.jsonwebtoken + jjwt-api + 0.12.5 + + + + io.jsonwebtoken + jjwt-impl + 0.12.5 + runtime + + + + io.jsonwebtoken + jjwt-jackson + 0.12.5 + runtime + + diff --git a/src/main/java/com/mallardromain/hotel/DTO/LoginRequest.java b/src/main/java/com/mallardromain/hotel/DTO/LoginRequest.java new file mode 100644 index 0000000..ddddb67 --- /dev/null +++ b/src/main/java/com/mallardromain/hotel/DTO/LoginRequest.java @@ -0,0 +1,23 @@ +package com.mallardromain.hotel.DTO; + +public class LoginRequest { + + private String username; + private String password; + + public String getUsername(){ + return username; + } + + public void setUsername(String username){ + this.username = username; + } + + public String getPassword(){ + return password; + } + + public void setPassword(String password){ + this.password = password; + } +} diff --git a/src/main/java/com/mallardromain/hotel/config/SecurityConfig.java b/src/main/java/com/mallardromain/hotel/config/SecurityConfig.java new file mode 100644 index 0000000..14877df --- /dev/null +++ b/src/main/java/com/mallardromain/hotel/config/SecurityConfig.java @@ -0,0 +1,42 @@ +package com.mallardromain.hotel.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.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import com.mallardromain.hotel.security.JWTFilter; + +@Configuration +public class SecurityConfig { + private final JWTFilter jwtFilter; + + public SecurityConfig(JWTFilter jwtFilter) { + this.jwtFilter = jwtFilter; + } + + @Bean + public SecurityFilterChain securityFilterChain( + HttpSecurity http + ) throws Exception { + + http.csrf(csrf -> csrf.disable()) + .sessionManagement(session -> + session.sessionCreationPolicy( + SessionCreationPolicy.STATELESS + ) + ) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/auth/**").permitAll() + .anyRequest().authenticated() + ) + .addFilterBefore( + jwtFilter, + UsernamePasswordAuthenticationFilter.class + ); + return http.build(); + } + +} diff --git a/src/main/java/com/mallardromain/hotel/controller/AuthController.java b/src/main/java/com/mallardromain/hotel/controller/AuthController.java new file mode 100644 index 0000000..07db939 --- /dev/null +++ b/src/main/java/com/mallardromain/hotel/controller/AuthController.java @@ -0,0 +1,54 @@ +package com.mallardromain.hotel.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.mallardromain.hotel.DTO.LoginRequest; +import com.mallardromain.hotel.service.JWTService; + +@RestController +@RequestMapping("/auth") +public class AuthController { + + private final JWTService jwtService; + + public AuthController(JWTService jwtService){ + this.jwtService = jwtService; + } + + @PostMapping("/login") + public ResponseEntity login( + @RequestBody LoginRequest request + ){ + //temps test1/2 + if ( + request.getUsername().equals("test1") + && + request.getPassword().equals("password1") + ) { + String token = jwtService + .generateToken(request.getUsername()); + + return ResponseEntity.ok(token); + } + + if ( + request.getUsername().equals("test2") + && + request.getPassword().equals("password2") + ) { + String token = jwtService + .generateToken(request.getUsername()); + + return ResponseEntity.ok(token); + } + + return ResponseEntity.status(401).body("Invalid username/password"); + } + + +} diff --git a/src/main/java/com/mallardromain/hotel/controller/RoomController.java b/src/main/java/com/mallardromain/hotel/controller/RoomController.java index f0b0a90..9350a76 100644 --- a/src/main/java/com/mallardromain/hotel/controller/RoomController.java +++ b/src/main/java/com/mallardromain/hotel/controller/RoomController.java @@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.*; import com.mallardromain.hotel.model.Room; import com.mallardromain.hotel.repository.RoomRepository; -import com.mallardromain.hotel.repository.RoomService; +import com.mallardromain.hotel.service.RoomService; @RestController @RequestMapping("/rooms") diff --git a/src/main/java/com/mallardromain/hotel/model/JWT.java b/src/main/java/com/mallardromain/hotel/model/JWT.java new file mode 100644 index 0000000..b9142e4 --- /dev/null +++ b/src/main/java/com/mallardromain/hotel/model/JWT.java @@ -0,0 +1,6 @@ +package com.mallardromain.hotel.model; + +public class JWT { + + +} diff --git a/src/main/java/com/mallardromain/hotel/model/Room.java b/src/main/java/com/mallardromain/hotel/model/Room.java index 22e2bb6..3ccd823 100644 --- a/src/main/java/com/mallardromain/hotel/model/Room.java +++ b/src/main/java/com/mallardromain/hotel/model/Room.java @@ -7,6 +7,7 @@ import jakarta.persistence.*; public class Room { @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String number; @@ -19,7 +20,7 @@ public class Room { } public Room(Integer id, String number, String status){ - this.id = id; + //this.id = id; id is/should be generated by the DB this.number = number; this.status = status; } diff --git a/src/main/java/com/mallardromain/hotel/security/JWTFilter.java b/src/main/java/com/mallardromain/hotel/security/JWTFilter.java new file mode 100644 index 0000000..76ff351 --- /dev/null +++ b/src/main/java/com/mallardromain/hotel/security/JWTFilter.java @@ -0,0 +1,75 @@ +package com.mallardromain.hotel.security; + +import java.io.IOException; +import java.util.Collections; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import com.mallardromain.hotel.service.JWTService; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JWTFilter extends OncePerRequestFilter { + + private final JWTService jwtService; + + public JWTFilter(JWTService jwtService){ + this.jwtService = jwtService; + } + + @Override + protected void doFilterInternal( + HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain + ) throws ServletException, IOException { + + String authHeader = request + .getHeader("Authorization"); + + if ( authHeader == null + || + !authHeader.startsWith("Bearer ") + ) { + + filterChain.doFilter(request, response); + return; + } + + String token = authHeader.substring(7); + + if (jwtService.isTockenValid(token)){ + + String username = jwtService + .extractUsername(token); + + UsernamePasswordAuthenticationToken auth = + new UsernamePasswordAuthenticationToken( + username, + null, + Collections.emptyList() + ); + + auth.setDetails( + new WebAuthenticationDetailsSource() + .buildDetails(request) + ); + + SecurityContextHolder.getContext() + .setAuthentication(auth); + } + + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/com/mallardromain/hotel/service/JWTService.java b/src/main/java/com/mallardromain/hotel/service/JWTService.java new file mode 100644 index 0000000..6749784 --- /dev/null +++ b/src/main/java/com/mallardromain/hotel/service/JWTService.java @@ -0,0 +1,58 @@ +package com.mallardromain.hotel.service; + +import java.security.Key; +import java.util.Date; + +import javax.crypto.SecretKey; + +import org.springframework.stereotype.Service; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; + +@Service +public class JWTService { + + private static final String SECRET = "NotHardCodedKeyThatIsAtLeast32CharactersLong!"; + + private final Key key = Keys.hmacShaKeyFor(SECRET.getBytes()); + + public String generateToken(String username){ + + return Jwts.builder() + .subject(username) + .issuedAt(new Date()) + .expiration( + new Date(System.currentTimeMillis() + 1000 * 60 * 60) + ) + .signWith(key) + .compact(); + } + + public boolean isTockenValid(String token){ + + try { + Jwts.parser() + .verifyWith((SecretKey) key) + .build() + .parseSignedClaims(token); + return true; + } catch (Exception e) { + return false; + } + } + + public String extractUsername(String token){ + + Claims claims = Jwts.parser() + .verifyWith((SecretKey) key) + .build() + .parseSignedClaims(token) + .getPayload(); + + return claims.getSubject(); + } + +} diff --git a/src/main/java/com/mallardromain/hotel/repository/RoomService.java b/src/main/java/com/mallardromain/hotel/service/RoomService.java similarity index 91% rename from src/main/java/com/mallardromain/hotel/repository/RoomService.java rename to src/main/java/com/mallardromain/hotel/service/RoomService.java index 40cb955..d4b13ea 100644 --- a/src/main/java/com/mallardromain/hotel/repository/RoomService.java +++ b/src/main/java/com/mallardromain/hotel/service/RoomService.java @@ -1,10 +1,12 @@ -package com.mallardromain.hotel.repository; +package com.mallardromain.hotel.service; import java.util.List; import org.springframework.stereotype.Service; import com.mallardromain.hotel.model.Room; +import com.mallardromain.hotel.repository.RoomRepository; + import jakarta.persistence.*; @Service