wip - compiling and tests fixed

This commit is contained in:
Dario Ghunney Ware 2025-05-07 12:03:37 +01:00
parent 8b28c543c4
commit f9cc7833b4
231 changed files with 1156 additions and 1042 deletions

View File

@ -2,6 +2,11 @@ MIT License
Copyright (c) 2024 Stirling Tools Copyright (c) 2024 Stirling Tools
Portions of this software are licensed as follows:
* All content that resides under the "enterprise/" directory of this repository, if that directory exists, is licensed under the license defined in "enterprise/LICENSE".
* Content outside of the above mentioned directories or restrictions above is available under the MIT License as defined below.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights

View File

@ -415,6 +415,7 @@ configurations.all {
dependencies { dependencies {
implementation project(':common') implementation project(':common')
implementation project(':enterprise')
//tmp for security bumps //tmp for security bumps
implementation 'ch.qos.logback:logback-core:1.5.18' implementation 'ch.qos.logback:logback-core:1.5.18'
@ -437,7 +438,7 @@ dependencies {
//security updates //security updates
implementation "org.springframework:spring-webmvc:6.2.6" implementation "org.springframework:spring-webmvc:6.2.6"
implementation("io.github.pixee:java-security-toolkit:1.2.1") implementation 'io.github.pixee:java-security-toolkit:1.2.1'
// Exclude Tomcat and include Jetty // Exclude Tomcat and include Jetty
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion") implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
@ -474,7 +475,6 @@ dependencies {
implementation 'com.coveo:saml-client:5.0.0' implementation 'com.coveo:saml-client:5.0.0'
} }
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion" testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
@ -499,9 +499,6 @@ dependencies {
runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion" runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion" // runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
// Image metadata extractor
implementation "com.drewnoakes:metadata-extractor:2.19.0"
implementation "commons-io:commons-io:2.19.0" implementation "commons-io:commons-io:2.19.0"
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8" implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8"
//general PDF //general PDF
@ -532,11 +529,6 @@ dependencies {
// https://mvnrepository.com/artifact/org.commonmark/commonmark // https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation "org.commonmark:commonmark:0.24.0" implementation "org.commonmark:commonmark:0.24.0"
implementation "org.commonmark:commonmark-ext-gfm-tables:0.24.0" implementation "org.commonmark:commonmark-ext-gfm-tables:0.24.0"
// https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17
implementation "com.bucket4j:bucket4j_jdk17-core:8.14.0"
implementation "com.fathzer:javaluator:3.0.6"
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion") developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion")
compileOnly "org.projectlombok:lombok:$lombokVersion" compileOnly "org.projectlombok:lombok:$lombokVersion"

View File

@ -30,14 +30,27 @@ dependencyManagement {
} }
dependencies { dependencies {
implementation "org.springframework.boot:spring-boot-starter-web" implementation 'org.springframework.boot:spring-boot-starter-web'
implementation "org.springframework.boot:spring-boot-starter-thymeleaf" implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
implementation 'com.fathzer:javaluator:3.0.6'
implementation 'io.github.pixee:java-security-toolkit:1.2.1'
implementation 'org.apache.commons:commons-lang3:3.17.0'
implementation 'com.drewnoakes:metadata-extractor:2.19.0' // Image metadata extractor
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
implementation 'org.apache.pdfbox:pdfbox:3.0.4'
implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0'
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6"
compileOnly "org.projectlombok:lombok:$lombokVersion" compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion"
testImplementation platform('org.junit:junit-bom:5.10.0') testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation "org.springframework.boot:spring-boot-starter-test" testImplementation "org.springframework.boot:spring-boot-starter-test"
testRuntimeOnly 'org.springframework.boot:spring-boot-starter-data-jpa'
testRuntimeOnly 'com.h2database:h2:2.3.232'
testRuntimeOnly 'org.postgresql:postgresql:42.7.5'
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }

View File

@ -1,5 +1,7 @@
package stirling.software.common.configuration; package stirling.software.common.configuration;
import io.github.pixee.security.SystemCommand;
import jakarta.annotation.PostConstruct;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -9,6 +11,7 @@ import java.util.Locale;
import java.util.Properties; import java.util.Properties;
import java.util.function.Predicate; import java.util.function.Predicate;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -36,6 +39,18 @@ public class AppConfig {
private final Environment env; private final Environment env;
@Getter
@Value("${baseUrl:http://localhost}")
private String baseUrl;
@Getter
@Value("${server.servlet.context-path:/}")
private String contextPath;
@Getter
@Value("${server.port:8080}")
private String serverPort;
@Bean @Bean
@ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true") @ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true")
public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) { public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config; package stirling.software.common.configuration;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -13,7 +13,7 @@ import java.util.List;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.util.YamlHelper;
/** /**
* A naive, line-based approach to merging "settings.yml" with "settings.yml.template" while * A naive, line-based approach to merging "settings.yml" with "settings.yml.template" while
@ -78,7 +78,7 @@ public class ConfigInitializer {
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath()); Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
if (Files.notExists(customSettingsPath)) { if (Files.notExists(customSettingsPath)) {
Files.createFile(customSettingsPath); Files.createFile(customSettingsPath);
log.info("Created custom_settings file: {}", customSettingsPath.toString()); log.info("Created custom_settings file: {}", customSettingsPath);
} }
} }

View File

@ -5,6 +5,7 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
@ -18,9 +19,7 @@ public class DatabaseConfig {
public final String DATASOURCE_DEFAULT_URL; public final String DATASOURCE_DEFAULT_URL;
public static final String DATASOURCE_URL_TEMPLATE = "jdbc:%s://%s:%4d/%s"; public static final String DATASOURCE_URL_TEMPLATE = "jdbc:%s://%s:%4d/%s";
public static final String DEFAULT_DRIVER = "org.h2.Driver";
public static final String DEFAULT_USERNAME = "sa"; public static final String DEFAULT_USERNAME = "sa";
public static final String POSTGRES_DRIVER = "org.postgresql.Driver";
private final ApplicationProperties.Datasource datasource; private final ApplicationProperties.Datasource datasource;
private final boolean runningProOrHigher; private final boolean runningProOrHigher;
@ -62,7 +61,7 @@ public class DatabaseConfig {
if (!datasource.getCustomDatabaseUrl().isBlank()) { if (!datasource.getCustomDatabaseUrl().isBlank()) {
if (datasource.getCustomDatabaseUrl().contains("postgresql")) { if (datasource.getCustomDatabaseUrl().contains("postgresql")) {
dataSourceBuilder.driverClassName(POSTGRES_DRIVER); dataSourceBuilder.driverClassName(DatabaseDriver.POSTGRESQL.getDriverClassName());
} }
dataSourceBuilder.url(datasource.getCustomDatabaseUrl()); dataSourceBuilder.url(datasource.getCustomDatabaseUrl());
@ -84,8 +83,9 @@ public class DatabaseConfig {
private DataSource useDefaultDataSource(DataSourceBuilder<?> dataSourceBuilder) { private DataSource useDefaultDataSource(DataSourceBuilder<?> dataSourceBuilder) {
log.info("Using default H2 database"); log.info("Using default H2 database");
dataSourceBuilder.url(DATASOURCE_DEFAULT_URL); dataSourceBuilder.url(DATASOURCE_DEFAULT_URL)
dataSourceBuilder.username(DEFAULT_USERNAME); .driverClassName(DatabaseDriver.H2.getDriverClassName())
.username(DEFAULT_USERNAME);
return dataSourceBuilder.build(); return dataSourceBuilder.build();
} }
@ -119,11 +119,11 @@ public class DatabaseConfig {
switch (driver) { switch (driver) {
case H2 -> { case H2 -> {
log.debug("H2 driver selected"); log.debug("H2 driver selected");
return DEFAULT_DRIVER; return DatabaseDriver.H2.getDriverClassName();
} }
case POSTGRESQL -> { case POSTGRESQL -> {
log.debug("Postgres driver selected"); log.debug("Postgres driver selected");
return POSTGRES_DRIVER; return DatabaseDriver.POSTGRESQL.getDriverClassName();
} }
default -> { default -> {
log.warn("{} driver selected", driverName); log.warn("{} driver selected", driverName);

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config; package stirling.software.common.configuration;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -9,7 +9,6 @@ import org.springframework.context.annotation.Configuration;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.CustomPaths.Operations; import stirling.software.common.model.ApplicationProperties.CustomPaths.Operations;
import stirling.software.common.model.ApplicationProperties.CustomPaths.Pipeline; import stirling.software.common.model.ApplicationProperties.CustomPaths.Pipeline;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.interfaces; package stirling.software.common.configuration.interfaces;
public interface ShowAdminInterface { public interface ShowAdminInterface {
default boolean getShowUpdateOnlyAdmins() { default boolean getShowUpdateOnlyAdmins() {

View File

@ -26,7 +26,7 @@ import stirling.software.common.model.provider.GitHubProvider;
import stirling.software.common.model.provider.GoogleProvider; import stirling.software.common.model.provider.GoogleProvider;
import stirling.software.common.model.provider.KeycloakProvider; import stirling.software.common.model.provider.KeycloakProvider;
import stirling.software.common.model.provider.Provider; import stirling.software.common.model.provider.Provider;
import stirling.software.common.util.Validator; import stirling.software.common.util.ValidationUtil;
@Data @Data
@Component @Component
@ -208,11 +208,11 @@ public class ApplicationProperties {
} }
public boolean isSettingsValid() { public boolean isSettingsValid() {
return !Validator.isStringEmpty(this.getIssuer()) return !ValidationUtil.isStringEmpty(this.getIssuer())
&& !Validator.isStringEmpty(this.getClientId()) && !ValidationUtil.isStringEmpty(this.getClientId())
&& !Validator.isStringEmpty(this.getClientSecret()) && !ValidationUtil.isStringEmpty(this.getClientSecret())
&& !Validator.isCollectionEmpty(this.getScopes()) && !ValidationUtil.isCollectionEmpty(this.getScopes())
&& !Validator.isStringEmpty(this.getUseAsUsername()); && !ValidationUtil.isStringEmpty(this.getUseAsUsername());
} }
@Data @Data

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.model;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.common.model;
import java.util.Calendar; import java.util.Calendar;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api; package stirling.software.common.model.api;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;

View File

@ -1,11 +1,10 @@
package stirling.software.SPDF.model.api.converters; package stirling.software.common.model.api.converters;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.common.model.api.PDFFile;
import stirling.software.SPDF.model.api.PDFFile;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.misc; package stirling.software.common.model.api.misc;
public enum HighContrastColorCombination { public enum HighContrastColorCombination {
WHITE_TEXT_ON_BLACK, WHITE_TEXT_ON_BLACK,

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.misc; package stirling.software.common.model.api.misc;
public enum ReplaceAndInvert { public enum ReplaceAndInvert {
HIGH_CONTRAST_COLOR, HIGH_CONTRAST_COLOR,

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.security; package stirling.software.common.model.api.security;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.exception; package stirling.software.common.model.exception;
public class BackupNotFoundException extends RuntimeException { public class BackupNotFoundException extends RuntimeException {
public BackupNotFoundException(String message) { public BackupNotFoundException(String message) {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.exception; package stirling.software.common.model.exception;
public class NoProviderFoundException extends Exception { public class NoProviderFoundException extends Exception {
public NoProviderFoundException(String message) { public NoProviderFoundException(String message) {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.service; package stirling.software.common.service;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -22,7 +22,7 @@ import org.springframework.web.multipart.MultipartFile;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.common.model.api.PDFFile;
/** /**
* Adaptive PDF document factory that optimizes memory usage based on file size and available system * Adaptive PDF document factory that optimizes memory usage based on file size and available system

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.service; package stirling.software.common.service;
import java.util.Calendar; import java.util.Calendar;
@ -7,9 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.PdfMetadata;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.PdfMetadata;
@Service @Service
public class PdfMetadataService { public class PdfMetadataService {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api.pipeline; package stirling.software.common.service;
public interface UserServiceInterface { public interface UserServiceInterface {
String getApiKeyForUser(String username); String getApiKeyForUser(String username);

View File

@ -1,10 +1,10 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
public class CheckProgramInstall { public class CheckProgramInstall {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import org.owasp.html.HtmlPolicyBuilder; import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory; import org.owasp.html.PolicyFactory;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static java.nio.file.StandardWatchEventKinds.*; import static java.nio.file.StandardWatchEventKinds.*;
@ -17,8 +17,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.SPDF.config.RuntimePathConfig;
@Component @Component
@Slf4j @Slf4j

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -16,8 +16,8 @@ import java.util.zip.ZipOutputStream;
import io.github.pixee.security.ZipSecurity; import io.github.pixee.security.ZipSecurity;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest; import stirling.software.common.model.api.converters.HTMLToPdfRequest;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
public class FileToPdf { public class FileToPdf {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -27,7 +27,6 @@ import io.github.pixee.security.Urls;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.YamlHelper;
import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.configuration.InstallationPathConfig;
@Slf4j @Slf4j

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.image.*; import java.awt.image.*;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -28,7 +28,7 @@ import io.github.pixee.security.Filenames;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
@Slf4j @Slf4j
@NoArgsConstructor @NoArgsConstructor

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -34,8 +34,7 @@ import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames; import io.github.pixee.security.Filenames;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
@Slf4j @Slf4j
public class PdfUtils { public class PdfUtils {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.util.List; import java.util.List;

View File

@ -1,9 +1,10 @@
package stirling.software.common.util; package stirling.software.common.util;
import java.util.Collection;
import stirling.software.common.model.provider.Provider; import stirling.software.common.model.provider.Provider;
import static stirling.software.common.util.ValidationUtil.isCollectionEmpty;
import static stirling.software.common.util.ValidationUtil.isStringEmpty;
public class Validator { public class ProviderUtil {
public static boolean validateProvider(Provider provider) { public static boolean validateProvider(Provider provider) {
if (provider == null) { if (provider == null) {
@ -24,12 +25,4 @@ public class Validator {
return true; return true;
} }
public static boolean isStringEmpty(String input) {
return input == null || input.isBlank();
}
public static boolean isCollectionEmpty(Collection<String> input) {
return input == null || input.isEmpty();
}
} }

View File

@ -1,6 +1,6 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
public class RequestUriUtils { public class RequestUriUtil {
public static boolean isStaticResource(String requestURI) { public static boolean isStaticResource(String requestURI) {

View File

@ -1,9 +1,7 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.awt.*; import java.awt.*;
import javax.swing.*;
public class UIScaling { public class UIScaling {
private static final double BASE_RESOLUTION_WIDTH = 1920.0; private static final double BASE_RESOLUTION_WIDTH = 1920.0;
private static final double BASE_RESOLUTION_HEIGHT = 1080.0; private static final double BASE_RESOLUTION_HEIGHT = 1080.0;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;

View File

@ -0,0 +1,15 @@
package stirling.software.common.util;
import java.util.Collection;
import stirling.software.common.model.provider.Provider;
public class ValidationUtil {
public static boolean isStringEmpty(String input) {
return input == null || input.isBlank();
}
public static boolean isCollectionEmpty(Collection<String> input) {
return input == null || input.isEmpty();
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config; package stirling.software.common.util;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc; package stirling.software.common.util.misc;
import java.awt.*; import java.awt.*;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -23,9 +23,8 @@ import org.springframework.core.io.InputStreamResource;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination; import stirling.software.common.model.api.misc.ReplaceAndInvert;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
@Slf4j @Slf4j
public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy { public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {

View File

@ -1,7 +1,7 @@
package stirling.software.SPDF.utils.misc; package stirling.software.common.util.misc;
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination; import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert; import stirling.software.common.model.api.misc.ReplaceAndInvert;
public class HighContrastColorReplaceDecider { public class HighContrastColorReplaceDecider {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc; package stirling.software.common.util.misc;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -18,8 +18,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy { public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc; package stirling.software.common.util.misc;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc; package stirling.software.common.util.misc;
import java.io.IOException; import java.io.IOException;
@ -8,8 +8,8 @@ import org.springframework.web.multipart.MultipartFile;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.common.model.api.PDFFile;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert; import stirling.software.common.model.api.misc.ReplaceAndInvert;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.propertyeditor; package stirling.software.common.util.propertyeditor;
import java.beans.PropertyEditorSupport; import java.beans.PropertyEditorSupport;
import java.util.ArrayList; import java.util.ArrayList;
@ -9,8 +9,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.api.security.RedactionArea;
import stirling.software.SPDF.model.api.security.RedactionArea;
@Slf4j @Slf4j
public class StringToArrayListPropertyEditor extends PropertyEditorSupport { public class StringToArrayListPropertyEditor extends PropertyEditorSupport {
@ -26,7 +25,8 @@ public class StringToArrayListPropertyEditor extends PropertyEditorSupport {
try { try {
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
TypeReference<ArrayList<RedactionArea>> typeRef = TypeReference<ArrayList<RedactionArea>> typeRef =
new TypeReference<ArrayList<RedactionArea>>() {}; new TypeReference<>() {
};
List<RedactionArea> list = objectMapper.readValue(text, typeRef); List<RedactionArea> list = objectMapper.readValue(text, typeRef);
setValue(list); setValue(list);
} catch (Exception e) { } catch (Exception e) {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.propertyeditor; package stirling.software.common.util.propertyeditor;
import java.beans.PropertyEditorSupport; import java.beans.PropertyEditorSupport;
import java.util.HashMap; import java.util.HashMap;
@ -15,7 +15,7 @@ public class StringToMapPropertyEditor extends PropertyEditorSupport {
public void setAsText(String text) throws IllegalArgumentException { public void setAsText(String text) throws IllegalArgumentException {
try { try {
TypeReference<HashMap<String, String>> typeRef = TypeReference<HashMap<String, String>> typeRef =
new TypeReference<HashMap<String, String>>() {}; new TypeReference<>() {};
Map<String, String> map = objectMapper.readValue(text, typeRef); Map<String, String> map = objectMapper.readValue(text, typeRef);
setValue(map); setValue(map);
} catch (Exception e) { } catch (Exception e) {

View File

@ -1,11 +1,6 @@
package stirling.software.SPDF.config.security.database; package stirling.software.common.configuration;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -13,15 +8,16 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.common.configuration.DatabaseConfig;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.common.model.exception.UnsupportedProviderException;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class DatabaseConfigTest { class DatabaseConfigTest {
@Mock private ApplicationProperties.Datasource datasource; @Mock
private ApplicationProperties.Datasource datasource;
private DatabaseConfig databaseConfig; private DatabaseConfig databaseConfig;
@ -48,6 +44,9 @@ class DatabaseConfigTest {
assertInstanceOf(DataSource.class, result); assertInstanceOf(DataSource.class, result);
} }
/**
* Must have PostgreSQL running to test this!
* */
@Test @Test
void testCustomUrlForDataSource() throws UnsupportedProviderException { void testCustomUrlForDataSource() throws UnsupportedProviderException {
when(datasource.isEnableCustomDatabase()).thenReturn(true); when(datasource.isEnableCustomDatabase()).thenReturn(true);
@ -60,6 +59,9 @@ class DatabaseConfigTest {
assertInstanceOf(DataSource.class, result); assertInstanceOf(DataSource.class, result);
} }
/**
* Must have PostgreSQL running to test this!
* */
@Test @Test
void testCustomConfigurationForDataSource() throws UnsupportedProviderException { void testCustomConfigurationForDataSource() throws UnsupportedProviderException {
when(datasource.isEnableCustomDatabase()).thenReturn(true); when(datasource.isEnableCustomDatabase()).thenReturn(true);

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -7,6 +7,8 @@ import java.time.LocalDateTime;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.CsvSource;
import stirling.software.common.model.FileInfo;
public class FileInfoTest { public class FileInfoTest {
@ParameterizedTest(name = "{index}: fileSize={0}") @ParameterizedTest(name = "{index}: fileSize={0}")

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -8,7 +8,7 @@ import java.io.IOException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest; import stirling.software.common.model.api.converters.HTMLToPdfRequest;
public class FileToPdfTest { public class FileToPdfTest {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -7,7 +7,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.common.model.enumeration.UsernameAttribute; import stirling.software.common.model.enumeration.UsernameAttribute;
import stirling.software.common.model.provider.GitHubProvider; import stirling.software.common.model.provider.GitHubProvider;
@ -18,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class ValidatorTest { class ProviderUtilTest {
@Test @Test
void testSuccessfulValidation() { void testSuccessfulValidation() {
@ -28,13 +27,13 @@ class ValidatorTest {
when(provider.getClientSecret()).thenReturn("clientSecret"); when(provider.getClientSecret()).thenReturn("clientSecret");
when(provider.getScopes()).thenReturn(List.of("read:user")); when(provider.getScopes()).thenReturn(List.of("read:user"));
assertTrue(Validator.validateProvider(provider)); assertTrue(ProviderUtil.validateProvider(provider));
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("providerParams") @MethodSource("providerParams")
void testUnsuccessfulValidation(Provider provider) { void testUnsuccessfulValidation(Provider provider) {
assertFalse(Validator.validateProvider(provider)); assertFalse(ProviderUtil.validateProvider(provider));
} }
public static Stream<Arguments> providerParams() { public static Stream<Arguments> providerParams() {

View File

@ -0,0 +1,26 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
public class RequestUriUtilTest {
@Test
public void testIsStaticResource() {
assertTrue(RequestUriUtil.isStaticResource("/css/styles.css"));
assertTrue(RequestUriUtil.isStaticResource("/js/script.js"));
assertTrue(RequestUriUtil.isStaticResource("/images/logo.png"));
assertTrue(RequestUriUtil.isStaticResource("/public/index.html"));
assertTrue(RequestUriUtil.isStaticResource("/pdfjs/pdf.worker.js"));
assertTrue(RequestUriUtil.isStaticResource("/api/v1/info/status"));
assertTrue(RequestUriUtil.isStaticResource("/some-path/icon.svg"));
assertFalse(RequestUriUtil.isStaticResource("/api/v1/users"));
assertFalse(RequestUriUtil.isStaticResource("/api/v1/orders"));
assertFalse(RequestUriUtil.isStaticResource("/"));
assertTrue(RequestUriUtil.isStaticResource("/login"));
assertFalse(RequestUriUtil.isStaticResource("/register"));
assertFalse(RequestUriUtil.isStaticResource("/api/v1/products"));
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils; package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;

45
enterprise/LICENSE Normal file
View File

@ -0,0 +1,45 @@
Stirling PDF Enterprise Edition (EE) license (the “EE License”)
Copyright (c) 2025-present Stirling Tools
With regard to the Stirling PDF Software:
This software and associated documentation files (the "Software") may only be
used in production, if you (and any entity that you represent) have agreed to,
and are in compliance with, the Stirling PDF Terms of Service, available
at https://www.stirlingpdf.com/terms-and-conditions (the “EE Terms”), or other
agreement governing the use of the Software, as agreed by you and Stirling PDF,
and otherwise have a valid Stirling PDF Enterprise Edition subscription for the
correct number of user seats. Subject to the foregoing sentence, you are free to
modify this Software and publish patches to the Software. You agree that Stirling PDF
and/or its licensors (as applicable) retain all right, title and interest in and
to all such modifications and/or patches, and all such modifications and/or
patches may only be used, copied, modified, displayed, distributed, or otherwise
exploited with a valid Stirling PDF Enterprise Edition subscription for the correct
number of user seats. Notwithstanding the foregoing, you may copy and modify
the Software for development and testing purposes, without requiring a
subscription. You agree that Stirling PDF and/or its licensors (as applicable) retain
all right, title and interest in and to all such modifications. You are not
granted any other rights beyond what is expressly stated herein. Subject to the
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
and/or sell the Software.
This EE License applies only to the part of this Software that is not
distributed as part of MIT License. Any part of this Software
distributed as part of MIT License or is served client-side as an image, font,
cascading stylesheet (CSS), file which produces or is compiled, arranged,
augmented, or combined into client-side JavaScript, in whole or in part, is
copyrighted under the MIT Expat license. The full text of this EE License shall
be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
For all third party components incorporated into the Stirling PDF Software, those
components are licensed under the original license provided by the owner of the
applicable component.

83
enterprise/build.gradle Normal file
View File

@ -0,0 +1,83 @@
plugins {
id 'java-library'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'stirling.software'
version = '0.46.0'
repositories {
mavenCentral()
maven { url = "https://build.shibboleth.net/maven/releases" }
maven { url = "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
}
java {
// 17 is lowest but we support and recommend 21
sourceCompatibility = JavaVersion.VERSION_17
}
ext {
lombokVersion = "1.18.38"
}
configurations.all {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
dependencyManagement {
imports {
mavenBom 'org.springframework.boot:spring-boot-dependencies:3.4.5'
}
}
dependencies {
implementation project(':common')
implementation 'org.springframework.boot:spring-boot-starter-jetty'
implementation 'io.swagger.core.v3:swagger-core-jakarta:2.2.30'
implementation 'org.springframework:spring-webmvc:6.2.6'
// implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0' todo: testing
implementation 'com.posthog.java:posthog:1.2.0'
// https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17
implementation 'com.bucket4j:bucket4j_jdk17-core:8.14.0'
implementation 'io.github.pixee:java-security-toolkit:1.2.1'
implementation 'org.bouncycastle:bcprov-jdk18on:1.80'
if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
implementation 'io.micrometer:micrometer-registry-prometheus'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation "org.springframework.session:spring-session-core:3.4.3"
implementation "org.springframework:spring-jdbc:6.2.6"
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
// Don't upgrade h2database
runtimeOnly "com.h2database:h2:2.3.232"
runtimeOnly "org.postgresql:postgresql:42.7.5"
constraints {
implementation "org.opensaml:opensaml-core:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
}
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
implementation 'com.coveo:saml-client:5.0.0'
}
compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test {
useJUnitPlatform()
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.EE; package stirling.software.enterprise.configuration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -7,15 +7,15 @@ import org.springframework.core.annotation.Order;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.EnterpriseEdition; import stirling.software.common.model.ApplicationProperties.EnterpriseEdition;
import stirling.software.common.model.ApplicationProperties.Premium; import stirling.software.common.model.ApplicationProperties.Premium;
import stirling.software.common.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive; import stirling.software.common.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive;
import static stirling.software.enterprise.configuration.KeygenLicenseVerifier.*;
@Slf4j
@Configuration @Configuration
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class EEAppConfig { public class EEAppConfig {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.EE; package stirling.software.enterprise.configuration;
import java.net.URI; import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
@ -19,7 +19,7 @@ import com.posthog.java.shaded.org.json.JSONObject;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.common.util.GeneralUtils;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
@Service @Service

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.EE; package stirling.software.enterprise.configuration;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -10,8 +10,8 @@ import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License; import stirling.software.enterprise.configuration.KeygenLicenseVerifier.License;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.common.util.GeneralUtils;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
@Component @Component

View File

@ -1,8 +1,11 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.Optional; import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.authentication.InternalAuthenticationServiceException;
@ -10,14 +13,9 @@ import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import stirling.software.enterprise.security.model.User;
import jakarta.servlet.ServletException; import stirling.software.enterprise.security.service.LoginAttemptService;
import jakarta.servlet.http.HttpServletRequest; import stirling.software.enterprise.security.service.UserService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.User;
@Slf4j @Slf4j
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

View File

@ -1,19 +1,17 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import java.io.IOException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import stirling.software.SPDF.utils.RequestUriUtils; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import stirling.software.common.util.RequestUriUtil;
import stirling.software.enterprise.security.service.LoginAttemptService;
import stirling.software.enterprise.security.service.UserService;
@Slf4j @Slf4j
public class CustomAuthenticationSuccessHandler public class CustomAuthenticationSuccessHandler
@ -48,7 +46,7 @@ public class CustomAuthenticationSuccessHandler
: null; : null;
if (savedRequest != null if (savedRequest != null
&& !RequestUriUtils.isStaticResource( && !RequestUriUtil.isStaticResource(
request.getContextPath(), savedRequest.getRedirectUrl())) { request.getContextPath(), savedRequest.getRedirectUrl())) {
// Redirect to the original destination // Redirect to the original destination
super.onAuthenticationSuccess(request, response, authentication); super.onAuthenticationSuccess(request, response, authentication);

View File

@ -1,35 +1,30 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import com.coveo.saml.SamlClient;
import com.coveo.saml.SamlException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import stirling.software.common.configuration.AppConfig;
import com.coveo.saml.SamlClient;
import com.coveo.saml.SamlException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.SPDFApplication;
import stirling.software.SPDF.config.security.saml2.CertificateUtils;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.utils.UrlUtils;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.ApplicationProperties.Security.SAML2; import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.common.model.provider.KeycloakProvider; import stirling.software.common.model.provider.KeycloakProvider;
import stirling.software.common.util.UrlUtils;
import stirling.software.enterprise.security.saml2.CertificateUtils;
import stirling.software.enterprise.security.saml2.CustomSaml2AuthenticatedPrincipal;
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@ -38,6 +33,7 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
public static final String LOGOUT_PATH = "/login?logout=true"; public static final String LOGOUT_PATH = "/login?logout=true";
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final AppConfig appConfig;
@Override @Override
public void onLogoutSuccess( public void onLogoutSuccess(
@ -102,7 +98,7 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
// Set service provider keys for the SamlClient // Set service provider keys for the SamlClient
samlClient.setSPKeys(certificate, privateKey); samlClient.setSPKeys(certificate, privateKey);
// Redirect to identity provider for logout // Redirect to identity provider for logout. todo: add relay state
samlClient.redirectToIdentityProvider(response, null, nameIdValue); samlClient.redirectToIdentityProvider(response, null, nameIdValue);
} catch (Exception e) { } catch (Exception e) {
log.error( log.error(
@ -172,11 +168,12 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
} }
} }
private static SamlClient getSamlClient( private SamlClient getSamlClient(
String registrationId, SAML2 samlConf, List<X509Certificate> certificates) String registrationId, SAML2 samlConf, List<X509Certificate> certificates)
throws SamlException { throws SamlException {
// fixMe: move to a config class
String serverUrl = String serverUrl =
SPDFApplication.getStaticBaseUrl() + ":" + SPDFApplication.getStaticPort(); appConfig.getBaseUrl() + ":" + appConfig.getServerPort();
String relyingPartyIdentifier = String relyingPartyIdentifier =
serverUrl + "/saml2/service-provider-metadata/" + registrationId; serverUrl + "/saml2/service-provider-metadata/" + registrationId;

View File

@ -1,26 +1,23 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import stirling.software.SPDF.model.User; import org.springframework.security.core.Authentication;
import stirling.software.SPDF.utils.RequestUriUtils; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import stirling.software.common.util.RequestUriUtil;
import stirling.software.enterprise.security.model.User;
import stirling.software.enterprise.security.service.UserService;
@Slf4j @Slf4j
@Component @Component
@ -40,7 +37,7 @@ public class FirstLoginFilter extends OncePerRequestFilter {
String requestURI = request.getRequestURI(); String requestURI = request.getRequestURI();
String contextPath = request.getContextPath(); String contextPath = request.getContextPath();
// Check if the request is for static resources // Check if the request is for static resources
boolean isStaticResource = RequestUriUtils.isStaticResource(contextPath, requestURI); boolean isStaticResource = RequestUriUtil.isStaticResource(contextPath, requestURI);
// If it's a static resource, just continue the filter chain and skip the logic below // If it's a static resource, just continue the filter chain and skip the logic below
if (isStaticResource) { if (isStaticResource) {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);

View File

@ -1,15 +1,16 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import stirling.software.common.util.RequestUriUtil;
import stirling.software.SPDF.utils.RequestUriUtils;
@RequiredArgsConstructor @RequiredArgsConstructor
public class IPRateLimitingFilter implements Filter { public class IPRateLimitingFilter implements Filter {
@ -29,7 +30,7 @@ public class IPRateLimitingFilter implements Filter {
String requestURI = httpRequest.getRequestURI(); String requestURI = httpRequest.getRequestURI();
// Check if the request is for static resources // Check if the request is for static resources
boolean isStaticResource = boolean isStaticResource =
RequestUriUtils.isStaticResource(httpRequest.getContextPath(), requestURI); RequestUriUtil.isStaticResource(httpRequest.getContextPath(), requestURI);
// If it's a static resource, just continue the filter chain and skip the logic below // If it's a static resource, just continue the filter chain and skip the logic below
if (isStaticResource) { if (isStaticResource) {

View File

@ -1,19 +1,16 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import java.sql.SQLException;
import java.util.UUID;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import java.sql.SQLException;
import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.model.Role;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.enterprise.security.model.Role;
import stirling.software.enterprise.security.service.DatabaseServiceInterface;
import stirling.software.enterprise.security.service.UserService;
@Slf4j @Slf4j
@Component @Component
@ -24,7 +21,7 @@ public class InitialSecuritySetup {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final DatabaseInterface databaseService; private final DatabaseServiceInterface databaseService;
@PostConstruct @PostConstruct
public void init() { public void init() {

View File

@ -1,9 +1,8 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor

View File

@ -0,0 +1,320 @@
package stirling.software.enterprise.security;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.ProviderManager;
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.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.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import stirling.software.common.configuration.AppConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.enterprise.security.database.repository.JPATokenRepositoryImpl;
import stirling.software.enterprise.security.database.repository.PersistentLoginRepository;
import stirling.software.enterprise.security.model.User;
import stirling.software.enterprise.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
import stirling.software.enterprise.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
import stirling.software.enterprise.security.saml2.CustomSaml2AuthenticationFailureHandler;
import stirling.software.enterprise.security.saml2.CustomSaml2AuthenticationSuccessHandler;
import stirling.software.enterprise.security.saml2.CustomSaml2ResponseAuthenticationConverter;
import stirling.software.enterprise.security.service.CustomOAuth2UserService;
import stirling.software.enterprise.security.service.CustomUserDetailsService;
import stirling.software.enterprise.security.service.LoginAttemptService;
import stirling.software.enterprise.security.service.UserService;
import stirling.software.enterprise.security.session.SessionPersistentRegistry;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@Slf4j
@DependsOn("runningProOrHigher")
public class SecurityConfiguration {
private final CustomUserDetailsService userDetailsService;
private final UserService userService;
private final boolean loginEnabledValue;
private final boolean runningProOrHigher;
private final ApplicationProperties applicationProperties;
private final AppConfig appConfig;
private final UserAuthenticationFilter userAuthenticationFilter;
private final LoginAttemptService loginAttemptService;
private final FirstLoginFilter firstLoginFilter;
private final SessionPersistentRegistry sessionRegistry;
private final PersistentLoginRepository persistentLoginRepository;
private final GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper;
private final RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations;
private final OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver;
public SecurityConfiguration(
PersistentLoginRepository persistentLoginRepository,
CustomUserDetailsService userDetailsService,
@Lazy UserService userService,
@Qualifier("loginEnabled") boolean loginEnabledValue,
@Qualifier("runningProOrHigher") boolean runningProOrHigher,
AppConfig appConfig,
ApplicationProperties applicationProperties,
UserAuthenticationFilter userAuthenticationFilter,
LoginAttemptService loginAttemptService,
FirstLoginFilter firstLoginFilter,
SessionPersistentRegistry sessionRegistry,
@Autowired(required = false) GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper,
@Autowired(required = false)
RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations,
@Autowired(required = false)
OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver) {
this.userDetailsService = userDetailsService;
this.userService = userService;
this.loginEnabledValue = loginEnabledValue;
this.runningProOrHigher = runningProOrHigher;
this.appConfig = appConfig;
this.applicationProperties = applicationProperties;
this.userAuthenticationFilter = userAuthenticationFilter;
this.loginAttemptService = loginAttemptService;
this.firstLoginFilter = firstLoginFilter;
this.sessionRegistry = sessionRegistry;
this.persistentLoginRepository = persistentLoginRepository;
this.oAuth2userAuthoritiesMapper = oAuth2userAuthoritiesMapper;
this.saml2RelyingPartyRegistrations = saml2RelyingPartyRegistrations;
this.saml2AuthenticationRequestResolver = saml2AuthenticationRequestResolver;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
if (applicationProperties.getSecurity().getCsrfDisabled() || !loginEnabledValue) {
http.csrf(csrf -> csrf.disable());
}
if (loginEnabledValue) {
http.addFilterBefore(
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
if (!applicationProperties.getSecurity().getCsrfDisabled()) {
CookieCsrfTokenRepository cookieRepo =
CookieCsrfTokenRepository.withHttpOnlyFalse();
CsrfTokenRequestAttributeHandler requestHandler =
new CsrfTokenRequestAttributeHandler();
requestHandler.setCsrfRequestAttributeName(null);
http.csrf(
csrf ->
csrf.ignoringRequestMatchers(
request -> {
String apiKey = request.getHeader("X-API-KEY");
// If there's no API key, don't ignore CSRF
// (return false)
if (apiKey == null || apiKey.trim().isEmpty()) {
return false;
}
// Validate API key using existing UserService
try {
Optional<User> user =
userService.getUserByApiKey(apiKey);
// If API key is valid, ignore CSRF (return
// true)
// If API key is invalid, don't ignore CSRF
// (return false)
return user.isPresent();
} catch (Exception e) {
// If there's any error validating the API
// key, don't ignore CSRF
return false;
}
})
.csrfTokenRepository(cookieRepo)
.csrfTokenRequestHandler(requestHandler));
}
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
http.sessionManagement(
sessionManagement ->
sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(10)
.maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry)
.expiredUrl("/login?logout=true"));
http.authenticationProvider(daoAuthenticationProvider());
http.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()));
http.logout(
logout ->
logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessHandler(
new CustomLogoutSuccessHandler(applicationProperties, appConfig))
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID", "remember-me"));
http.rememberMe(
rememberMeConfigurer -> // Use the configurator directly
rememberMeConfigurer
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds( // 14 days
14 * 24 * 60 * 60)
.userDetailsService( // Your existing UserDetailsService
userDetailsService)
.useSecureCookie( // Enable secure cookie
true)
.rememberMeParameter( // Form parameter name
"remember-me")
.rememberMeCookieName( // Cookie name
"remember-me")
.alwaysRemember(false));
http.authorizeHttpRequests(
authz ->
authz.requestMatchers(
req -> {
String uri = req.getRequestURI();
String contextPath = req.getContextPath();
// Remove the context path from the URI
String trimmedUri =
uri.startsWith(contextPath)
? uri.substring(
contextPath.length())
: uri;
return trimmedUri.startsWith("/login")
|| trimmedUri.startsWith("/oauth")
|| trimmedUri.startsWith("/saml2")
|| trimmedUri.endsWith(".svg")
|| trimmedUri.startsWith("/register")
|| trimmedUri.startsWith("/error")
|| trimmedUri.startsWith("/images/")
|| trimmedUri.startsWith("/public/")
|| trimmedUri.startsWith("/css/")
|| trimmedUri.startsWith("/fonts/")
|| trimmedUri.startsWith("/js/")
|| trimmedUri.startsWith(
"/api/v1/info/status");
})
.permitAll()
.anyRequest()
.authenticated());
// Handle User/Password Logins
if (applicationProperties.getSecurity().isUserPass()) {
http.formLogin(
formLogin ->
formLogin
.loginPage("/login")
.successHandler(
new CustomAuthenticationSuccessHandler(
loginAttemptService, userService))
.failureHandler(
new CustomAuthenticationFailureHandler(
loginAttemptService, userService))
.defaultSuccessUrl("/")
.permitAll());
}
// Handle OAUTH2 Logins
if (applicationProperties.getSecurity().isOauth2Active()) {
http.oauth2Login(
oauth2 ->
oauth2.loginPage("/oauth2")
/*
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
If user exists, login proceeds as usual. If user does not exist, then it is auto-created but only if 'OAUTH2AutoCreateUser'
is set as true, else login fails with an error message advising the same.
*/
.successHandler(
new CustomOAuth2AuthenticationSuccessHandler(
loginAttemptService,
applicationProperties,
userService))
.failureHandler(
new CustomOAuth2AuthenticationFailureHandler())
. // Add existing Authorities from the database
userInfoEndpoint(
userInfoEndpoint ->
userInfoEndpoint
.oidcUserService(
new CustomOAuth2UserService(
applicationProperties,
userService,
loginAttemptService))
.userAuthoritiesMapper(
oAuth2userAuthoritiesMapper))
.permitAll());
}
// Handle SAML
if (applicationProperties.getSecurity().isSaml2Active() && runningProOrHigher) {
// Configure the authentication provider
OpenSaml4AuthenticationProvider authenticationProvider =
new OpenSaml4AuthenticationProvider();
authenticationProvider.setResponseAuthenticationConverter(
new CustomSaml2ResponseAuthenticationConverter(userService));
http.authenticationProvider(authenticationProvider)
.saml2Login(
saml2 -> {
try {
saml2.loginPage("/saml2")
.relyingPartyRegistrationRepository(
saml2RelyingPartyRegistrations)
.authenticationManager(
new ProviderManager(authenticationProvider))
.successHandler(
new CustomSaml2AuthenticationSuccessHandler(
loginAttemptService,
applicationProperties,
userService))
.failureHandler(
new CustomSaml2AuthenticationFailureHandler())
.authenticationRequestResolver(
saml2AuthenticationRequestResolver);
} catch (Exception e) {
log.error("Error configuring SAML 2 login", e);
throw new RuntimeException(e);
}
});
}
} else {
log.debug("SAML 2 login is not enabled. Using default.");
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
}
return http.build();
}
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
@Bean
public IPRateLimitingFilter rateLimitingFilter() {
// Example limit TODO add config level
int maxRequestsPerIp = 1000000;
return new IPRateLimitingFilter(maxRequestsPerIp, maxRequestsPerIp);
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
return new JPATokenRepositoryImpl(persistentLoginRepository);
}
@Bean
public boolean activeSecurity() {
return true;
}
}

View File

@ -1,9 +1,13 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -16,21 +20,14 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
import stirling.software.SPDF.model.User;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.ApplicationProperties.Security.SAML2; import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.enterprise.security.model.ApiKeyAuthenticationToken;
import stirling.software.enterprise.security.model.User;
import stirling.software.enterprise.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.enterprise.security.service.UserService;
import stirling.software.enterprise.security.session.SessionPersistentRegistry;
@Slf4j @Slf4j
@Component @Component

View File

@ -1,10 +1,17 @@
package stirling.software.SPDF.config.security; package stirling.software.enterprise.security;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.ConsumptionProbe;
import io.github.pixee.security.Newlines;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@ -13,18 +20,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import stirling.software.enterprise.security.model.Role;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.ConsumptionProbe;
import io.github.pixee.security.Newlines;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.model.Role;
@Component @Component
public class UserBasedRateLimitingFilter extends OncePerRequestFilter { public class UserBasedRateLimitingFilter extends OncePerRequestFilter {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api; package stirling.software.enterprise.security.controller.api;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -26,8 +26,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.enterprise.security.database.H2SQLCondition;
import stirling.software.SPDF.config.security.database.DatabaseService; import stirling.software.enterprise.security.service.DatabaseService;
@Slf4j @Slf4j
@Controller @Controller

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api; package stirling.software.enterprise.security.controller.api;
import java.io.IOException; import java.io.IOException;
import java.security.Principal; import java.security.Principal;
@ -30,15 +30,15 @@ import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService; import stirling.software.enterprise.security.model.AuthenticationType;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.enterprise.security.model.Role;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.enterprise.security.model.User;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.api.user.UsernameAndPass;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.enterprise.security.model.api.user.UsernameAndPass;
import stirling.software.enterprise.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.enterprise.security.service.UserService;
import stirling.software.enterprise.security.session.SessionPersistentRegistry;
@Controller @Controller
@Tag(name = "User", description = "User APIs") @Tag(name = "User", description = "User APIs")

View File

@ -1,6 +1,6 @@
package stirling.software.SPDF.controller.web; package stirling.software.enterprise.security.controller.web;
import static stirling.software.common.util.Validator.validateProvider; import static stirling.software.common.util.ProviderUtil.validateProvider;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -29,13 +29,11 @@ import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.enterprise.security.model.Authority;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.enterprise.security.model.Role;
import stirling.software.SPDF.model.Authority; import stirling.software.enterprise.security.model.SessionEntity;
import stirling.software.SPDF.model.Role; import stirling.software.enterprise.security.model.User;
import stirling.software.SPDF.model.SessionEntity; import stirling.software.enterprise.security.database.repository.UserRepository;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.UserRepository;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security; import stirling.software.common.model.ApplicationProperties.Security;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
@ -44,6 +42,8 @@ import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.common.model.provider.GitHubProvider; import stirling.software.common.model.provider.GitHubProvider;
import stirling.software.common.model.provider.GoogleProvider; import stirling.software.common.model.provider.GoogleProvider;
import stirling.software.common.model.provider.KeycloakProvider; import stirling.software.common.model.provider.KeycloakProvider;
import stirling.software.enterprise.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.enterprise.security.session.SessionPersistentRegistry;
@Controller @Controller
@Slf4j @Slf4j

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.web; package stirling.software.enterprise.security.controller.web;
import java.util.List; import java.util.List;
@ -14,8 +14,8 @@ import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.security.database.DatabaseService; import stirling.software.common.model.FileInfo;
import stirling.software.SPDF.utils.FileInfo; import stirling.software.enterprise.security.service.DatabaseService;
@Controller @Controller
@Tag(name = "Database Management", description = "Database management and security APIs") @Tag(name = "Database Management", description = "Database management and security APIs")

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api; package stirling.software.enterprise.security.database;
import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.ConditionContext;
@ -12,8 +12,12 @@ public class H2SQLCondition implements Condition {
Boolean.parseBoolean( Boolean.parseBoolean(
context.getEnvironment() context.getEnvironment()
.getProperty("system.datasource.enableCustomDatabase")); .getProperty("system.datasource.enableCustomDatabase"));
if (!enableCustomDatabase) {
return false;
}
String dataSourceType = context.getEnvironment().getProperty("system.datasource.type"); String dataSourceType = context.getEnvironment().getProperty("system.datasource.type");
return !enableCustomDatabase return "h2".equalsIgnoreCase(dataSourceType);
|| (enableCustomDatabase && "h2".equalsIgnoreCase(dataSourceType));
} }
} }

View File

@ -1,23 +1,19 @@
package stirling.software.SPDF.config.security.database; package stirling.software.enterprise.security.database;
import java.sql.SQLException; import java.sql.SQLException;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.controller.api.H2SQLCondition;
import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.enterprise.security.service.DatabaseServiceInterface;
@Component @Component
@Conditional(H2SQLCondition.class) @Conditional(H2SQLCondition.class)
@RequiredArgsConstructor @RequiredArgsConstructor
public class ScheduledTasks { public class ScheduledTasks {
private final DatabaseInterface databaseService; private final DatabaseServiceInterface databaseService;
@Scheduled(cron = "0 0 0 * * ?") @Scheduled(cron = "0 0 0 * * ?")
public void performBackup() throws SQLException, UnsupportedProviderException { public void performBackup() throws SQLException, UnsupportedProviderException {

View File

@ -1,11 +1,11 @@
package stirling.software.SPDF.repository; package stirling.software.enterprise.security.database.repository;
import java.util.Set; import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.Authority; import stirling.software.enterprise.security.model.Authority;
@Repository @Repository
public interface AuthorityRepository extends JpaRepository<Authority, Long> { public interface AuthorityRepository extends JpaRepository<Authority, Long> {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.repository; package stirling.software.enterprise.security.database.repository;
import java.util.Date; import java.util.Date;
@ -6,7 +6,7 @@ import org.springframework.security.web.authentication.rememberme.PersistentReme
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import stirling.software.SPDF.model.PersistentLogin; import stirling.software.enterprise.security.model.PersistentLogin;
public class JPATokenRepositoryImpl implements PersistentTokenRepository { public class JPATokenRepositoryImpl implements PersistentTokenRepository {

View File

@ -1,9 +1,9 @@
package stirling.software.SPDF.repository; package stirling.software.enterprise.security.database.repository;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.PersistentLogin; import stirling.software.enterprise.security.model.PersistentLogin;
@Repository @Repository
public interface PersistentLoginRepository extends JpaRepository<PersistentLogin, String> { public interface PersistentLoginRepository extends JpaRepository<PersistentLogin, String> {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.repository; package stirling.software.enterprise.security.database.repository;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -8,7 +8,7 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.User; import stirling.software.enterprise.security.model.User;
@Repository @Repository
public interface UserRepository extends JpaRepository<User, Long> { public interface UserRepository extends JpaRepository<User, Long> {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
import java.util.Collection; import java.util.Collection;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
public class AttemptCounter { public class AttemptCounter {
private int attemptCount; private int attemptCount;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
public enum AuthenticationType { public enum AuthenticationType {
WEB, WEB,

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
import java.io.Serializable; import java.io.Serializable;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
import java.util.Date; import java.util.Date;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model; package stirling.software.enterprise.security.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.user; package stirling.software.enterprise.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.user; package stirling.software.enterprise.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.user; package stirling.software.enterprise.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.user; package stirling.software.enterprise.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,7 +1,10 @@
package stirling.software.SPDF.config.security.oauth2; package stirling.software.enterprise.security.oauth2;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.LockedException;
@ -10,12 +13,6 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class CustomOAuth2AuthenticationFailureHandler public class CustomOAuth2AuthenticationFailureHandler
extends SimpleUrlAuthenticationFailureHandler { extends SimpleUrlAuthenticationFailureHandler {

View File

@ -1,29 +1,25 @@
package stirling.software.SPDF.config.security.oauth2; package stirling.software.enterprise.security.oauth2;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.security.web.savedrequest.SavedRequest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.utils.RequestUriUtils;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.common.util.RequestUriUtil;
import stirling.software.enterprise.security.model.AuthenticationType;
import stirling.software.enterprise.security.service.LoginAttemptService;
import stirling.software.enterprise.security.service.UserService;
@RequiredArgsConstructor @RequiredArgsConstructor
public class CustomOAuth2AuthenticationSuccessHandler public class CustomOAuth2AuthenticationSuccessHandler
@ -56,7 +52,7 @@ public class CustomOAuth2AuthenticationSuccessHandler
: null; : null;
if (savedRequest != null if (savedRequest != null
&& !RequestUriUtils.isStaticResource(contextPath, savedRequest.getRedirectUrl())) { && !RequestUriUtil.isStaticResource(contextPath, savedRequest.getRedirectUrl())) {
// Redirect to the original destination // Redirect to the original destination
super.onAuthenticationSuccess(request, response, authentication); super.onAuthenticationSuccess(request, response, authentication);
} else { } else {

View File

@ -1,15 +1,11 @@
package stirling.software.SPDF.config.security.oauth2; package stirling.software.enterprise.security.oauth2;
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
import static stirling.software.common.util.Validator.isStringEmpty;
import static stirling.software.common.util.Validator.validateProvider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -22,20 +18,20 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
import org.springframework.security.oauth2.client.registration.ClientRegistrations; import org.springframework.security.oauth2.client.registration.ClientRegistrations;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.exception.NoProviderFoundException;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2.Client; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.common.model.enumeration.UsernameAttribute; import stirling.software.common.model.enumeration.UsernameAttribute;
import stirling.software.common.model.exception.NoProviderFoundException;
import stirling.software.common.model.provider.GitHubProvider; import stirling.software.common.model.provider.GitHubProvider;
import stirling.software.common.model.provider.GoogleProvider; import stirling.software.common.model.provider.GoogleProvider;
import stirling.software.common.model.provider.KeycloakProvider; import stirling.software.common.model.provider.KeycloakProvider;
import stirling.software.common.model.provider.Provider; import stirling.software.common.model.provider.Provider;
import stirling.software.enterprise.security.model.User;
import stirling.software.enterprise.security.service.UserService;
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
import static stirling.software.common.util.ProviderUtil.validateProvider;
import static stirling.software.common.util.ValidationUtil.isStringEmpty;
@Slf4j @Slf4j
@Configuration @Configuration

Some files were not shown because too many files have changed in this diff Show More