mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
feat(docker): update base images to Java 25, Spring 4, Jackson 3, Gradle 9 and optimize JVM options (Project Lilliput) (#5725)
Co-authored-by: Anthony Stirling <[email protected]>
This commit is contained in:
co-authored by
Anthony Stirling
parent
24128dd318
commit
1f9b90ad57
+8
-14
@@ -2,21 +2,22 @@ package stirling.software.proprietary.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.TaskDecorator;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class AsyncConfig {
|
||||
|
||||
/**
|
||||
* MDC context-propagating task decorator Copies MDC context from the caller thread to the async
|
||||
* executor thread
|
||||
* MDC context-propagating task decorator. Copies MDC context from the caller thread to the
|
||||
* virtual thread executing the task.
|
||||
*/
|
||||
static class MDCContextTaskDecorator implements TaskDecorator {
|
||||
@Override
|
||||
@@ -42,16 +43,9 @@ public class AsyncConfig {
|
||||
|
||||
@Bean(name = "auditExecutor")
|
||||
public Executor auditExecutor() {
|
||||
ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
|
||||
exec.setCorePoolSize(2);
|
||||
exec.setMaxPoolSize(8);
|
||||
exec.setQueueCapacity(1_000);
|
||||
exec.setThreadNamePrefix("audit-");
|
||||
|
||||
// Set the task decorator to propagate MDC context
|
||||
exec.setTaskDecorator(new MDCContextTaskDecorator());
|
||||
|
||||
exec.initialize();
|
||||
return exec;
|
||||
TaskExecutorAdapter adapter =
|
||||
new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
|
||||
adapter.setTaskDecorator(new MDCContextTaskDecorator());
|
||||
return adapter;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -1,15 +1,12 @@
|
||||
package stirling.software.proprietary.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/** Configuration to enable scheduling for the audit system. */
|
||||
/** Configuration for audit system transaction management. */
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableScheduling
|
||||
public class AuditJpaConfig {
|
||||
// This configuration enables scheduling for audit cleanup tasks
|
||||
// JPA repositories are now managed by DatabaseConfig to avoid conflicts
|
||||
// No additional beans or methods needed
|
||||
// Scheduling is enabled on SPDFApplication — no duplicate @EnableScheduling needed.
|
||||
// JPA repositories are now managed by DatabaseConfig to avoid conflicts.
|
||||
}
|
||||
|
||||
+6
-3
@@ -12,8 +12,6 @@ import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -21,6 +19,8 @@ import stirling.software.proprietary.model.security.PersistentAuditEvent;
|
||||
import stirling.software.proprietary.repository.PersistentAuditEventRepository;
|
||||
import stirling.software.proprietary.util.SecretMasker;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@Component
|
||||
@Primary
|
||||
@RequiredArgsConstructor
|
||||
@@ -68,7 +68,10 @@ public class CustomAuditEventRepository implements AuditEventRepository {
|
||||
.build();
|
||||
repo.save(ent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); // fail-open
|
||||
log.error(
|
||||
"Failed to persist audit event (fail-open); principal={}",
|
||||
ev.getPrincipal(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -28,9 +28,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -47,6 +44,9 @@ import stirling.software.proprietary.model.security.PersistentAuditEvent;
|
||||
import stirling.software.proprietary.repository.PersistentAuditEventRepository;
|
||||
import stirling.software.proprietary.security.config.EnterpriseEndpoint;
|
||||
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/** REST endpoints for the audit dashboard. */
|
||||
@Slf4j
|
||||
@RestController
|
||||
@@ -266,7 +266,7 @@ public class AuditDashboardController {
|
||||
headers.setContentDispositionFormData("attachment", "audit_export.json");
|
||||
|
||||
return ResponseEntity.ok().headers(headers).body(jsonBytes);
|
||||
} catch (JsonProcessingException e) {
|
||||
} catch (JacksonException e) {
|
||||
log.error("Error serializing audit events to JSON", e);
|
||||
return ResponseEntity.internalServerError().build();
|
||||
}
|
||||
|
||||
+5
-5
@@ -20,9 +20,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -32,6 +29,9 @@ import stirling.software.proprietary.model.security.PersistentAuditEvent;
|
||||
import stirling.software.proprietary.repository.PersistentAuditEventRepository;
|
||||
import stirling.software.proprietary.security.config.EnterpriseEndpoint;
|
||||
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/** REST API controller for audit data used by React frontend. */
|
||||
@Slf4j
|
||||
@ProprietaryUiDataApi
|
||||
@@ -332,7 +332,7 @@ public class AuditRestController {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> parsed = objectMapper.readValue(event.getData(), Map.class);
|
||||
details = parsed;
|
||||
} catch (JsonProcessingException e) {
|
||||
} catch (JacksonException e) {
|
||||
log.warn("Failed to parse audit event data as JSON: {}", event.getData());
|
||||
details.put("rawData", event.getData());
|
||||
}
|
||||
@@ -380,7 +380,7 @@ public class AuditRestController {
|
||||
headers.setContentDispositionFormData("attachment", "audit_export.json");
|
||||
|
||||
return ResponseEntity.ok().headers(headers).body(jsonBytes);
|
||||
} catch (JsonProcessingException e) {
|
||||
} catch (JacksonException e) {
|
||||
log.error("Error serializing audit events to JSON", e);
|
||||
return ResponseEntity.internalServerError().build();
|
||||
}
|
||||
|
||||
+4
-4
@@ -15,9 +15,6 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import lombok.Data;
|
||||
@@ -54,6 +51,9 @@ import stirling.software.proprietary.security.service.TeamService;
|
||||
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.proprietary.service.UserLicenseSettingsService;
|
||||
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@Slf4j
|
||||
@ProprietaryUiDataApi
|
||||
public class ProprietaryUIDataController {
|
||||
@@ -414,7 +414,7 @@ public class ProprietaryUIDataController {
|
||||
String settingsJson;
|
||||
try {
|
||||
settingsJson = objectMapper.writeValueAsString(user.get().getSettings());
|
||||
} catch (JsonProcessingException e) {
|
||||
} catch (JacksonException e) {
|
||||
log.error("Error converting settings map", e);
|
||||
return ResponseEntity.status(500).build();
|
||||
}
|
||||
|
||||
+4
-4
@@ -8,9 +8,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -20,6 +17,9 @@ import stirling.software.proprietary.model.security.PersistentAuditEvent;
|
||||
import stirling.software.proprietary.repository.PersistentAuditEventRepository;
|
||||
import stirling.software.proprietary.security.config.EnterpriseEndpoint;
|
||||
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/** REST API controller for usage analytics data used by React frontend. */
|
||||
@Slf4j
|
||||
@ProprietaryUiDataApi
|
||||
@@ -135,7 +135,7 @@ public class UsageRestController {
|
||||
return normalizeEndpoint(requestUri.toString());
|
||||
}
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
} catch (JacksonException e) {
|
||||
log.debug("Failed to parse audit data JSON: {}", dataJson, e);
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -6,9 +6,9 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.DatabaseDriver;
|
||||
import org.springframework.boot.persistence.autoconfigure.EntityScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
@@ -75,10 +75,18 @@ public class DatabaseConfig {
|
||||
}
|
||||
|
||||
private DataSource useDefaultDataSource(DataSourceBuilder<?> dataSourceBuilder) {
|
||||
// Support AOT training: override URL via system property to avoid H2 file lock
|
||||
// conflicts when the AOT RECORD phase starts a second Spring context
|
||||
String overrideUrl = System.getProperty("stirling.datasource.url");
|
||||
String url =
|
||||
(overrideUrl != null && !overrideUrl.isBlank())
|
||||
? overrideUrl
|
||||
: DATASOURCE_DEFAULT_URL;
|
||||
|
||||
log.info("Using default H2 database");
|
||||
|
||||
dataSourceBuilder
|
||||
.url(DATASOURCE_DEFAULT_URL)
|
||||
.url(url)
|
||||
.driverClassName(DatabaseDriver.H2.getDriverClassName())
|
||||
.username(DEFAULT_USERNAME);
|
||||
|
||||
|
||||
+16
-13
@@ -14,15 +14,17 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.CorsConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml5AuthenticationRequestResolver;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||
@@ -82,7 +84,7 @@ public class SecurityConfiguration {
|
||||
private final PersistentLoginRepository persistentLoginRepository;
|
||||
private final GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper;
|
||||
private final RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations;
|
||||
private final OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver;
|
||||
private final OpenSaml5AuthenticationRequestResolver saml2AuthenticationRequestResolver;
|
||||
private final stirling.software.proprietary.service.UserLicenseSettingsService
|
||||
licenseSettingsService;
|
||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||
@@ -105,7 +107,7 @@ public class SecurityConfiguration {
|
||||
@Autowired(required = false)
|
||||
RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations,
|
||||
@Autowired(required = false)
|
||||
OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver,
|
||||
OpenSaml5AuthenticationRequestResolver saml2AuthenticationRequestResolver,
|
||||
@Autowired(required = false) ClientRegistrationRepository clientRegistrationRepository,
|
||||
stirling.software.proprietary.service.UserLicenseSettingsService
|
||||
licenseSettingsService) {
|
||||
@@ -151,7 +153,8 @@ public class SecurityConfiguration {
|
||||
// Default to allowing all origins when nothing is configured
|
||||
cfg.setAllowedOriginPatterns(List.of("*"));
|
||||
log.info(
|
||||
"No CORS allowed origins configured in settings.yml (system.corsAllowedOrigins); allowing all origins.");
|
||||
"No CORS allowed origins configured in settings.yml"
|
||||
+ " (system.corsAllowedOrigins); allowing all origins.");
|
||||
}
|
||||
|
||||
// Explicitly configure supported HTTP methods (include OPTIONS for preflight)
|
||||
@@ -225,7 +228,7 @@ public class SecurityConfiguration {
|
||||
http.cors(cors -> cors.configurationSource(corsSource));
|
||||
} else {
|
||||
// Explicitly disable CORS when no origins are configured
|
||||
http.cors(cors -> cors.disable());
|
||||
http.cors(CorsConfigurer::disable);
|
||||
}
|
||||
|
||||
http.csrf(CsrfConfigurer::disable);
|
||||
@@ -233,24 +236,24 @@ public class SecurityConfiguration {
|
||||
// Configure X-Frame-Options based on settings.yml configuration
|
||||
// When login is disabled, automatically disable X-Frame-Options to allow embedding
|
||||
if (!loginEnabledValue) {
|
||||
http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable()));
|
||||
http.headers(headers -> headers.frameOptions(FrameOptionsConfig::disable));
|
||||
} else {
|
||||
String xFrameOption = securityProperties.getXFrameOptions();
|
||||
if (xFrameOption != null) {
|
||||
http.headers(
|
||||
headers -> {
|
||||
if ("DISABLED".equalsIgnoreCase(xFrameOption)) {
|
||||
headers.frameOptions(frameOptions -> frameOptions.disable());
|
||||
headers.frameOptions(FrameOptionsConfig::disable);
|
||||
} else if ("SAMEORIGIN".equalsIgnoreCase(xFrameOption)) {
|
||||
headers.frameOptions(frameOptions -> frameOptions.sameOrigin());
|
||||
headers.frameOptions(FrameOptionsConfig::sameOrigin);
|
||||
} else {
|
||||
// Default to DENY
|
||||
headers.frameOptions(frameOptions -> frameOptions.deny());
|
||||
headers.frameOptions(FrameOptionsConfig::deny);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// If not configured, use default DENY
|
||||
http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.deny()));
|
||||
http.headers(headers -> headers.frameOptions(FrameOptionsConfig::deny));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,8 +384,8 @@ public class SecurityConfiguration {
|
||||
}
|
||||
// Handle SAML
|
||||
if (securityProperties.isSaml2Active() && runningProOrHigher) {
|
||||
OpenSaml4AuthenticationProvider authenticationProvider =
|
||||
new OpenSaml4AuthenticationProvider();
|
||||
OpenSaml5AuthenticationProvider authenticationProvider =
|
||||
new OpenSaml5AuthenticationProvider();
|
||||
authenticationProvider.setResponseAuthenticationConverter(
|
||||
new CustomSaml2ResponseAuthenticationConverter(userService));
|
||||
http.authenticationProvider(authenticationProvider)
|
||||
|
||||
+90
-87
@@ -12,11 +12,6 @@ import org.bouncycastle.crypto.signers.Ed25519Signer;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.posthog.java.shaded.org.json.JSONException;
|
||||
import com.posthog.java.shaded.org.json.JSONObject;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -24,6 +19,9 @@ import stirling.software.common.model.ApplicationProperties;
|
||||
import stirling.software.common.util.GeneralUtils;
|
||||
import stirling.software.common.util.RegexPatternUtils;
|
||||
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@@ -47,7 +45,7 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
private static final String JWT_PREFIX = "key/";
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final ObjectMapper objectMapper;
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
// Shared HTTP client for connection pooling
|
||||
@@ -135,11 +133,11 @@ public class KeygenLicenseVerifier {
|
||||
String algorithm = "";
|
||||
|
||||
try {
|
||||
JSONObject attrs = new JSONObject(payload);
|
||||
encryptedData = (String) attrs.get("enc");
|
||||
encodedSignature = (String) attrs.get("sig");
|
||||
algorithm = (String) attrs.get("alg");
|
||||
} catch (JSONException e) {
|
||||
JsonNode attrs = objectMapper.readTree(payload);
|
||||
encryptedData = attrs.path("enc").asText("");
|
||||
encodedSignature = attrs.path("sig").asText("");
|
||||
algorithm = attrs.path("alg").asText("");
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to parse license file: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
@@ -215,11 +213,17 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
private boolean processCertificateData(String certData, LicenseContext context) {
|
||||
try {
|
||||
JSONObject licenseData = new JSONObject(certData);
|
||||
JSONObject metaObj = licenseData.optJSONObject("meta");
|
||||
if (metaObj != null) {
|
||||
String issuedStr = metaObj.optString("issued", null);
|
||||
String expiryStr = metaObj.optString("expiry", null);
|
||||
JsonNode licenseData = objectMapper.readTree(certData);
|
||||
JsonNode metaObj = licenseData.path("meta");
|
||||
if (!metaObj.isMissingNode() && metaObj.isObject()) {
|
||||
String issuedStr =
|
||||
metaObj.path("issued").isNull()
|
||||
? null
|
||||
: metaObj.path("issued").asText(null);
|
||||
String expiryStr =
|
||||
metaObj.path("expiry").isNull()
|
||||
? null
|
||||
: metaObj.path("expiry").asText(null);
|
||||
|
||||
if (issuedStr != null && expiryStr != null) {
|
||||
java.time.Instant issued = java.time.Instant.parse(issuedStr);
|
||||
@@ -244,31 +248,32 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
|
||||
// Get the main license data
|
||||
JSONObject dataObj = licenseData.optJSONObject("data");
|
||||
if (dataObj == null) {
|
||||
JsonNode dataObj = licenseData.path("data");
|
||||
if (dataObj.isMissingNode() || !dataObj.isObject()) {
|
||||
log.error("No data object found in certificate");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract license or machine information
|
||||
JSONObject attributesObj = dataObj.optJSONObject("attributes");
|
||||
if (attributesObj != null) {
|
||||
JsonNode attributesObj = dataObj.path("attributes");
|
||||
if (!attributesObj.isMissingNode() && attributesObj.isObject()) {
|
||||
log.info("Found attributes in certificate data");
|
||||
|
||||
// Check for floating license
|
||||
context.isFloatingLicense = attributesObj.optBoolean("floating", false);
|
||||
context.maxMachines = attributesObj.optInt("maxMachines", 1);
|
||||
context.isFloatingLicense = attributesObj.path("floating").asBoolean(false);
|
||||
context.maxMachines = attributesObj.path("maxMachines").asInt(1);
|
||||
|
||||
// Extract metadata
|
||||
JSONObject metadataObj = attributesObj.optJSONObject("metadata");
|
||||
if (metadataObj != null) {
|
||||
JsonNode metadataObj = attributesObj.path("metadata");
|
||||
if (!metadataObj.isMissingNode() && metadataObj.isObject()) {
|
||||
// Check if this is an old license (no planType) with isEnterprise flag
|
||||
context.isEnterpriseLicense = metadataObj.optBoolean("isEnterprise", false);
|
||||
context.isEnterpriseLicense = metadataObj.path("isEnterprise").asBoolean(false);
|
||||
|
||||
// Extract user count - default based on license type
|
||||
// Old licenses: Only had isEnterprise flag
|
||||
// New licenses: Have planType field with "server" or "enterprise"
|
||||
int users = metadataObj.optInt("users", context.isEnterpriseLicense ? 1 : 0);
|
||||
int users =
|
||||
metadataObj.path("users").asInt(context.isEnterpriseLicense ? 1 : 0);
|
||||
|
||||
// SERVER license (isEnterprise=false, users=0) = unlimited
|
||||
// ENTERPRISE license (isEnterprise=true, users>0) = limited seats
|
||||
@@ -282,7 +287,7 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
|
||||
// Check license status if available
|
||||
String status = attributesObj.optString("status", null);
|
||||
String status = attributesObj.path("status").asText(null);
|
||||
if (status != null
|
||||
&& !"ACTIVE".equals(status)
|
||||
&& !"EXPIRING".equals(status)) { // Accept "EXPIRING" status as valid
|
||||
@@ -372,11 +377,11 @@ public class KeygenLicenseVerifier {
|
||||
try {
|
||||
log.info("Processing license payload: {}", payload);
|
||||
|
||||
JSONObject licenseData = new JSONObject(payload);
|
||||
JsonNode licenseData = objectMapper.readTree(payload);
|
||||
|
||||
JSONObject licenseObj = licenseData.optJSONObject("license");
|
||||
if (licenseObj == null) {
|
||||
String id = licenseData.optString("id", null);
|
||||
JsonNode licenseObj = licenseData.path("license");
|
||||
if (licenseObj.isMissingNode() || !licenseObj.isObject()) {
|
||||
String id = licenseData.path("id").asText(null);
|
||||
if (id != null) {
|
||||
log.info("Found license ID: {}", id);
|
||||
licenseObj = licenseData; // Use the root object as the license object
|
||||
@@ -386,18 +391,18 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
String licenseId = licenseObj.optString("id", "unknown");
|
||||
String licenseId = licenseObj.path("id").asText("unknown");
|
||||
log.info("Processing license with ID: {}", licenseId);
|
||||
|
||||
// Check for floating license in license object
|
||||
context.isFloatingLicense = licenseObj.optBoolean("floating", false);
|
||||
context.maxMachines = licenseObj.optInt("maxMachines", 1);
|
||||
context.isFloatingLicense = licenseObj.path("floating").asBoolean(false);
|
||||
context.maxMachines = licenseObj.path("maxMachines").asInt(1);
|
||||
if (context.isFloatingLicense) {
|
||||
log.info("Detected floating license with max machines: {}", context.maxMachines);
|
||||
}
|
||||
|
||||
// Check expiry date
|
||||
String expiryStr = licenseObj.optString("expiry", null);
|
||||
String expiryStr = licenseObj.path("expiry").asText(null);
|
||||
if (expiryStr != null && !"null".equals(expiryStr)) {
|
||||
java.time.Instant expiry = java.time.Instant.parse(expiryStr);
|
||||
java.time.Instant now = java.time.Instant.now();
|
||||
@@ -413,9 +418,9 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
|
||||
// Extract account, product, policy info
|
||||
JSONObject accountObj = licenseData.optJSONObject("account");
|
||||
if (accountObj != null) {
|
||||
String accountId = accountObj.optString("id", "unknown");
|
||||
JsonNode accountObj = licenseData.path("account");
|
||||
if (!accountObj.isMissingNode() && accountObj.isObject()) {
|
||||
String accountId = accountObj.path("id").asText("unknown");
|
||||
log.info("License belongs to account: {}", accountId);
|
||||
|
||||
// Verify this matches your expected account ID
|
||||
@@ -426,14 +431,14 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
|
||||
// Extract policy information if available
|
||||
JSONObject policyObj = licenseData.optJSONObject("policy");
|
||||
if (policyObj != null) {
|
||||
String policyId = policyObj.optString("id", "unknown");
|
||||
JsonNode policyObj = licenseData.path("policy");
|
||||
if (!policyObj.isMissingNode() && policyObj.isObject()) {
|
||||
String policyId = policyObj.path("id").asText("unknown");
|
||||
log.info("License uses policy: {}", policyId);
|
||||
|
||||
// Check for floating license in policy
|
||||
boolean policyFloating = policyObj.optBoolean("floating", false);
|
||||
int policyMaxMachines = policyObj.optInt("maxMachines", 1);
|
||||
boolean policyFloating = policyObj.path("floating").asBoolean(false);
|
||||
int policyMaxMachines = policyObj.path("maxMachines").asInt(1);
|
||||
|
||||
// Policy settings take precedence
|
||||
if (policyFloating) {
|
||||
@@ -445,16 +450,21 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
|
||||
// Extract max users and isEnterprise from policy or metadata
|
||||
context.isEnterpriseLicense = policyObj.optBoolean("isEnterprise", false);
|
||||
int users = policyObj.optInt("users", -1);
|
||||
context.isEnterpriseLicense = policyObj.path("isEnterprise").asBoolean(false);
|
||||
int users = policyObj.path("users").asInt(-1);
|
||||
|
||||
if (users == -1) {
|
||||
// Try to get users from metadata if not at policy level
|
||||
Object metadataObj = policyObj.opt("metadata");
|
||||
if (metadataObj instanceof JSONObject metadata) {
|
||||
JsonNode metadataObj = policyObj.path("metadata");
|
||||
if (!metadataObj.isMissingNode() && metadataObj.isObject()) {
|
||||
context.isEnterpriseLicense =
|
||||
metadata.optBoolean("isEnterprise", context.isEnterpriseLicense);
|
||||
users = metadata.optInt("users", context.isEnterpriseLicense ? 1 : 0);
|
||||
metadataObj
|
||||
.path("isEnterprise")
|
||||
.asBoolean(context.isEnterpriseLicense);
|
||||
users =
|
||||
metadataObj
|
||||
.path("users")
|
||||
.asInt(context.isEnterpriseLicense ? 1 : 0);
|
||||
} else {
|
||||
// Default based on license type
|
||||
users = context.isEnterpriseLicense ? 1 : 0;
|
||||
@@ -493,9 +503,9 @@ public class KeygenLicenseVerifier {
|
||||
validateLicense(licenseKey, machineFingerprint, context);
|
||||
if (validationResponse != null) {
|
||||
boolean isValid = validationResponse.path("meta").path("valid").asBoolean();
|
||||
String licenseId = validationResponse.path("data").path("id").asText();
|
||||
String licenseId = validationResponse.path("data").path("id").asText("");
|
||||
if (!isValid) {
|
||||
String code = validationResponse.path("meta").path("code").asText();
|
||||
String code = validationResponse.path("meta").path("code").asText("");
|
||||
log.info(code);
|
||||
if ("NO_MACHINE".equals(code)
|
||||
|| "NO_MACHINES".equals(code)
|
||||
@@ -579,8 +589,8 @@ public class KeygenLicenseVerifier {
|
||||
JsonNode metaNode = jsonResponse.path("meta");
|
||||
boolean isValid = metaNode.path("valid").asBoolean();
|
||||
|
||||
String detail = metaNode.path("detail").asText();
|
||||
String code = metaNode.path("code").asText();
|
||||
String detail = metaNode.path("detail").asText("");
|
||||
String code = metaNode.path("code").asText("");
|
||||
|
||||
log.info("License validity: {}", isValid);
|
||||
log.info("Validation detail: {}", detail);
|
||||
@@ -604,7 +614,7 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
if (includedNode.isArray()) {
|
||||
for (JsonNode node : includedNode) {
|
||||
if ("policies".equals(node.path("type").asText())) {
|
||||
if ("policies".equals(node.path("type").asText(""))) {
|
||||
policyNode = node;
|
||||
break;
|
||||
}
|
||||
@@ -690,9 +700,9 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
for (JsonNode machine : machines) {
|
||||
if (machineFingerprint.equals(
|
||||
machine.path("attributes").path("fingerprint").asText())) {
|
||||
machine.path("attributes").path("fingerprint").asText(""))) {
|
||||
isCurrentMachineActivated = true;
|
||||
currentMachineId = machine.path("id").asText();
|
||||
currentMachineId = machine.path("id").asText("");
|
||||
log.info(
|
||||
"Current machine is already activated with ID: {}",
|
||||
currentMachineId);
|
||||
@@ -726,7 +736,7 @@ public class KeygenLicenseVerifier {
|
||||
java.time.Instant.parse(createdStr);
|
||||
if (oldestTime == null || createdTime.isBefore(oldestTime)) {
|
||||
oldestTime = createdTime;
|
||||
oldestMachineId = machine.path("id").asText();
|
||||
oldestMachineId = machine.path("id").asText("");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn(
|
||||
@@ -740,7 +750,7 @@ public class KeygenLicenseVerifier {
|
||||
if (oldestMachineId == null) {
|
||||
log.warn(
|
||||
"Could not determine oldest machine by timestamp, using first machine in list");
|
||||
oldestMachineId = machines.path(0).path("id").asText();
|
||||
oldestMachineId = machines.path(0).path("id").asText("");
|
||||
}
|
||||
|
||||
log.info("Deregistering machine with ID: {}", oldestMachineId);
|
||||
@@ -770,35 +780,28 @@ public class KeygenLicenseVerifier {
|
||||
hostname = "Unknown";
|
||||
}
|
||||
|
||||
JSONObject body =
|
||||
new JSONObject()
|
||||
.put(
|
||||
"data",
|
||||
new JSONObject()
|
||||
.put("type", "machines")
|
||||
.put(
|
||||
"attributes",
|
||||
new JSONObject()
|
||||
.put("fingerprint", machineFingerprint)
|
||||
.put(
|
||||
"platform",
|
||||
System.getProperty("os.name"))
|
||||
.put("name", hostname))
|
||||
.put(
|
||||
"relationships",
|
||||
new JSONObject()
|
||||
.put(
|
||||
"license",
|
||||
new JSONObject()
|
||||
.put(
|
||||
"data",
|
||||
new JSONObject()
|
||||
.put(
|
||||
"type",
|
||||
"licenses")
|
||||
.put(
|
||||
"id",
|
||||
licenseId)))));
|
||||
tools.jackson.databind.node.ObjectNode attributes = objectMapper.createObjectNode();
|
||||
attributes.put("fingerprint", machineFingerprint);
|
||||
attributes.put("platform", System.getProperty("os.name"));
|
||||
attributes.put("name", hostname);
|
||||
|
||||
tools.jackson.databind.node.ObjectNode licenseRef = objectMapper.createObjectNode();
|
||||
licenseRef.put("type", "licenses");
|
||||
licenseRef.put("id", licenseId);
|
||||
|
||||
tools.jackson.databind.node.ObjectNode licenseRelation = objectMapper.createObjectNode();
|
||||
licenseRelation.set("data", licenseRef);
|
||||
|
||||
tools.jackson.databind.node.ObjectNode relationships = objectMapper.createObjectNode();
|
||||
relationships.set("license", licenseRelation);
|
||||
|
||||
tools.jackson.databind.node.ObjectNode data = objectMapper.createObjectNode();
|
||||
data.put("type", "machines");
|
||||
data.set("attributes", attributes);
|
||||
data.set("relationships", relationships);
|
||||
|
||||
tools.jackson.databind.node.ObjectNode body = objectMapper.createObjectNode();
|
||||
body.set("data", data);
|
||||
|
||||
HttpRequest request =
|
||||
HttpRequest.newBuilder()
|
||||
|
||||
+6
-6
@@ -27,9 +27,6 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
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;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
@@ -49,6 +46,9 @@ import stirling.software.proprietary.security.model.api.admin.SettingValueRespon
|
||||
import stirling.software.proprietary.security.model.api.admin.UpdateSettingValueRequest;
|
||||
import stirling.software.proprietary.security.model.api.admin.UpdateSettingsRequest;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@AdminApi
|
||||
@RequiredArgsConstructor
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@@ -543,7 +543,8 @@ public class AdminSettingsController {
|
||||
pendingChanges.clear();
|
||||
|
||||
// Give the HTTP response time to complete, then exit
|
||||
new Thread(
|
||||
Thread.ofVirtual()
|
||||
.start(
|
||||
() -> {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
@@ -554,8 +555,7 @@ public class AdminSettingsController {
|
||||
log.error("Restart interrupted: {}", e.getMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
})
|
||||
.start();
|
||||
});
|
||||
|
||||
return ResponseEntity.ok(
|
||||
Map.of(
|
||||
|
||||
+6
-5
@@ -20,9 +20,6 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import lombok.Data;
|
||||
@@ -31,6 +28,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.common.configuration.RuntimePathConfig;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/ui-data")
|
||||
@@ -39,6 +39,7 @@ public class UIDataTessdataController {
|
||||
|
||||
private static final Pattern INVALID_LANG_CHARS_PATTERN = Pattern.compile("[^A-Za-z0-9_+\\-]");
|
||||
private final RuntimePathConfig runtimePathConfig;
|
||||
private final ObjectMapper objectMapper;
|
||||
private static volatile List<String> cachedRemoteTessdata = null;
|
||||
private static volatile long cachedRemoteTessdataExpiry = 0L;
|
||||
private static final long REMOTE_TESSDATA_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
||||
@@ -223,9 +224,9 @@ public class UIDataTessdataController {
|
||||
}
|
||||
|
||||
try (InputStream is = connection.getInputStream()) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
List<Map<String, Object>> items =
|
||||
mapper.readValue(is, new TypeReference<List<Map<String, Object>>>() {});
|
||||
objectMapper.readValue(
|
||||
is, new TypeReference<List<Map<String, Object>>>() {});
|
||||
List<String> languages =
|
||||
items.stream()
|
||||
.map(item -> (String) item.get("name"))
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ public class ApiKeyAuthenticationToken extends AbstractAuthenticationToken {
|
||||
private Object credentials;
|
||||
|
||||
public ApiKeyAuthenticationToken(String apiKey) {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
this.principal = null;
|
||||
this.credentials = apiKey;
|
||||
setAuthenticated(false);
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import org.opensaml.saml.saml2.core.AuthnStatement;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken;
|
||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.ResponseToken;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
+4
-4
@@ -15,7 +15,7 @@ import org.springframework.security.saml2.provider.service.registration.InMemory
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml5AuthenticationRequestResolver;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -151,10 +151,10 @@ public class Saml2Configuration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
|
||||
public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver(
|
||||
public OpenSaml5AuthenticationRequestResolver authenticationRequestResolver(
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||
OpenSaml4AuthenticationRequestResolver resolver =
|
||||
new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationRepository);
|
||||
OpenSaml5AuthenticationRequestResolver resolver =
|
||||
new OpenSaml5AuthenticationRequestResolver(relyingPartyRegistrationRepository);
|
||||
|
||||
resolver.setRelayStateResolver(
|
||||
request -> {
|
||||
|
||||
+8
-7
@@ -20,9 +20,6 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
@@ -40,21 +37,25 @@ import stirling.software.proprietary.security.model.JwtVerificationKey;
|
||||
import stirling.software.proprietary.security.model.exception.AuthenticationFailureException;
|
||||
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class JwtService implements JwtServiceInterface {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final KeyPersistenceServiceInterface keyPersistenceService;
|
||||
private final boolean v2Enabled;
|
||||
private final ApplicationProperties.Security securityProperties;
|
||||
|
||||
@Autowired
|
||||
public JwtService(
|
||||
ObjectMapper objectMapper,
|
||||
@Qualifier("v2Enabled") boolean v2Enabled,
|
||||
KeyPersistenceServiceInterface keyPersistenceService,
|
||||
ApplicationProperties applicationProperties) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.v2Enabled = v2Enabled;
|
||||
this.keyPersistenceService = keyPersistenceService;
|
||||
this.securityProperties = applicationProperties.getSecurity();
|
||||
@@ -374,14 +375,14 @@ public class JwtService implements JwtServiceInterface {
|
||||
|
||||
byte[] headerBytes = Base64.getUrlDecoder().decode(tokenParts[0]);
|
||||
Map<String, Object> header =
|
||||
OBJECT_MAPPER.readValue(
|
||||
objectMapper.readValue(
|
||||
headerBytes, new TypeReference<Map<String, Object>>() {});
|
||||
Object keyId = header.get("kid");
|
||||
return keyId instanceof String ? (String) keyId : null;
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.debug("Failed to decode Base64 JWT header: {}", e.getMessage());
|
||||
return null;
|
||||
} catch (java.io.IOException e) {
|
||||
} catch (tools.jackson.core.JacksonException e) {
|
||||
log.debug("Failed to parse JWT header as JSON: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
+5
-4
@@ -15,8 +15,6 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.common.configuration.InstallationPathConfig;
|
||||
@@ -24,6 +22,8 @@ import stirling.software.common.service.PersonalSignatureServiceInterface;
|
||||
import stirling.software.proprietary.model.api.signature.SavedSignatureRequest;
|
||||
import stirling.software.proprietary.model.api.signature.SavedSignatureResponse;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Service for managing user signatures with authentication and storage limits. This proprietary
|
||||
* version enforces per-user quotas and requires authentication. Provides access to personal
|
||||
@@ -36,15 +36,16 @@ public class SignatureService implements PersonalSignatureServiceInterface {
|
||||
private static final Pattern FILENAME_VALIDATION_PATTERN = Pattern.compile("^[a-zA-Z0-9_.-]+$");
|
||||
private final String SIGNATURE_BASE_PATH;
|
||||
private final String ALL_USERS_FOLDER = "ALL_USERS";
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
// Storage limits per user
|
||||
private static final int MAX_SIGNATURES_PER_USER = 20;
|
||||
private static final long MAX_SIGNATURE_SIZE_BYTES = 2_000_000; // 2MB per signature
|
||||
private static final long MAX_TOTAL_USER_STORAGE_BYTES = 20_000_000; // 20MB total per user
|
||||
|
||||
public SignatureService() {
|
||||
public SignatureService(ObjectMapper objectMapper) {
|
||||
SIGNATURE_BASE_PATH = InstallationPathConfig.getSignaturesPath();
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-3
@@ -16,8 +16,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
import stirling.software.common.model.enumeration.Role;
|
||||
import stirling.software.proprietary.config.AuditConfigurationProperties;
|
||||
@@ -35,6 +33,9 @@ import stirling.software.proprietary.security.service.MfaService;
|
||||
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.proprietary.service.UserLicenseSettingsService;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ProprietaryUIDataControllerTest {
|
||||
|
||||
@@ -63,7 +64,7 @@ class ProprietaryUIDataControllerTest {
|
||||
applicationProperties.getSecurity().getSaml2().setEnabled(false);
|
||||
|
||||
auditConfig = new AuditConfigurationProperties(applicationProperties);
|
||||
objectMapper = new ObjectMapper();
|
||||
objectMapper = JsonMapper.builder().build();
|
||||
|
||||
controller =
|
||||
new ProprietaryUIDataController(
|
||||
|
||||
+4
-3
@@ -26,8 +26,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
import stirling.software.common.model.enumeration.Role;
|
||||
import stirling.software.proprietary.security.model.AuthenticationType;
|
||||
@@ -42,10 +40,13 @@ import stirling.software.proprietary.security.service.RefreshRateLimitService;
|
||||
import stirling.software.proprietary.security.service.TotpService;
|
||||
import stirling.software.proprietary.security.service.UserService;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AuthControllerLoginTest {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final ObjectMapper objectMapper = JsonMapper.builder().build();
|
||||
|
||||
private MockMvc mockMvc;
|
||||
private ApplicationProperties.Security securityProperties;
|
||||
|
||||
+4
-3
@@ -26,8 +26,6 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import stirling.software.proprietary.security.model.AuthenticationType;
|
||||
import stirling.software.proprietary.security.model.User;
|
||||
import stirling.software.proprietary.security.service.CustomUserDetailsService;
|
||||
@@ -37,12 +35,15 @@ import stirling.software.proprietary.security.service.MfaService;
|
||||
import stirling.software.proprietary.security.service.TotpService;
|
||||
import stirling.software.proprietary.security.service.UserService;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AuthControllerMfaTest {
|
||||
|
||||
private static final String USERNAME = "[email protected]";
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final ObjectMapper objectMapper = JsonMapper.builder().build();
|
||||
|
||||
private MockMvc mockMvc;
|
||||
private Authentication authentication;
|
||||
|
||||
+15
-13
@@ -19,6 +19,8 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import stirling.software.common.configuration.RuntimePathConfig;
|
||||
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
class UIDataTessdataControllerTest {
|
||||
|
||||
@Test
|
||||
@@ -27,7 +29,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn("ignored/path");
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -49,7 +51,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -77,7 +79,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -100,7 +102,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng", "fra");
|
||||
@@ -139,7 +141,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -164,7 +166,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected boolean isWritableDirectory(Path dir) {
|
||||
return false;
|
||||
@@ -186,7 +188,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -217,7 +219,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -258,7 +260,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng", "fra");
|
||||
@@ -282,7 +284,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -307,7 +309,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -330,7 +332,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(missingDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected List<String> getRemoteTessdataLanguages() {
|
||||
return List.of("eng");
|
||||
@@ -352,7 +354,7 @@ class UIDataTessdataControllerTest {
|
||||
Mockito.when(runtimePathConfig.getTessDataPath()).thenReturn(tempDir.toString());
|
||||
|
||||
UIDataTessdataController controller =
|
||||
new UIDataTessdataController(runtimePathConfig) {
|
||||
new UIDataTessdataController(runtimePathConfig, JsonMapper.builder().build()) {
|
||||
@Override
|
||||
protected boolean isWritableDirectory(Path dir) {
|
||||
return false;
|
||||
|
||||
+4
-3
@@ -21,8 +21,6 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
import stirling.software.proprietary.model.Team;
|
||||
import stirling.software.proprietary.security.database.repository.UserRepository;
|
||||
@@ -35,10 +33,13 @@ import stirling.software.proprietary.security.service.UserService;
|
||||
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.proprietary.service.UserLicenseSettingsService;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class UserControllerTest {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final ObjectMapper objectMapper = JsonMapper.builder().build();
|
||||
|
||||
@Mock private UserService userService;
|
||||
@Mock private SessionPersistentRegistry sessionRegistry;
|
||||
|
||||
+5
-1
@@ -36,6 +36,9 @@ import stirling.software.proprietary.security.model.JwtVerificationKey;
|
||||
import stirling.software.proprietary.security.model.User;
|
||||
import stirling.software.proprietary.security.model.exception.AuthenticationFailureException;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class JwtServiceTest {
|
||||
|
||||
@@ -66,7 +69,8 @@ class JwtServiceTest {
|
||||
testVerificationKey = new JwtVerificationKey("test-key-id", encodedPublicKey);
|
||||
|
||||
ApplicationProperties applicationProperties = new ApplicationProperties();
|
||||
jwtService = new JwtService(true, keystoreService, applicationProperties);
|
||||
ObjectMapper objectMapper = JsonMapper.builder().build();
|
||||
jwtService = new JwtService(objectMapper, true, keystoreService, applicationProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user