From 34a5328a2c003458d9aaa8d38b6b15991f517c5a Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Sun, 4 Feb 2024 20:53:24 -0800 Subject: [PATCH] Complete JWT token support. --- .../filter/JwtAuthenticationFilter.java | 66 ++++++++++++------- .../wisemapping/rest/JwtAuthController.java | 4 +- .../wisemapping/rest/model/RestJwtUser.java | 15 ++--- .../wisemapping/security/JwtTokenUtil.java | 6 +- wise-api/src/main/resources/application.yml | 16 +++-- 5 files changed, 64 insertions(+), 43 deletions(-) diff --git a/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java b/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java index ca177411..29b41939 100644 --- a/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java +++ b/wise-api/src/main/java/com/wisemapping/filter/JwtAuthenticationFilter.java @@ -18,9 +18,11 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.util.Optional; @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { + private static final String BEARER_TOKEN_PREFIX = "Bearer "; @Autowired private UserDetailsService userDetailsService; @@ -32,33 +34,51 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { - final String authorizationHeader = request.getHeader("Authorization"); - String username = null; - String jwtToken = null; - // Extract username from token ... - if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { - jwtToken = authorizationHeader.substring(7); - try { - username = jwtTokenUtil.extractFromJwtToken(jwtToken); - } catch (Exception e) { - // Handle token extraction/validation errors - logger.debug("Error extracting username from token: " + e.getMessage()); + final Optional token = getJwtTokenFromRequest(request); + if (token.isPresent() && SecurityContextHolder.getContext().getAuthentication() == null) { + // Extract email from token ... + final Optional email = extractEmailFromToken(token.get()); + + if (email.isPresent() && jwtTokenUtil.validateJwtToken(token.get())) { + // Is it an existing user ? + final UserDetails userDetails = userDetailsService.loadUserByUsername(email.get()); + if (userDetails != null) { + final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + } else { + logger.trace("User " + email.get() + " could not be found"); + } } } - - if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { - final UserDetails userDetails = userDetailsService.loadUserByUsername(username); - - if (jwtTokenUtil.validateJwtToken(jwtToken)) { - final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( - userDetails, null, userDetails.getAuthorities()); - authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - } - } - filterChain.doFilter(request, response); } + + private Optional extractEmailFromToken(final @NotNull String token) { + Optional result = Optional.empty(); + try { + result = Optional.of(jwtTokenUtil.extractFromJwtToken(token)); + } catch (Exception e) { + // Handle token extraction/validation errors + logger.debug("Error extracting email from token: " + e.getMessage()); + } + return result; + } + + private static Optional getJwtTokenFromRequest(@NotNull HttpServletRequest request) { + Optional result = Optional.empty(); + + final String authorizationHeader = request.getHeader("Authorization"); + if (authorizationHeader != null) { + if (authorizationHeader.startsWith(BEARER_TOKEN_PREFIX)) { + logger.trace("JWT Bearer token found"); + final String token = authorizationHeader.substring(BEARER_TOKEN_PREFIX.length()); + result = Optional.of(token); + } + } + return result; + } } diff --git a/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java b/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java index 402eec38..95e5b969 100644 --- a/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java +++ b/wise-api/src/main/java/com/wisemapping/rest/JwtAuthController.java @@ -55,11 +55,11 @@ public class JwtAuthController { public ResponseEntity createAuthenticationToken(@RequestBody RestJwtUser user, @NotNull HttpServletResponse response) throws Exception { // Is a valid user ? - authenticate(user.getUsername(), user.getPassword()); + authenticate(user.getEmail(), user.getPassword()); // Create token ... final UserDetails userDetails = userDetailsService - .loadUserByUsername(user.getUsername()); + .loadUserByUsername(user.getEmail()); final String token = jwtTokenUtil.generateJwtToken(userDetails); diff --git a/wise-api/src/main/java/com/wisemapping/rest/model/RestJwtUser.java b/wise-api/src/main/java/com/wisemapping/rest/model/RestJwtUser.java index 0eb10aa1..a4f519ba 100644 --- a/wise-api/src/main/java/com/wisemapping/rest/model/RestJwtUser.java +++ b/wise-api/src/main/java/com/wisemapping/rest/model/RestJwtUser.java @@ -33,21 +33,20 @@ import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_NULL) public class RestJwtUser { - private String username; + private String email; private String password; - - public RestJwtUser(@NotNull String username, @NotNull String password) { - this.setUsername(username); + public RestJwtUser(@NotNull String email, @NotNull String password) { + this.setEmail(email); this.setPassword(password); } - public String getUsername() { - return this.username; + public String getEmail() { + return this.email; } - public void setUsername(String username) { - this.username = username; + public void setEmail(String email) { + this.email = email; } public String getPassword() { diff --git a/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java b/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java index da80fc82..3d751907 100644 --- a/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java +++ b/wise-api/src/main/java/com/wisemapping/security/JwtTokenUtil.java @@ -21,14 +21,14 @@ public class JwtTokenUtil implements Serializable { @Value("${app.jwt.secret}") private String jwtSecret; - @Value("${app.jwt.expirationMs}") - private int jwtExpirationMs; + @Value("${app.jwt.expirationMin}") + private int jwtExpirationMin; public String generateJwtToken(@NotNull final UserDetails user) { return Jwts.builder() .setSubject((user.getUsername())) .setIssuedAt(new Date()) - .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)) + .setExpiration(new Date((new Date()).getTime() + jwtExpirationMin * 1000L * 60)) .signWith(key(), SignatureAlgorithm.HS256) .compact(); } diff --git a/wise-api/src/main/resources/application.yml b/wise-api/src/main/resources/application.yml index b911ec91..b02c1c65 100755 --- a/wise-api/src/main/resources/application.yml +++ b/wise-api/src/main/resources/application.yml @@ -29,12 +29,20 @@ spring: mode: always platform: hsqldb +# Login ... +logging: + level: + org: + apache: + tomcat: INFO + root: TRACE + # Application Configuration. app: jwt: secret: dlqxKAg685SaKhsQXIMeM=JWCw3bkl3Ei3Tb7LMlnd19oMd66burPNlJ0Po1qguyjgpakQTk2CN3 - expirationMs: 10000 + expirationMin: 10080 # One week admin: user: admin@wisemapping.org @@ -48,12 +56,6 @@ google: enabled: true secretKey: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe siteKey: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI -logging: - level: - org: - apache: - tomcat: INFO - root: INFO mail: password: '' serverSendEmail: root@localhost