From 9d535ed7a59b3ba3ee83ef5f8cf4bffa0ae9d022 Mon Sep 17 00:00:00 2001 From: Dario Ghunney Ware Date: Mon, 8 Sep 2025 11:58:23 +0100 Subject: [PATCH] added additional checks for v2/jwt props --- .../common/model/ApplicationProperties.java | 2 +- .../controller/api/misc/ShowJavascript.java | 38 +++++++++++-------- .../security/InitialSecuritySetup.java | 18 +++++++++ .../filter/JwtAuthenticationFilter.java | 28 ++++++++++++++ .../service/CustomUserDetailsService.java | 7 +++- 5 files changed, 74 insertions(+), 19 deletions(-) diff --git a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index 83548bb59..b2ee7f5a6 100644 --- a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -379,7 +379,7 @@ public class ApplicationProperties { public String getBaseTmpDir() { return baseTmpDir != null && !baseTmpDir.isEmpty() ? baseTmpDir - : java.lang.System.getProperty("java.io.tmpdir") + "/stirling-pdf"; + : java.lang.System.getProperty("java.io.tmpdir") + "stirling-pdf"; } @JsonIgnore diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java index 6c413cd36..65888e55d 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java @@ -1,9 +1,8 @@ package stirling.software.SPDF.controller.api.misc; -import io.github.pixee.security.Filenames; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; +import java.nio.charset.StandardCharsets; +import java.util.Map; + import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDNameTreeNode; import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript; @@ -14,13 +13,17 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; + +import io.github.pixee.security.Filenames; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.model.api.PDFFile; import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.util.WebResponseUtils; -import java.nio.charset.StandardCharsets; -import java.util.Map; - @RestController @RequestMapping("/api/v1/misc") @Tag(name = "Misc", description = "Miscellaneous APIs") @@ -55,12 +58,14 @@ public class ShowJavascript { if (jsCodeStr != null && !jsCodeStr.trim().isEmpty()) { script.append("// File: ") - .append(Filenames.toSimpleFileName(inputFile.getOriginalFilename())) - .append(", Script: ") - .append(name) - .append("\n") - .append(jsCodeStr) - .append("\n"); + .append( + Filenames.toSimpleFileName( + inputFile.getOriginalFilename())) + .append(", Script: ") + .append(name) + .append("\n") + .append(jsCodeStr) + .append("\n"); foundScript = true; } } @@ -68,9 +73,10 @@ public class ShowJavascript { } if (!foundScript) { - script = new StringBuilder("PDF '") - .append(Filenames.toSimpleFileName(inputFile.getOriginalFilename())) - .append("' does not contain Javascript"); + script = + new StringBuilder("PDF '") + .append(Filenames.toSimpleFileName(inputFile.getOriginalFilename())) + .append("' does not contain Javascript"); } return WebResponseUtils.bytesToWebResponse( diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java index e145e2754..16ac73c1f 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import jakarta.annotation.PostConstruct; @@ -26,6 +27,9 @@ import stirling.software.proprietary.security.service.UserService; @RequiredArgsConstructor public class InitialSecuritySetup { + @Value("${v2:false}") + private boolean v2Enabled = false; + private final UserService userService; private final TeamService teamService; private final ApplicationProperties applicationProperties; @@ -43,6 +47,7 @@ public class InitialSecuritySetup { } } + configureJWTSettings(); assignUsersToDefaultTeamIfMissing(); initializeInternalApiUser(); } catch (IllegalArgumentException | SQLException | UnsupportedProviderException e) { @@ -51,6 +56,19 @@ public class InitialSecuritySetup { } } + private void configureJWTSettings() { + ApplicationProperties.Security.Jwt jwtProperties = + applicationProperties.getSecurity().getJwt(); + + if (!v2Enabled) { + log.debug("v2 is disabled - disabling all JWT features"); + jwtProperties.setEnableKeystore(false); + jwtProperties.setEnableKeyRotation(false); + jwtProperties.setEnableKeyCleanup(false); + jwtProperties.setSecureCookie(false); + } + } + private void assignUsersToDefaultTeamIfMissing() { Team defaultTeam = teamService.getOrCreateDefaultTeam(); Team internalTeam = teamService.getOrCreateInternalTeam(); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/JwtAuthenticationFilter.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/JwtAuthenticationFilter.java index faf50832f..a3bdbe871 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/JwtAuthenticationFilter.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/filter/JwtAuthenticationFilter.java @@ -62,6 +62,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + validateAndNormalizeJwtSettings(); + if (!jwtService.isJwtEnabled()) { filterChain.doFilter(request, response); return; @@ -112,6 +114,32 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { filterChain.doFilter(request, response); } + private void validateAndNormalizeJwtSettings() { + ApplicationProperties.Security.Jwt jwtProperties = securityProperties.getJwt(); + + boolean enableKeystore = jwtProperties.isEnableKeystore(); + boolean enableKeyRotation = jwtProperties.isEnableKeyRotation(); + boolean enableKeyCleanup = jwtProperties.isEnableKeyCleanup(); + boolean secureCookie = jwtProperties.isSecureCookie(); + + // If any JWT property is disabled, disable all JWT properties for consistency + if (!enableKeystore || !enableKeyRotation || !enableKeyCleanup || !secureCookie) { + log.debug( + "One or more JWT properties are disabled - normalizing all JWT settings to false"); + log.debug( + "Current settings: keystore={}, rotation={}, cleanup={}, secureCookie={}", + enableKeystore, + enableKeyRotation, + enableKeyCleanup, + secureCookie); + + jwtProperties.setEnableKeystore(false); + jwtProperties.setEnableKeyRotation(false); + jwtProperties.setEnableKeyCleanup(false); + jwtProperties.setSecureCookie(false); + } + } + private boolean apiKeyExists(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java index df3934bbd..71cae3f1a 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java @@ -75,8 +75,11 @@ public class CustomUserDetailsService implements UserDetailsService { */ private AuthenticationType determinePreferredSSOType() { // Check what SSO types are enabled and prefer in order: OAUTH2 > SAML2 > fallback to OAUTH2 - boolean oauth2Enabled = securityProperties.getOauth2() != null && securityProperties.getOauth2().getEnabled(); - boolean saml2Enabled = securityProperties.getSaml2() != null && securityProperties.getSaml2().getEnabled(); + boolean oauth2Enabled = + securityProperties.getOauth2() != null + && securityProperties.getOauth2().getEnabled(); + boolean saml2Enabled = + securityProperties.getSaml2() != null && securityProperties.getSaml2().getEnabled(); if (oauth2Enabled) { return AuthenticationType.OAUTH2;