From 09e472327bc245a7ff929ffe4f88e878048b5064 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Fri, 27 Feb 2026 11:01:50 +0000 Subject: [PATCH] init, but broken --- .../common/service/PdfMetadataService.java | 5 +++- .../SPDF/controller/api/UIDataController.java | 3 ++- .../SPDF/service/PdfMetadataServiceTest.java | 24 +++++++++++++++++++ .../security/service/UserService.java | 12 +++++++++- .../security/service/UserServiceTest.java | 21 ++++++++++++++++ build.gradle | 2 +- 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/app/common/src/main/java/stirling/software/common/service/PdfMetadataService.java b/app/common/src/main/java/stirling/software/common/service/PdfMetadataService.java index 0d2eebc10f..7b74111870 100644 --- a/app/common/src/main/java/stirling/software/common/service/PdfMetadataService.java +++ b/app/common/src/main/java/stirling/software/common/service/PdfMetadataService.java @@ -169,7 +169,10 @@ public class PdfMetadataService { .getAuthor(); if (userService != null) { - author = author.replace("username", userService.getCurrentUsername()); + String username = userService.getCurrentUsername(); + if (username != null) { + author = author.replace("username", username); + } } } pdf.getDocumentInformation().setAuthor(author); diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java index b9af74ddbf..229edde4c8 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.java @@ -168,7 +168,8 @@ public class UIDataController { public ResponseEntity getSignData() { String username = ""; if (userService != null) { - username = userService.getCurrentUsername(); + String currentUsername = userService.getCurrentUsername(); + username = currentUsername != null ? currentUsername : ""; } List signatures = signatureService.getAvailableSignatures(username); diff --git a/app/core/src/test/java/stirling/software/SPDF/service/PdfMetadataServiceTest.java b/app/core/src/test/java/stirling/software/SPDF/service/PdfMetadataServiceTest.java index f7f682b4d5..fb6716ee78 100644 --- a/app/core/src/test/java/stirling/software/SPDF/service/PdfMetadataServiceTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/service/PdfMetadataServiceTest.java @@ -191,6 +191,30 @@ class PdfMetadataServiceTest { // We don't verify setProducer here to avoid the "Too many actual invocations" error } + @Test + void testSetMetadataToPdf_WithProFeaturesAndMissingUsername() { + PDDocument testDocument = mock(PDDocument.class); + PDDocumentInformation testInfo = mock(PDDocumentInformation.class); + when(testDocument.getDocumentInformation()).thenReturn(testInfo); + + PdfMetadataService proService = + new PdfMetadataService( + applicationProperties, STIRLING_PDF_LABEL, true, userService); + + PdfMetadata testMetadata = PdfMetadata.builder().author("Original Author").build(); + + CustomMetadata customMetadata = + applicationProperties.getPremium().getProFeatures().getCustomMetadata(); + when(customMetadata.isAutoUpdateMetadata()).thenReturn(true); + when(customMetadata.getAuthor()).thenReturn("Pro Author username"); + when(userService.getCurrentUsername()).thenReturn(null); + + proService.setMetadataToPdf(testDocument, testMetadata, false); + + // When username is null, the "username" placeholder should not be replaced + verify(testInfo).setAuthor("Pro Author username"); + } + @Test void testSetMetadataToPdf_ExistingDocument() { // Create a fresh document diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java index dbff599974..b5659473a8 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java @@ -522,7 +522,17 @@ public class UserService implements UserServiceInterface { @Override public String getCurrentUsername() { - Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + log.debug("No authentication found in security context when resolving username"); + return null; + } + + Object principal = authentication.getPrincipal(); + if (principal == null) { + log.debug("No principal found on authentication object when resolving username"); + return null; + } if (principal instanceof UserDetails detailsUser) { return detailsUser.getUsername(); diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java index 5b4575e648..a1d3af827c 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/UserServiceTest.java @@ -16,6 +16,8 @@ import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.context.MessageSource; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import stirling.software.common.model.ApplicationProperties; @@ -150,6 +152,25 @@ class UserServiceTest { assertEquals(AuthenticationType.SAML2, captured.getAuthenticationType()); } + @Test + void getCurrentUsernameReturnsNullWhenAuthenticationMissing() { + SecurityContextHolder.clearContext(); + + assertNull(userService.getCurrentUsername()); + } + + @Test + void getCurrentUsernameReturnsUsernameForAuthenticatedPrincipal() { + SecurityContextHolder.getContext() + .setAuthentication( + new UsernamePasswordAuthenticationToken( + "alice", "n/a", java.util.List.of())); + + assertEquals("alice", userService.getCurrentUsername()); + + SecurityContextHolder.clearContext(); + } + @Test void addApiKeyToUserGeneratesAndPersists() { User user = new User(); diff --git a/build.gradle b/build.gradle index e3bd51554b..9551ddcdc4 100644 --- a/build.gradle +++ b/build.gradle @@ -78,7 +78,7 @@ springBoot { allprojects { group = 'stirling.software' - version = '2.5.3' + version = '2.6.0' configurations.configureEach { exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"