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