From 2fb60eee8dde32dd42def1bb3f5a84c63eee3a70 Mon Sep 17 00:00:00 2001 From: DarioGii Date: Wed, 9 Jul 2025 16:28:44 +0100 Subject: [PATCH] Clean up --- .../common/configuration/AppConfig.java | 6 +-- .../filter/JWTAuthenticationFilter.java | 35 ++++++++++-- .../AuthenticationFailureException.java | 4 ++ .../security/service/JWTService.java | 54 ++++++++++++------- .../security/service/JWTServiceInterface.java | 2 +- 5 files changed, 73 insertions(+), 28 deletions(-) diff --git a/common/src/main/java/stirling/software/common/configuration/AppConfig.java b/common/src/main/java/stirling/software/common/configuration/AppConfig.java index b983769a8..f611f42ca 100644 --- a/common/src/main/java/stirling/software/common/configuration/AppConfig.java +++ b/common/src/main/java/stirling/software/common/configuration/AppConfig.java @@ -10,7 +10,6 @@ import java.util.Properties; import java.util.function.Predicate; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -151,9 +150,8 @@ public class AppConfig { @Bean(name = "activeSecurity") public boolean missingActiveSecurity() { return ClassUtils.isPresent( - "stirling.software.proprietary.security.configuration.SecurityConfiguration", - this.getClass().getClassLoader() - ); + "stirling.software.proprietary.security.configuration.SecurityConfiguration", + this.getClass().getClassLoader()); } @Bean(name = "directoryFilter") diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/JWTAuthenticationFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/JWTAuthenticationFilter.java index 9a14ce276..975e5732f 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/JWTAuthenticationFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/JWTAuthenticationFilter.java @@ -53,17 +53,21 @@ public class JWTAuthenticationFilter extends OncePerRequestFilter { String jwtToken = jwtService.extractTokenFromRequest(request); if (jwtToken == null) { - // Special handling for root path - redirect to login instead of 401 + // Redirect to /login instead of 401 if ("/".equals(request.getRequestURI()) && "GET".equalsIgnoreCase(request.getMethod())) { response.sendRedirect("/login"); return; } - throw new AuthenticationFailureException("JWT is missing from request"); + sendUnauthorizedResponse(response, "JWT is missing from the request"); + return; } - if (!jwtService.validateToken(jwtToken)) { - throw new AuthenticationFailureException("JWT is invalid or expired"); + try { + jwtService.validateToken(jwtToken); + } catch (AuthenticationFailureException e) { + sendUnauthorizedResponse(response, e.getMessage()); + return; } String tokenUsername = jwtService.extractUsername(jwtToken); @@ -134,4 +138,27 @@ public class JWTAuthenticationFilter extends OncePerRequestFilter { return false; } + + private void sendUnauthorizedResponse(HttpServletResponse response, String message) + throws IOException { + int unauthorized = HttpServletResponse.SC_UNAUTHORIZED; + + response.setStatus(unauthorized); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + + String jsonResponse = + String.format( + """ + { + "error": "Unauthorized", + "message": "%s", + "status": %d + } + """, + message, unauthorized); + + response.getWriter().write(jsonResponse); + response.getWriter().flush(); + } } diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java index ec773dadf..f2cd5e242 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/exception/AuthenticationFailureException.java @@ -6,4 +6,8 @@ public class AuthenticationFailureException extends AuthenticationException { public AuthenticationFailureException(String message) { super(message); } + + public AuthenticationFailureException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTService.java index 1d7b6144b..63847ba63 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTService.java @@ -26,6 +26,7 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import stirling.software.common.model.ApplicationProperties; +import stirling.software.proprietary.security.model.exception.AuthenticationFailureException; @Slf4j @Service @@ -69,27 +70,29 @@ public class JWTService implements JWTServiceInterface { } @Override - public boolean validateToken(String token) { + public void validateToken(String token) { if (!isJwtEnabled()) { - return false; + throw new IllegalStateException("JWT is not enabled"); } try { - Jwts.parser().verifyWith(keyPair.getPublic()).build().parseSignedClaims(token); - return true; + extractAllClaimsFromToken(token); } catch (SignatureException e) { - log.warn("Invalid JWT signature: {}", e.getMessage()); + log.warn("Invalid signature: {}", e.getMessage()); + throw new AuthenticationFailureException("Invalid signature", e); } catch (MalformedJwtException e) { - log.warn("Invalid JWT token: {}", e.getMessage()); + log.warn("Invalid token: {}", e.getMessage()); + throw new AuthenticationFailureException("Invalid token", e); } catch (ExpiredJwtException e) { - log.warn("JWT token is expired: {}", e.getMessage()); + log.warn("The token has expired: {}", e.getMessage()); + throw new AuthenticationFailureException("The token has expired", e); } catch (UnsupportedJwtException e) { - log.warn("JWT token is unsupported: {}", e.getMessage()); + log.warn("The token is unsupported: {}", e.getMessage()); + throw new AuthenticationFailureException("The token is unsupported", e); } catch (IllegalArgumentException e) { - log.warn("JWT claims string is empty: {}", e.getMessage()); + log.warn("Claims are empty: {}", e.getMessage()); + throw new AuthenticationFailureException("Claims are empty", e); } - - return false; } @Override @@ -118,15 +121,28 @@ public class JWTService implements JWTServiceInterface { } private Claims extractAllClaimsFromToken(String token) { - if (!isJwtEnabled()) { - throw new IllegalStateException("JWT is not enabled"); + try { + return Jwts.parser() + .verifyWith(keyPair.getPublic()) + .build() + .parseSignedClaims(token) + .getPayload(); + } catch (SignatureException e) { + log.warn("Invalid JWT signature: {}", e.getMessage()); + throw new AuthenticationFailureException("Invalid JWT signature", e); + } catch (MalformedJwtException e) { + log.warn("Invalid JWT token: {}", e.getMessage()); + throw new AuthenticationFailureException("Invalid JWT token", e); + } catch (ExpiredJwtException e) { + log.warn("JWT token is expired: {}", e.getMessage()); + throw new AuthenticationFailureException("JWT token is expired", e); + } catch (UnsupportedJwtException e) { + log.warn("JWT token is unsupported: {}", e.getMessage()); + throw new AuthenticationFailureException("JWT token is unsupported", e); + } catch (IllegalArgumentException e) { + log.warn("JWT claims are empty: {}", e.getMessage()); + throw new AuthenticationFailureException("JWT claims are empty", e); } - - return Jwts.parser() - .verifyWith(keyPair.getPublic()) - .build() - .parseSignedClaims(token) - .getPayload(); } @Override diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTServiceInterface.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTServiceInterface.java index 222d494cd..86772af8e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTServiceInterface.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/JWTServiceInterface.java @@ -34,7 +34,7 @@ public interface JWTServiceInterface { * @param token the JWT token to validate * @return true if token is valid, false otherwise */ - boolean validateToken(String token); + void validateToken(String token); /** * Extract username from JWT token