diff --git a/build.gradle b/build.gradle index 643bcfacf..819a63980 100644 --- a/build.gradle +++ b/build.gradle @@ -170,16 +170,16 @@ subprojects { test { useJUnitPlatform() } - + // Ensure all packaging tasks depend on writeVersion from root project tasks.withType(org.springframework.boot.gradle.tasks.bundling.BootJar) { dependsOn(rootProject.tasks.writeVersion) } - + tasks.withType(Jar) { dependsOn(rootProject.tasks.writeVersion) } - + tasks.withType(org.gradle.api.tasks.bundling.Zip) { dependsOn(rootProject.tasks.writeVersion) } diff --git a/common/build.gradle b/common/build.gradle index c55648f06..bb8503de9 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -5,7 +5,13 @@ bootRun { spotless { java { target sourceSets.main.allJava - googleJavaFormat(googleJavaFormatVersion).aosp() + googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false) + + importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling") + toggleOffOn() + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() } } dependencies { diff --git a/common/src/main/java/org/apache/pdfbox/examples/util/DeletingRandomAccessFile.java b/common/src/main/java/org/apache/pdfbox/examples/util/DeletingRandomAccessFile.java index d6e131ff9..2c0341e19 100644 --- a/common/src/main/java/org/apache/pdfbox/examples/util/DeletingRandomAccessFile.java +++ b/common/src/main/java/org/apache/pdfbox/examples/util/DeletingRandomAccessFile.java @@ -4,9 +4,11 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import lombok.extern.slf4j.Slf4j; + import org.apache.pdfbox.io.RandomAccessReadBufferedFile; +import lombok.extern.slf4j.Slf4j; + /** A custom RandomAccessRead implementation that deletes the file when closed */ @Slf4j public class DeletingRandomAccessFile extends RandomAccessReadBufferedFile { diff --git a/common/src/main/java/stirling/software/common/configuration/AppConfig.java b/common/src/main/java/stirling/software/common/configuration/AppConfig.java index 393e29f1f..02614584b 100644 --- a/common/src/main/java/stirling/software/common/configuration/AppConfig.java +++ b/common/src/main/java/stirling/software/common/configuration/AppConfig.java @@ -8,9 +8,7 @@ import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.function.Predicate; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -24,6 +22,11 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.thymeleaf.spring6.SpringTemplateEngine; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; @Lazy diff --git a/common/src/main/java/stirling/software/common/configuration/ConfigInitializer.java b/common/src/main/java/stirling/software/common/configuration/ConfigInitializer.java index 436e0c909..50090ee51 100644 --- a/common/src/main/java/stirling/software/common/configuration/ConfigInitializer.java +++ b/common/src/main/java/stirling/software/common/configuration/ConfigInitializer.java @@ -10,7 +10,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.List; + import lombok.extern.slf4j.Slf4j; + import stirling.software.common.util.YamlHelper; /** diff --git a/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java b/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java index 7bb41812d..320d9aaac 100644 --- a/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java +++ b/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java @@ -3,13 +3,16 @@ package stirling.software.common.configuration; import java.io.IOException; import java.io.InputStream; import java.util.Map; -import lombok.extern.slf4j.Slf4j; + import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.thymeleaf.IEngineConfiguration; import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver; import org.thymeleaf.templateresource.FileTemplateResource; import org.thymeleaf.templateresource.ITemplateResource; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.InputStreamTemplateResource; @Slf4j diff --git a/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java b/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java index 591238eab..d087f2a7a 100644 --- a/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java +++ b/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java @@ -2,6 +2,7 @@ package stirling.software.common.configuration; import java.io.File; import java.nio.file.Paths; + import lombok.extern.slf4j.Slf4j; @Slf4j diff --git a/common/src/main/java/stirling/software/common/configuration/PostHogConfig.java b/common/src/main/java/stirling/software/common/configuration/PostHogConfig.java index 3cc89e640..589b5cac9 100644 --- a/common/src/main/java/stirling/software/common/configuration/PostHogConfig.java +++ b/common/src/main/java/stirling/software/common/configuration/PostHogConfig.java @@ -1,12 +1,15 @@ package stirling.software.common.configuration; -import com.posthog.java.PostHog; -import jakarta.annotation.PreDestroy; -import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import com.posthog.java.PostHog; + +import jakarta.annotation.PreDestroy; + +import lombok.extern.slf4j.Slf4j; + @Configuration @Slf4j public class PostHogConfig { diff --git a/common/src/main/java/stirling/software/common/configuration/PostHogLoggerImpl.java b/common/src/main/java/stirling/software/common/configuration/PostHogLoggerImpl.java index 19c4b0a92..5fadfb352 100644 --- a/common/src/main/java/stirling/software/common/configuration/PostHogLoggerImpl.java +++ b/common/src/main/java/stirling/software/common/configuration/PostHogLoggerImpl.java @@ -1,9 +1,11 @@ package stirling.software.common.configuration; -import com.posthog.java.PostHogLogger; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import com.posthog.java.PostHogLogger; + +import lombok.extern.slf4j.Slf4j; + @Slf4j @Component public class PostHogLoggerImpl implements PostHogLogger { diff --git a/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java b/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java index 99c125a0c..53fa97c25 100644 --- a/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java +++ b/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java @@ -2,10 +2,13 @@ package stirling.software.common.configuration; import java.nio.file.Files; import java.nio.file.Path; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; + import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Configuration; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.CustomPaths.Operations; import stirling.software.common.model.ApplicationProperties.CustomPaths.Pipeline; diff --git a/common/src/main/java/stirling/software/common/configuration/YamlPropertySourceFactory.java b/common/src/main/java/stirling/software/common/configuration/YamlPropertySourceFactory.java index 17ad21bfd..efb98f260 100644 --- a/common/src/main/java/stirling/software/common/configuration/YamlPropertySourceFactory.java +++ b/common/src/main/java/stirling/software/common/configuration/YamlPropertySourceFactory.java @@ -1,6 +1,7 @@ package stirling.software.common.configuration; import java.util.Properties; + import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; diff --git a/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index 27cc9b3ca..f5b67c866 100644 --- a/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -12,11 +12,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; -import lombok.Data; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; -import lombok.extern.slf4j.Slf4j; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.core.Ordered; @@ -28,6 +24,13 @@ import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.EncodedResource; import org.springframework.stereotype.Component; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.configuration.YamlPropertySourceFactory; import stirling.software.common.model.exception.UnsupportedProviderException; @@ -486,14 +489,14 @@ public class ApplicationProperties { public static class EnterpriseFeatures { private PersistentMetrics persistentMetrics = new PersistentMetrics(); private Audit audit = new Audit(); - + @Data public static class Audit { private boolean enabled = true; private int level = 2; // 0=OFF, 1=BASIC, 2=STANDARD, 3=VERBOSE private int retentionDays = 90; } - + @Data public static class PersistentMetrics { private boolean enabled; diff --git a/common/src/main/java/stirling/software/common/model/FileInfo.java b/common/src/main/java/stirling/software/common/model/FileInfo.java index 2c2b13ed5..41a3a4717 100644 --- a/common/src/main/java/stirling/software/common/model/FileInfo.java +++ b/common/src/main/java/stirling/software/common/model/FileInfo.java @@ -5,6 +5,7 @@ import java.nio.file.Paths; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; + import lombok.AllArgsConstructor; import lombok.Data; diff --git a/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java b/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java index eb7dc61f8..4bc81cafa 100644 --- a/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java +++ b/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; + import org.thymeleaf.templateresource.ITemplateResource; public class InputStreamTemplateResource implements ITemplateResource { diff --git a/common/src/main/java/stirling/software/common/model/PdfMetadata.java b/common/src/main/java/stirling/software/common/model/PdfMetadata.java index a640e9c63..ef8684788 100644 --- a/common/src/main/java/stirling/software/common/model/PdfMetadata.java +++ b/common/src/main/java/stirling/software/common/model/PdfMetadata.java @@ -1,6 +1,7 @@ package stirling.software.common.model; import java.util.Calendar; + import lombok.Builder; import lombok.Data; diff --git a/common/src/main/java/stirling/software/common/model/api/GeneralFile.java b/common/src/main/java/stirling/software/common/model/api/GeneralFile.java index ee67e53f5..84675dcb5 100644 --- a/common/src/main/java/stirling/software/common/model/api/GeneralFile.java +++ b/common/src/main/java/stirling/software/common/model/api/GeneralFile.java @@ -1,9 +1,11 @@ package stirling.software.common.model.api; +import org.springframework.web.multipart.MultipartFile; + import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; -import org.springframework.web.multipart.MultipartFile; @Data @EqualsAndHashCode diff --git a/common/src/main/java/stirling/software/common/model/api/PDFFile.java b/common/src/main/java/stirling/software/common/model/api/PDFFile.java index 3dcceb9a4..8ea3f0456 100644 --- a/common/src/main/java/stirling/software/common/model/api/PDFFile.java +++ b/common/src/main/java/stirling/software/common/model/api/PDFFile.java @@ -1,10 +1,12 @@ package stirling.software.common.model.api; +import org.springframework.web.multipart.MultipartFile; + import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import org.springframework.web.multipart.MultipartFile; @Data @NoArgsConstructor diff --git a/common/src/main/java/stirling/software/common/model/api/converters/EmlToPdfRequest.java b/common/src/main/java/stirling/software/common/model/api/converters/EmlToPdfRequest.java index 97ea125ad..b6425a99f 100644 --- a/common/src/main/java/stirling/software/common/model/api/converters/EmlToPdfRequest.java +++ b/common/src/main/java/stirling/software/common/model/api/converters/EmlToPdfRequest.java @@ -1,8 +1,10 @@ package stirling.software.common.model.api.converters; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; + import stirling.software.common.model.api.PDFFile; @Data diff --git a/common/src/main/java/stirling/software/common/model/api/converters/HTMLToPdfRequest.java b/common/src/main/java/stirling/software/common/model/api/converters/HTMLToPdfRequest.java index 59cc09e27..106d36f17 100644 --- a/common/src/main/java/stirling/software/common/model/api/converters/HTMLToPdfRequest.java +++ b/common/src/main/java/stirling/software/common/model/api/converters/HTMLToPdfRequest.java @@ -1,8 +1,10 @@ package stirling.software.common.model.api.converters; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; + import stirling.software.common.model.api.PDFFile; @Data diff --git a/common/src/main/java/stirling/software/common/model/api/security/RedactionArea.java b/common/src/main/java/stirling/software/common/model/api/security/RedactionArea.java index 349363f74..e0028a8ae 100644 --- a/common/src/main/java/stirling/software/common/model/api/security/RedactionArea.java +++ b/common/src/main/java/stirling/software/common/model/api/security/RedactionArea.java @@ -1,6 +1,7 @@ package stirling.software.common.model.api.security; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/common/src/main/java/stirling/software/common/model/enumeration/Role.java b/common/src/main/java/stirling/software/common/model/enumeration/Role.java index 6924808a1..9e3231918 100644 --- a/common/src/main/java/stirling/software/common/model/enumeration/Role.java +++ b/common/src/main/java/stirling/software/common/model/enumeration/Role.java @@ -2,6 +2,7 @@ package stirling.software.common.model.enumeration; import java.util.LinkedHashMap; import java.util.Map; + import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/common/src/main/java/stirling/software/common/model/oauth2/GitHubProvider.java b/common/src/main/java/stirling/software/common/model/oauth2/GitHubProvider.java index a62eb21fb..ef5c15497 100644 --- a/common/src/main/java/stirling/software/common/model/oauth2/GitHubProvider.java +++ b/common/src/main/java/stirling/software/common/model/oauth2/GitHubProvider.java @@ -2,7 +2,9 @@ package stirling.software.common.model.oauth2; import java.util.ArrayList; import java.util.Collection; + import lombok.NoArgsConstructor; + import stirling.software.common.model.enumeration.UsernameAttribute; @NoArgsConstructor diff --git a/common/src/main/java/stirling/software/common/model/oauth2/GoogleProvider.java b/common/src/main/java/stirling/software/common/model/oauth2/GoogleProvider.java index 34ce9d106..b229ddc53 100644 --- a/common/src/main/java/stirling/software/common/model/oauth2/GoogleProvider.java +++ b/common/src/main/java/stirling/software/common/model/oauth2/GoogleProvider.java @@ -2,7 +2,9 @@ package stirling.software.common.model.oauth2; import java.util.ArrayList; import java.util.Collection; + import lombok.NoArgsConstructor; + import stirling.software.common.model.enumeration.UsernameAttribute; @NoArgsConstructor diff --git a/common/src/main/java/stirling/software/common/model/oauth2/KeycloakProvider.java b/common/src/main/java/stirling/software/common/model/oauth2/KeycloakProvider.java index 420230a0e..5d01fa865 100644 --- a/common/src/main/java/stirling/software/common/model/oauth2/KeycloakProvider.java +++ b/common/src/main/java/stirling/software/common/model/oauth2/KeycloakProvider.java @@ -2,7 +2,9 @@ package stirling.software.common.model.oauth2; import java.util.ArrayList; import java.util.Collection; + import lombok.NoArgsConstructor; + import stirling.software.common.model.enumeration.UsernameAttribute; @NoArgsConstructor diff --git a/common/src/main/java/stirling/software/common/model/oauth2/Provider.java b/common/src/main/java/stirling/software/common/model/oauth2/Provider.java index 3c24720cc..55b6b4257 100644 --- a/common/src/main/java/stirling/software/common/model/oauth2/Provider.java +++ b/common/src/main/java/stirling/software/common/model/oauth2/Provider.java @@ -5,8 +5,10 @@ import static stirling.software.common.model.enumeration.UsernameAttribute.EMAIL import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; + import lombok.Data; import lombok.NoArgsConstructor; + import stirling.software.common.model.enumeration.UsernameAttribute; import stirling.software.common.model.exception.UnsupportedClaimException; diff --git a/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java b/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java index 04c8b1e28..e4b9173d0 100644 --- a/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java +++ b/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java @@ -8,8 +8,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.concurrent.atomic.AtomicLong; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.apache.pdfbox.Loader; import org.apache.pdfbox.examples.util.DeletingRandomAccessFile; import org.apache.pdfbox.io.IOUtils; @@ -19,6 +18,10 @@ import org.apache.pdfbox.io.ScratchFile; import org.apache.pdfbox.pdmodel.PDDocument; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.api.PDFFile; /** diff --git a/common/src/main/java/stirling/software/common/service/PdfMetadataService.java b/common/src/main/java/stirling/software/common/service/PdfMetadataService.java index 86481b88a..621e19d46 100644 --- a/common/src/main/java/stirling/software/common/service/PdfMetadataService.java +++ b/common/src/main/java/stirling/software/common/service/PdfMetadataService.java @@ -1,10 +1,12 @@ package stirling.software.common.service; import java.util.Calendar; + import org.apache.pdfbox.pdmodel.PDDocument; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.PdfMetadata; diff --git a/common/src/main/java/stirling/software/common/service/PostHogService.java b/common/src/main/java/stirling/software/common/service/PostHogService.java index 16102a4e0..2bc219832 100644 --- a/common/src/main/java/stirling/software/common/service/PostHogService.java +++ b/common/src/main/java/stirling/software/common/service/PostHogService.java @@ -1,6 +1,5 @@ package stirling.software.common.service; -import com.posthog.java.PostHog; import java.io.File; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; @@ -17,11 +16,15 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.TimeZone; + import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; + +import com.posthog.java.PostHog; + import stirling.software.common.model.ApplicationProperties; @Service diff --git a/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java b/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java index 1de2b2d20..f39daf8ae 100644 --- a/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java +++ b/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java @@ -3,6 +3,7 @@ package stirling.software.common.util; import java.io.IOException; import java.util.Arrays; import java.util.List; + import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult; public class CheckProgramInstall { diff --git a/common/src/main/java/stirling/software/common/util/EmlToPdf.java b/common/src/main/java/stirling/software/common/util/EmlToPdf.java index 2fec5e9f2..a97673745 100644 --- a/common/src/main/java/stirling/software/common/util/EmlToPdf.java +++ b/common/src/main/java/stirling/software/common/util/EmlToPdf.java @@ -19,10 +19,7 @@ import java.util.Map; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; -import lombok.Data; -import lombok.Getter; -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; + import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; @@ -38,6 +35,12 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; + +import lombok.Data; +import lombok.Getter; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.api.converters.EmlToPdfRequest; @Slf4j diff --git a/common/src/main/java/stirling/software/common/util/ErrorUtils.java b/common/src/main/java/stirling/software/common/util/ErrorUtils.java index d8738af23..75097c67e 100644 --- a/common/src/main/java/stirling/software/common/util/ErrorUtils.java +++ b/common/src/main/java/stirling/software/common/util/ErrorUtils.java @@ -2,6 +2,7 @@ package stirling.software.common.util; import java.io.PrintWriter; import java.io.StringWriter; + import org.springframework.ui.Model; import org.springframework.web.servlet.ModelAndView; diff --git a/common/src/main/java/stirling/software/common/util/FileMonitor.java b/common/src/main/java/stirling/software/common/util/FileMonitor.java index 8628c9de4..3d1fe4f58 100644 --- a/common/src/main/java/stirling/software/common/util/FileMonitor.java +++ b/common/src/main/java/stirling/software/common/util/FileMonitor.java @@ -11,10 +11,13 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; import java.util.stream.Stream; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.RuntimePathConfig; @Component diff --git a/common/src/main/java/stirling/software/common/util/FileToPdf.java b/common/src/main/java/stirling/software/common/util/FileToPdf.java index 132a50881..8439b67a2 100644 --- a/common/src/main/java/stirling/software/common/util/FileToPdf.java +++ b/common/src/main/java/stirling/software/common/util/FileToPdf.java @@ -1,6 +1,5 @@ package stirling.software.common.util; -import io.github.pixee.security.ZipSecurity; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; @@ -14,6 +13,9 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; + +import io.github.pixee.security.ZipSecurity; + import stirling.software.common.model.api.converters.HTMLToPdfRequest; import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult; diff --git a/common/src/main/java/stirling/software/common/util/GeneralUtils.java b/common/src/main/java/stirling/software/common/util/GeneralUtils.java index b5d26876e..3353cdfeb 100644 --- a/common/src/main/java/stirling/software/common/util/GeneralUtils.java +++ b/common/src/main/java/stirling/software/common/util/GeneralUtils.java @@ -1,8 +1,5 @@ package stirling.software.common.util; -import com.fathzer.soft.javaluator.DoubleEvaluator; -import io.github.pixee.security.HostValidator; -import io.github.pixee.security.Urls; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -17,11 +14,19 @@ import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.UUID; -import lombok.extern.slf4j.Slf4j; + import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.web.multipart.MultipartFile; + +import com.fathzer.soft.javaluator.DoubleEvaluator; + +import io.github.pixee.security.HostValidator; +import io.github.pixee.security.Urls; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.InstallationPathConfig; @Slf4j diff --git a/common/src/main/java/stirling/software/common/util/ImageProcessingUtils.java b/common/src/main/java/stirling/software/common/util/ImageProcessingUtils.java index 03b9e17cf..ae6c0b66f 100644 --- a/common/src/main/java/stirling/software/common/util/ImageProcessingUtils.java +++ b/common/src/main/java/stirling/software/common/util/ImageProcessingUtils.java @@ -1,18 +1,22 @@ package stirling.software.common.util; +import java.awt.geom.AffineTransform; +import java.awt.image.*; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import javax.imageio.ImageIO; + +import org.springframework.web.multipart.MultipartFile; + import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; import com.drew.metadata.Metadata; import com.drew.metadata.MetadataException; import com.drew.metadata.exif.ExifSubIFDDirectory; -import java.awt.geom.AffineTransform; -import java.awt.image.*; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import javax.imageio.ImageIO; + import lombok.extern.slf4j.Slf4j; -import org.springframework.web.multipart.MultipartFile; @Slf4j public class ImageProcessingUtils { diff --git a/common/src/main/java/stirling/software/common/util/PDFToFile.java b/common/src/main/java/stirling/software/common/util/PDFToFile.java index 87563f7b8..f763f5414 100644 --- a/common/src/main/java/stirling/software/common/util/PDFToFile.java +++ b/common/src/main/java/stirling/software/common/util/PDFToFile.java @@ -1,8 +1,5 @@ package stirling.software.common.util; -import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; -import com.vladsch.flexmark.util.data.MutableDataSet; -import io.github.pixee.security.Filenames; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -15,14 +12,22 @@ import java.util.List; import java.util.Objects; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; + +import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; +import com.vladsch.flexmark.util.data.MutableDataSet; + +import io.github.pixee.security.Filenames; + +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult; @Slf4j diff --git a/common/src/main/java/stirling/software/common/util/PdfUtils.java b/common/src/main/java/stirling/software/common/util/PdfUtils.java index 774abe078..3986110e5 100644 --- a/common/src/main/java/stirling/software/common/util/PdfUtils.java +++ b/common/src/main/java/stirling/software/common/util/PdfUtils.java @@ -1,6 +1,5 @@ package stirling.software.common.util; -import io.github.pixee.security.Filenames; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; @@ -11,9 +10,10 @@ import java.util.HashMap; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; + import javax.imageio.*; import javax.imageio.stream.ImageOutputStream; -import lombok.extern.slf4j.Slf4j; + import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -30,6 +30,11 @@ import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.text.PDFTextStripper; import org.springframework.web.multipart.MultipartFile; + +import io.github.pixee.security.Filenames; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.service.CustomPDFDocumentFactory; @Slf4j diff --git a/common/src/main/java/stirling/software/common/util/ProcessExecutor.java b/common/src/main/java/stirling/software/common/util/ProcessExecutor.java index b250ef333..09c5ff675 100644 --- a/common/src/main/java/stirling/software/common/util/ProcessExecutor.java +++ b/common/src/main/java/stirling/software/common/util/ProcessExecutor.java @@ -1,6 +1,5 @@ package stirling.software.common.util; -import io.github.pixee.security.BoundedLineReader; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -13,7 +12,11 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; + +import io.github.pixee.security.BoundedLineReader; + import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; @Slf4j diff --git a/common/src/main/java/stirling/software/common/util/UrlUtils.java b/common/src/main/java/stirling/software/common/util/UrlUtils.java index 8bdf522bc..445ef0a60 100644 --- a/common/src/main/java/stirling/software/common/util/UrlUtils.java +++ b/common/src/main/java/stirling/software/common/util/UrlUtils.java @@ -1,9 +1,10 @@ package stirling.software.common.util; -import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.ServerSocket; +import jakarta.servlet.http.HttpServletRequest; + public class UrlUtils { public static String getOrigin(HttpServletRequest request) { diff --git a/common/src/main/java/stirling/software/common/util/WebResponseUtils.java b/common/src/main/java/stirling/software/common/util/WebResponseUtils.java index 2af95a594..62a0e3246 100644 --- a/common/src/main/java/stirling/software/common/util/WebResponseUtils.java +++ b/common/src/main/java/stirling/software/common/util/WebResponseUtils.java @@ -1,10 +1,10 @@ package stirling.software.common.util; -import io.github.pixee.security.Filenames; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; + import org.apache.pdfbox.pdmodel.PDDocument; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -12,6 +12,8 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; +import io.github.pixee.security.Filenames; + public class WebResponseUtils { public static ResponseEntity boasToWebResponse( diff --git a/common/src/main/java/stirling/software/common/util/YamlHelper.java b/common/src/main/java/stirling/software/common/util/YamlHelper.java index b30fcfe40..4de2bd597 100644 --- a/common/src/main/java/stirling/software/common/util/YamlHelper.java +++ b/common/src/main/java/stirling/software/common/util/YamlHelper.java @@ -13,7 +13,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Function; -import lombok.extern.slf4j.Slf4j; + import org.snakeyaml.engine.v2.api.Dump; import org.snakeyaml.engine.v2.api.DumpSettings; import org.snakeyaml.engine.v2.api.LoadSettings; @@ -30,6 +30,8 @@ import org.snakeyaml.engine.v2.nodes.Tag; import org.snakeyaml.engine.v2.parser.ParserImpl; import org.snakeyaml.engine.v2.scanner.StreamReader; +import lombok.extern.slf4j.Slf4j; + @Slf4j public class YamlHelper { diff --git a/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java b/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java index 688312bd8..dc1781236 100644 --- a/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java +++ b/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java @@ -8,7 +8,7 @@ import java.io.IOException; import java.nio.file.Files; import java.util.List; import java.util.Set; -import lombok.extern.slf4j.Slf4j; + import org.apache.pdfbox.Loader; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -21,6 +21,9 @@ import org.apache.pdfbox.pdmodel.font.Standard14Fonts; import org.apache.pdfbox.text.TextPosition; import org.springframework.core.io.InputStreamResource; import org.springframework.web.multipart.MultipartFile; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.api.misc.HighContrastColorCombination; import stirling.software.common.model.api.misc.ReplaceAndInvert; diff --git a/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java b/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java index 9b374457a..df40737d3 100644 --- a/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java +++ b/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java @@ -7,7 +7,9 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.file.Files; + import javax.imageio.ImageIO; + import org.apache.pdfbox.Loader; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -16,6 +18,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.pdfbox.rendering.PDFRenderer; import org.springframework.core.io.InputStreamResource; import org.springframework.web.multipart.MultipartFile; + import stirling.software.common.model.api.misc.ReplaceAndInvert; public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy { diff --git a/common/src/main/java/stirling/software/common/util/misc/PdfTextStripperCustom.java b/common/src/main/java/stirling/software/common/util/misc/PdfTextStripperCustom.java index 9578596cc..5e140ace6 100644 --- a/common/src/main/java/stirling/software/common/util/misc/PdfTextStripperCustom.java +++ b/common/src/main/java/stirling/software/common/util/misc/PdfTextStripperCustom.java @@ -3,6 +3,7 @@ package stirling.software.common.util.misc; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.List; + import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.text.PDFTextStripperByArea; import org.apache.pdfbox.text.TextPosition; diff --git a/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java b/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java index a5f4ed8ae..5bb87b343 100644 --- a/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java +++ b/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java @@ -1,10 +1,13 @@ package stirling.software.common.util.misc; import java.io.IOException; -import lombok.Data; -import lombok.EqualsAndHashCode; + import org.springframework.core.io.InputStreamResource; import org.springframework.web.multipart.MultipartFile; + +import lombok.Data; +import lombok.EqualsAndHashCode; + import stirling.software.common.model.api.PDFFile; import stirling.software.common.model.api.misc.ReplaceAndInvert; diff --git a/common/src/main/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditor.java b/common/src/main/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditor.java index f28407ddb..98cba7e8c 100644 --- a/common/src/main/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditor.java +++ b/common/src/main/java/stirling/software/common/util/propertyeditor/StringToArrayListPropertyEditor.java @@ -1,12 +1,15 @@ package stirling.software.common.util.propertyeditor; +import java.beans.PropertyEditorSupport; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import java.beans.PropertyEditorSupport; -import java.util.ArrayList; -import java.util.List; + import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.api.security.RedactionArea; @Slf4j diff --git a/common/src/main/java/stirling/software/common/util/propertyeditor/StringToMapPropertyEditor.java b/common/src/main/java/stirling/software/common/util/propertyeditor/StringToMapPropertyEditor.java index 4ebfe4c34..4a9afc2f6 100644 --- a/common/src/main/java/stirling/software/common/util/propertyeditor/StringToMapPropertyEditor.java +++ b/common/src/main/java/stirling/software/common/util/propertyeditor/StringToMapPropertyEditor.java @@ -1,11 +1,12 @@ package stirling.software.common.util.propertyeditor; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import java.beans.PropertyEditorSupport; import java.util.HashMap; import java.util.Map; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + public class StringToMapPropertyEditor extends PropertyEditorSupport { private final ObjectMapper objectMapper = new ObjectMapper(); diff --git a/proprietary/build.gradle b/proprietary/build.gradle index 716e145be..3e37b398e 100644 --- a/proprietary/build.gradle +++ b/proprietary/build.gradle @@ -7,7 +7,13 @@ bootRun { spotless { java { target sourceSets.main.allJava - googleJavaFormat(googleJavaFormatVersion).aosp() + googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false) + + importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling") + toggleOffOn() + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() } } dependencies { diff --git a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditAspect.java b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditAspect.java index 519c901fd..8b9d46103 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditAspect.java +++ b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditAspect.java @@ -1,7 +1,8 @@ package stirling.software.proprietary.audit; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.Method; +import java.util.Map; + import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -10,18 +11,17 @@ import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import stirling.software.proprietary.config.AuditConfigurationProperties; -import stirling.software.proprietary.service.AuditService; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -/** - * Aspect for processing {@link Audited} annotations. - */ +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import stirling.software.proprietary.config.AuditConfigurationProperties; +import stirling.software.proprietary.service.AuditService; + +/** Aspect for processing {@link Audited} annotations. */ @Aspect @Component @Slf4j @@ -36,18 +36,20 @@ public class AuditAspect { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); Audited auditedAnnotation = method.getAnnotation(Audited.class); - + // Fast path: use unified check to determine if we should audit // This avoids all data collection if auditing is disabled if (!AuditUtils.shouldAudit(method, auditConfig)) { return joinPoint.proceed(); } - + // Only create the map once we know we'll use it - Map auditData = AuditUtils.createBaseAuditData(joinPoint, auditedAnnotation.level()); - + Map auditData = + AuditUtils.createBaseAuditData(joinPoint, auditedAnnotation.level()); + // Add HTTP information if we're in a web context - ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + ServletRequestAttributes attrs = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attrs != null) { HttpServletRequest req = attrs.getRequest(); String path = req.getRequestURI(); @@ -55,51 +57,55 @@ public class AuditAspect { AuditUtils.addHttpData(auditData, httpMethod, path, auditedAnnotation.level()); AuditUtils.addFileData(auditData, joinPoint, auditedAnnotation.level()); } - + // Add arguments if requested and if at VERBOSE level, or if specifically requested - boolean includeArgs = auditedAnnotation.includeArgs() && - (auditedAnnotation.level() == AuditLevel.VERBOSE || - auditConfig.getAuditLevel() == AuditLevel.VERBOSE); - + boolean includeArgs = + auditedAnnotation.includeArgs() + && (auditedAnnotation.level() == AuditLevel.VERBOSE + || auditConfig.getAuditLevel() == AuditLevel.VERBOSE); + if (includeArgs) { AuditUtils.addMethodArguments(auditData, joinPoint, AuditLevel.VERBOSE); } - + // Record start time for latency calculation long startTime = System.currentTimeMillis(); Object result; try { // Execute the method result = joinPoint.proceed(); - + // Add success status auditData.put("status", "success"); - + // Add result if requested and if at VERBOSE level - boolean includeResult = auditedAnnotation.includeResult() && - (auditedAnnotation.level() == AuditLevel.VERBOSE || - auditConfig.getAuditLevel() == AuditLevel.VERBOSE); - + boolean includeResult = + auditedAnnotation.includeResult() + && (auditedAnnotation.level() == AuditLevel.VERBOSE + || auditConfig.getAuditLevel() == AuditLevel.VERBOSE); + if (includeResult && result != null) { // Use safe string conversion with size limiting auditData.put("result", AuditUtils.safeToString(result, 1000)); } - + return result; } catch (Throwable ex) { // Always add failure information regardless of level auditData.put("status", "failure"); auditData.put("errorType", ex.getClass().getName()); auditData.put("errorMessage", ex.getMessage()); - + // Re-throw the exception throw ex; } finally { - // Add timing information - use isHttpRequest=false to ensure we get timing for non-HTTP methods + // Add timing information - use isHttpRequest=false to ensure we get timing for non-HTTP + // methods HttpServletResponse resp = attrs != null ? attrs.getResponse() : null; boolean isHttpRequest = attrs != null; - AuditUtils.addTimingData(auditData, startTime, resp, auditedAnnotation.level(), isHttpRequest); - + AuditUtils.addTimingData( + auditData, startTime, resp, auditedAnnotation.level(), isHttpRequest); + // Resolve the event type based on annotation and context String httpMethod = null; String path = null; @@ -108,15 +114,15 @@ public class AuditAspect { httpMethod = req.getMethod(); path = req.getRequestURI(); } - - AuditEventType eventType = AuditUtils.resolveEventType( - method, - joinPoint.getTarget().getClass(), - path, - httpMethod, - auditedAnnotation - ); - + + AuditEventType eventType = + AuditUtils.resolveEventType( + method, + joinPoint.getTarget().getClass(), + path, + httpMethod, + auditedAnnotation); + // Check if we should use string type instead String typeString = auditedAnnotation.typeString(); if (eventType == AuditEventType.HTTP_REQUEST && StringUtils.isNotEmpty(typeString)) { @@ -128,4 +134,4 @@ public class AuditAspect { } } } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditEventType.java b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditEventType.java index 421f41ce5..a18e83467 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditEventType.java +++ b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditEventType.java @@ -1,43 +1,41 @@ package stirling.software.proprietary.audit; -/** - * Standardized audit event types for the application. - */ +/** Standardized audit event types for the application. */ public enum AuditEventType { // Authentication events - BASIC level USER_LOGIN("User login"), - USER_LOGOUT("User logout"), + USER_LOGOUT("User logout"), USER_FAILED_LOGIN("Failed login attempt"), - + // User/admin events - BASIC level USER_PROFILE_UPDATE("User or profile operation"), - + // System configuration events - STANDARD level SETTINGS_CHANGED("System or admin settings operation"), - + // File operations - STANDARD level FILE_OPERATION("File operation"), - + // PDF operations - STANDARD level PDF_PROCESS("PDF processing operation"), - + // HTTP requests - STANDARD level HTTP_REQUEST("HTTP request"); - + private final String description; - + AuditEventType(String description) { this.description = description; } - + public String getDescription() { return description; } - + /** - * Get the enum value from a string representation. - * Useful for backward compatibility with string-based event types. - * + * Get the enum value from a string representation. Useful for backward compatibility with + * string-based event types. + * * @param type The string representation of the event type * @return The corresponding enum value or null if not found */ @@ -45,18 +43,18 @@ public enum AuditEventType { if (type == null) { return null; } - + try { return AuditEventType.valueOf(type); } catch (IllegalArgumentException e) { // If the exact enum name doesn't match, try finding a similar one for (AuditEventType eventType : values()) { - if (eventType.name().equalsIgnoreCase(type) || - eventType.getDescription().equalsIgnoreCase(type)) { + if (eventType.name().equalsIgnoreCase(type) + || eventType.getDescription().equalsIgnoreCase(type)) { return eventType; } } return null; } } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditLevel.java b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditLevel.java index 79ca32922..136559a94 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditLevel.java +++ b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditLevel.java @@ -1,80 +1,69 @@ package stirling.software.proprietary.audit; -/** - * Defines the different levels of audit logging available in the application. - */ +/** Defines the different levels of audit logging available in the application. */ public enum AuditLevel { /** - * OFF - No audit logging (level 0) - * Disables all audit logging except for critical security events + * OFF - No audit logging (level 0) Disables all audit logging except for critical security + * events */ OFF(0), - + /** - * BASIC - Minimal audit logging (level 1) - * Includes: - * - Authentication events (login, logout, failed logins) - * - Password changes - * - User/role changes - * - System configuration changes + * BASIC - Minimal audit logging (level 1) Includes: - Authentication events (login, logout, + * failed logins) - Password changes - User/role changes - System configuration changes */ BASIC(1), - + /** - * STANDARD - Standard audit logging (level 2) - * Includes everything in BASIC plus: - * - All HTTP requests (basic info: URL, method, status) - * - File operations (upload, download, process) - * - PDF operations (view, edit, etc.) - * - User operations + * STANDARD - Standard audit logging (level 2) Includes everything in BASIC plus: - All HTTP + * requests (basic info: URL, method, status) - File operations (upload, download, process) - + * PDF operations (view, edit, etc.) - User operations */ STANDARD(2), - + /** - * VERBOSE - Detailed audit logging (level 3) - * Includes everything in STANDARD plus: - * - Request headers and parameters - * - Method parameters - * - Operation results - * - Detailed timing information + * VERBOSE - Detailed audit logging (level 3) Includes everything in STANDARD plus: - Request + * headers and parameters - Method parameters - Operation results - Detailed timing information */ VERBOSE(3); - + private final int level; - + AuditLevel(int level) { this.level = level; } - + public int getLevel() { return level; } - + /** * Checks if this audit level includes the specified level + * * @param otherLevel The level to check against * @return true if this level is equal to or greater than the specified level */ public boolean includes(AuditLevel otherLevel) { return this.level >= otherLevel.level; } - + /** * Get an AuditLevel from an integer value + * * @param level The integer level (0-3) * @return The corresponding AuditLevel */ public static AuditLevel fromInt(int level) { // Ensure level is within valid bounds int boundedLevel = Math.min(Math.max(level, 0), 3); - + for (AuditLevel auditLevel : values()) { if (auditLevel.level == boundedLevel) { return auditLevel; } } - + // Default to STANDARD if somehow we didn't match return STANDARD; } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditUtils.java b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditUtils.java index 35153d956..a0808f71e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/audit/AuditUtils.java +++ b/proprietary/src/main/java/stirling/software/proprietary/audit/AuditUtils.java @@ -1,19 +1,5 @@ package stirling.software.proprietary.audit; -import lombok.extern.slf4j.Slf4j; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.reflect.MethodSignature; -import org.slf4j.MDC; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; -import org.springframework.web.multipart.MultipartFile; -import stirling.software.common.util.RequestUriUtils; -import stirling.software.proprietary.config.AuditConfigurationProperties; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.lang.reflect.Method; import java.time.Instant; import java.util.Arrays; @@ -24,10 +10,26 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.MDC; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + +import stirling.software.common.util.RequestUriUtils; +import stirling.software.proprietary.config.AuditConfigurationProperties; /** - * Shared utilities for audit aspects to ensure consistent behavior - * across different audit mechanisms. + * Shared utilities for audit aspects to ensure consistent behavior across different audit + * mechanisms. */ @Slf4j public class AuditUtils { @@ -39,12 +41,13 @@ public class AuditUtils { * @param auditLevel The current audit level * @return A map with standard audit data */ - public static Map createBaseAuditData(ProceedingJoinPoint joinPoint, AuditLevel auditLevel) { + public static Map createBaseAuditData( + ProceedingJoinPoint joinPoint, AuditLevel auditLevel) { Map data = new HashMap<>(); - + // Common data for all levels data.put("timestamp", Instant.now().toString()); - + // Add principal if available Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getName() != null) { @@ -52,16 +55,18 @@ public class AuditUtils { } else { data.put("principal", "system"); } - + // Add class name and method name only at VERBOSE level if (auditLevel.includes(AuditLevel.VERBOSE)) { data.put("className", joinPoint.getTarget().getClass().getName()); - data.put("methodName", ((MethodSignature) joinPoint.getSignature()).getMethod().getName()); + data.put( + "methodName", + ((MethodSignature) joinPoint.getSignature()).getMethod().getName()); } - + return data; } - + /** * Add HTTP-specific information to the audit data if available * @@ -70,45 +75,50 @@ public class AuditUtils { * @param path The request path * @param auditLevel The current audit level */ - public static void addHttpData(Map data, String httpMethod, String path, AuditLevel auditLevel) { + public static void addHttpData( + Map data, String httpMethod, String path, AuditLevel auditLevel) { if (httpMethod == null || path == null) { return; // Skip if we don't have basic HTTP info } - + // BASIC level HTTP data data.put("httpMethod", httpMethod); data.put("path", path); - + // Get request attributes safely - ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + ServletRequestAttributes attrs = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attrs == null) { return; // No request context available } - + HttpServletRequest req = attrs.getRequest(); if (req == null) { return; // No request available } - + // STANDARD level HTTP data if (auditLevel.includes(AuditLevel.STANDARD)) { data.put("clientIp", req.getRemoteAddr()); - data.put("sessionId", req.getSession(false) != null ? req.getSession(false).getId() : null); + data.put( + "sessionId", + req.getSession(false) != null ? req.getSession(false).getId() : null); data.put("requestId", MDC.get("requestId")); - + // Form data for POST/PUT/PATCH - if (("POST".equalsIgnoreCase(httpMethod) || - "PUT".equalsIgnoreCase(httpMethod) || - "PATCH".equalsIgnoreCase(httpMethod)) && req.getContentType() != null) { - + if (("POST".equalsIgnoreCase(httpMethod) + || "PUT".equalsIgnoreCase(httpMethod) + || "PATCH".equalsIgnoreCase(httpMethod)) + && req.getContentType() != null) { + String contentType = req.getContentType(); - if (contentType.contains("application/x-www-form-urlencoded") || - contentType.contains("multipart/form-data")) { - + if (contentType.contains("application/x-www-form-urlencoded") + || contentType.contains("multipart/form-data")) { + Map params = new HashMap<>(req.getParameterMap()); // Remove CSRF token from logged parameters params.remove("_csrf"); - + if (!params.isEmpty()) { data.put("formParams", params); } @@ -116,7 +126,7 @@ public class AuditUtils { } } } - + /** * Add file information to the audit data if available * @@ -124,27 +134,33 @@ public class AuditUtils { * @param joinPoint The AspectJ join point * @param auditLevel The current audit level */ - public static void addFileData(Map data, ProceedingJoinPoint joinPoint, AuditLevel auditLevel) { + public static void addFileData( + Map data, ProceedingJoinPoint joinPoint, AuditLevel auditLevel) { if (auditLevel.includes(AuditLevel.STANDARD)) { - List files = Arrays.stream(joinPoint.getArgs()) - .filter(a -> a instanceof MultipartFile) - .map(a -> (MultipartFile)a) - .collect(Collectors.toList()); + List files = + Arrays.stream(joinPoint.getArgs()) + .filter(a -> a instanceof MultipartFile) + .map(a -> (MultipartFile) a) + .collect(Collectors.toList()); if (!files.isEmpty()) { - List> fileInfos = files.stream().map(f -> { - Map m = new HashMap<>(); - m.put("name", f.getOriginalFilename()); - m.put("size", f.getSize()); - m.put("type", f.getContentType()); - return m; - }).collect(Collectors.toList()); + List> fileInfos = + files.stream() + .map( + f -> { + Map m = new HashMap<>(); + m.put("name", f.getOriginalFilename()); + m.put("size", f.getSize()); + m.put("type", f.getContentType()); + return m; + }) + .collect(Collectors.toList()); data.put("files", fileInfos); } } } - + /** * Add method arguments to the audit data * @@ -152,28 +168,30 @@ public class AuditUtils { * @param joinPoint The AspectJ join point * @param auditLevel The current audit level */ - public static void addMethodArguments(Map data, ProceedingJoinPoint joinPoint, AuditLevel auditLevel) { + public static void addMethodArguments( + Map data, ProceedingJoinPoint joinPoint, AuditLevel auditLevel) { if (auditLevel.includes(AuditLevel.VERBOSE)) { MethodSignature sig = (MethodSignature) joinPoint.getSignature(); String[] names = sig.getParameterNames(); Object[] vals = joinPoint.getArgs(); if (names != null && vals != null) { IntStream.range(0, names.length) - .forEach(i -> { - if (vals[i] != null) { - // Convert objects to safe string representation - data.put("arg_" + names[i], safeToString(vals[i], 500)); - } else { - data.put("arg_" + names[i], null); - } - }); + .forEach( + i -> { + if (vals[i] != null) { + // Convert objects to safe string representation + data.put("arg_" + names[i], safeToString(vals[i], 500)); + } else { + data.put("arg_" + names[i], null); + } + }); } } } - + /** * Safely convert an object to string with size limiting - * + * * @param obj The object to convert * @param maxLength Maximum length of the resulting string * @return A safe string representation, truncated if needed @@ -182,7 +200,7 @@ public class AuditUtils { if (obj == null) { return "null"; } - + String result; try { // Handle common types directly to avoid toString() overhead @@ -196,19 +214,19 @@ public class AuditUtils { // For complex objects, use toString but handle exceptions result = obj.toString(); } - + // Truncate if necessary if (result != null && result.length() > maxLength) { return StringUtils.truncate(result, maxLength - 3) + "..."; } - + return result; } catch (Exception e) { // If toString() fails, return the class name return "[" + obj.getClass().getName() + " - toString() failed]"; } } - + /** * Determine if a method should be audited based on config and annotation * @@ -221,17 +239,16 @@ public class AuditUtils { if (!auditConfig.isEnabled()) { return false; } - + // Check for annotation override Audited auditedAnnotation = method.getAnnotation(Audited.class); - AuditLevel requiredLevel = (auditedAnnotation != null) - ? auditedAnnotation.level() - : AuditLevel.BASIC; - + AuditLevel requiredLevel = + (auditedAnnotation != null) ? auditedAnnotation.level() : AuditLevel.BASIC; + // Check if the required level is enabled return auditConfig.getAuditLevel().includes(requiredLevel); } - + /** * Add timing and response status data to the audit record * @@ -241,14 +258,19 @@ public class AuditUtils { * @param level The current audit level * @param isHttpRequest Whether this is an HTTP request (controller) or a regular method call */ - public static void addTimingData(Map data, long startTime, HttpServletResponse response, AuditLevel level, boolean isHttpRequest) { + public static void addTimingData( + Map data, + long startTime, + HttpServletResponse response, + AuditLevel level, + boolean isHttpRequest) { if (level.includes(AuditLevel.STANDARD)) { // For HTTP requests, let ControllerAuditAspect handle timing separately // For non-HTTP methods, add execution time here if (!isHttpRequest) { data.put("latencyMs", System.currentTimeMillis() - startTime); } - + // Add HTTP status code if available if (response != null) { try { @@ -259,7 +281,7 @@ public class AuditUtils { } } } - + /** * Resolve the event type to use for auditing, considering annotations and context * @@ -270,34 +292,45 @@ public class AuditUtils { * @param annotation The @Audited annotation (may be null) * @return The resolved event type (never null) */ - public static AuditEventType resolveEventType(Method method, Class controller, String path, String httpMethod, Audited annotation) { + public static AuditEventType resolveEventType( + Method method, + Class controller, + String path, + String httpMethod, + Audited annotation) { // First check if we have an explicit annotation if (annotation != null && annotation.type() != AuditEventType.HTTP_REQUEST) { return annotation.type(); } - + // For HTTP methods, infer based on controller and path if (httpMethod != null && path != null) { String cls = controller.getSimpleName().toLowerCase(); String pkg = controller.getPackage().getName().toLowerCase(); - + if ("GET".equals(httpMethod)) return AuditEventType.HTTP_REQUEST; - - if (cls.contains("user") || cls.contains("auth") || pkg.contains("auth") - || path.startsWith("/user") || path.startsWith("/login")) { + + if (cls.contains("user") + || cls.contains("auth") + || pkg.contains("auth") + || path.startsWith("/user") + || path.startsWith("/login")) { return AuditEventType.USER_PROFILE_UPDATE; - } else if (cls.contains("admin") || path.startsWith("/admin") || path.startsWith("/settings")) { + } else if (cls.contains("admin") + || path.startsWith("/admin") + || path.startsWith("/settings")) { return AuditEventType.SETTINGS_CHANGED; - } else if (cls.contains("file") || path.startsWith("/file") + } else if (cls.contains("file") + || path.startsWith("/file") || path.matches("(?i).*/(upload|download)/.*")) { return AuditEventType.FILE_OPERATION; } } - + // Default for non-HTTP methods or when no specific match return AuditEventType.PDF_PROCESS; } - + /** * Determine the appropriate audit level to use * @@ -306,17 +339,18 @@ public class AuditUtils { * @param auditConfig The audit configuration * @return The audit level to use */ - public static AuditLevel getEffectiveAuditLevel(Method method, AuditLevel defaultLevel, AuditConfigurationProperties auditConfig) { + public static AuditLevel getEffectiveAuditLevel( + Method method, AuditLevel defaultLevel, AuditConfigurationProperties auditConfig) { Audited auditedAnnotation = method.getAnnotation(Audited.class); if (auditedAnnotation != null) { // Method has @Audited - use its level return auditedAnnotation.level(); } - + // Use default level (typically from global config) return defaultLevel; } - + /** * Determine the appropriate audit event type to use * @@ -326,42 +360,50 @@ public class AuditUtils { * @param httpMethod The HTTP method * @return The determined audit event type */ - public static AuditEventType determineAuditEventType(Method method, Class controller, String path, String httpMethod) { + public static AuditEventType determineAuditEventType( + Method method, Class controller, String path, String httpMethod) { // First check for explicit annotation Audited auditedAnnotation = method.getAnnotation(Audited.class); if (auditedAnnotation != null) { return auditedAnnotation.type(); } - + // Otherwise infer from controller and path String cls = controller.getSimpleName().toLowerCase(); String pkg = controller.getPackage().getName().toLowerCase(); - + if ("GET".equals(httpMethod)) return AuditEventType.HTTP_REQUEST; - - if (cls.contains("user") || cls.contains("auth") || pkg.contains("auth") - || path.startsWith("/user") || path.startsWith("/login")) { + + if (cls.contains("user") + || cls.contains("auth") + || pkg.contains("auth") + || path.startsWith("/user") + || path.startsWith("/login")) { return AuditEventType.USER_PROFILE_UPDATE; - } else if (cls.contains("admin") || path.startsWith("/admin") || path.startsWith("/settings")) { + } else if (cls.contains("admin") + || path.startsWith("/admin") + || path.startsWith("/settings")) { return AuditEventType.SETTINGS_CHANGED; - } else if (cls.contains("file") || path.startsWith("/file") + } else if (cls.contains("file") + || path.startsWith("/file") || path.matches("(?i).*/(upload|download)/.*")) { return AuditEventType.FILE_OPERATION; } else { return AuditEventType.PDF_PROCESS; } } - + /** * Get the current HTTP request if available * * @return The current request or null if not in a request context */ public static HttpServletRequest getCurrentRequest() { - ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + ServletRequestAttributes attrs = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); return attrs != null ? attrs.getRequest() : null; } - + /** * Check if a GET request is for a static resource * @@ -369,7 +411,8 @@ public class AuditUtils { * @return true if this is a static resource request */ public static boolean isStaticResourceRequest(HttpServletRequest request) { - return request != null && !RequestUriUtils.isTrackableResource( - request.getContextPath(), request.getRequestURI()); + return request != null + && !RequestUriUtils.isTrackableResource( + request.getContextPath(), request.getRequestURI()); } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/audit/Audited.java b/proprietary/src/main/java/stirling/software/proprietary/audit/Audited.java index dff976d8e..9c0c99a15 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/audit/Audited.java +++ b/proprietary/src/main/java/stirling/software/proprietary/audit/Audited.java @@ -7,61 +7,51 @@ import java.lang.annotation.Target; /** * Annotation for methods that should be audited. - * - * Usage: - * - *
- * {@code 
+ *
+ * 

Usage: + * + *

{@code
  * @Audited(type = AuditEventType.USER_REGISTRATION, level = AuditLevel.BASIC)
  * public void registerUser(String username) {
  *    // Method implementation
  * }
- * }
- * 
- * + * }
+ * * For backward compatibility, string-based event types are still supported: - * - *
- * {@code 
+ *
+ * 
{@code
  * @Audited(typeString = "CUSTOM_EVENT_TYPE", level = AuditLevel.BASIC)
  * public void customOperation() {
  *    // Method implementation
  * }
- * }
- * 
+ * }
*/ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Audited { - + /** - * The type of audit event using the standardized AuditEventType enum. - * This is the preferred way to specify the event type. - * - * If both type() and typeString() are specified, type() takes precedence. + * The type of audit event using the standardized AuditEventType enum. This is the preferred way + * to specify the event type. + * + *

If both type() and typeString() are specified, type() takes precedence. */ AuditEventType type() default AuditEventType.HTTP_REQUEST; - + /** - * The type of audit event as a string (e.g., "FILE_UPLOAD", "USER_REGISTRATION"). - * Provided for backward compatibility and custom event types not in the enum. - * - * If both type() and typeString() are specified, type() takes precedence. + * The type of audit event as a string (e.g., "FILE_UPLOAD", "USER_REGISTRATION"). Provided for + * backward compatibility and custom event types not in the enum. + * + *

If both type() and typeString() are specified, type() takes precedence. */ String typeString() default ""; - - /** - * The audit level at which this event should be logged - */ + + /** The audit level at which this event should be logged */ AuditLevel level() default AuditLevel.STANDARD; - - /** - * Should method arguments be included in the audit event - */ + + /** Should method arguments be included in the audit event */ boolean includeArgs() default true; - - /** - * Should the method return value be included in the audit event - */ + + /** Should the method return value be included in the audit event */ boolean includeResult() default false; -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/audit/ControllerAuditAspect.java b/proprietary/src/main/java/stirling/software/proprietary/audit/ControllerAuditAspect.java index 6f3990a68..740555439 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/audit/ControllerAuditAspect.java +++ b/proprietary/src/main/java/stirling/software/proprietary/audit/ControllerAuditAspect.java @@ -1,7 +1,9 @@ package stirling.software.proprietary.audit; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Map; + import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -19,17 +21,16 @@ import org.springframework.web.context.request.ServletRequestAttributes; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.config.AuditConfigurationProperties; import stirling.software.proprietary.service.AuditService; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - /** - * Aspect for automatically auditing controller methods with web mappings - * (GetMapping, PostMapping, etc.) + * Aspect for automatically auditing controller methods with web mappings (GetMapping, PostMapping, + * etc.) */ @Aspect @Component @@ -40,65 +41,57 @@ public class ControllerAuditAspect { private final AuditService auditService; private final AuditConfigurationProperties auditConfig; - - @Around("execution(* org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(..))") + @Around( + "execution(* org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(..))") public Object auditStaticResource(ProceedingJoinPoint jp) throws Throwable { return auditController(jp, "GET"); } - /** - * Intercept all methods with GetMapping annotation - */ + + /** Intercept all methods with GetMapping annotation */ @Around("@annotation(org.springframework.web.bind.annotation.GetMapping)") public Object auditGetMethod(ProceedingJoinPoint joinPoint) throws Throwable { return auditController(joinPoint, "GET"); } - /** - * Intercept all methods with PostMapping annotation - */ + /** Intercept all methods with PostMapping annotation */ @Around("@annotation(org.springframework.web.bind.annotation.PostMapping)") public Object auditPostMethod(ProceedingJoinPoint joinPoint) throws Throwable { return auditController(joinPoint, "POST"); } - /** - * Intercept all methods with PutMapping annotation - */ + /** Intercept all methods with PutMapping annotation */ @Around("@annotation(org.springframework.web.bind.annotation.PutMapping)") public Object auditPutMethod(ProceedingJoinPoint joinPoint) throws Throwable { return auditController(joinPoint, "PUT"); } - /** - * Intercept all methods with DeleteMapping annotation - */ + /** Intercept all methods with DeleteMapping annotation */ @Around("@annotation(org.springframework.web.bind.annotation.DeleteMapping)") public Object auditDeleteMethod(ProceedingJoinPoint joinPoint) throws Throwable { return auditController(joinPoint, "DELETE"); } - /** - * Intercept all methods with PatchMapping annotation - */ + /** Intercept all methods with PatchMapping annotation */ @Around("@annotation(org.springframework.web.bind.annotation.PatchMapping)") public Object auditPatchMethod(ProceedingJoinPoint joinPoint) throws Throwable { return auditController(joinPoint, "PATCH"); } - private Object auditController(ProceedingJoinPoint joinPoint, String httpMethod) throws Throwable { + private Object auditController(ProceedingJoinPoint joinPoint, String httpMethod) + throws Throwable { MethodSignature sig = (MethodSignature) joinPoint.getSignature(); Method method = sig.getMethod(); - + // Fast path: check if auditing is enabled before doing any work // This avoids all data collection if auditing is disabled if (!AuditUtils.shouldAudit(method, auditConfig)) { return joinPoint.proceed(); } - + // Check if method is explicitly annotated with @Audited Audited auditedAnnotation = method.getAnnotation(Audited.class); AuditLevel level = auditConfig.getAuditLevel(); - + // If @Audited annotation is present, respect its level setting if (auditedAnnotation != null) { // Use the level from annotation if it's stricter than global level @@ -115,21 +108,22 @@ public class ControllerAuditAspect { } } - ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + ServletRequestAttributes attrs = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest req = attrs != null ? attrs.getRequest() : null; HttpServletResponse resp = attrs != null ? attrs.getResponse() : null; long start = System.currentTimeMillis(); - + // Use AuditUtils to create the base audit data Map data = AuditUtils.createBaseAuditData(joinPoint, level); - + // Add HTTP-specific information AuditUtils.addHttpData(data, httpMethod, path, level); - + // Add file information if present AuditUtils.addFileData(data, joinPoint, level); - + // Add method arguments if at VERBOSE level if (level.includes(AuditLevel.VERBOSE)) { AuditUtils.addMethodArguments(data, joinPoint, level); @@ -150,34 +144,35 @@ public class ControllerAuditAspect { data.put("latencyMs", System.currentTimeMillis() - start); if (resp != null) data.put("statusCode", resp.getStatus()); } - + // Call AuditUtils but with isHttpRequest=true to skip additional timing AuditUtils.addTimingData(data, start, resp, level, true); - + // Add result for VERBOSE level if (level.includes(AuditLevel.VERBOSE) && result != null) { // Use safe string conversion with size limiting data.put("result", AuditUtils.safeToString(result, 1000)); } - + // Resolve the event type using the unified method - AuditEventType eventType = AuditUtils.resolveEventType( - method, - joinPoint.getTarget().getClass(), - path, - httpMethod, - auditedAnnotation - ); - + AuditEventType eventType = + AuditUtils.resolveEventType( + method, + joinPoint.getTarget().getClass(), + path, + httpMethod, + auditedAnnotation); + // Check if we should use string type instead (for backward compatibility) if (auditedAnnotation != null) { String typeString = auditedAnnotation.typeString(); - if (eventType == AuditEventType.HTTP_REQUEST && StringUtils.isNotEmpty(typeString)) { + if (eventType == AuditEventType.HTTP_REQUEST + && StringUtils.isNotEmpty(typeString)) { auditService.audit(typeString, data, level); return result; } } - + // Use the enum type auditService.audit(eventType, data, level); } @@ -191,14 +186,15 @@ public class ControllerAuditAspect { RequestMapping cm = method.getDeclaringClass().getAnnotation(RequestMapping.class); if (cm != null && cm.value().length > 0) base = cm.value()[0]; String mp = ""; - Annotation ann = switch (httpMethod) { - case "GET" -> method.getAnnotation(GetMapping.class); - case "POST" -> method.getAnnotation(PostMapping.class); - case "PUT" -> method.getAnnotation(PutMapping.class); - case "DELETE" -> method.getAnnotation(DeleteMapping.class); - case "PATCH" -> method.getAnnotation(PatchMapping.class); - default -> null; - }; + Annotation ann = + switch (httpMethod) { + case "GET" -> method.getAnnotation(GetMapping.class); + case "POST" -> method.getAnnotation(PostMapping.class); + case "PUT" -> method.getAnnotation(PutMapping.class); + case "DELETE" -> method.getAnnotation(DeleteMapping.class); + case "PATCH" -> method.getAnnotation(PatchMapping.class); + default -> null; + }; if (ann instanceof GetMapping gm && gm.value().length > 0) mp = gm.value()[0]; if (ann instanceof PostMapping pm && pm.value().length > 0) mp = pm.value()[0]; if (ann instanceof PutMapping pum && pum.value().length > 0) mp = pum.value()[0]; diff --git a/proprietary/src/main/java/stirling/software/proprietary/config/AsyncConfig.java b/proprietary/src/main/java/stirling/software/proprietary/config/AsyncConfig.java index 2926b9e89..54610f80a 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/config/AsyncConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/config/AsyncConfig.java @@ -1,5 +1,8 @@ package stirling.software.proprietary.config; +import java.util.Map; +import java.util.concurrent.Executor; + import org.slf4j.MDC; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -7,23 +10,20 @@ import org.springframework.core.task.TaskDecorator; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import java.util.Map; -import java.util.concurrent.Executor; - @Configuration @EnableAsync public class AsyncConfig { /** - * MDC context-propagating task decorator - * Copies MDC context from the caller thread to the async executor thread + * MDC context-propagating task decorator Copies MDC context from the caller thread to the async + * executor thread */ static class MDCContextTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { // Capture the MDC context from the current thread Map contextMap = MDC.getCopyOfContextMap(); - + return () -> { try { // Set the captured context on the worker thread @@ -47,11 +47,11 @@ public class AsyncConfig { exec.setMaxPoolSize(8); exec.setQueueCapacity(1_000); exec.setThreadNamePrefix("audit-"); - + // Set the task decorator to propagate MDC context exec.setTaskDecorator(new MDCContextTaskDecorator()); - + exec.initialize(); return exec; } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/config/AuditConfigurationProperties.java b/proprietary/src/main/java/stirling/software/proprietary/config/AuditConfigurationProperties.java index 6e30fa4c8..16b019a3b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/config/AuditConfigurationProperties.java +++ b/proprietary/src/main/java/stirling/software/proprietary/config/AuditConfigurationProperties.java @@ -1,17 +1,18 @@ package stirling.software.proprietary.config; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.audit.AuditLevel; /** - * Configuration properties for the audit system. - * Reads values from the ApplicationProperties under premium.enterpriseFeatures.audit + * Configuration properties for the audit system. Reads values from the ApplicationProperties under + * premium.enterpriseFeatures.audit */ @Slf4j @Getter @@ -22,47 +23,53 @@ public class AuditConfigurationProperties { private final boolean enabled; private final int level; private final int retentionDays; - + public AuditConfigurationProperties(ApplicationProperties applicationProperties) { - ApplicationProperties.Premium.EnterpriseFeatures.Audit auditConfig = - applicationProperties.getPremium().getEnterpriseFeatures().getAudit(); + ApplicationProperties.Premium.EnterpriseFeatures.Audit auditConfig = + applicationProperties.getPremium().getEnterpriseFeatures().getAudit(); // Read values directly from configuration this.enabled = auditConfig.isEnabled(); - + // Ensure level is within valid bounds (0-3) int configLevel = auditConfig.getLevel(); this.level = Math.min(Math.max(configLevel, 0), 3); - + // Retention days (0 means infinite) this.retentionDays = auditConfig.getRetentionDays(); - - log.debug("Initialized audit configuration: enabled={}, level={}, retentionDays={} (0=infinite)", - this.enabled, this.level, this.retentionDays); + + log.debug( + "Initialized audit configuration: enabled={}, level={}, retentionDays={} (0=infinite)", + this.enabled, + this.level, + this.retentionDays); } - + /** * Get the audit level as an enum + * * @return The current AuditLevel */ public AuditLevel getAuditLevel() { return AuditLevel.fromInt(level); } - + /** * Check if the current audit level includes the specified level + * * @param requiredLevel The level to check against * @return true if auditing is enabled and the current level includes the required level */ public boolean isLevelEnabled(AuditLevel requiredLevel) { return enabled && getAuditLevel().includes(requiredLevel); } - + /** * Get the effective retention period in days + * * @return The number of days to retain audit records, or -1 for infinite retention */ public int getEffectiveRetentionDays() { // 0 means infinite retention return retentionDays <= 0 ? -1 : retentionDays; } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/config/AuditJpaConfig.java b/proprietary/src/main/java/stirling/software/proprietary/config/AuditJpaConfig.java index c0ca3e4b4..a43f6b69d 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/config/AuditJpaConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/config/AuditJpaConfig.java @@ -5,9 +5,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.transaction.annotation.EnableTransactionManagement; -/** - * Configuration to explicitly enable JPA repositories and scheduling for the audit system. - */ +/** Configuration to explicitly enable JPA repositories and scheduling for the audit system. */ @Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = "stirling.software.proprietary.repository") @@ -16,4 +14,4 @@ public class AuditJpaConfig { // This configuration enables JPA repositories in the specified package // and enables scheduling for audit cleanup tasks // No additional beans or methods needed -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/config/CustomAuditEventRepository.java b/proprietary/src/main/java/stirling/software/proprietary/config/CustomAuditEventRepository.java index bd9a86d89..c5ed53bf6 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/config/CustomAuditEventRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/config/CustomAuditEventRepository.java @@ -1,8 +1,8 @@ package stirling.software.proprietary.config; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.time.Instant; +import java.util.List; +import java.util.Map; import org.slf4j.MDC; import org.springframework.boot.actuate.audit.AuditEvent; @@ -11,14 +11,16 @@ import org.springframework.context.annotation.Primary; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.model.security.PersistentAuditEvent; import stirling.software.proprietary.repository.PersistentAuditEventRepository; import stirling.software.proprietary.util.SecretMasker; -import java.time.Instant; -import java.util.List; -import java.util.Map; - @Component @Primary @RequiredArgsConstructor @@ -40,35 +42,33 @@ public class CustomAuditEventRepository implements AuditEventRepository { public void add(AuditEvent ev) { try { Map clean = - CollectionUtils.isEmpty(ev.getData()) - ? Map.of() - : SecretMasker.mask(ev.getData()); + CollectionUtils.isEmpty(ev.getData()) + ? Map.of() + : SecretMasker.mask(ev.getData()); - - if (clean.isEmpty() || - (clean.size() == 1 && clean.containsKey("details"))) { - return; - } + if (clean.isEmpty() || (clean.size() == 1 && clean.containsKey("details"))) { + return; + } String rid = MDC.get("requestId"); - - + if (rid != null) { clean = new java.util.HashMap<>(clean); clean.put("requestId", rid); } String auditEventData = mapper.writeValueAsString(clean); - log.debug("AuditEvent data (JSON): {}",auditEventData); - - PersistentAuditEvent ent = PersistentAuditEvent.builder() - .principal(ev.getPrincipal()) - .type(ev.getType()) - .data(auditEventData) - .timestamp(ev.getTimestamp()) - .build(); + log.debug("AuditEvent data (JSON): {}", auditEventData); + + PersistentAuditEvent ent = + PersistentAuditEvent.builder() + .principal(ev.getPrincipal()) + .type(ev.getType()) + .data(auditEventData) + .timestamp(ev.getTimestamp()) + .build(); repo.save(ent); } catch (Exception e) { - e.printStackTrace(); // fail-open + e.printStackTrace(); // fail-open } } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/config/HttpRequestAuditPublisher.java b/proprietary/src/main/java/stirling/software/proprietary/config/HttpRequestAuditPublisher.java index e69de29bb..8b1378917 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/config/HttpRequestAuditPublisher.java +++ b/proprietary/src/main/java/stirling/software/proprietary/config/HttpRequestAuditPublisher.java @@ -0,0 +1 @@ + diff --git a/proprietary/src/main/java/stirling/software/proprietary/controller/AuditDashboardController.java b/proprietary/src/main/java/stirling/software/proprietary/controller/AuditDashboardController.java index c871dbfc0..67b71ccd8 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/controller/AuditDashboardController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/controller/AuditDashboardController.java @@ -33,8 +33,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.audit.AuditEventType; import stirling.software.proprietary.audit.AuditLevel; import stirling.software.proprietary.config.AuditConfigurationProperties; @@ -42,10 +44,7 @@ import stirling.software.proprietary.model.security.PersistentAuditEvent; import stirling.software.proprietary.repository.PersistentAuditEventRepository; import stirling.software.proprietary.security.config.EnterpriseEndpoint; -/** - * Controller for the audit dashboard. - * Admin-only access. - */ +/** Controller for the audit dashboard. Admin-only access. */ @Slf4j @Controller @RequestMapping("/audit") @@ -58,28 +57,24 @@ public class AuditDashboardController { private final AuditConfigurationProperties auditConfig; private final ObjectMapper objectMapper; - /** - * Display the audit dashboard. - */ + /** Display the audit dashboard. */ @GetMapping public String showDashboard(Model model) { model.addAttribute("auditEnabled", auditConfig.isEnabled()); model.addAttribute("auditLevel", auditConfig.getAuditLevel()); model.addAttribute("auditLevelInt", auditConfig.getLevel()); model.addAttribute("retentionDays", auditConfig.getRetentionDays()); - + // Add audit level enum values for display model.addAttribute("auditLevels", AuditLevel.values()); - + // Add audit event types for the dropdown model.addAttribute("auditEventTypes", AuditEventType.values()); - + return "audit/dashboard"; } - - /** - * Get audit events data for the dashboard tables. - */ + + /** Get audit events data for the dashboard tables. */ @GetMapping("/data") @ResponseBody public Map getAuditData( @@ -87,11 +82,13 @@ public class AuditDashboardController { @RequestParam(value = "size", defaultValue = "30") int size, @RequestParam(value = "type", required = false) String type, @RequestParam(value = "principal", required = false) String principal, - @RequestParam(value = "startDate", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, - @RequestParam(value = "endDate", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate, HttpServletRequest request) { - + @RequestParam(value = "startDate", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + LocalDate startDate, + @RequestParam(value = "endDate", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + LocalDate endDate, + HttpServletRequest request) { Pageable pageable = PageRequest.of(page, size, Sort.by("timestamp").descending()); Page events; @@ -102,7 +99,9 @@ public class AuditDashboardController { mode = "principal + type + startDate + endDate"; Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); - events = auditRepository.findByPrincipalAndTypeAndTimestampBetween(principal, type, start, end, pageable); + events = + auditRepository.findByPrincipalAndTypeAndTimestampBetween( + principal, type, start, end, pageable); } else if (type != null && principal != null) { mode = "principal + type"; events = auditRepository.findByPrincipalAndType(principal, type, pageable); @@ -115,7 +114,9 @@ public class AuditDashboardController { mode = "principal + startDate + endDate"; Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); - events = auditRepository.findByPrincipalAndTimestampBetween(principal, start, end, pageable); + events = + auditRepository.findByPrincipalAndTimestampBetween( + principal, start, end, pageable); } else if (startDate != null && endDate != null) { mode = "startDate + endDate"; Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); @@ -144,85 +145,93 @@ public class AuditDashboardController { return response; } - - /** - * Get statistics for charts. - */ + /** Get statistics for charts. */ @GetMapping("/stats") @ResponseBody public Map getAuditStats( @RequestParam(value = "days", defaultValue = "7") int days) { - + // Get events from the last X days Instant startDate = Instant.now().minus(java.time.Duration.ofDays(days)); List events = auditRepository.findByTimestampAfter(startDate); - + // Count events by type - Map eventsByType = events.stream() - .collect(Collectors.groupingBy(PersistentAuditEvent::getType, Collectors.counting())); - + Map eventsByType = + events.stream() + .collect( + Collectors.groupingBy( + PersistentAuditEvent::getType, Collectors.counting())); + // Count events by principal - Map eventsByPrincipal = events.stream() - .collect(Collectors.groupingBy(PersistentAuditEvent::getPrincipal, Collectors.counting())); - + Map eventsByPrincipal = + events.stream() + .collect( + Collectors.groupingBy( + PersistentAuditEvent::getPrincipal, Collectors.counting())); + // Count events by day - Map eventsByDay = events.stream() - .collect(Collectors.groupingBy( - e -> LocalDateTime.ofInstant(e.getTimestamp(), ZoneId.systemDefault()) - .format(DateTimeFormatter.ISO_LOCAL_DATE), - Collectors.counting())); - + Map eventsByDay = + events.stream() + .collect( + Collectors.groupingBy( + e -> + LocalDateTime.ofInstant( + e.getTimestamp(), + ZoneId.systemDefault()) + .format(DateTimeFormatter.ISO_LOCAL_DATE), + Collectors.counting())); + Map stats = new HashMap<>(); stats.put("eventsByType", eventsByType); stats.put("eventsByPrincipal", eventsByPrincipal); stats.put("eventsByDay", eventsByDay); stats.put("totalEvents", events.size()); - + return stats; } - - /** - * Get all unique event types from the database for filtering. - */ + + /** Get all unique event types from the database for filtering. */ @GetMapping("/types") @ResponseBody public List getAuditTypes() { // Get distinct event types from the database List dbTypes = auditRepository.findDistinctEventTypes(); - + // Include standard enum types in case they're not in the database yet - List enumTypes = Arrays.stream(AuditEventType.values()) - .map(AuditEventType::name) - .collect(Collectors.toList()); - + List enumTypes = + Arrays.stream(AuditEventType.values()) + .map(AuditEventType::name) + .collect(Collectors.toList()); + // Combine both sources, remove duplicates, and sort Set combinedTypes = new HashSet<>(); combinedTypes.addAll(dbTypes); combinedTypes.addAll(enumTypes); - + return combinedTypes.stream().sorted().collect(Collectors.toList()); } - - /** - * Export audit data as CSV. - */ + + /** Export audit data as CSV. */ @GetMapping("/export") public ResponseEntity exportAuditData( @RequestParam(value = "type", required = false) String type, @RequestParam(value = "principal", required = false) String principal, - @RequestParam(value = "startDate", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, - @RequestParam(value = "endDate", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { - + @RequestParam(value = "startDate", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + LocalDate startDate, + @RequestParam(value = "endDate", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + LocalDate endDate) { + // Get data with same filtering as getAuditData List events; - + if (type != null && principal != null && startDate != null && endDate != null) { Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); - events = auditRepository.findAllByPrincipalAndTypeAndTimestampBetweenForExport( - principal, type, start, end); + events = + auditRepository.findAllByPrincipalAndTypeAndTimestampBetweenForExport( + principal, type, start, end); } else if (type != null && principal != null) { events = auditRepository.findAllByPrincipalAndTypeForExport(principal, type); } else if (type != null && startDate != null && endDate != null) { @@ -232,7 +241,9 @@ public class AuditDashboardController { } else if (principal != null && startDate != null && endDate != null) { Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); - events = auditRepository.findAllByPrincipalAndTimestampBetweenForExport(principal, start, end); + events = + auditRepository.findAllByPrincipalAndTimestampBetweenForExport( + principal, start, end); } else if (startDate != null && endDate != null) { Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); @@ -244,13 +255,13 @@ public class AuditDashboardController { } else { events = auditRepository.findAll(); } - + // Convert to CSV StringBuilder csv = new StringBuilder(); csv.append("ID,Principal,Type,Timestamp,Data\n"); - + DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - + for (PersistentAuditEvent event : events) { csv.append(event.getId()).append(","); csv.append(escapeCSV(event.getPrincipal())).append(","); @@ -258,39 +269,38 @@ public class AuditDashboardController { csv.append(formatter.format(event.getTimestamp())).append(","); csv.append(escapeCSV(event.getData())).append("\n"); } - + byte[] csvBytes = csv.toString().getBytes(); - + // Set up HTTP headers for download HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDispositionFormData("attachment", "audit_export.csv"); - - return ResponseEntity.ok() - .headers(headers) - .body(csvBytes); + + return ResponseEntity.ok().headers(headers).body(csvBytes); } - - /** - * Export audit data as JSON. - */ + + /** Export audit data as JSON. */ @GetMapping("/export/json") public ResponseEntity exportAuditDataJson( @RequestParam(value = "type", required = false) String type, @RequestParam(value = "principal", required = false) String principal, - @RequestParam(value = "startDate", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, - @RequestParam(value = "endDate", required = false) - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { - + @RequestParam(value = "startDate", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + LocalDate startDate, + @RequestParam(value = "endDate", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + LocalDate endDate) { + // Get data with same filtering as getAuditData List events; - + if (type != null && principal != null && startDate != null && endDate != null) { Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); - events = auditRepository.findAllByPrincipalAndTypeAndTimestampBetweenForExport( - principal, type, start, end); + events = + auditRepository.findAllByPrincipalAndTypeAndTimestampBetweenForExport( + principal, type, start, end); } else if (type != null && principal != null) { events = auditRepository.findAllByPrincipalAndTypeForExport(principal, type); } else if (type != null && startDate != null && endDate != null) { @@ -300,7 +310,9 @@ public class AuditDashboardController { } else if (principal != null && startDate != null && endDate != null) { Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); - events = auditRepository.findAllByPrincipalAndTimestampBetweenForExport(principal, start, end); + events = + auditRepository.findAllByPrincipalAndTimestampBetweenForExport( + principal, start, end); } else if (startDate != null && endDate != null) { Instant start = startDate.atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant end = endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); @@ -312,28 +324,24 @@ public class AuditDashboardController { } else { events = auditRepository.findAll(); } - + // Convert to JSON try { byte[] jsonBytes = objectMapper.writeValueAsBytes(events); - + // Set up HTTP headers for download HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setContentDispositionFormData("attachment", "audit_export.json"); - - return ResponseEntity.ok() - .headers(headers) - .body(jsonBytes); + + return ResponseEntity.ok().headers(headers).body(jsonBytes); } catch (JsonProcessingException e) { log.error("Error serializing audit events to JSON", e); return ResponseEntity.internalServerError().build(); } } - - /** - * Helper method to escape CSV fields. - */ + + /** Helper method to escape CSV fields. */ private String escapeCSV(String field) { if (field == null) { return ""; @@ -341,4 +349,4 @@ public class AuditDashboardController { // Replace double quotes with two double quotes and wrap in quotes return "\"" + field.replace("\"", "\"\"") + "\""; } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/model/Team.java b/proprietary/src/main/java/stirling/software/proprietary/model/Team.java index 7d9533a16..5157b3233 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/model/Team.java +++ b/proprietary/src/main/java/stirling/software/proprietary/model/Team.java @@ -1,10 +1,13 @@ package stirling.software.proprietary.model; -import jakarta.persistence.*; import java.io.Serializable; import java.util.HashSet; import java.util.Set; + +import jakarta.persistence.*; + import lombok.*; + import stirling.software.proprietary.security.model.User; @Entity diff --git a/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java b/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java index 8fb520156..bec0eb21c 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java +++ b/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java @@ -1,23 +1,29 @@ package stirling.software.proprietary.model.security; -import jakarta.persistence.*; -import lombok.*; -import org.hibernate.annotations.Index; - import java.time.Instant; +import jakarta.persistence.*; + +import lombok.*; + @Entity @Table( - name = "audit_events", - indexes = { - @jakarta.persistence.Index(name = "idx_audit_timestamp", columnList = "timestamp"), - @jakarta.persistence.Index(name = "idx_audit_principal", columnList = "principal"), - @jakarta.persistence.Index(name = "idx_audit_type", columnList = "type"), - @jakarta.persistence.Index(name = "idx_audit_principal_type", columnList = "principal,type"), - @jakarta.persistence.Index(name = "idx_audit_type_timestamp", columnList = "type,timestamp") - } -) -@Data @Builder @NoArgsConstructor @AllArgsConstructor + name = "audit_events", + indexes = { + @jakarta.persistence.Index(name = "idx_audit_timestamp", columnList = "timestamp"), + @jakarta.persistence.Index(name = "idx_audit_principal", columnList = "principal"), + @jakarta.persistence.Index(name = "idx_audit_type", columnList = "type"), + @jakarta.persistence.Index( + name = "idx_audit_principal_type", + columnList = "principal,type"), + @jakarta.persistence.Index( + name = "idx_audit_type_timestamp", + columnList = "type,timestamp") + }) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor public class PersistentAuditEvent { @Id @@ -27,8 +33,7 @@ public class PersistentAuditEvent { private String principal; private String type; - @Lob - private String data; // JSON blob + @Lob private String data; // JSON blob private Instant timestamp; -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/repository/PersistentAuditEventRepository.java b/proprietary/src/main/java/stirling/software/proprietary/repository/PersistentAuditEventRepository.java index 60d1ee3ed..af6d7d554 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/repository/PersistentAuditEventRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/repository/PersistentAuditEventRepository.java @@ -15,58 +15,104 @@ import org.springframework.transaction.annotation.Transactional; import stirling.software.proprietary.model.security.PersistentAuditEvent; @Repository -public interface PersistentAuditEventRepository - extends JpaRepository { - +public interface PersistentAuditEventRepository extends JpaRepository { + // Basic queries - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%'))") - Page findByPrincipal(@Param("principal") String principal, Pageable pageable); + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%'))") + Page findByPrincipal( + @Param("principal") String principal, Pageable pageable); + Page findByType(String type, Pageable pageable); - Page findByTimestampBetween(Instant startDate, Instant endDate, Pageable pageable); - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type") - Page findByPrincipalAndType(@Param("principal") String principal, @Param("type") String type, Pageable pageable); - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.timestamp BETWEEN :startDate AND :endDate") - Page findByPrincipalAndTimestampBetween(@Param("principal") String principal, @Param("startDate") Instant startDate, @Param("endDate") Instant endDate, Pageable pageable); - Page findByTypeAndTimestampBetween(String type, Instant startDate, Instant endDate, Pageable pageable); - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type AND e.timestamp BETWEEN :startDate AND :endDate") - Page findByPrincipalAndTypeAndTimestampBetween(@Param("principal") String principal, @Param("type") String type, @Param("startDate") Instant startDate, @Param("endDate") Instant endDate, Pageable pageable); - + + Page findByTimestampBetween( + Instant startDate, Instant endDate, Pageable pageable); + + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type") + Page findByPrincipalAndType( + @Param("principal") String principal, @Param("type") String type, Pageable pageable); + + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.timestamp BETWEEN :startDate AND :endDate") + Page findByPrincipalAndTimestampBetween( + @Param("principal") String principal, + @Param("startDate") Instant startDate, + @Param("endDate") Instant endDate, + Pageable pageable); + + Page findByTypeAndTimestampBetween( + String type, Instant startDate, Instant endDate, Pageable pageable); + + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type AND e.timestamp BETWEEN :startDate AND :endDate") + Page findByPrincipalAndTypeAndTimestampBetween( + @Param("principal") String principal, + @Param("type") String type, + @Param("startDate") Instant startDate, + @Param("endDate") Instant endDate, + Pageable pageable); + // Non-paged versions for export - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%'))") + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%'))") List findAllByPrincipalForExport(@Param("principal") String principal); + @Query("SELECT e FROM PersistentAuditEvent e WHERE e.type = :type") List findByTypeForExport(@Param("type") String type); + @Query("SELECT e FROM PersistentAuditEvent e WHERE e.timestamp BETWEEN :startDate AND :endDate") - List findAllByTimestampBetweenForExport(@Param("startDate") Instant startDate, @Param("endDate") Instant endDate); + List findAllByTimestampBetweenForExport( + @Param("startDate") Instant startDate, @Param("endDate") Instant endDate); + @Query("SELECT e FROM PersistentAuditEvent e WHERE e.timestamp > :startDate") List findByTimestampAfter(@Param("startDate") Instant startDate); - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type") - List findAllByPrincipalAndTypeForExport(@Param("principal") String principal, @Param("type") String type); - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.timestamp BETWEEN :startDate AND :endDate") - List findAllByPrincipalAndTimestampBetweenForExport(@Param("principal") String principal, @Param("startDate") Instant startDate, @Param("endDate") Instant endDate); - @Query("SELECT e FROM PersistentAuditEvent e WHERE e.type = :type AND e.timestamp BETWEEN :startDate AND :endDate") - List findAllByTypeAndTimestampBetweenForExport(@Param("type") String type, @Param("startDate") Instant startDate, @Param("endDate") Instant endDate); - @Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type AND e.timestamp BETWEEN :startDate AND :endDate") - List findAllByPrincipalAndTypeAndTimestampBetweenForExport(@Param("principal") String principal, @Param("type") String type, @Param("startDate") Instant startDate, @Param("endDate") Instant endDate); - + + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type") + List findAllByPrincipalAndTypeForExport( + @Param("principal") String principal, @Param("type") String type); + + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.timestamp BETWEEN :startDate AND :endDate") + List findAllByPrincipalAndTimestampBetweenForExport( + @Param("principal") String principal, + @Param("startDate") Instant startDate, + @Param("endDate") Instant endDate); + + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE e.type = :type AND e.timestamp BETWEEN :startDate AND :endDate") + List findAllByTypeAndTimestampBetweenForExport( + @Param("type") String type, + @Param("startDate") Instant startDate, + @Param("endDate") Instant endDate); + + @Query( + "SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type AND e.timestamp BETWEEN :startDate AND :endDate") + List findAllByPrincipalAndTypeAndTimestampBetweenForExport( + @Param("principal") String principal, + @Param("type") String type, + @Param("startDate") Instant startDate, + @Param("endDate") Instant endDate); + // Cleanup queries @Query("DELETE FROM PersistentAuditEvent e WHERE e.timestamp < ?1") @Modifying @Transactional int deleteByTimestampBefore(Instant cutoffDate); - + // Find IDs for batch deletion - using JPQL with setMaxResults instead of native query @Query("SELECT e.id FROM PersistentAuditEvent e WHERE e.timestamp < ?1 ORDER BY e.id") List findIdsForBatchDeletion(Instant cutoffDate, Pageable pageable); - + // Stats queries @Query("SELECT e.type, COUNT(e) FROM PersistentAuditEvent e GROUP BY e.type") List countByType(); - + @Query("SELECT e.principal, COUNT(e) FROM PersistentAuditEvent e GROUP BY e.principal") List countByPrincipal(); - + // Get distinct event types for filtering @Query("SELECT DISTINCT e.type FROM PersistentAuditEvent e ORDER BY e.type") List findDistinctEventTypes(); -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java index 3be32c367..4141155a1 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationFailureHandler.java @@ -1,13 +1,8 @@ package stirling.software.proprietary.security; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.InternalAuthenticationServiceException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java index 24e0a6bbf..d5180c321 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/CustomAuthenticationSuccessHandler.java @@ -1,7 +1,6 @@ package stirling.software.proprietary.security; + import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; @@ -11,11 +10,9 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; -import java.io.IOException; + import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; -import org.springframework.security.web.savedrequest.SavedRequest; + import stirling.software.common.util.RequestUriUtils; import stirling.software.proprietary.audit.AuditEventType; import stirling.software.proprietary.audit.AuditLevel; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java index 8aa47a7fa..033ea913c 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/CustomLogoutSuccessHandler.java @@ -1,22 +1,27 @@ package stirling.software.proprietary.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.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.List; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.core.io.Resource; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; + +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.common.configuration.AppConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java b/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java index 306ffab2f..4b09fe0e9 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/InitialSecuritySetup.java @@ -1,13 +1,17 @@ package stirling.software.proprietary.security; -import jakarta.annotation.PostConstruct; import java.sql.SQLException; import java.util.List; import java.util.Optional; import java.util.UUID; + +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.enumeration.Role; import stirling.software.common.model.exception.UnsupportedProviderException; @@ -62,9 +66,10 @@ public class InitialSecuritySetup { } userService.saveAll(usersWithoutTeam); // batch save - if(usersWithoutTeam != null && !usersWithoutTeam.isEmpty()) { - log.info( - "Assigned {} user(s) without a team to the default team.", usersWithoutTeam.size()); + if (usersWithoutTeam != null && !usersWithoutTeam.isEmpty()) { + log.info( + "Assigned {} user(s) without a team to the default team.", + usersWithoutTeam.size()); } } diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java b/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java index 4faeb9041..25b3c5096 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/RateLimitResetScheduler.java @@ -1,8 +1,10 @@ package stirling.software.proprietary.security; -import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + import stirling.software.proprietary.security.filter.IPRateLimitingFilter; @Component diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/config/AccountWebController.java b/proprietary/src/main/java/stirling/software/proprietary/security/config/AccountWebController.java index 9ea537e23..0d846fc3d 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/config/AccountWebController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/config/AccountWebController.java @@ -2,10 +2,6 @@ package stirling.software.proprietary.security.config; import static stirling.software.common.util.ProviderUtils.validateProvider; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletRequest; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Date; @@ -14,7 +10,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; @@ -23,6 +19,16 @@ import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.servlet.http.HttpServletRequest; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpoint.java b/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpoint.java index 800867017..26c56d4a8 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpoint.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpoint.java @@ -8,4 +8,4 @@ import java.lang.annotation.Target; /** Annotation to mark endpoints that require an Enterprise license. */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) -public @interface EnterpriseEndpoint {} \ No newline at end of file +public @interface EnterpriseEndpoint {} diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpointAspect.java b/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpointAspect.java index b0189f2bd..8c390a93e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpointAspect.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/config/EnterpriseEndpointAspect.java @@ -27,4 +27,4 @@ public class EnterpriseEndpointAspect { } return joinPoint.proceed(); } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java index cc8f40556..e6afa6e40 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/DatabaseConfig.java @@ -1,8 +1,7 @@ package stirling.software.proprietary.security.configuration; import javax.sql.DataSource; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -12,6 +11,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java index 43bb83511..c9b6e9d77 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java @@ -1,13 +1,16 @@ package stirling.software.proprietary.security.configuration; import java.util.Properties; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSenderImpl; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; /** diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java index c75ba4f4e..ab809a037 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java @@ -1,7 +1,7 @@ package stirling.software.proprietary.security.configuration; 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; @@ -27,6 +27,9 @@ 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.servlet.util.matcher.PathPatternRequestMatcher; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.AppConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.CustomAuthenticationFailureHandler; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/EEAppConfig.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/EEAppConfig.java index 7fd375dd8..215b82347 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/EEAppConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/EEAppConfig.java @@ -8,6 +8,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.EnterpriseEdition; import stirling.software.common.model.ApplicationProperties.Premium; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/KeygenLicenseVerifier.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/KeygenLicenseVerifier.java index f4d0bae69..969385a33 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/KeygenLicenseVerifier.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/KeygenLicenseVerifier.java @@ -1,20 +1,24 @@ package stirling.software.proprietary.security.configuration.ee; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.posthog.java.shaded.org.json.JSONException; -import com.posthog.java.shaded.org.json.JSONObject; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.Base64; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; import org.bouncycastle.crypto.signers.Ed25519Signer; import org.bouncycastle.util.encoders.Hex; import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.posthog.java.shaded.org.json.JSONException; +import com.posthog.java.shaded.org.json.JSONObject; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.util.GeneralUtils; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/LicenseKeyChecker.java b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/LicenseKeyChecker.java index 14a69d991..15baef7db 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/LicenseKeyChecker.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/configuration/ee/LicenseKeyChecker.java @@ -4,9 +4,12 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import lombok.extern.slf4j.Slf4j; + import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.util.GeneralUtils; import stirling.software.proprietary.security.configuration.ee.KeygenLicenseVerifier.License; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java index 6bc4a091c..dec64c46f 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/DatabaseController.java @@ -1,17 +1,12 @@ package stirling.software.proprietary.security.controller.api; -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.eclipse.jetty.http.HttpStatus; import org.springframework.context.annotation.Conditional; import org.springframework.core.io.InputStreamResource; @@ -23,6 +18,15 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.security.database.H2SQLCondition; import stirling.software.proprietary.security.service.DatabaseService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/EmailController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/EmailController.java index d691a89a2..7fb767573 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/EmailController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/EmailController.java @@ -1,11 +1,5 @@ package stirling.software.proprietary.security.controller.api; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.mail.MessagingException; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -14,6 +8,16 @@ import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.mail.MessagingException; +import jakarta.validation.Valid; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.security.model.api.Email; import stirling.software.proprietary.security.service.EmailService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/TeamController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/TeamController.java index 57b9c7a17..fa8588e7b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/TeamController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/TeamController.java @@ -1,14 +1,19 @@ package stirling.software.proprietary.security.controller.api; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.transaction.Transactional; import java.util.Optional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.view.RedirectView; + +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.transaction.Transactional; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.model.Team; import stirling.software.proprietary.security.config.PremiumEndpoint; import stirling.software.proprietary.security.database.repository.UserRepository; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java index d2ce0d774..4401403c6 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java @@ -1,17 +1,12 @@ package stirling.software.proprietary.security.controller.api; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.transaction.Transactional; import java.io.IOException; import java.security.Principal; import java.sql.SQLException; import java.util.List; import java.util.Map; import java.util.Optional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -25,6 +20,16 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.view.RedirectView; + +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.transaction.Transactional; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.enumeration.Role; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java index 0915c704c..940c0c13f 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java @@ -1,14 +1,19 @@ package stirling.software.proprietary.security.controller.web; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletRequest; import java.util.List; -import lombok.RequiredArgsConstructor; + import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; + +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.servlet.http.HttpServletRequest; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.model.FileInfo; import stirling.software.proprietary.security.service.DatabaseService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java b/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java index 9e5b8bb84..2dd9b3478 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java @@ -1,18 +1,22 @@ package stirling.software.proprietary.security.controller.web; -import jakarta.servlet.http.HttpServletRequest; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; + +import jakarta.servlet.http.HttpServletRequest; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.model.Team; import stirling.software.proprietary.model.dto.TeamWithUserCountDTO; import stirling.software.proprietary.security.database.repository.SessionRepository; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java index 835dc1917..6821414aa 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/ScheduledTasks.java @@ -1,10 +1,13 @@ package stirling.software.proprietary.security.database; import java.sql.SQLException; -import lombok.RequiredArgsConstructor; + import org.springframework.context.annotation.Conditional; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.model.exception.UnsupportedProviderException; import stirling.software.proprietary.security.service.DatabaseServiceInterface; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java index 32018ca98..e8d74ec01 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/AuthorityRepository.java @@ -1,8 +1,10 @@ package stirling.software.proprietary.security.database.repository; import java.util.Set; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; + import stirling.software.proprietary.security.model.Authority; @Repository diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java index f849454db..ec7a0078b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImpl.java @@ -1,9 +1,11 @@ package stirling.software.proprietary.security.database.repository; import java.util.Date; + import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import org.springframework.transaction.annotation.Transactional; + import stirling.software.proprietary.security.model.PersistentLogin; public class JPATokenRepositoryImpl implements PersistentTokenRepository { diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java index a9ddf8a37..2ab956676 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/PersistentLoginRepository.java @@ -2,6 +2,7 @@ package stirling.software.proprietary.security.database.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; + import stirling.software.proprietary.security.model.PersistentLogin; @Repository diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java index f764c7753..3eb1ad90b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/SessionRepository.java @@ -1,13 +1,16 @@ package stirling.software.proprietary.security.database.repository; -import jakarta.transaction.Transactional; import java.util.Date; import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; + +import jakarta.transaction.Transactional; + import stirling.software.proprietary.security.model.SessionEntity; @Repository diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java index 4f4f2e98c..4d74dbfd8 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/database/repository/UserRepository.java @@ -2,10 +2,12 @@ package stirling.software.proprietary.security.database.repository; import java.util.List; import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; + import stirling.software.proprietary.model.Team; import stirling.software.proprietary.security.model.User; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/EnterpriseEndpointFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/EnterpriseEndpointFilter.java index 91a62d646..5ee61f8ff 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/EnterpriseEndpointFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/EnterpriseEndpointFilter.java @@ -1,14 +1,16 @@ package stirling.software.proprietary.security.filter; +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +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 java.io.IOException; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; @Component public class EnterpriseEndpointFilter extends OncePerRequestFilter { diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java index a96e6e769..3bae72195 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/FirstLoginFilter.java @@ -1,20 +1,24 @@ package stirling.software.proprietary.security.filter; +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.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; 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 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 stirling.software.common.util.RequestUriUtils; import stirling.software.proprietary.security.model.User; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java index ebc0f949e..028768c08 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/IPRateLimitingFilter.java @@ -1,15 +1,18 @@ package stirling.software.proprietary.security.filter; +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + 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.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; + import lombok.RequiredArgsConstructor; + import stirling.software.common.util.RequestUriUtils; @RequiredArgsConstructor diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java index de97ec785..e9addd239 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserAuthenticationFilter.java @@ -1,13 +1,9 @@ package stirling.software.proprietary.security.filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpStatus; @@ -20,6 +16,14 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Component; 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.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.SAML2; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java index 31db979b0..4d1d7bbed 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/filter/UserBasedRateLimitingFilter.java @@ -1,17 +1,10 @@ package stirling.software.proprietary.security.filter; -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.time.Duration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; @@ -20,6 +13,17 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; + +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.common.model.enumeration.Role; @Component diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/ApiKeyAuthenticationToken.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/ApiKeyAuthenticationToken.java index adc0a52c0..1db14aaaf 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/ApiKeyAuthenticationToken.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/ApiKeyAuthenticationToken.java @@ -1,6 +1,7 @@ package stirling.software.proprietary.security.model; import java.util.Collection; + import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/Authority.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/Authority.java index 9f998e070..382d3a71e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/Authority.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/Authority.java @@ -1,5 +1,7 @@ package stirling.software.proprietary.security.model; +import java.io.Serializable; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -8,7 +10,7 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import java.io.Serializable; + import lombok.Getter; import lombok.Setter; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/PersistentLogin.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/PersistentLogin.java index aed62a749..ef096f7fb 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/PersistentLogin.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/PersistentLogin.java @@ -1,10 +1,12 @@ package stirling.software.proprietary.security.model; +import java.util.Date; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; -import java.util.Date; + import lombok.Data; @Entity diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/SessionEntity.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/SessionEntity.java index c39b2e674..db94eae6f 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/SessionEntity.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/SessionEntity.java @@ -1,10 +1,12 @@ package stirling.software.proprietary.security.model; +import java.io.Serializable; +import java.util.Date; + import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; -import java.io.Serializable; -import java.util.Date; + import lombok.Data; @Entity diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java index 200b0fb3b..d3e232f61 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/User.java @@ -1,17 +1,20 @@ package stirling.software.proprietary.security.model; -import jakarta.persistence.*; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; + +import jakarta.persistence.*; + import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; + import stirling.software.common.model.enumeration.Role; import stirling.software.proprietary.model.Team; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java index c8ca3891f..4e9421aba 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/Email.java @@ -1,10 +1,13 @@ package stirling.software.proprietary.security.model.api; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + import stirling.software.common.model.api.GeneralFile; @Data diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserDetails.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserDetails.java index 1335f5243..3f630f61d 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserDetails.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserDetails.java @@ -1,6 +1,7 @@ package stirling.software.proprietary.security.model.api.user; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserUsername.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserUsername.java index b3895cfd8..d158e6b32 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserUsername.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UpdateUserUsername.java @@ -1,6 +1,7 @@ package stirling.software.proprietary.security.model.api.user; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/Username.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/Username.java index 4d65d226c..c5fd081f6 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/Username.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/Username.java @@ -1,6 +1,7 @@ package stirling.software.proprietary.security.model.api.user; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UsernameAndPass.java b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UsernameAndPass.java index a3d870159..0a21cba87 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UsernameAndPass.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/model/api/user/UsernameAndPass.java @@ -1,6 +1,7 @@ package stirling.software.proprietary.security.model.api.user; import io.swagger.v3.oas.annotations.media.Schema; + import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java index 92b053b8a..7175a5b5d 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationFailureHandler.java @@ -1,10 +1,7 @@ package stirling.software.proprietary.security.oauth2; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.LockedException; @@ -13,6 +10,12 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; 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 public class CustomOAuth2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java index 1c4d04e55..71bd42a85 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java @@ -1,18 +1,22 @@ package stirling.software.proprietary.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.sql.SQLException; -import lombok.RequiredArgsConstructor; + import org.springframework.security.authentication.LockedException; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; 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.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java index 13c90d7af..6516cc7d7 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/oauth2/OAuth2Configuration.java @@ -9,7 +9,7 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; -import lombok.extern.slf4j.Slf4j; + import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -23,6 +23,9 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio import org.springframework.security.oauth2.client.registration.ClientRegistrations; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2.Client; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/repository/TeamRepository.java b/proprietary/src/main/java/stirling/software/proprietary/security/repository/TeamRepository.java index c3571b447..ccf72be0a 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/repository/TeamRepository.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/repository/TeamRepository.java @@ -2,9 +2,11 @@ package stirling.software.proprietary.security.repository; import java.util.List; import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; + import stirling.software.proprietary.model.Team; import stirling.software.proprietary.model.dto.TeamWithUserCountDTO; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java index c2957e241..fff03fd4f 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CertificateUtils.java @@ -6,6 +6,7 @@ import java.nio.charset.StandardCharsets; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; + import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java index 055ac8f4e..a39a39092 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticatedPrincipal.java @@ -3,6 +3,7 @@ package stirling.software.proprietary.security.saml2; import java.io.Serializable; import java.util.List; import java.util.Map; + import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java index a7e663aac..7bf0c3a3b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationFailureHandler.java @@ -1,9 +1,7 @@ package stirling.software.proprietary.security.saml2; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import lombok.extern.slf4j.Slf4j; + import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.authentication.ProviderNotFoundException; import org.springframework.security.core.AuthenticationException; @@ -11,6 +9,11 @@ import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + @Slf4j @ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true") public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java index 47391e4d0..2170a9632 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2AuthenticationSuccessHandler.java @@ -1,17 +1,21 @@ package stirling.software.proprietary.security.saml2; +import java.io.IOException; +import java.sql.SQLException; + +import org.springframework.security.authentication.LockedException; +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.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; -import java.io.IOException; -import java.sql.SQLException; + import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.authentication.LockedException; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; -import org.springframework.security.web.savedrequest.SavedRequest; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.SAML2; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java index d1c24b420..e8326c1e3 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/CustomSaml2ResponseAuthenticationConverter.java @@ -5,8 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.opensaml.core.xml.XMLObject; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.Attribute; @@ -17,6 +16,10 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.security.model.User; import stirling.software.proprietary.security.service.UserService; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java index 8482b8753..7fd4768b3 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/saml2/SAML2Configuration.java @@ -1,11 +1,9 @@ package stirling.software.proprietary.security.saml2; -import jakarta.servlet.http.HttpServletRequest; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.UUID; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.opensaml.saml.saml2.core.AuthnRequest; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -20,6 +18,12 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; + +import jakarta.servlet.http.HttpServletRequest; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.SAML2; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java index 5687a3b92..19e300585 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/AppUpdateAuthService.java @@ -1,10 +1,13 @@ package stirling.software.proprietary.security.service; import java.util.Optional; -import lombok.RequiredArgsConstructor; + import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.configuration.interfaces.ShowAdminInterface; import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.database.repository.UserRepository; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java index b889a06e5..0b286e894 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomOAuth2UserService.java @@ -1,7 +1,7 @@ package stirling.software.proprietary.security.service; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; + import org.springframework.security.authentication.LockedException; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; @@ -10,6 +10,9 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.security.oauth2.core.oidc.user.OidcUser; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties.Security.OAUTH2; import stirling.software.common.model.enumeration.UsernameAttribute; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java index 014666971..6ece48a4e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/CustomUserDetailsService.java @@ -2,7 +2,7 @@ package stirling.software.proprietary.security.service; import java.util.Collection; import java.util.Set; -import lombok.RequiredArgsConstructor; + import org.springframework.security.authentication.LockedException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -10,6 +10,9 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + import stirling.software.proprietary.security.database.repository.UserRepository; import stirling.software.proprietary.security.model.Authority; import stirling.software.proprietary.security.model.User; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java index 00967f821..6474ae7ea 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseService.java @@ -18,11 +18,15 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; + import javax.sql.DataSource; -import lombok.extern.slf4j.Slf4j; + import org.springframework.jdbc.datasource.init.CannotReadScriptException; import org.springframework.jdbc.datasource.init.ScriptException; import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.FileInfo; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseServiceInterface.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseServiceInterface.java index 17035094e..613432f0a 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseServiceInterface.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/DatabaseServiceInterface.java @@ -2,6 +2,7 @@ package stirling.software.proprietary.security.service; import java.sql.SQLException; import java.util.List; + import stirling.software.common.model.FileInfo; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java index 79506c25a..08860a340 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java @@ -1,14 +1,17 @@ package stirling.software.proprietary.security.service; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeMessage; -import lombok.RequiredArgsConstructor; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; + +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; + +import lombok.RequiredArgsConstructor; + import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.model.api.Email; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java index 852fc8ab9..ecc04bac5 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/LoginAttemptService.java @@ -1,11 +1,15 @@ package stirling.software.proprietary.security.service; -import jakarta.annotation.PostConstruct; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; + +import org.springframework.stereotype.Service; + +import jakarta.annotation.PostConstruct; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; + import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.model.AttemptCounter; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/TeamService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/TeamService.java index 102301924..194a2a967 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/TeamService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/TeamService.java @@ -1,7 +1,9 @@ package stirling.software.proprietary.security.service; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + import stirling.software.proprietary.model.Team; import stirling.software.proprietary.security.repository.TeamRepository; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java b/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java index d365cf58a..50c8027f6 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/service/UserService.java @@ -9,8 +9,7 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.function.Supplier; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -25,6 +24,10 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.enumeration.Role; import stirling.software.common.model.exception.UnsupportedProviderException; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java index a0487381f..b69dfaefb 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/CustomHttpSessionListener.java @@ -1,9 +1,11 @@ package stirling.software.proprietary.security.session; +import org.springframework.stereotype.Component; + import jakarta.servlet.http.HttpSessionEvent; import jakarta.servlet.http.HttpSessionListener; + import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; @Component @Slf4j diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java index 5d482e94d..8931866ad 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionPersistentRegistry.java @@ -1,6 +1,5 @@ package stirling.software.proprietary.security.session; -import jakarta.transaction.Transactional; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -8,13 +7,18 @@ import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Optional; -import lombok.RequiredArgsConstructor; + import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Component; + +import jakarta.transaction.Transactional; + +import lombok.RequiredArgsConstructor; + import stirling.software.proprietary.security.database.repository.SessionRepository; import stirling.software.proprietary.security.model.SessionEntity; import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal; diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java index 7cb5c21fd..eccd7332e 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionRegistryConfig.java @@ -3,6 +3,7 @@ package stirling.software.proprietary.security.session; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.session.SessionRegistryImpl; + import stirling.software.proprietary.security.database.repository.SessionRepository; @Configuration diff --git a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java index 83403f9f7..1f491bf4d 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java +++ b/proprietary/src/main/java/stirling/software/proprietary/security/session/SessionScheduled.java @@ -4,11 +4,13 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.List; -import lombok.RequiredArgsConstructor; + import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.core.session.SessionInformation; import org.springframework.stereotype.Component; +import lombok.RequiredArgsConstructor; + @Component @RequiredArgsConstructor public class SessionScheduled { diff --git a/proprietary/src/main/java/stirling/software/proprietary/service/AuditCleanupService.java b/proprietary/src/main/java/stirling/software/proprietary/service/AuditCleanupService.java index 442deecb1..8a70a1b7a 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/service/AuditCleanupService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/service/AuditCleanupService.java @@ -13,12 +13,11 @@ import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.config.AuditConfigurationProperties; import stirling.software.proprietary.repository.PersistentAuditEventRepository; -/** - * Service to periodically clean up old audit events based on retention policy. - */ +/** Service to periodically clean up old audit events based on retention policy. */ @Slf4j @Service @RequiredArgsConstructor @@ -26,87 +25,85 @@ public class AuditCleanupService { private final PersistentAuditEventRepository auditRepository; private final AuditConfigurationProperties auditConfig; - + // Default batch size for deletions private static final int BATCH_SIZE = 10000; - + /** - * Scheduled task that runs daily to clean up old audit events. - * The retention period is configurable in settings.yml. + * Scheduled task that runs daily to clean up old audit events. The retention period is + * configurable in settings.yml. */ @Scheduled(fixedDelay = 1, initialDelay = 1, timeUnit = TimeUnit.DAYS) public void cleanupOldAuditEvents() { if (!auditConfig.isEnabled()) { return; } - + int retentionDays = auditConfig.getRetentionDays(); if (retentionDays <= 0) { return; } - + log.info("Starting audit cleanup for events older than {} days", retentionDays); - + try { Instant cutoffDate = Instant.now().minus(retentionDays, ChronoUnit.DAYS); int totalDeleted = batchDeleteEvents(cutoffDate); - log.info("Successfully cleaned up {} audit events older than {}", totalDeleted, cutoffDate); + log.info( + "Successfully cleaned up {} audit events older than {}", + totalDeleted, + cutoffDate); } catch (Exception e) { log.error("Error cleaning up old audit events", e); } } - + /** - * Performs batch deletion of events to prevent long-running transactions - * and potential database locks. + * Performs batch deletion of events to prevent long-running transactions and potential database + * locks. */ private int batchDeleteEvents(Instant cutoffDate) { int totalDeleted = 0; boolean hasMore = true; - + while (hasMore) { // Start a new transaction for each batch List batchIds = findBatchOfIdsToDelete(cutoffDate); - + if (batchIds.isEmpty()) { hasMore = false; } else { int deleted = deleteBatch(batchIds); totalDeleted += deleted; - + // If we got fewer records than the batch size, we're done if (batchIds.size() < BATCH_SIZE) { hasMore = false; } } } - + return totalDeleted; } - - /** - * Finds a batch of IDs to delete. - */ + + /** Finds a batch of IDs to delete. */ @Transactional(readOnly = true) private List findBatchOfIdsToDelete(Instant cutoffDate) { PageRequest pageRequest = PageRequest.of(0, BATCH_SIZE, Sort.by("id")); return auditRepository.findIdsForBatchDeletion(cutoffDate, pageRequest); } - - /** - * Deletes a batch of events by ID. - * Each batch is in its own transaction. - */ + + /** Deletes a batch of events by ID. Each batch is in its own transaction. */ @Transactional private int deleteBatch(List batchIds) { if (batchIds.isEmpty()) { return 0; } - + int batchSize = batchIds.size(); auditRepository.deleteAllByIdInBatch(batchIds); log.debug("Deleted batch of {} audit events", batchSize); - + return batchSize; } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java b/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java index 218969ffa..73b57286b 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java +++ b/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java @@ -1,21 +1,22 @@ package stirling.software.proprietary.service; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; +import java.util.Map; + import org.springframework.boot.actuate.audit.AuditEvent; import org.springframework.boot.actuate.audit.AuditEventRepository; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + import stirling.software.proprietary.audit.AuditEventType; import stirling.software.proprietary.audit.AuditLevel; import stirling.software.proprietary.config.AuditConfigurationProperties; -import java.util.Map; - /** - * Service for creating manual audit events throughout the application. - * This provides easy access to audit functionality in any component. + * Service for creating manual audit events throughout the application. This provides easy access to + * audit functionality in any component. */ @Slf4j @Service @@ -24,18 +25,20 @@ public class AuditService { private final AuditEventRepository repository; private final AuditConfigurationProperties auditConfig; private final boolean runningEE; - - public AuditService(AuditEventRepository repository, - AuditConfigurationProperties auditConfig, - @org.springframework.beans.factory.annotation.Qualifier("runningEE") boolean runningEE) { + + public AuditService( + AuditEventRepository repository, + AuditConfigurationProperties auditConfig, + @org.springframework.beans.factory.annotation.Qualifier("runningEE") + boolean runningEE) { this.repository = repository; this.auditConfig = auditConfig; this.runningEE = runningEE; } /** - * Record an audit event for the current authenticated user with a specific audit level - * using the standardized AuditEventType enum + * Record an audit event for the current authenticated user with a specific audit level using + * the standardized AuditEventType enum * * @param type The event type from AuditEventType enum * @param data Additional event data (will be automatically sanitized) @@ -43,17 +46,19 @@ public class AuditService { */ public void audit(AuditEventType type, Map data, AuditLevel level) { // Skip auditing if this level is not enabled or if not Enterprise edition - if (!auditConfig.isEnabled() || !auditConfig.getAuditLevel().includes(level) || !runningEE) { + if (!auditConfig.isEnabled() + || !auditConfig.getAuditLevel().includes(level) + || !runningEE) { return; } - + String principal = getCurrentUsername(); repository.add(new AuditEvent(principal, type.name(), data)); } /** - * Record an audit event for the current authenticated user with standard level - * using the standardized AuditEventType enum + * Record an audit event for the current authenticated user with standard level using the + * standardized AuditEventType enum * * @param type The event type from AuditEventType enum * @param data Additional event data (will be automatically sanitized) @@ -64,26 +69,27 @@ public class AuditService { } /** - * Record an audit event for a specific user with a specific audit level - * using the standardized AuditEventType enum + * Record an audit event for a specific user with a specific audit level using the standardized + * AuditEventType enum * * @param principal The username or system identifier * @param type The event type from AuditEventType enum * @param data Additional event data (will be automatically sanitized) * @param level The minimum audit level required for this event to be logged */ - public void audit(String principal, AuditEventType type, Map data, AuditLevel level) { + public void audit( + String principal, AuditEventType type, Map data, AuditLevel level) { // Skip auditing if this level is not enabled or if not Enterprise edition if (!auditConfig.isLevelEnabled(level) || !runningEE) { return; } - + repository.add(new AuditEvent(principal, type.name(), data)); } /** - * Record an audit event for a specific user with standard level - * using the standardized AuditEventType enum + * Record an audit event for a specific user with standard level using the standardized + * AuditEventType enum * * @param principal The username or system identifier * @param type The event type from AuditEventType enum @@ -95,8 +101,8 @@ public class AuditService { } /** - * Record an audit event for the current authenticated user with a specific audit level - * using a string-based event type (for backward compatibility) + * Record an audit event for the current authenticated user with a specific audit level using a + * string-based event type (for backward compatibility) * * @param type The event type (e.g., "FILE_UPLOAD", "PASSWORD_CHANGE") * @param data Additional event data (will be automatically sanitized) @@ -107,14 +113,14 @@ public class AuditService { if (!auditConfig.isLevelEnabled(level) || !runningEE) { return; } - + String principal = getCurrentUsername(); repository.add(new AuditEvent(principal, type, data)); } /** - * Record an audit event for the current authenticated user with standard level - * using a string-based event type (for backward compatibility) + * Record an audit event for the current authenticated user with standard level using a + * string-based event type (for backward compatibility) * * @param type The event type (e.g., "FILE_UPLOAD", "PASSWORD_CHANGE") * @param data Additional event data (will be automatically sanitized) @@ -125,8 +131,8 @@ public class AuditService { } /** - * Record an audit event for a specific user with a specific audit level - * using a string-based event type (for backward compatibility) + * Record an audit event for a specific user with a specific audit level using a string-based + * event type (for backward compatibility) * * @param principal The username or system identifier * @param type The event type (e.g., "FILE_UPLOAD", "PASSWORD_CHANGE") @@ -138,13 +144,13 @@ public class AuditService { if (!auditConfig.isLevelEnabled(level) || !runningEE) { return; } - + repository.add(new AuditEvent(principal, type, data)); } /** - * Record an audit event for a specific user with standard level - * using a string-based event type (for backward compatibility) + * Record an audit event for a specific user with standard level using a string-based event type + * (for backward compatibility) * * @param principal The username or system identifier * @param type The event type (e.g., "FILE_UPLOAD", "PASSWORD_CHANGE") @@ -155,11 +161,9 @@ public class AuditService { audit(principal, type, data, AuditLevel.STANDARD); } - /** - * Get the current authenticated username or "system" if none - */ + /** Get the current authenticated username or "system" if none */ private String getCurrentUsername() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); return (auth != null && auth.getName() != null) ? auth.getName() : "system"; } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/util/SecretMasker.java b/proprietary/src/main/java/stirling/software/proprietary/util/SecretMasker.java index 82a0f7a52..ee48323e5 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/util/SecretMasker.java +++ b/proprietary/src/main/java/stirling/software/proprietary/util/SecretMasker.java @@ -1,15 +1,10 @@ package stirling.software.proprietary.util; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import java.util.stream.Collectors; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; - import lombok.extern.slf4j.Slf4j; /** Redacts any map values whose keys match common secret/token patterns. */ @@ -17,45 +12,40 @@ import lombok.extern.slf4j.Slf4j; public final class SecretMasker { private static final Pattern SENSITIVE = - Pattern.compile("(?i)(password|token|secret|api[_-]?key|authorization|auth|jwt|cred|cert)"); + Pattern.compile( + "(?i)(password|token|secret|api[_-]?key|authorization|auth|jwt|cred|cert)"); private SecretMasker() {} - public static Map mask(Map in) { + public static Map mask(Map in) { if (in == null) return null; return in.entrySet().stream() - .filter(e -> e.getValue() != null) - .collect(Collectors.toMap( - Map.Entry::getKey, - e -> deepMaskValue(e.getKey(), e.getValue()) - )); + .filter(e -> e.getValue() != null) + .collect( + Collectors.toMap( + Map.Entry::getKey, e -> deepMaskValue(e.getKey(), e.getValue()))); } private static Object deepMask(Object value) { - if (value instanceof Map m) { + if (value instanceof Map m) { return m.entrySet().stream() - .filter(e -> e.getValue() != null) - .collect(Collectors.toMap( - Map.Entry::getKey, - e -> deepMaskValue((String)e.getKey(), e.getValue()) - )); + .filter(e -> e.getValue() != null) + .collect( + Collectors.toMap( + Map.Entry::getKey, + e -> deepMaskValue((String) e.getKey(), e.getValue()))); } else if (value instanceof List list) { - return list.stream() - .map(SecretMasker::deepMask).toList(); + return list.stream().map(SecretMasker::deepMask).toList(); } else { return value; } } - private static Object deepMaskValue(String key, Object value) { if (key != null && SENSITIVE.matcher(key).find()) { return "***REDACTED***"; } return deepMask(value); } - - - -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/web/AuditWebFilter.java b/proprietary/src/main/java/stirling/software/proprietary/web/AuditWebFilter.java index a7dd6ea66..b6f5b47f3 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/web/AuditWebFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/web/AuditWebFilter.java @@ -1,11 +1,8 @@ package stirling.software.proprietary.web; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.io.IOException; +import java.util.Map; + import org.slf4j.MDC; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; @@ -13,18 +10,16 @@ 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 org.springframework.web.util.ContentCachingRequestWrapper; -import org.springframework.web.util.ContentCachingResponseWrapper; -import java.io.IOException; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; -/** - * Filter that stores additional request information for audit purposes - */ +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** Filter that stores additional request information for audit purposes */ @Slf4j @Component @Order(Ordered.HIGHEST_PRECEDENCE + 10) @@ -37,10 +32,10 @@ public class AuditWebFilter extends OncePerRequestFilter { private static final String CONTENT_TYPE_HEADER = "Content-Type"; @Override - protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + // Store key request info in MDC for logging and later audit use try { // Store request headers @@ -48,42 +43,43 @@ public class AuditWebFilter extends OncePerRequestFilter { if (userAgent != null) { MDC.put("userAgent", userAgent); } - + String referer = request.getHeader(REFERER_HEADER); if (referer != null) { MDC.put("referer", referer); } - + String acceptLanguage = request.getHeader(ACCEPT_LANGUAGE_HEADER); if (acceptLanguage != null) { MDC.put("acceptLanguage", acceptLanguage); } - + String contentType = request.getHeader(CONTENT_TYPE_HEADER); if (contentType != null) { MDC.put("contentType", contentType); } - + // Store authenticated user roles if available Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getAuthorities() != null) { - String roles = auth.getAuthorities().stream() - .map(a -> a.getAuthority()) - .reduce((a, b) -> a + "," + b) - .orElse(""); + String roles = + auth.getAuthorities().stream() + .map(a -> a.getAuthority()) + .reduce((a, b) -> a + "," + b) + .orElse(""); MDC.put("userRoles", roles); } - + // Store query parameters (without values for privacy) Map parameterMap = request.getParameterMap(); if (parameterMap != null && !parameterMap.isEmpty()) { String params = String.join(",", parameterMap.keySet()); MDC.put("queryParams", params); } - + // Continue with the filter chain filterChain.doFilter(request, response); - + } finally { // Clear MDC after request is processed MDC.remove("userAgent"); @@ -94,4 +90,4 @@ public class AuditWebFilter extends OncePerRequestFilter { MDC.remove("queryParams"); } } -} \ No newline at end of file +} diff --git a/proprietary/src/main/java/stirling/software/proprietary/web/CorrelationIdFilter.java b/proprietary/src/main/java/stirling/software/proprietary/web/CorrelationIdFilter.java index 6357990a0..a60a531e3 100644 --- a/proprietary/src/main/java/stirling/software/proprietary/web/CorrelationIdFilter.java +++ b/proprietary/src/main/java/stirling/software/proprietary/web/CorrelationIdFilter.java @@ -1,33 +1,33 @@ package stirling.software.proprietary.web; -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 lombok.extern.slf4j.Slf4j; +import java.io.IOException; +import java.util.UUID; + import org.slf4j.MDC; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; -import java.io.IOException; -import java.util.UUID; +import io.github.pixee.security.Newlines; -/** - * Guarantees every request carries a stable X-Request-Id; propagates to MDC. - */ +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + +/** Guarantees every request carries a stable X-Request-Id; propagates to MDC. */ @Slf4j @Component public class CorrelationIdFilter extends OncePerRequestFilter { - public static final String HEADER = "X-Request-Id"; - public static final String MDC_KEY = "requestId"; + public static final String HEADER = "X-Request-Id"; + public static final String MDC_KEY = "requestId"; @Override - protected void doFilterInternal(HttpServletRequest req, - HttpServletResponse res, - FilterChain chain) + protected void doFilterInternal( + HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException { try { diff --git a/proprietary/src/main/resources/static/js/audit/dashboard.js b/proprietary/src/main/resources/static/js/audit/dashboard.js index 3d013fa2e..5cc670908 100644 --- a/proprietary/src/main/resources/static/js/audit/dashboard.js +++ b/proprietary/src/main/resources/static/js/audit/dashboard.js @@ -44,12 +44,12 @@ function setupThemeChangeListener() { // Observe the document element for theme changes observer.observe(document.documentElement, { attributes: true }); - + // Also observe body for class changes observer.observe(document.body, { attributes: true }); } -document.addEventListener('DOMContentLoaded', function() { +document.addEventListener('DOMContentLoaded', function() { // Initialize DOM references auditTableBody = document.getElementById('auditTableBody'); pageSizeSelect = document.getElementById('pageSizeSelect'); @@ -60,25 +60,25 @@ document.addEventListener('DOMContentLoaded', function() { endDateFilterInput = document.getElementById('endDateFilter'); applyFiltersButton = document.getElementById('applyFilters'); resetFiltersButton = document.getElementById('resetFilters'); - + // Load event types for dropdowns loadEventTypes(); - + // Show a loading message immediately if (auditTableBody) { - auditTableBody.innerHTML = + auditTableBody.innerHTML = '

' + window.i18n.loading + ''; } - + // Make a direct API call first to avoid validation issues loadAuditData(0, pageSize); - + // Load statistics for dashboard loadStats(7); - + // Setup theme change listener setupThemeChangeListener(); - + // Set up event listeners pageSizeSelect.addEventListener('change', function() { pageSize = parseInt(this.value); @@ -87,7 +87,7 @@ document.addEventListener('DOMContentLoaded', function() { window.requestedPage = 0; loadAuditData(0, pageSize); }); - + applyFiltersButton.addEventListener('click', function() { typeFilter = typeFilterInput.value.trim(); principalFilter = principalFilterInput.value.trim(); @@ -97,31 +97,31 @@ document.addEventListener('DOMContentLoaded', function() { window.requestedPage = 0; loadAuditData(0, pageSize); }); - + resetFiltersButton.addEventListener('click', function() { // Reset input fields typeFilterInput.value = ''; principalFilterInput.value = ''; startDateFilterInput.value = ''; endDateFilterInput.value = ''; - + // Reset filter variables typeFilter = ''; principalFilter = ''; startDateFilter = ''; endDateFilter = ''; - + // Reset page currentPage = 0; window.requestedPage = 0; - + // Update UI document.getElementById('currentPage').textContent = '1'; // Load data with reset filters loadAuditData(0, pageSize); }); - + // Reset export filters button document.getElementById('resetExportFilters').addEventListener('click', function() { exportTypeFilter.value = ''; @@ -129,43 +129,43 @@ document.addEventListener('DOMContentLoaded', function() { exportStartDateFilter.value = ''; exportEndDateFilter.value = ''; }); - + // Make radio buttons behave like toggle buttons const radioLabels = document.querySelectorAll('label.btn-outline-primary'); radioLabels.forEach(label => { const radio = label.querySelector('input[type="radio"]'); - + if (radio) { // Highlight the checked radio button's label if (radio.checked) { label.classList.add('active'); } - + // Handle clicking on the label label.addEventListener('click', function() { // Remove active class from all labels radioLabels.forEach(l => l.classList.remove('active')); - + // Add active class to this label this.classList.add('active'); - + // Check this radio button radio.checked = true; }); } }); - + // Handle export button exportButton.onclick = function(e) { e.preventDefault(); - + // Get selected format with fallback const selectedRadio = document.querySelector('input[name="exportFormat"]:checked'); const exportFormat = selectedRadio ? selectedRadio.value : 'csv'; exportAuditData(exportFormat); return false; }; - + // Set up pagination buttons document.getElementById('page-first').onclick = function() { if (currentPage > 0) { @@ -173,28 +173,28 @@ document.addEventListener('DOMContentLoaded', function() { } return false; }; - + document.getElementById('page-prev').onclick = function() { if (currentPage > 0) { goToPage(currentPage - 1); } return false; }; - + document.getElementById('page-next').onclick = function() { if (currentPage < totalPages - 1) { goToPage(currentPage + 1); } return false; }; - + document.getElementById('page-last').onclick = function() { if (totalPages > 0 && currentPage < totalPages - 1) { goToPage(totalPages - 1); } return false; }; - + // Set up tab change events const tabEls = document.querySelectorAll('button[data-bs-toggle="tab"]'); tabEls.forEach(tabEl => { @@ -214,41 +214,41 @@ document.addEventListener('DOMContentLoaded', function() { function loadAuditData(targetPage, realPageSize) { const requestedPage = targetPage !== undefined ? targetPage : window.requestedPage || 0; realPageSize = realPageSize || pageSize; - + showLoading('table-loading'); - + // Always request page 0 from server, but with increased page size if needed let url = `/audit/data?page=${requestedPage}&size=${realPageSize}`; - + if (typeFilter) url += `&type=${encodeURIComponent(typeFilter)}`; if (principalFilter) url += `&principal=${encodeURIComponent(principalFilter)}`; if (startDateFilter) url += `&startDate=${startDateFilter}`; if (endDateFilter) url += `&endDate=${endDateFilter}`; - + // Update page indicator if (document.getElementById('page-indicator')) { document.getElementById('page-indicator').textContent = `Page ${requestedPage + 1} of ?`; } - + fetch(url) .then(response => { return response.json(); }) .then(data => { - - + + // Calculate the correct slice of data to show for the requested page let displayContent = data.content; - + // Render the correct slice of data renderTable(displayContent); - + // Calculate total pages based on the actual total elements const calculatedTotalPages = Math.ceil(data.totalElements / realPageSize); totalPages = calculatedTotalPages; currentPage = requestedPage; // Use our tracked page, not server's - - + + // Update UI document.getElementById('currentPage').textContent = currentPage + 1; document.getElementById('totalPages').textContent = totalPages; @@ -256,41 +256,41 @@ function loadAuditData(targetPage, realPageSize) { if (document.getElementById('page-indicator')) { document.getElementById('page-indicator').textContent = `Page ${currentPage + 1} of ${totalPages}`; } - + // Re-enable buttons with correct state document.getElementById('page-first').disabled = currentPage === 0; document.getElementById('page-prev').disabled = currentPage === 0; document.getElementById('page-next').disabled = currentPage >= totalPages - 1; document.getElementById('page-last').disabled = currentPage >= totalPages - 1; - + hideLoading('table-loading'); - + // Restore original page size for next operations if (window.originalPageSize && realPageSize !== window.originalPageSize) { pageSize = window.originalPageSize; - + } - + // Store original page size for recovery window.originalPageSize = realPageSize; - + // Clear busy flag window.paginationBusy = false; - + }) .catch(error => { - + if (auditTableBody) { auditTableBody.innerHTML = `${window.i18n.errorLoading} ${error.message}`; } hideLoading('table-loading'); - + // Re-enable buttons document.getElementById('page-first').disabled = false; document.getElementById('page-prev').disabled = false; document.getElementById('page-next').disabled = false; document.getElementById('page-last').disabled = false; - + // Clear busy flag window.paginationBusy = false; }); @@ -301,7 +301,7 @@ function loadStats(days) { showLoading('type-chart-loading'); showLoading('user-chart-loading'); showLoading('time-chart-loading'); - + fetch(`/audit/stats?days=${days}`) .then(response => response.json()) .then(data => { @@ -327,29 +327,29 @@ function exportAuditData(format) { const principal = exportPrincipalFilter.value.trim(); const startDate = exportStartDateFilter.value; const endDate = exportEndDateFilter.value; - + let url = format === 'json' ? '/audit/export/json?' : '/audit/export?'; - + if (type) url += `&type=${encodeURIComponent(type)}`; if (principal) url += `&principal=${encodeURIComponent(principal)}`; if (startDate) url += `&startDate=${startDate}`; if (endDate) url += `&endDate=${endDate}`; - + // Trigger download window.location.href = url; } // Render table with audit data function renderTable(events) { - + if (!events || events.length === 0) { auditTableBody.innerHTML = '' + window.i18n.noEventsFound + ''; return; } - + try { auditTableBody.innerHTML = ''; - + events.forEach((event, index) => { try { const row = document.createElement('tr'); @@ -360,10 +360,10 @@ function renderTable(events) { ${escapeHtml(event.type || 'N/A')} `; - + // Store event data for modal row.dataset.event = JSON.stringify(event); - + // Add click handler for details button const detailsButton = row.querySelector('.view-details'); if (detailsButton) { @@ -371,13 +371,13 @@ function renderTable(events) { showEventDetails(event); }); } - + auditTableBody.appendChild(row); } catch (rowError) { - + } }); - + } catch (e) { auditTableBody.innerHTML = '' + window.i18n.errorRendering + ' ' + e.message + ''; } @@ -392,13 +392,13 @@ function showEventDetails(event) { const modalTimestamp = document.getElementById('modal-timestamp'); const modalData = document.getElementById('modal-data'); const eventDetailsModal = document.getElementById('eventDetailsModal'); - + // Set modal content if (modalId) modalId.textContent = event.id; if (modalPrincipal) modalPrincipal.textContent = event.principal; if (modalType) modalType.textContent = event.type; if (modalTimestamp) modalTimestamp.textContent = formatDate(event.timestamp); - + // Format JSON data if (modalData) { try { @@ -408,7 +408,7 @@ function showEventDetails(event) { modalData.textContent = event.data || 'No data available'; } } - + // Show the modal if (eventDetailsModal) { const modal = new bootstrap.Modal(eventDetailsModal); @@ -420,32 +420,32 @@ function showEventDetails(event) { // Direct pagination approach - server seems to be hard-limited to returning 20 items function goToPage(page) { - + // Basic validation - totalPages may not be initialized on first load if (page < 0) { return; } - + // Skip validation against totalPages on first load if (totalPages > 0 && page >= totalPages) { return; } - + // Simple guard flag if (window.paginationBusy) { return; } window.paginationBusy = true; - + try { // Store the requested page for later window.requestedPage = page; currentPage = page; - + // Update UI immediately for user feedback document.getElementById('currentPage').textContent = page + 1; - + // Load data with this page loadAuditData(page, pageSize); } catch (e) { @@ -457,27 +457,27 @@ function goToPage(page) { function renderCharts(data) { // Get theme colors const colors = getThemeColors(); - + // Prepare data for charts const typeLabels = Object.keys(data.eventsByType); const typeValues = Object.values(data.eventsByType); - + const userLabels = Object.keys(data.eventsByPrincipal); const userValues = Object.values(data.eventsByPrincipal); - + // Sort days for time chart const timeLabels = Object.keys(data.eventsByDay).sort(); const timeValues = timeLabels.map(day => data.eventsByDay[day] || 0); - + // Chart.js global defaults for dark mode compatibility Chart.defaults.color = colors.text; Chart.defaults.borderColor = colors.grid; - + // Type chart if (typeChart) { typeChart.destroy(); } - + const typeCtx = document.getElementById('typeChart').getContext('2d'); typeChart = new Chart(typeCtx, { type: 'bar', @@ -600,12 +600,12 @@ function renderCharts(data) { } } }); - + // User chart if (userChart) { userChart.destroy(); } - + const userCtx = document.getElementById('userChart').getContext('2d'); userChart = new Chart(userCtx, { type: 'pie', @@ -640,7 +640,7 @@ function renderCharts(data) { generateLabels: function(chart) { const original = Chart.overrides.pie.plugins.legend.labels.generateLabels; const labels = original.call(this, chart); - + if (colors.isDarkMode) { labels.forEach(label => { // Enhance contrast for dark mode @@ -649,7 +649,7 @@ function renderCharts(data) { label.lineWidth = 2; // Thicker border }); } - + return labels; } } @@ -673,14 +673,14 @@ function renderCharts(data) { } } }); - + // Time chart if (timeChart) { timeChart.destroy(); } - + const timeCtx = document.getElementById('timeChart').getContext('2d'); - + // Get first color for line chart with appropriate transparency let bgColor, borderColor; if (colors.isDarkMode) { @@ -690,7 +690,7 @@ function renderCharts(data) { bgColor = 'rgba(0, 96, 170, 0.2)'; // Dark blue with transparency borderColor = 'rgb(0, 96, 170)'; // Dark blue solid } - + timeChart = new Chart(timeCtx, { type: 'line', data: { @@ -841,20 +841,20 @@ function loadEventTypes() { if (!types || types.length === 0) { return; } - + // Populate the type filter dropdowns const typeFilter = document.getElementById('typeFilter'); const exportTypeFilter = document.getElementById('exportTypeFilter'); - + // Clear existing options except the first one (All event types) while (typeFilter.options.length > 1) { typeFilter.remove(1); } - + while (exportTypeFilter.options.length > 1) { exportTypeFilter.remove(1); } - + // Add new options types.forEach(type => { // Main filter dropdown @@ -862,7 +862,7 @@ function loadEventTypes() { option.value = type; option.textContent = type; typeFilter.appendChild(option); - + // Export filter dropdown const exportOption = document.createElement('option'); exportOption.value = type; @@ -878,17 +878,17 @@ function loadEventTypes() { // Get theme colors for charts function getThemeColors() { const isDarkMode = document.documentElement.getAttribute('data-bs-theme') === 'dark'; - + // In dark mode, use higher contrast colors for text - const textColor = isDarkMode ? + const textColor = isDarkMode ? 'rgb(255, 255, 255)' : // White for dark mode for maximum contrast getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-on-surface').trim(); - + // Use a more visible grid color in dark mode const gridColor = isDarkMode ? 'rgba(255, 255, 255, 0.2)' : // Semi-transparent white for dark mode getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-outline-variant').trim(); - + // Define bright, high-contrast colors for both dark and light modes const chartColorsDark = [ 'rgb(162, 201, 255)', // Light blue - primary @@ -902,7 +902,7 @@ function getThemeColors() { 'rgb(212, 172, 25)', // Yellow - image 'rgb(245, 84, 84)', // Red - advance ]; - + const chartColorsLight = [ 'rgb(0, 96, 170)', // Blue - primary 'rgb(88, 90, 138)', // Purple - tertiary @@ -915,7 +915,7 @@ function getThemeColors() { 'rgb(212, 172, 25)', // Yellow - image 'rgb(245, 84, 84)', // Red - advance ]; - + return { text: textColor, grid: gridColor, @@ -935,7 +935,7 @@ function getChartColors(count, opacity = 0.6) { for (let i = 0; i < count; i++) { // Get the raw color and add opacity let color = themeColors.chartColors[i % themeColors.chartColors.length]; - // If it's rgb() format, convert to rgba() + // If it's rgb() format, convert to rgba() if (color.startsWith('rgb(')) { color = color.replace('rgb(', '').replace(')', ''); result.push(`rgba(${color}, ${opacity})`); @@ -949,7 +949,7 @@ function getChartColors(count, opacity = 0.6) { } catch (e) { console.warn('Error using theme colors, falling back to default colors', e); } - + // Base colors - a larger palette than the default const colors = [ [54, 162, 235], // blue @@ -973,9 +973,9 @@ function getChartColors(count, opacity = 0.6) { [41, 128, 185], // belize hole [142, 68, 173] // wisteria ]; - + const result = []; - + // Always use the same format regardless of color source if (count > colors.length) { // Generate colors algorithmically for large sets @@ -984,7 +984,7 @@ function getChartColors(count, opacity = 0.6) { const hue = (i * 360 / count) % 360; const sat = 70 + Math.random() * 10; // 70-80% const light = 50 + Math.random() * 10; // 50-60% - + result.push(`hsla(${hue}, ${sat}%, ${light}%, ${opacity})`); } } else { @@ -994,6 +994,6 @@ function getChartColors(count, opacity = 0.6) { result.push(`rgba(${color[0]}, ${color[1]}, ${color[2]}, ${opacity})`); } } - + return result; -} \ No newline at end of file +} diff --git a/stirling-pdf/build.gradle b/stirling-pdf/build.gradle index c7a85dad4..a97d04808 100644 --- a/stirling-pdf/build.gradle +++ b/stirling-pdf/build.gradle @@ -15,7 +15,13 @@ configurations { spotless { java { target sourceSets.main.allJava - googleJavaFormat(googleJavaFormatVersion).aosp() + googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false) + + importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling") + toggleOffOn() + trimTrailingWhitespace() + leadingTabsToSpaces() + endWithNewline() } } diff --git a/stirling-pdf/src/main/java/stirling/software/SPDF/SPDFApplication.java b/stirling-pdf/src/main/java/stirling/software/SPDF/SPDFApplication.java index 27bef32e4..2131b4239 100644 --- a/stirling-pdf/src/main/java/stirling/software/SPDF/SPDFApplication.java +++ b/stirling-pdf/src/main/java/stirling/software/SPDF/SPDFApplication.java @@ -219,7 +219,7 @@ public class SPDFApplication { log.info("Additional features in jar"); return new String[] {"security"}; } else { - log.info("Without additional features in jar"); + log.info("Without additional features in jar"); return new String[] {"default"}; } } diff --git a/stirling-pdf/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java b/stirling-pdf/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java index 05057b609..eb9f2be33 100644 --- a/stirling-pdf/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java +++ b/stirling-pdf/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java @@ -13,11 +13,23 @@ import jakarta.servlet.http.HttpServletResponse; public class CleanUrlInterceptor implements HandlerInterceptor { - private static final List ALLOWED_PARAMS = Arrays.asList( - "lang", "endpoint", "endpoints", "logout", "error", "errorOAuth", "file", "messageType", "infoMessage", - "page", "size", "type", "principal", "startDate", "endDate" - ); - + private static final List ALLOWED_PARAMS = + Arrays.asList( + "lang", + "endpoint", + "endpoints", + "logout", + "error", + "errorOAuth", + "file", + "messageType", + "infoMessage", + "page", + "size", + "type", + "principal", + "startDate", + "endDate"); @Override public boolean preHandle(