From 3641dbcdf979b94120bea1a809173baef3c35409 Mon Sep 17 00:00:00 2001 From: "Max W." <66736561+Walzen665@users.noreply.github.com> Date: Mon, 9 Sep 2024 17:15:08 +0200 Subject: [PATCH] Added basic JWT authentication working state --- .../biblenotes/config/SecurityConfig.java | 5 ++- .../biblenotes/rest/ApiRestController.java | 10 +++++ .../mappings/AuthenticationController.java | 44 +++++++++++++++++++ .../rest/mappings/TestController.java | 14 ++++++ .../rest/ro/AuthenticationRequest.java | 16 +++++++ .../security/JwtAuthenticationFilter.java | 8 +++- src/main/resources/application.properties | 2 +- 7 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 src/main/java/de/w665/biblenotes/rest/ApiRestController.java create mode 100644 src/main/java/de/w665/biblenotes/rest/mappings/AuthenticationController.java create mode 100644 src/main/java/de/w665/biblenotes/rest/mappings/TestController.java create mode 100644 src/main/java/de/w665/biblenotes/rest/ro/AuthenticationRequest.java diff --git a/src/main/java/de/w665/biblenotes/config/SecurityConfig.java b/src/main/java/de/w665/biblenotes/config/SecurityConfig.java index edbd6f3..fd68887 100644 --- a/src/main/java/de/w665/biblenotes/config/SecurityConfig.java +++ b/src/main/java/de/w665/biblenotes/config/SecurityConfig.java @@ -39,10 +39,11 @@ public class SecurityConfig { .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // No session will be created by Spring Security ) .authorizeHttpRequests(authorize -> authorize - .requestMatchers("/api/v1/**").authenticated() // Secure all /api/v1/** routes + .requestMatchers("/api/v1/auth/login").permitAll() // Allow access to login endpoint + .requestMatchers("/api/v1/**").authenticated() // Secure all other /api/v1/** routes .anyRequest().permitAll() // All other requests are allowed without authentication ) - .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) // Apply JWT filter + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) // Ensure JWT filter is applied after login is allowed .logout(LogoutConfigurer::permitAll) .rememberMe(Customizer.withDefaults()); diff --git a/src/main/java/de/w665/biblenotes/rest/ApiRestController.java b/src/main/java/de/w665/biblenotes/rest/ApiRestController.java new file mode 100644 index 0000000..3314b85 --- /dev/null +++ b/src/main/java/de/w665/biblenotes/rest/ApiRestController.java @@ -0,0 +1,10 @@ +package de.w665.biblenotes.rest; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1") +public abstract class ApiRestController { +} + diff --git a/src/main/java/de/w665/biblenotes/rest/mappings/AuthenticationController.java b/src/main/java/de/w665/biblenotes/rest/mappings/AuthenticationController.java new file mode 100644 index 0000000..02e5ac8 --- /dev/null +++ b/src/main/java/de/w665/biblenotes/rest/mappings/AuthenticationController.java @@ -0,0 +1,44 @@ +package de.w665.biblenotes.rest.mappings; + +import de.w665.biblenotes.rest.ro.AuthenticationRequest; +import de.w665.biblenotes.service.AuthenticationService; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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 java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +@RequestMapping("/api/v1/auth") +public class AuthenticationController { + + private final AuthenticationService authenticationService; + + public AuthenticationController(AuthenticationService authenticationService) { + this.authenticationService = authenticationService; + } + + @PostMapping("/login") + public ResponseEntity createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest, HttpServletRequest request) { + log.debug("Received AuthenticationRequest for username: " + authenticationRequest.getUsername()); + String token = authenticationService.authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword(), request.getRemoteAddr()); + + Map response = new HashMap<>(); + response.put("token", token); + response.put("success", token != null); + + if(token == null) { + log.debug("Authentication failed for username: " + authenticationRequest.getUsername()); + return new ResponseEntity<>(response, HttpStatus.UNAUTHORIZED); + } + + return new ResponseEntity<>(response, HttpStatus.OK); + } +} \ No newline at end of file diff --git a/src/main/java/de/w665/biblenotes/rest/mappings/TestController.java b/src/main/java/de/w665/biblenotes/rest/mappings/TestController.java new file mode 100644 index 0000000..c03ef22 --- /dev/null +++ b/src/main/java/de/w665/biblenotes/rest/mappings/TestController.java @@ -0,0 +1,14 @@ +package de.w665.biblenotes.rest.mappings; + +import de.w665.biblenotes.rest.ApiRestController; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TestController extends ApiRestController { + + @GetMapping("/test") + public String test() { + return "Test"; + } +} diff --git a/src/main/java/de/w665/biblenotes/rest/ro/AuthenticationRequest.java b/src/main/java/de/w665/biblenotes/rest/ro/AuthenticationRequest.java new file mode 100644 index 0000000..702c883 --- /dev/null +++ b/src/main/java/de/w665/biblenotes/rest/ro/AuthenticationRequest.java @@ -0,0 +1,16 @@ +package de.w665.biblenotes.rest.ro; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@NoArgsConstructor +@Getter +@Setter +@ToString +public class AuthenticationRequest { + private String username; + private String password; +} + diff --git a/src/main/java/de/w665/biblenotes/rest/security/JwtAuthenticationFilter.java b/src/main/java/de/w665/biblenotes/rest/security/JwtAuthenticationFilter.java index d36c2a4..8f0cc00 100644 --- a/src/main/java/de/w665/biblenotes/rest/security/JwtAuthenticationFilter.java +++ b/src/main/java/de/w665/biblenotes/rest/security/JwtAuthenticationFilter.java @@ -28,13 +28,19 @@ import java.util.List; public class JwtAuthenticationFilter extends OncePerRequestFilter { private final AuthenticationService authenticationService; - private final RequestMatcher requestMatcher = new AntPathRequestMatcher("/api/v1/secure/**"); + private final RequestMatcher requestMatcher = new AntPathRequestMatcher("/api/v1/**"); // The filter will verify authentication for all requests starting with /api/v1/ @Override protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { logger.debug("Filtering request: " + request.getRequestURI()); + if ("/api/v1/auth/login".equals(request.getRequestURI())) { + logger.debug("Login request detected. Skipping JWT authentication."); + filterChain.doFilter(request, response); + return; + } + if(!requestMatcher.matches(request)) { logger.debug("Request does not match the secure path. Skipping JWT authentication."); filterChain.doFilter(request, response); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0296e5b..1ba2a61 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -8,7 +8,7 @@ rethinkdb.port=28015 rethinkdb.database=biblenotes # Logging -logging.level.de.w665.biblenotes=INFO +logging.level.de.w665.biblenotes=DEBUG # Static path spring.web.resources.static-locations=classpath:/static/browser/