mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-05-28 21:02:00 +00:00
auditTest
This commit is contained in:
parent
4d6f951604
commit
8e363f503e
@ -92,4 +92,4 @@ EXPOSE 8080/tcp
|
|||||||
|
|
||||||
# Set user and run command
|
# Set user and run command
|
||||||
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
||||||
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 0.0.0.0"]
|
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 127.0.0.1"]
|
@ -43,7 +43,12 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
|||||||
PYTHONPATH=/usr/lib/libreoffice/program:/opt/venv/lib/python3.12/site-packages \
|
PYTHONPATH=/usr/lib/libreoffice/program:/opt/venv/lib/python3.12/site-packages \
|
||||||
UNO_PATH=/usr/lib/libreoffice/program \
|
UNO_PATH=/usr/lib/libreoffice/program \
|
||||||
URE_BOOTSTRAP=file:///usr/lib/libreoffice/program/fundamentalrc \
|
URE_BOOTSTRAP=file:///usr/lib/libreoffice/program/fundamentalrc \
|
||||||
PATH=$PATH:/opt/venv/bin
|
PATH=$PATH:/opt/venv/bin \
|
||||||
|
LIBREOFFICE_HOME=/usr/lib/libreoffice \
|
||||||
|
SAL_USE_VCLPLUGIN=svp \
|
||||||
|
OOO_FORCE_DESKTOP=headless \
|
||||||
|
DISPLAY=:99 \
|
||||||
|
LD_LIBRARY_PATH=/usr/lib/libreoffice/program
|
||||||
|
|
||||||
|
|
||||||
# JDK for app
|
# JDK for app
|
||||||
@ -53,6 +58,11 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a
|
|||||||
apk upgrade --no-cache -a && \
|
apk upgrade --no-cache -a && \
|
||||||
apk add --no-cache \
|
apk add --no-cache \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
libxcb libx11 libxtst libxi \
|
||||||
|
xvfb-run \
|
||||||
|
dbus \
|
||||||
|
cairo \
|
||||||
|
mesa-dri-gallium \
|
||||||
tzdata \
|
tzdata \
|
||||||
tini \
|
tini \
|
||||||
bash \
|
bash \
|
||||||
@ -101,4 +111,4 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a
|
|||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
# Set user and run command
|
# Set user and run command
|
||||||
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
||||||
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 0.0.0.0"]
|
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 127.0.0.1"]
|
||||||
|
@ -429,6 +429,7 @@ dependencies {
|
|||||||
|
|
||||||
// Exclude Tomcat and include Jetty
|
// Exclude Tomcat and include Jetty
|
||||||
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-aop:$springBootVersion")
|
||||||
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
|
||||||
|
|
||||||
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAspectJAutoProxy
|
||||||
|
public class AopConfig {
|
||||||
|
// No body needed; annotation-driven
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class AuditAspect {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuditService auditService;
|
||||||
|
|
||||||
|
@Before(
|
||||||
|
"@annotation(RequestMapping) || @annotation(GetMapping) || @annotation(PostMapping) || " +
|
||||||
|
"@annotation(PutMapping) || @annotation(DeleteMapping) || @annotation(PatchMapping)"
|
||||||
|
)
|
||||||
|
public void logApiCall(JoinPoint joinPoint) {
|
||||||
|
try {
|
||||||
|
// Grab the current request
|
||||||
|
HttpServletRequest request =
|
||||||
|
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
|
|
||||||
|
// Basic info
|
||||||
|
String method = request.getMethod();
|
||||||
|
String endpoint = request.getRequestURI();
|
||||||
|
Map<String, String[]> requestParams = request.getParameterMap();
|
||||||
|
String userAgent = request.getHeader("User-Agent");
|
||||||
|
String ipAddress = getClientIp(request);
|
||||||
|
String username = getCurrentUsername();
|
||||||
|
|
||||||
|
// Extract file metadata if multipart
|
||||||
|
MultipartFile[] files = extractFiles(request);
|
||||||
|
|
||||||
|
// Pass to the audit service
|
||||||
|
auditService.logRequest(
|
||||||
|
method,
|
||||||
|
endpoint,
|
||||||
|
requestParams,
|
||||||
|
userAgent,
|
||||||
|
ipAddress,
|
||||||
|
username,
|
||||||
|
files
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Log and continue
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getClientIp(HttpServletRequest request) {
|
||||||
|
// Some networks use X-Forwarded-For to pass client IP
|
||||||
|
String xForwardedFor = request.getHeader("X-Forwarded-For");
|
||||||
|
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
|
||||||
|
return xForwardedFor.split(",")[0];
|
||||||
|
}
|
||||||
|
return request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCurrentUsername() {
|
||||||
|
// If using Spring Security
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (auth != null && auth.isAuthenticated()) {
|
||||||
|
return auth.getName();
|
||||||
|
}
|
||||||
|
return "anonymous";
|
||||||
|
}
|
||||||
|
|
||||||
|
private MultipartFile[] extractFiles(HttpServletRequest request) {
|
||||||
|
if (request instanceof MultipartHttpServletRequest multipartRequest) {
|
||||||
|
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
|
||||||
|
if (!fileMap.isEmpty()) {
|
||||||
|
return fileMap.values().toArray(new MultipartFile[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new MultipartFile[0];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.model.api.security.AuditLog;
|
||||||
|
import stirling.software.SPDF.repository.AuditLogRepository;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class AuditService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuditLogRepository auditLogRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public void logRequest(
|
||||||
|
String method,
|
||||||
|
String endpoint,
|
||||||
|
Map<String, String[]> requestParams,
|
||||||
|
String userAgent,
|
||||||
|
String ipAddress,
|
||||||
|
String username,
|
||||||
|
MultipartFile[] files
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Build the AuditLog entity
|
||||||
|
AuditLog auditLog = new AuditLog();
|
||||||
|
auditLog.setMethod(method);
|
||||||
|
auditLog.setEndpoint(endpoint);
|
||||||
|
|
||||||
|
// Convert all text form fields (key -> array of values) to JSON for readability
|
||||||
|
String paramsJson = requestParams != null && !requestParams.isEmpty()
|
||||||
|
? objectMapper.writeValueAsString(requestParams)
|
||||||
|
: null;
|
||||||
|
auditLog.setRequestParams(paramsJson);
|
||||||
|
|
||||||
|
auditLog.setUserAgent(userAgent);
|
||||||
|
auditLog.setIpAddress(ipAddress);
|
||||||
|
auditLog.setUsername(username);
|
||||||
|
auditLog.setTimestamp(LocalDateTime.now());
|
||||||
|
|
||||||
|
// Only log metadata for files
|
||||||
|
if (files != null && files.length > 0) {
|
||||||
|
String fileNamesStr = Arrays.stream(files)
|
||||||
|
.map(file -> String.format(
|
||||||
|
"[name=%s, size=%d, type=%s]",
|
||||||
|
file.getOriginalFilename(),
|
||||||
|
file.getSize(),
|
||||||
|
file.getContentType()
|
||||||
|
))
|
||||||
|
.collect(Collectors.joining("; "));
|
||||||
|
auditLog.setFileNames(fileNamesStr);
|
||||||
|
}
|
||||||
|
log.info(auditLog.toString());
|
||||||
|
// Persist
|
||||||
|
auditLogRepository.save(auditLog);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Log error but do not disrupt the main request flow
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package stirling.software.SPDF.model.api.security;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "audit_logs")
|
||||||
|
@Data
|
||||||
|
public class AuditLog {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String method;
|
||||||
|
private String endpoint;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
private String requestParams; // text form params in JSON
|
||||||
|
private String userAgent;
|
||||||
|
private String ipAddress;
|
||||||
|
private String username;
|
||||||
|
private LocalDateTime timestamp;
|
||||||
|
|
||||||
|
// Store file metadata (comma or semicolon-separated)
|
||||||
|
@Lob
|
||||||
|
private String fileNames;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.security.AuditLog;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface AuditLogRepository extends JpaRepository<AuditLog, Long> {
|
||||||
|
// Additional custom queries, if needed
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user