style: improve formatting and import order consistency across codebase (#3761)

# Description of Changes

This pull request applies consistent formatting and import ordering
across the codebase. Specifically:

- Reordered imports according to the configured Spotless `importOrder()`
directive.
- Enabled formatting flags such as `trimTrailingWhitespace`,
`leadingTabsToSpaces`, and `endWithNewline`.
- Resolved inconsistencies in blank lines and spacing between imports
and annotations.
- Applied consistent formatting to annotations and method declarations.
- Removed unused or redundant import statements.

This change improves code readability, enforces a consistent style, and
prepares the codebase for future automated formatting checks.

---

## Checklist

### General

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

### Documentation

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

### UI Changes (if applicable)

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

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Ludy 2025-06-18 18:00:26 +02:00 committed by GitHub
parent a208d55525
commit 8632ccb870
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
136 changed files with 1328 additions and 954 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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;
/**

View File

@ -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

View File

@ -2,6 +2,7 @@ package stirling.software.common.configuration;
import java.io.File;
import java.nio.file.Paths;
import lombok.extern.slf4j.Slf4j;
@Slf4j

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -1,6 +1,7 @@
package stirling.software.common.model;
import java.util.Calendar;
import lombok.Builder;
import lombok.Data;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -2,6 +2,7 @@ package stirling.software.common.model.enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
/**

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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<byte[]> boasToWebResponse(

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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 {

View File

@ -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
@ -44,10 +44,12 @@ public class AuditAspect {
}
// Only create the map once we know we'll use it
Map<String, Object> auditData = AuditUtils.createBaseAuditData(joinPoint, auditedAnnotation.level());
Map<String, Object> 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();
@ -57,9 +59,10 @@ public class AuditAspect {
}
// 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);
@ -76,9 +79,10 @@ public class AuditAspect {
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
@ -95,10 +99,12 @@ public class AuditAspect {
// 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;
@ -109,13 +115,13 @@ public class AuditAspect {
path = req.getRequestURI();
}
AuditEventType eventType = AuditUtils.resolveEventType(
AuditEventType eventType =
AuditUtils.resolveEventType(
method,
joinPoint.getTarget().getClass(),
path,
httpMethod,
auditedAnnotation
);
auditedAnnotation);
// Check if we should use string type instead
String typeString = auditedAnnotation.typeString();

View File

@ -1,8 +1,6 @@
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"),
@ -35,8 +33,8 @@ public enum AuditEventType {
}
/**
* 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
@ -51,8 +49,8 @@ public enum AuditEventType {
} 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;
}
}

View File

@ -1,42 +1,29 @@
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);
@ -52,6 +39,7 @@ public enum AuditLevel {
/**
* 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
*/
@ -61,6 +49,7 @@ public enum AuditLevel {
/**
* Get an AuditLevel from an integer value
*
* @param level The integer level (0-3)
* @return The corresponding AuditLevel
*/

View File

@ -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,7 +41,8 @@ public class AuditUtils {
* @param auditLevel The current audit level
* @return A map with standard audit data
*/
public static Map<String, Object> createBaseAuditData(ProceedingJoinPoint joinPoint, AuditLevel auditLevel) {
public static Map<String, Object> createBaseAuditData(
ProceedingJoinPoint joinPoint, AuditLevel auditLevel) {
Map<String, Object> data = new HashMap<>();
// Common data for all levels
@ -56,7 +59,9 @@ public class AuditUtils {
// 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;
@ -70,7 +75,8 @@ public class AuditUtils {
* @param path The request path
* @param auditLevel The current audit level
*/
public static void addHttpData(Map<String, Object> data, String httpMethod, String path, AuditLevel auditLevel) {
public static void addHttpData(
Map<String, Object> data, String httpMethod, String path, AuditLevel auditLevel) {
if (httpMethod == null || path == null) {
return; // Skip if we don't have basic HTTP info
}
@ -80,7 +86,8 @@ public class AuditUtils {
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
}
@ -93,17 +100,20 @@ public class AuditUtils {
// 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<String, String[]> params = new HashMap<>(req.getParameterMap());
// Remove CSRF token from logged parameters
@ -124,21 +134,27 @@ public class AuditUtils {
* @param joinPoint The AspectJ join point
* @param auditLevel The current audit level
*/
public static void addFileData(Map<String, Object> data, ProceedingJoinPoint joinPoint, AuditLevel auditLevel) {
public static void addFileData(
Map<String, Object> data, ProceedingJoinPoint joinPoint, AuditLevel auditLevel) {
if (auditLevel.includes(AuditLevel.STANDARD)) {
List<MultipartFile> files = Arrays.stream(joinPoint.getArgs())
List<MultipartFile> files =
Arrays.stream(joinPoint.getArgs())
.filter(a -> a instanceof MultipartFile)
.map(a -> (MultipartFile)a)
.map(a -> (MultipartFile) a)
.collect(Collectors.toList());
if (!files.isEmpty()) {
List<Map<String,Object>> fileInfos = files.stream().map(f -> {
Map<String,Object> m = new HashMap<>();
List<Map<String, Object>> fileInfos =
files.stream()
.map(
f -> {
Map<String, Object> m = new HashMap<>();
m.put("name", f.getOriginalFilename());
m.put("size", f.getSize());
m.put("type", f.getContentType());
return m;
}).collect(Collectors.toList());
})
.collect(Collectors.toList());
data.put("files", fileInfos);
}
@ -152,14 +168,16 @@ public class AuditUtils {
* @param joinPoint The AspectJ join point
* @param auditLevel The current audit level
*/
public static void addMethodArguments(Map<String, Object> data, ProceedingJoinPoint joinPoint, AuditLevel auditLevel) {
public static void addMethodArguments(
Map<String, Object> 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 -> {
.forEach(
i -> {
if (vals[i] != null) {
// Convert objects to safe string representation
data.put("arg_" + names[i], safeToString(vals[i], 500));
@ -224,9 +242,8 @@ public class AuditUtils {
// 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);
@ -241,7 +258,12 @@ 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<String, Object> data, long startTime, HttpServletResponse response, AuditLevel level, boolean isHttpRequest) {
public static void addTimingData(
Map<String, Object> 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
@ -270,7 +292,12 @@ 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();
@ -283,12 +310,18 @@ public class AuditUtils {
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;
}
@ -306,7 +339,8 @@ 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
@ -326,7 +360,8 @@ 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) {
@ -339,12 +374,18 @@ public class AuditUtils {
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 {
@ -358,7 +399,8 @@ public class AuditUtils {
* @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;
}
@ -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(
return request != null
&& !RequestUriUtils.isTrackableResource(
request.getContextPath(), request.getRequestURI());
}
}

View File

@ -8,60 +8,50 @@ import java.lang.annotation.Target;
/**
* Annotation for methods that should be audited.
*
* Usage:
* <p>Usage:
*
* <pre>
* {@code
* <pre>{@code
* @Audited(type = AuditEventType.USER_REGISTRATION, level = AuditLevel.BASIC)
* public void registerUser(String username) {
* // Method implementation
* }
* }
* </pre>
* }</pre>
*
* For backward compatibility, string-based event types are still supported:
*
* <pre>
* {@code
* <pre>{@code
* @Audited(typeString = "CUSTOM_EVENT_TYPE", level = AuditLevel.BASIC)
* public void customOperation() {
* // Method implementation
* }
* }
* </pre>
* }</pre>
*/
@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.
* 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.
* <p>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.
* 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.
* <p>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;
}

View File

@ -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,52 +41,44 @@ 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();
@ -115,7 +108,8 @@ 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;
@ -161,18 +155,19 @@ public class ControllerAuditAspect {
}
// Resolve the event type using the unified method
AuditEventType eventType = AuditUtils.resolveEventType(
AuditEventType eventType =
AuditUtils.resolveEventType(
method,
joinPoint.getTarget().getClass(),
path,
httpMethod,
auditedAnnotation
);
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;
}
@ -191,7 +186,8 @@ 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) {
Annotation ann =
switch (httpMethod) {
case "GET" -> method.getAnnotation(GetMapping.class);
case "POST" -> method.getAnnotation(PostMapping.class);
case "PUT" -> method.getAnnotation(PutMapping.class);

View File

@ -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,16 +10,13 @@ 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

View File

@ -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
@ -36,12 +37,16 @@ public class AuditConfigurationProperties {
// 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() {
@ -50,6 +55,7 @@ public class AuditConfigurationProperties {
/**
* 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
*/
@ -59,6 +65,7 @@ public class AuditConfigurationProperties {
/**
* Get the effective retention period in days
*
* @return The number of days to retain audit records, or -1 for infinite retention
*/
public int getEffectiveRetentionDays() {

View File

@ -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")

View File

@ -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
@ -44,23 +46,21 @@ public class CustomAuditEventRepository implements AuditEventRepository {
? Map.of()
: SecretMasker.mask(ev.getData());
if (clean.isEmpty() ||
(clean.size() == 1 && clean.containsKey("details"))) {
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);
log.debug("AuditEvent data (JSON): {}", auditEventData);
PersistentAuditEvent ent = PersistentAuditEvent.builder()
PersistentAuditEvent ent =
PersistentAuditEvent.builder()
.principal(ev.getPrincipal())
.type(ev.getType())
.data(auditEventData)

View File

@ -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,9 +57,7 @@ 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());
@ -77,9 +74,7 @@ public class AuditDashboardController {
return "audit/dashboard";
}
/**
* Get audit events data for the dashboard tables.
*/
/** Get audit events data for the dashboard tables. */
@GetMapping("/data")
@ResponseBody
public Map<String, Object> getAuditData(
@ -88,10 +83,12 @@ public class AuditDashboardController {
@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,
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate startDate,
@RequestParam(value = "endDate", required = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate, HttpServletRequest request) {
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate endDate,
HttpServletRequest request) {
Pageable pageable = PageRequest.of(page, size, Sort.by("timestamp").descending());
Page<PersistentAuditEvent> 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,10 +145,7 @@ public class AuditDashboardController {
return response;
}
/**
* Get statistics for charts.
*/
/** Get statistics for charts. */
@GetMapping("/stats")
@ResponseBody
public Map<String, Object> getAuditStats(
@ -158,17 +156,28 @@ public class AuditDashboardController {
List<PersistentAuditEvent> events = auditRepository.findByTimestampAfter(startDate);
// Count events by type
Map<String, Long> eventsByType = events.stream()
.collect(Collectors.groupingBy(PersistentAuditEvent::getType, Collectors.counting()));
Map<String, Long> eventsByType =
events.stream()
.collect(
Collectors.groupingBy(
PersistentAuditEvent::getType, Collectors.counting()));
// Count events by principal
Map<String, Long> eventsByPrincipal = events.stream()
.collect(Collectors.groupingBy(PersistentAuditEvent::getPrincipal, Collectors.counting()));
Map<String, Long> eventsByPrincipal =
events.stream()
.collect(
Collectors.groupingBy(
PersistentAuditEvent::getPrincipal, Collectors.counting()));
// Count events by day
Map<String, Long> eventsByDay = events.stream()
.collect(Collectors.groupingBy(
e -> LocalDateTime.ofInstant(e.getTimestamp(), ZoneId.systemDefault())
Map<String, Long> eventsByDay =
events.stream()
.collect(
Collectors.groupingBy(
e ->
LocalDateTime.ofInstant(
e.getTimestamp(),
ZoneId.systemDefault())
.format(DateTimeFormatter.ISO_LOCAL_DATE),
Collectors.counting()));
@ -181,9 +190,7 @@ public class AuditDashboardController {
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<String> getAuditTypes() {
@ -191,7 +198,8 @@ public class AuditDashboardController {
List<String> dbTypes = auditRepository.findDistinctEventTypes();
// Include standard enum types in case they're not in the database yet
List<String> enumTypes = Arrays.stream(AuditEventType.values())
List<String> enumTypes =
Arrays.stream(AuditEventType.values())
.map(AuditEventType::name)
.collect(Collectors.toList());
@ -203,17 +211,17 @@ public class AuditDashboardController {
return combinedTypes.stream().sorted().collect(Collectors.toList());
}
/**
* Export audit data as CSV.
*/
/** Export audit data as CSV. */
@GetMapping("/export")
public ResponseEntity<byte[]> 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,
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate startDate,
@RequestParam(value = "endDate", required = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate endDate) {
// Get data with same filtering as getAuditData
List<PersistentAuditEvent> events;
@ -221,7 +229,8 @@ public class AuditDashboardController {
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(
events =
auditRepository.findAllByPrincipalAndTypeAndTimestampBetweenForExport(
principal, type, start, end);
} else if (type != null && principal != null) {
events = auditRepository.findAllByPrincipalAndTypeForExport(principal, type);
@ -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();
@ -266,22 +277,20 @@ public class AuditDashboardController {
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<byte[]> 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,
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate startDate,
@RequestParam(value = "endDate", required = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate endDate) {
// Get data with same filtering as getAuditData
List<PersistentAuditEvent> events;
@ -289,7 +298,8 @@ public class AuditDashboardController {
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(
events =
auditRepository.findAllByPrincipalAndTypeAndTimestampBetweenForExport(
principal, type, start, end);
} else if (type != null && principal != null) {
events = auditRepository.findAllByPrincipalAndTypeForExport(principal, type);
@ -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();
@ -322,18 +334,14 @@ public class AuditDashboardController {
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 "";

View File

@ -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

View File

@ -1,11 +1,11 @@
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",
@ -13,11 +13,17 @@ import java.time.Instant;
@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
@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;
}

View File

@ -15,39 +15,85 @@ import org.springframework.transaction.annotation.Transactional;
import stirling.software.proprietary.model.security.PersistentAuditEvent;
@Repository
public interface PersistentAuditEventRepository
extends JpaRepository<PersistentAuditEvent, Long> {
public interface PersistentAuditEventRepository extends JpaRepository<PersistentAuditEvent, Long> {
// Basic queries
@Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%'))")
Page<PersistentAuditEvent> findByPrincipal(@Param("principal") String principal, Pageable pageable);
@Query(
"SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%'))")
Page<PersistentAuditEvent> findByPrincipal(
@Param("principal") String principal, Pageable pageable);
Page<PersistentAuditEvent> findByType(String type, Pageable pageable);
Page<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> findByPrincipalAndTimestampBetween(@Param("principal") String principal, @Param("startDate") Instant startDate, @Param("endDate") Instant endDate, Pageable pageable);
Page<PersistentAuditEvent> 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<PersistentAuditEvent> findByPrincipalAndTypeAndTimestampBetween(@Param("principal") String principal, @Param("type") String type, @Param("startDate") Instant startDate, @Param("endDate") Instant endDate, Pageable pageable);
Page<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> findByPrincipalAndTimestampBetween(
@Param("principal") String principal,
@Param("startDate") Instant startDate,
@Param("endDate") Instant endDate,
Pageable pageable);
Page<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> findAllByPrincipalForExport(@Param("principal") String principal);
@Query("SELECT e FROM PersistentAuditEvent e WHERE e.type = :type")
List<PersistentAuditEvent> findByTypeForExport(@Param("type") String type);
@Query("SELECT e FROM PersistentAuditEvent e WHERE e.timestamp BETWEEN :startDate AND :endDate")
List<PersistentAuditEvent> findAllByTimestampBetweenForExport(@Param("startDate") Instant startDate, @Param("endDate") Instant endDate);
List<PersistentAuditEvent> findAllByTimestampBetweenForExport(
@Param("startDate") Instant startDate, @Param("endDate") Instant endDate);
@Query("SELECT e FROM PersistentAuditEvent e WHERE e.timestamp > :startDate")
List<PersistentAuditEvent> findByTimestampAfter(@Param("startDate") Instant startDate);
@Query("SELECT e FROM PersistentAuditEvent e WHERE UPPER(e.principal) LIKE UPPER(CONCAT('%', :principal, '%')) AND e.type = :type")
List<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> 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<PersistentAuditEvent> 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")

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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()) {
if (usersWithoutTeam != null && !usersWithoutTeam.isEmpty()) {
log.info(
"Assigned {} user(s) without a team to the default team.", usersWithoutTeam.size());
"Assigned {} user(s) without a team to the default team.",
usersWithoutTeam.size());
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
/**

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

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