feat(common,core,proprietary): remove unused injections, enhance type safety, and improve test mocks (#4213)

# Description of Changes

This PR introduces several refactorings and minor enhancements across
the `common`, `core`, and `proprietary` modules:

- **Dependency Injection Cleanup**
- Removed unused constructor-injected dependencies (e.g.,
`FileOrUploadService`, `ApplicationProperties`, redundant `@Autowired`
annotations).
  - Simplified constructors to only require actively used dependencies.

- **Model Enhancements**
- Added `@NoArgsConstructor` to `FileInfo`, `PdfMetadata`, and
`SignatureFile` to improve serialization/deserialization support.

- **Service Improvements**
- Improved `JobExecutorService` content type retrieval by assigning
`MediaType` to a variable before conversion.
- Enhanced `KeyPersistenceService` with type-safe
`.filter(JwtVerificationKey.class::isInstance)`.
- Annotated `decodePublicKey` in `KeyPersistenceService` with
`@Override` for clarity.

- **Controller & API Changes**
- Updated `AdminSettingsController` to use
`TypeReference<Map<String,Object>>` for safer conversion.
- Improved long log and description strings with consistent formatting.

- **Testing Updates**
- Replaced `.lenient()` mock settings with
`.defaultAnswer(RETURNS_DEFAULTS)` for `FileToPdf` static mocks.
- Used `ArgumentMatchers.<TypeReference<List<BookmarkItem>>>any()` in
`EditTableOfContentsControllerTest` for type safety.
- Updated `UserServiceTest` default `AuthenticationType` from `SSO` to
`OAUTH2`.

- **Formatting**
  - Broke up long log/debug lines for better readability.
  - Removed redundant `@SuppressWarnings` where type safety was ensured.

These changes aim to make the codebase leaner, more type-safe, and
maintainable, while improving test reliability.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Ludy 2025-08-20 16:36:39 +02:00 committed by GitHub
parent c10474fd30
commit ab7cef5a97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 91 additions and 71 deletions

View File

@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.FileOrUploadService;
import stirling.software.common.service.FileStorage;
import stirling.software.common.service.JobExecutorService;
@ -34,7 +33,6 @@ public class AutoJobAspect {
private final JobExecutorService jobExecutorService;
private final HttpServletRequest request;
private final FileOrUploadService fileOrUploadService;
private final FileStorage fileStorage;
@Around("@annotation(autoJobPostMapping)")
@ -53,7 +51,8 @@ public class AutoJobAspect {
boolean trackProgress = autoJobPostMapping.trackProgress();
log.debug(
"AutoJobPostMapping execution with async={}, timeout={}, retryCount={}, trackProgress={}",
"AutoJobPostMapping execution with async={}, timeout={}, retryCount={},"
+ " trackProgress={}",
async,
timeout > 0 ? timeout : "default",
retryCount,
@ -148,7 +147,8 @@ public class AutoJobAspect {
} catch (Throwable ex) {
lastException = ex;
log.error(
"AutoJobAspect caught exception during job execution (attempt {}/{}): {}",
"AutoJobAspect caught exception during job execution (attempt"
+ " {}/{}): {}",
currentAttempt,
maxRetries,
ex.getMessage(),

View File

@ -8,9 +8,11 @@ import java.util.Locale;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FileInfo {
private static final DateTimeFormatter DATE_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

View File

@ -2,11 +2,15 @@ package stirling.software.common.model;
import java.util.Calendar;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PdfMetadata {
private String author;
private String producer;

View File

@ -252,8 +252,10 @@ public class JobExecutorService {
}
}
if (response.getHeaders().getContentType() != null) {
contentType = response.getHeaders().getContentType().toString();
MediaType mediaType = response.getHeaders().getContentType();
if (mediaType != null) {
contentType = mediaType.toString();
}
// Store byte array directly to disk

View File

@ -4,7 +4,6 @@ import org.owasp.html.AttributePolicy;
import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;
import org.owasp.html.Sanitizers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import stirling.software.common.model.ApplicationProperties;
@ -16,7 +15,6 @@ public class CustomHtmlSanitizer {
private final SsrfProtectionService ssrfProtectionService;
private final ApplicationProperties applicationProperties;
@Autowired
public CustomHtmlSanitizer(
SsrfProtectionService ssrfProtectionService,
ApplicationProperties applicationProperties) {

View File

@ -29,7 +29,6 @@ import jakarta.servlet.http.HttpServletRequest;
import stirling.software.common.aop.AutoJobAspect;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.FileOrUploadService;
import stirling.software.common.service.FileStorage;
import stirling.software.common.service.JobExecutorService;
import stirling.software.common.service.JobQueue;
@ -44,8 +43,6 @@ class AutoJobPostMappingIntegrationTest {
@Mock private HttpServletRequest request;
@Mock private FileOrUploadService fileOrUploadService;
@Mock private FileStorage fileStorage;
@Mock private ResourceMonitor resourceMonitor;
@ -54,8 +51,7 @@ class AutoJobPostMappingIntegrationTest {
@BeforeEach
void setUp() {
autoJobAspect =
new AutoJobAspect(jobExecutorService, request, fileOrUploadService, fileStorage);
autoJobAspect = new AutoJobAspect(jobExecutorService, request, fileStorage);
}
@Mock private ProceedingJoinPoint joinPoint;

View File

@ -586,7 +586,10 @@ class EmlToPdfTest {
when(mockPdDocument.getNumberOfPages()).thenReturn(1);
try (MockedStatic<FileToPdf> fileToPdf =
mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) {
mockStatic(
FileToPdf.class,
org.mockito.Mockito.withSettings()
.defaultAnswer(org.mockito.Answers.RETURNS_DEFAULTS))) {
fileToPdf
.when(
() ->
@ -657,7 +660,10 @@ class EmlToPdfTest {
when(mockPdDocument.getNumberOfPages()).thenReturn(1);
try (MockedStatic<FileToPdf> fileToPdf =
mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) {
mockStatic(
FileToPdf.class,
org.mockito.Mockito.withSettings()
.defaultAnswer(org.mockito.Answers.RETURNS_DEFAULTS))) {
fileToPdf
.when(
() ->
@ -724,7 +730,10 @@ class EmlToPdfTest {
String errorMessage = "Conversion failed";
try (MockedStatic<FileToPdf> fileToPdf =
mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) {
mockStatic(
FileToPdf.class,
org.mockito.Mockito.withSettings()
.defaultAnswer(org.mockito.Answers.RETURNS_DEFAULTS))) {
fileToPdf
.when(
() ->

View File

@ -27,7 +27,6 @@ import stirling.software.SPDF.UI.WebBrowser;
import stirling.software.common.configuration.AppConfig;
import stirling.software.common.configuration.ConfigInitializer;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.util.UrlUtils;
@Slf4j
@ -46,17 +45,14 @@ public class SPDFApplication {
private final AppConfig appConfig;
private final Environment env;
private final ApplicationProperties applicationProperties;
private final WebBrowser webBrowser;
public SPDFApplication(
AppConfig appConfig,
Environment env,
ApplicationProperties applicationProperties,
@Autowired(required = false) WebBrowser webBrowser) {
this.appConfig = appConfig;
this.env = env;
this.applicationProperties = applicationProperties;
this.webBrowser = webBrowser;
}

View File

@ -6,8 +6,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
@ -18,11 +16,12 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Component
@RequiredArgsConstructor
@Slf4j
public class EndpointInspector implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger logger = LoggerFactory.getLogger(EndpointInspector.class);
private final ApplicationContext applicationContext;
private final Set<String> validGetEndpoints = new HashSet<>();
@ -71,13 +70,13 @@ public class EndpointInspector implements ApplicationListener<ContextRefreshedEv
}
if (validGetEndpoints.isEmpty()) {
logger.warn("No endpoints discovered. Adding common endpoints as fallback.");
log.warn("No endpoints discovered. Adding common endpoints as fallback.");
validGetEndpoints.add("/");
validGetEndpoints.add("/api/**");
validGetEndpoints.add("/**");
}
} catch (Exception e) {
logger.error("Error discovering endpoints", e);
log.error("Error discovering endpoints", e);
}
}
@ -203,10 +202,10 @@ public class EndpointInspector implements ApplicationListener<ContextRefreshedEv
private void logAllEndpoints() {
Set<String> sortedEndpoints = new TreeSet<>(validGetEndpoints);
logger.info("=== BEGIN: All discovered GET endpoints ===");
log.info("=== BEGIN: All discovered GET endpoints ===");
for (String endpoint : sortedEndpoints) {
logger.info("Endpoint: {}", endpoint);
log.info("Endpoint: {}", endpoint);
}
logger.info("=== END: All discovered GET endpoints ===");
log.info("=== END: All discovered GET endpoints ===");
}
}

View File

@ -2,8 +2,10 @@ package stirling.software.SPDF.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SignatureFile {
private String fileName;

View File

@ -4,8 +4,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@ -13,15 +11,15 @@ import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.search.Search;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointInspector;
import stirling.software.common.service.PostHogService;
@Service
@RequiredArgsConstructor
@Slf4j
public class MetricsAggregatorService {
private static final Logger logger = LoggerFactory.getLogger(MetricsAggregatorService.class);
private final MeterRegistry meterRegistry;
private final PostHogService postHogService;
private final EndpointInspector endpointInspector;
@ -66,7 +64,7 @@ public class MetricsAggregatorService {
if ("GET".equals(method)
&& validateGetEndpoints
&& !endpointInspector.isValidGetEndpoint(uri)) {
logger.debug("Skipping invalid GET endpoint: {}", uri);
log.debug("Skipping invalid GET endpoint: {}", uri);
return;
}
@ -77,7 +75,7 @@ public class MetricsAggregatorService {
double lastCount = lastSentMetrics.getOrDefault(key, 0.0);
double difference = currentCount - lastCount;
if (difference > 0) {
logger.debug("{}, {}", key, difference);
log.debug("{}, {}", key, difference);
metrics.put(key, difference);
lastSentMetrics.put(key, currentCount);
}

View File

@ -20,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ -202,7 +203,9 @@ class EditTableOfContentsControllerTest {
bookmarks.add(bookmark);
when(pdfDocumentFactory.load(mockFile)).thenReturn(mockDocument);
when(objectMapper.readValue(eq(request.getBookmarkData()), any(TypeReference.class)))
when(objectMapper.readValue(
eq(request.getBookmarkData()),
ArgumentMatchers.<TypeReference<List<BookmarkItem>>>any()))
.thenReturn(bookmarks);
when(mockDocument.getDocumentCatalog()).thenReturn(mockCatalog);
when(mockDocument.getNumberOfPages()).thenReturn(5);
@ -242,7 +245,8 @@ class EditTableOfContentsControllerTest {
request.setFileInput(mockFile);
String bookmarkJson =
"[{\"title\":\"Chapter 1\",\"pageNumber\":1,\"children\":[{\"title\":\"Section 1.1\",\"pageNumber\":2,\"children\":[]}]}]";
"[{\"title\":\"Chapter 1\",\"pageNumber\":1,\"children\":[{\"title\":\"Section"
+ " 1.1\",\"pageNumber\":2,\"children\":[]}]}]";
request.setBookmarkData(bookmarkJson);
List<BookmarkItem> bookmarks = new ArrayList<>();
@ -261,7 +265,9 @@ class EditTableOfContentsControllerTest {
bookmarks.add(parentBookmark);
when(pdfDocumentFactory.load(mockFile)).thenReturn(mockDocument);
when(objectMapper.readValue(eq(bookmarkJson), any(TypeReference.class)))
when(objectMapper.readValue(
eq(bookmarkJson),
ArgumentMatchers.<TypeReference<List<BookmarkItem>>>any()))
.thenReturn(bookmarks);
when(mockDocument.getDocumentCatalog()).thenReturn(mockCatalog);
when(mockDocument.getNumberOfPages()).thenReturn(5);
@ -292,7 +298,8 @@ class EditTableOfContentsControllerTest {
EditTableOfContentsRequest request = new EditTableOfContentsRequest();
request.setFileInput(mockFile);
request.setBookmarkData(
"[{\"title\":\"Chapter 1\",\"pageNumber\":-5,\"children\":[]},{\"title\":\"Chapter 2\",\"pageNumber\":100,\"children\":[]}]");
"[{\"title\":\"Chapter 1\",\"pageNumber\":-5,\"children\":[]},{\"title\":\"Chapter"
+ " 2\",\"pageNumber\":100,\"children\":[]}]");
List<BookmarkItem> bookmarks = new ArrayList<>();
@ -310,7 +317,9 @@ class EditTableOfContentsControllerTest {
bookmarks.add(bookmark2);
when(pdfDocumentFactory.load(mockFile)).thenReturn(mockDocument);
when(objectMapper.readValue(eq(request.getBookmarkData()), any(TypeReference.class)))
when(objectMapper.readValue(
eq(request.getBookmarkData()),
ArgumentMatchers.<TypeReference<List<BookmarkItem>>>any()))
.thenReturn(bookmarks);
when(mockDocument.getDocumentCatalog()).thenReturn(mockCatalog);
when(mockDocument.getNumberOfPages()).thenReturn(5);

View File

@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.HtmlUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
@ -81,7 +82,8 @@ public class AdminSettingsController {
@Operation(
summary = "Get all application settings",
description =
"Retrieve all current application settings. Use includePending=true to include settings that will take effect after restart. Admin access required.")
"Retrieve all current application settings. Use includePending=true to include"
+ " settings that will take effect after restart. Admin access required.")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "Settings retrieved successfully"),
@ -95,7 +97,9 @@ public class AdminSettingsController {
log.debug("Admin requested all application settings (includePending={})", includePending);
// Convert ApplicationProperties to Map
Map<String, Object> settings = objectMapper.convertValue(applicationProperties, Map.class);
Map<String, Object> settings =
objectMapper.convertValue(
applicationProperties, new TypeReference<Map<String, Object>>() {});
if (includePending && !pendingChanges.isEmpty()) {
// Merge pending changes into the settings map
@ -112,7 +116,8 @@ public class AdminSettingsController {
@Operation(
summary = "Get pending settings changes",
description =
"Retrieve settings that have been modified but not yet applied (require restart). Admin access required.")
"Retrieve settings that have been modified but not yet applied (require"
+ " restart). Admin access required.")
@ApiResponses(
value = {
@ApiResponse(
@ -137,7 +142,8 @@ public class AdminSettingsController {
@Operation(
summary = "Update application settings (delta updates)",
description =
"Update specific application settings using dot notation keys. Only sends changed values. Changes take effect on restart. Admin access required.")
"Update specific application settings using dot notation keys. Only sends"
+ " changed values. Changes take effect on restart. Admin access required.")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "Settings updated successfully"),
@ -178,7 +184,8 @@ public class AdminSettingsController {
return ResponseEntity.ok(
String.format(
"Successfully updated %d setting(s). Changes will take effect on application restart.",
"Successfully updated %d setting(s). Changes will take effect on"
+ " application restart.",
updatedCount));
} catch (IOException e) {
@ -199,7 +206,8 @@ public class AdminSettingsController {
@Operation(
summary = "Get specific settings section",
description =
"Retrieve settings for a specific section (e.g., security, system, ui). Admin access required.")
"Retrieve settings for a specific section (e.g., security, system, ui). Admin"
+ " access required.")
@ApiResponses(
value = {
@ApiResponse(
@ -288,7 +296,8 @@ public class AdminSettingsController {
String escapedSectionName = HtmlUtils.htmlEscape(sectionName);
return ResponseEntity.ok(
String.format(
"Successfully updated %d setting(s) in section '%s'. Changes will take effect on application restart.",
"Successfully updated %d setting(s) in section '%s'. Changes will take"
+ " effect on application restart.",
updatedCount, escapedSectionName));
} catch (IOException e) {
@ -308,7 +317,8 @@ public class AdminSettingsController {
@Operation(
summary = "Get specific setting value",
description =
"Retrieve value for a specific setting key using dot notation. Admin access required.")
"Retrieve value for a specific setting key using dot notation. Admin access"
+ " required.")
@ApiResponses(
value = {
@ApiResponse(
@ -348,7 +358,8 @@ public class AdminSettingsController {
@Operation(
summary = "Update specific setting value",
description =
"Update value for a specific setting key using dot notation. Admin access required.")
"Update value for a specific setting key using dot notation. Admin access"
+ " required.")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "Setting updated successfully"),
@ -376,7 +387,8 @@ public class AdminSettingsController {
String escapedKey = HtmlUtils.htmlEscape(key);
return ResponseEntity.ok(
String.format(
"Successfully updated setting '%s'. Changes will take effect on application restart.",
"Successfully updated setting '%s'. Changes will take effect on"
+ " application restart.",
escapedKey));
} catch (IOException e) {
@ -532,7 +544,6 @@ public class AdminSettingsController {
* Recursively mask sensitive fields in settings map. Sensitive fields are replaced with a
* status indicator showing if they're configured.
*/
@SuppressWarnings("unchecked")
private Map<String, Object> maskSensitiveFields(Map<String, Object> settings) {
return maskSensitiveFieldsWithPath(settings, "");
}

View File

@ -128,7 +128,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
// Check if the authenticated user is disabled and invalidate their session if so
if (authentication != null && authentication.isAuthenticated()) {
LoginMethod loginMethod = LoginMethod.UNKNOWN;
UserLoginType loginMethod = UserLoginType.UNKNOWN;
boolean blockRegistration = false;
@ -137,20 +137,20 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
String username = null;
if (principal instanceof UserDetails detailsUser) {
username = detailsUser.getUsername();
loginMethod = LoginMethod.USERDETAILS;
loginMethod = UserLoginType.USERDETAILS;
} else if (principal instanceof OAuth2User oAuth2User) {
username = oAuth2User.getName();
loginMethod = LoginMethod.OAUTH2USER;
loginMethod = UserLoginType.OAUTH2USER;
OAUTH2 oAuth = securityProp.getOauth2();
blockRegistration = oAuth != null && oAuth.getBlockRegistration();
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal saml2User) {
username = saml2User.name();
loginMethod = LoginMethod.SAML2USER;
loginMethod = UserLoginType.SAML2USER;
SAML2 saml2 = securityProp.getSaml2();
blockRegistration = saml2 != null && saml2.getBlockRegistration();
} else if (principal instanceof String stringUser) {
username = stringUser;
loginMethod = LoginMethod.STRINGUSER;
loginMethod = UserLoginType.STRINGUSER;
}
// Retrieve all active sessions for the user
@ -164,8 +164,8 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
boolean isUserDisabled = userService.isUserDisabled(username);
boolean notSsoLogin =
!LoginMethod.OAUTH2USER.equals(loginMethod)
&& !LoginMethod.SAML2USER.equals(loginMethod);
!UserLoginType.OAUTH2USER.equals(loginMethod)
&& !UserLoginType.SAML2USER.equals(loginMethod);
// Block user registration if not allowed by configuration
if (blockRegistration && !isUserExists) {
@ -200,7 +200,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
filterChain.doFilter(request, response);
}
private enum LoginMethod {
private enum UserLoginType {
USERDETAILS("UserDetails"),
OAUTH2USER("OAuth2User"),
STRINGUSER("StringUser"),
@ -209,7 +209,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
private String method;
LoginMethod(String method) {
UserLoginType(String method) {
this.method = method;
}

View File

@ -12,7 +12,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseCookie;
@ -53,7 +52,6 @@ public class JwtService implements JwtServiceInterface {
private final KeyPersistenceServiceInterface keyPersistenceService;
private final boolean v2Enabled;
@Autowired
public JwtService(
@Qualifier("v2Enabled") boolean v2Enabled,
KeyPersistenceServiceInterface keyPersistenceService) {
@ -155,7 +153,8 @@ public class JwtService implements JwtServiceInterface {
keyPair = specificKeyPair.get();
} else {
log.warn(
"Key ID {} not found in keystore, token may have been signed with an expired key",
"Key ID {} not found in keystore, token may have been signed with an"
+ " expired key",
keyId);
if (keyId.equals(keyPersistenceService.getActiveKey().getKeyId())) {

View File

@ -8,7 +8,6 @@ import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@ -30,7 +29,6 @@ public class KeyPairCleanupService {
private final KeyPersistenceService keyPersistenceService;
private final ApplicationProperties.Security.Jwt jwtProperties;
@Autowired
public KeyPairCleanupService(
KeyPersistenceService keyPersistenceService,
ApplicationProperties applicationProperties) {

View File

@ -20,7 +20,6 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
@ -43,16 +42,13 @@ public class KeyPersistenceService implements KeyPersistenceServiceInterface {
public static final String KEY_SUFFIX = ".key";
private final ApplicationProperties.Security.Jwt jwtProperties;
private final CacheManager cacheManager;
private final Cache verifyingKeyCache;
private volatile JwtVerificationKey activeKey;
@Autowired
public KeyPersistenceService(
ApplicationProperties applicationProperties, CacheManager cacheManager) {
this.jwtProperties = applicationProperties.getSecurity().getJwt();
this.cacheManager = cacheManager;
this.verifyingKeyCache = cacheManager.getCache("verifyingKeys");
}
@ -159,7 +155,7 @@ public class KeyPersistenceService implements KeyPersistenceServiceInterface {
nativeCache.asMap().size());
return nativeCache.asMap().values().stream()
.filter(value -> value instanceof JwtVerificationKey)
.filter(JwtVerificationKey.class::isInstance)
.map(value -> (JwtVerificationKey) value)
.filter(
key -> {
@ -233,6 +229,7 @@ public class KeyPersistenceService implements KeyPersistenceServiceInterface {
return Base64.getEncoder().encodeToString(publicKey.getEncoded());
}
@Override
public PublicKey decodePublicKey(String encodedKey)
throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] keyBytes = Base64.getDecoder().decode(encodedKey);

View File

@ -189,7 +189,7 @@ class UserServiceTest {
void testSaveUser_WithValidEmail_Success() throws Exception {
// Given
String emailUsername = "test@example.com";
AuthenticationType authType = AuthenticationType.SSO;
AuthenticationType authType = AuthenticationType.OAUTH2;
when(teamRepository.findByName("Default")).thenReturn(Optional.of(mockTeam));
when(userRepository.save(any(User.class))).thenReturn(mockUser);