From a695e4a77a50da14154e0015ede897e0dfb63ecd Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Mon, 25 May 2026 15:50:38 +0100 Subject: [PATCH 01/11] [backend] feat(audit-log): login/logout/SSO auth event hooks + tests (#5483) --- .../io/openaev/config/AppSecurityConfig.java | 20 ++++++++++++++++-- .../config/security/OpenSamlConfig.java | 5 ++++- .../java/io/openaev/rest/user/UserApi.java | 5 +++++ ...soRefererAuthenticationFailureHandler.java | 8 ++++++- ...soRefererAuthenticationSuccessHandler.java | 21 +++++++++++++++++++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index 37b8b1349c1..26238383ae9 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -5,6 +5,7 @@ import static org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; import com.fasterxml.jackson.databind.ObjectMapper; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.config.security.OpenSamlConfig; import io.openaev.config.security.SecurityService; import io.openaev.database.model.User; @@ -63,6 +64,7 @@ public class AppSecurityConfig { private final SecurityService securityService; private final UserEventService userEventService; private final UserMappingService userMappingService; + private final AccessControlAuditLogger accessControlAuditLogger; @Resource protected ObjectMapper mapper; @@ -117,6 +119,18 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .logout( logout -> logout + // Audit Log: audit handler fires first, then Spring Security's built-in + // SecurityContextLogoutHandler + // invalidates the session and clears cookies + .addLogoutHandler( + (request, response, authentication) -> { + try { + accessControlAuditLogger.logAuthEvent( + "logout", "success", null, null, null); + } catch (Exception e) { + // Never block the logout flow + } + }) .invalidateHttpSession(true) .deleteCookies("JSESSIONID", openAEVConfig.getCookieName()) .logoutSuccessUrl( @@ -131,9 +145,11 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { auth.authorizationRequestResolver( authorizationRequestResolver( http.getSharedObject(ClientRegistrationRepository.class)))) - .successHandler(new SsoRefererAuthenticationSuccessHandler()) + .successHandler( + new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger)) .failureHandler( - new SsoRefererAuthenticationFailureHandler(this.userEventService))); + new SsoRefererAuthenticationFailureHandler( + this.userEventService, this.accessControlAuditLogger))); } if (openAEVConfig.isAuthSaml2Enable()) { diff --git a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java index 8e15fd693fa..746cbaa4864 100644 --- a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java @@ -5,6 +5,7 @@ import static io.openaev.database.model.User.ROLE_USER; import static org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.config.OpenAEVSaml2User; import io.openaev.database.model.User; import io.openaev.security.SsoRefererAuthenticationSuccessHandler; @@ -48,6 +49,7 @@ public class OpenSamlConfig { private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository; private final UserEventService userEventService; + private final AccessControlAuditLogger accessControlAuditLogger; public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception { if (this.relyingPartyRegistrationRepository == null) { @@ -66,7 +68,8 @@ public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception saml2Login -> saml2Login .authenticationManager(new ProviderManager(authenticationProvider)) - .successHandler(new SsoRefererAuthenticationSuccessHandler())); + .successHandler( + new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger))); } // -- PRIVATE -- diff --git a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java index 427dd32003c..d03dd1bbde8 100644 --- a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java +++ b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java @@ -2,6 +2,7 @@ import io.openaev.aop.AccessControl; import io.openaev.aop.UserRoleDescription; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.config.SessionManager; import io.openaev.database.model.Action; import io.openaev.database.model.ResourceType; @@ -51,6 +52,7 @@ public class UserApi extends RestBehavior { private final UserRepository userRepository; private final UserService userService; private final UserEventService userEventService; + private final AccessControlAuditLogger accessControlAuditLogger; @Operation(description = "Endpoint to login", summary = "Endpoint to login") @ApiResponses( @@ -70,11 +72,14 @@ public User login(@Valid @RequestBody LoginUserInput input) { if (userService.isUserPasswordValid(user, input.getPassword())) { userService.createUserSession(user); userEventService.createLoginSuccessEvent(user); + accessControlAuditLogger.logAuthEvent("login", "success", "local", null, null); return user; } } userEventService.createLoginFailedEvent( "local login", BadCredentialsException.class.getSimpleName()); + accessControlAuditLogger.logAuthEvent( + "login", "error", "local", BadCredentialsException.class.getSimpleName(), null); throw new BadCredentialsException("Invalid credential."); } diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java index d8ae63f2fb2..15509da1b7f 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java @@ -2,6 +2,7 @@ import static org.springframework.http.HttpHeaders.REFERER; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.service.user_events.UserEventService; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -18,9 +19,12 @@ public class SsoRefererAuthenticationFailureHandler extends SimpleUrlAuthenticat private RequestCache requestCache = new HttpSessionRequestCache(); private final UserEventService userEventService; + private final AccessControlAuditLogger accessControlAuditLogger; - public SsoRefererAuthenticationFailureHandler(UserEventService userEventService) { + public SsoRefererAuthenticationFailureHandler( + UserEventService userEventService, AccessControlAuditLogger accessControlAuditLogger) { this.userEventService = userEventService; + this.accessControlAuditLogger = accessControlAuditLogger; } @Override @@ -29,6 +33,8 @@ public void onAuthenticationFailure( throws ServletException, IOException { userEventService.createLoginFailedEvent( request.getRequestURI(), exception.getClass().getSimpleName()); + accessControlAuditLogger.logAuthEvent( + "login", "error", request.getRequestURI(), exception.getClass().getSimpleName(), null); this.saveException(request, exception); SavedRequest savedRequest = this.requestCache.getRequest(request, response); diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java index d6e25b67fda..186e9780239 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java @@ -2,12 +2,14 @@ import static org.springframework.http.HttpHeaders.REFERER; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; @@ -16,12 +18,31 @@ public class SsoRefererAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final RequestCache requestCache = new HttpSessionRequestCache(); + private final AccessControlAuditLogger accessControlAuditLogger; + + public SsoRefererAuthenticationSuccessHandler(AccessControlAuditLogger accessControlAuditLogger) { + this.accessControlAuditLogger = accessControlAuditLogger; + } @Override public void onAuthenticationSuccess( HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { + + // Audit: log SSO login success + try { + String provider = "sso"; + if (authentication instanceof OAuth2AuthenticationToken oauth2Token) { + provider = oauth2Token.getAuthorizedClientRegistrationId(); + } + + accessControlAuditLogger.logAuthEvent("login", "success", provider, null, null); + } catch (Exception e) { + // Never block the login flow + } + SavedRequest savedRequest = this.requestCache.getRequest(request, response); + if (savedRequest != null) { List refererValues = savedRequest.getHeaderValues(REFERER); if (refererValues.size() == 1) { From b65e4594255cf6067a6ae33e3853a6beccde0977 Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Mon, 25 May 2026 16:02:26 +0100 Subject: [PATCH 02/11] [backend] feat(audit-log): only provider stays in try-catch, so it always runs the logging action (#5483) --- .../security/SsoRefererAuthenticationSuccessHandler.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java index 186e9780239..e493df0f851 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java @@ -30,17 +30,18 @@ public void onAuthenticationSuccess( throws ServletException, IOException { // Audit: log SSO login success + String provider = "sso"; + try { - String provider = "sso"; if (authentication instanceof OAuth2AuthenticationToken oauth2Token) { provider = oauth2Token.getAuthorizedClientRegistrationId(); } - - accessControlAuditLogger.logAuthEvent("login", "success", provider, null, null); } catch (Exception e) { // Never block the login flow } + accessControlAuditLogger.logAuthEvent("login", "success", provider, null, null); + SavedRequest savedRequest = this.requestCache.getRequest(request, response); if (savedRequest != null) { From ac06681feefb998b343f90b6241333ae26c5a5e4 Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Mon, 25 May 2026 17:54:44 +0100 Subject: [PATCH 03/11] [backend] feat(audit-log): fix circular dependency injection issue (#5483) --- .../src/main/java/io/openaev/config/AppSecurityConfig.java | 7 ++++++- .../java/io/openaev/config/security/OpenSamlConfig.java | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index 26238383ae9..04adda34f46 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -19,9 +19,11 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.security.config.Customizer; @@ -64,7 +66,10 @@ public class AppSecurityConfig { private final SecurityService securityService; private final UserEventService userEventService; private final UserMappingService userMappingService; - private final AccessControlAuditLogger accessControlAuditLogger; + + @Autowired + @Lazy + private AccessControlAuditLogger accessControlAuditLogger; @Resource protected ObjectMapper mapper; diff --git a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java index 746cbaa4864..456f2bdf894 100644 --- a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java @@ -18,6 +18,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; import org.springframework.core.env.Environment; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -49,7 +50,10 @@ public class OpenSamlConfig { private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository; private final UserEventService userEventService; - private final AccessControlAuditLogger accessControlAuditLogger; + + @Autowired + @Lazy + private AccessControlAuditLogger accessControlAuditLogger; public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception { if (this.relyingPartyRegistrationRepository == null) { From 9c1a3e55f67bc060b8ea6896195519c00497bb1a Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 10:17:26 +0100 Subject: [PATCH 04/11] [backend] feat(audit-log): prepare request context when logout callback runs without context (#5483) --- .../audit_log/AccessControlAuditLogger.java | 22 ++++++- .../io/openaev/config/AppSecurityConfig.java | 18 ++++-- .../config/ThreadPoolTaskLoggerConfig.java | 60 ++++++++++++------- .../config/security/OpenSamlConfig.java | 4 +- .../java/io/openaev/service/LogService.java | 32 +++++++--- 5 files changed, 96 insertions(+), 40 deletions(-) diff --git a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java index e1f3b503343..a4748401801 100644 --- a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java +++ b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.JsonNode; import io.openaev.aop.AccessControl; import io.openaev.aop.AccessControlAspect; +import io.openaev.config.ThreadPoolTaskLoggerConfig; import io.openaev.database.model.Action; import io.openaev.database.model.ResourceType; import io.openaev.service.LogService; @@ -42,7 +43,24 @@ public boolean isAuditLoggingValid(Action action) { } /** Wraps the audit service call in try/catch — audit must never break the business flow. */ - @Async("accessControlAuditLoggerExecutor") + @Async("taskLoggerExecutor") + public CompletableFuture logAuthEventWithRequestContext( + ThreadPoolTaskLoggerConfig.ThreadRequestContextHolder.RequestContextData rcd, + String eventScope, + String eventStatus, + String provider, + String reason, + String logUUID) { + + if (rcd != null) { + ThreadPoolTaskLoggerConfig.ThreadRequestContextHolder.setRequestContextData(rcd); + } + + return logAuthEvent(eventScope, eventStatus, provider, reason, logUUID); + } + + /** Wraps the audit service call in try/catch — audit must never break the business flow. */ + @Async("taskLoggerExecutor") public CompletableFuture logAuthEvent( String eventScope, String eventStatus, String provider, String reason, String logUUID) { boolean status = false; @@ -64,7 +82,7 @@ public CompletableFuture logAuthEvent( return CompletableFuture.completedFuture(status); } - @Async("accessControlAuditLoggerExecutor") + @Async("taskLoggerExecutor") public CompletableFuture logAccessControlEvent( String eventScope, String eventStatus, diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index 04adda34f46..2aae8465741 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -67,9 +67,7 @@ public class AppSecurityConfig { private final UserEventService userEventService; private final UserMappingService userMappingService; - @Autowired - @Lazy - private AccessControlAuditLogger accessControlAuditLogger; + @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; @Resource protected ObjectMapper mapper; @@ -129,12 +127,22 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // invalidates the session and clears cookies .addLogoutHandler( (request, response, authentication) -> { + ThreadPoolTaskLoggerConfig.ThreadRequestContextHolder.RequestContextData + rcd = null; try { - accessControlAuditLogger.logAuthEvent( - "logout", "success", null, null, null); + rcd = + ThreadPoolTaskLoggerConfig.buildThreadRequestContextHolder( + request, authentication); } catch (Exception e) { // Never block the logout flow + log.error( + "Failed to prepare request context on logout event: {}", + e.getMessage(), + e); } + + accessControlAuditLogger.logAuthEventWithRequestContext( + rcd, "logout", "success", null, null, null); }) .invalidateHttpSession(true) .deleteCookies("JSESSIONID", openAEVConfig.getCookieName()) diff --git a/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java b/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java index 03592842389..a5225cde5e5 100644 --- a/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java @@ -10,6 +10,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.context.request.RequestContextHolder; @@ -21,49 +22,36 @@ public class ThreadPoolTaskLoggerConfig { private ThreadPoolTaskExecutor createBaseExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - // TODO: find a better way to configure this variables dynamically - maybe through properties + // TODO AUDIT: find a better way to configure this variables dynamically - maybe through properties // file. executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setQueueCapacity(1000); - executor.setThreadNamePrefix("AuditLogger-"); + executor.setThreadNamePrefix("TaskLogger-"); return executor; } - @Bean(name = "accessControlAuditLoggerExecutor") + @Bean(name = "taskLoggerExecutor") public Executor contextAwareExecutor() { ThreadPoolTaskExecutor executor = createBaseExecutor(); executor.setTaskDecorator( runnable -> { - // CAPTURE REQUEST HEADERS AND IP, REQUEST URI and BODY (PARENT THREAD) + // CAPTURE REQUEST (PARENT THREAD) var requestAttributes = RequestContextHolder.getRequestAttributes(); HttpServletRequest request = requestAttributes instanceof ServletRequestAttributes attrs ? attrs.getRequest() : null; - Map headers; - String remoteAddress, method, url; - - if (request != null) { - headers = HttpReqRespUtils.extractHeaders(request); - remoteAddress = request.getRemoteAddr(); - method = request.getMethod(); - - url = request.getRequestURL().toString(); - } else { - headers = null; - remoteAddress = method = url = null; - } // CAPTURE LOGs CONTEXT var mdcContext = MDC.getCopyOfContextMap(); // CAPTURE AUTHENTICATION CONTEXT (PARENT THREAD) var originalSecurityContext = SecurityContextHolder.getContext(); - var authentication = originalSecurityContext.getAuthentication(); + Authentication authentication = originalSecurityContext.getAuthentication(); SecurityContext securityContextCopy = SecurityContextHolder.createEmptyContext(); // SAFE COPY (IMPORTANT) @@ -75,12 +63,14 @@ public Executor contextAwareExecutor() { // CAPTURE LOCALE CONTEXT (PARENT THREAD) var localeContext = LocaleContextHolder.getLocaleContext(); + // CREATE REQUEST CONTEXT HOLDER DATA WITH REQUEST HEADERS AND IP, REQUEST URI... + ThreadRequestContextHolder.RequestContextData rcd = + buildThreadRequestContextHolder(request, authentication); + return () -> { try { // STORE HEADERS AND REMOTE ADDRESS - ThreadRequestContextHolder.setRequestContextData( - new ThreadRequestContextHolder.RequestContextData( - headers, remoteAddress, method, url)); + ThreadRequestContextHolder.setRequestContextData(rcd); // RESTORE MDC if (mdcContext != null) { @@ -112,10 +102,36 @@ public Executor contextAwareExecutor() { return executor; } + public static ThreadRequestContextHolder.RequestContextData buildThreadRequestContextHolder( + HttpServletRequest request, Authentication authentication) { + // GET REQUEST HEADERS AND IP, REQUEST URI and BODY (PARENT THREAD) + Map headers; + String remoteAddress, method, url; + + if (request != null) { + headers = HttpReqRespUtils.extractHeaders(request); + remoteAddress = request.getRemoteAddr(); + method = request.getMethod(); + + url = request.getRequestURL().toString(); + } else { + headers = null; + remoteAddress = method = url = null; + } + + // STORE HEADERS AND REMOTE ADDRESS + return new ThreadRequestContextHolder.RequestContextData( + headers, remoteAddress, method, url, authentication); + } + public static class ThreadRequestContextHolder { public record RequestContextData( - Map headers, String remoteAddress, String method, String url) {} + Map headers, + String remoteAddress, + String method, + String url, + Authentication authentication) {} private static final ThreadLocal> CONTEXT = new ThreadLocal<>(); diff --git a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java index 456f2bdf894..c75814ddf33 100644 --- a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java @@ -51,9 +51,7 @@ public class OpenSamlConfig { private final UserEventService userEventService; - @Autowired - @Lazy - private AccessControlAuditLogger accessControlAuditLogger; + @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception { if (this.relyingPartyRegistrationRepository == null) { diff --git a/openaev-api/src/main/java/io/openaev/service/LogService.java b/openaev-api/src/main/java/io/openaev/service/LogService.java index 4db13c44c38..318f3b578fd 100644 --- a/openaev-api/src/main/java/io/openaev/service/LogService.java +++ b/openaev-api/src/main/java/io/openaev/service/LogService.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import io.openaev.config.OpenAEVAnonymous; import io.openaev.config.OpenAEVPrincipal; import io.openaev.config.SessionHelper; import io.openaev.config.ThreadPoolTaskLoggerConfig; @@ -20,13 +21,11 @@ import io.openaev.utils.object.ObjectRedactionUtils; import jakarta.servlet.http.HttpServletRequest; import java.time.Instant; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; /** @@ -252,15 +251,32 @@ private LogEvent buildBaseAuditLog( /** Resolves the current user ID from the security context, or null if anonymous. */ private String resolveUserId() { + String id = null; + try { OpenAEVPrincipal principal = SessionHelper.currentUser(); - if (principal == null || "anonymous".equals(principal.getId())) { - return null; + + if (principal != null && !(principal instanceof OpenAEVAnonymous)) id = principal.getId(); + + if (id == null) { + ThreadPoolTaskLoggerConfig.ThreadRequestContextHolder.RequestContextData + requestContextData = + ThreadPoolTaskLoggerConfig.ThreadRequestContextHolder.getRequestContextData(); + Authentication auth = requestContextData.authentication(); + + if (auth != null) { + Object princ = auth.getPrincipal(); + + if (princ instanceof OpenAEVPrincipal user) { + id = user.getId(); + } + } } - return principal.getId(); } catch (Exception e) { - return null; + log.warn("[LOG] Failed to resolve user ID: {}", e.getMessage(), e); } + + return id; } /** Populates user metadata (email, IP, user agent) on the given audit log document. */ From 2dc5029101e7842eecbb236d95b42f568a08e1e6 Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 10:32:40 +0100 Subject: [PATCH 05/11] [backend] feat(audit-log): Renaming AccessControlAuditLogger to AuditLogger since this class has nothing to do with accesscontrol. (#5483) --- ...AccessControlAuditLogger.java => AuditLogger.java} | 2 +- .../java/io/openaev/config/AppSecurityConfig.java | 11 +++++------ .../io/openaev/config/security/OpenSamlConfig.java | 7 +++---- .../src/main/java/io/openaev/rest/user/UserApi.java | 8 ++++---- .../SsoRefererAuthenticationFailureHandler.java | 10 +++++----- .../SsoRefererAuthenticationSuccessHandler.java | 10 +++++----- 6 files changed, 23 insertions(+), 25 deletions(-) rename openaev-api/src/main/java/io/openaev/aop/audit_log/{AccessControlAuditLogger.java => AuditLogger.java} (98%) diff --git a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java b/openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java similarity index 98% rename from openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java rename to openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java index a4748401801..340817d0bdc 100644 --- a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java +++ b/openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java @@ -28,7 +28,7 @@ @ConditionalOnProperty(name = "openaev.audit-logs.service.enabled", havingValue = "true") @RequiredArgsConstructor @Slf4j -public class AccessControlAuditLogger { +public class AuditLogger { private final AuditRequestValidator auditRequestValidator; diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index 2aae8465741..23463b9f710 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -5,7 +5,7 @@ import static org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; import com.fasterxml.jackson.databind.ObjectMapper; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.config.security.OpenSamlConfig; import io.openaev.config.security.SecurityService; import io.openaev.database.model.User; @@ -67,7 +67,7 @@ public class AppSecurityConfig { private final UserEventService userEventService; private final UserMappingService userMappingService; - @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; + @Autowired @Lazy private AuditLogger auditLogger; @Resource protected ObjectMapper mapper; @@ -141,7 +141,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { e); } - accessControlAuditLogger.logAuthEventWithRequestContext( + auditLogger.logAuthEventWithRequestContext( rcd, "logout", "success", null, null, null); }) .invalidateHttpSession(true) @@ -158,11 +158,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { auth.authorizationRequestResolver( authorizationRequestResolver( http.getSharedObject(ClientRegistrationRepository.class)))) - .successHandler( - new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger)) + .successHandler(new SsoRefererAuthenticationSuccessHandler(this.auditLogger)) .failureHandler( new SsoRefererAuthenticationFailureHandler( - this.userEventService, this.accessControlAuditLogger))); + this.userEventService, this.auditLogger))); } if (openAEVConfig.isAuthSaml2Enable()) { diff --git a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java index c75814ddf33..78b76478745 100644 --- a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java @@ -5,7 +5,7 @@ import static io.openaev.database.model.User.ROLE_USER; import static org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.config.OpenAEVSaml2User; import io.openaev.database.model.User; import io.openaev.security.SsoRefererAuthenticationSuccessHandler; @@ -51,7 +51,7 @@ public class OpenSamlConfig { private final UserEventService userEventService; - @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; + @Autowired @Lazy private AuditLogger auditLogger; public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception { if (this.relyingPartyRegistrationRepository == null) { @@ -70,8 +70,7 @@ public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception saml2Login -> saml2Login .authenticationManager(new ProviderManager(authenticationProvider)) - .successHandler( - new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger))); + .successHandler(new SsoRefererAuthenticationSuccessHandler(this.auditLogger))); } // -- PRIVATE -- diff --git a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java index d03dd1bbde8..16e7d8b7977 100644 --- a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java +++ b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java @@ -2,7 +2,7 @@ import io.openaev.aop.AccessControl; import io.openaev.aop.UserRoleDescription; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.config.SessionManager; import io.openaev.database.model.Action; import io.openaev.database.model.ResourceType; @@ -52,7 +52,7 @@ public class UserApi extends RestBehavior { private final UserRepository userRepository; private final UserService userService; private final UserEventService userEventService; - private final AccessControlAuditLogger accessControlAuditLogger; + private final AuditLogger auditLogger; @Operation(description = "Endpoint to login", summary = "Endpoint to login") @ApiResponses( @@ -72,13 +72,13 @@ public User login(@Valid @RequestBody LoginUserInput input) { if (userService.isUserPasswordValid(user, input.getPassword())) { userService.createUserSession(user); userEventService.createLoginSuccessEvent(user); - accessControlAuditLogger.logAuthEvent("login", "success", "local", null, null); + auditLogger.logAuthEvent("login", "success", "local", null, null); return user; } } userEventService.createLoginFailedEvent( "local login", BadCredentialsException.class.getSimpleName()); - accessControlAuditLogger.logAuthEvent( + auditLogger.logAuthEvent( "login", "error", "local", BadCredentialsException.class.getSimpleName(), null); throw new BadCredentialsException("Invalid credential."); } diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java index 15509da1b7f..de7bf31d867 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java @@ -2,7 +2,7 @@ import static org.springframework.http.HttpHeaders.REFERER; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.service.user_events.UserEventService; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -19,12 +19,12 @@ public class SsoRefererAuthenticationFailureHandler extends SimpleUrlAuthenticat private RequestCache requestCache = new HttpSessionRequestCache(); private final UserEventService userEventService; - private final AccessControlAuditLogger accessControlAuditLogger; + private final AuditLogger auditLogger; public SsoRefererAuthenticationFailureHandler( - UserEventService userEventService, AccessControlAuditLogger accessControlAuditLogger) { + UserEventService userEventService, AuditLogger auditLogger) { this.userEventService = userEventService; - this.accessControlAuditLogger = accessControlAuditLogger; + this.auditLogger = auditLogger; } @Override @@ -33,7 +33,7 @@ public void onAuthenticationFailure( throws ServletException, IOException { userEventService.createLoginFailedEvent( request.getRequestURI(), exception.getClass().getSimpleName()); - accessControlAuditLogger.logAuthEvent( + auditLogger.logAuthEvent( "login", "error", request.getRequestURI(), exception.getClass().getSimpleName(), null); this.saveException(request, exception); diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java index e493df0f851..672b02da4e5 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java @@ -2,7 +2,7 @@ import static org.springframework.http.HttpHeaders.REFERER; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -18,10 +18,10 @@ public class SsoRefererAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final RequestCache requestCache = new HttpSessionRequestCache(); - private final AccessControlAuditLogger accessControlAuditLogger; + private final AuditLogger auditLogger; - public SsoRefererAuthenticationSuccessHandler(AccessControlAuditLogger accessControlAuditLogger) { - this.accessControlAuditLogger = accessControlAuditLogger; + public SsoRefererAuthenticationSuccessHandler(AuditLogger auditLogger) { + this.auditLogger = auditLogger; } @Override @@ -40,7 +40,7 @@ public void onAuthenticationSuccess( // Never block the login flow } - accessControlAuditLogger.logAuthEvent("login", "success", provider, null, null); + auditLogger.logAuthEvent("login", "success", provider, null, null); SavedRequest savedRequest = this.requestCache.getRequest(request, response); From 1c82e43b2308f42532dd70a8d1f26311b1f6d788 Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 10:33:45 +0100 Subject: [PATCH 06/11] [backend] feat(audit-log): lint some code (#5483) --- .../java/io/openaev/config/ThreadPoolTaskLoggerConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java b/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java index a5225cde5e5..f3f2f4beb13 100644 --- a/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/ThreadPoolTaskLoggerConfig.java @@ -22,8 +22,8 @@ public class ThreadPoolTaskLoggerConfig { private ThreadPoolTaskExecutor createBaseExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - // TODO AUDIT: find a better way to configure this variables dynamically - maybe through properties - // file. + // TODO AUDIT: find a better way to configure this variables dynamically - maybe through + // properties file. executor.setCorePoolSize(10); executor.setMaxPoolSize(50); From ba6f05be6a8772095cae72091deee4637a3db08c Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 11:42:41 +0100 Subject: [PATCH 07/11] [backend] feat(audit-log): put back the AccessControlAuditLogger class name so I could rebase it easily from main (#5483) --- ...{AuditLogger.java => AccessControlAuditLogger.java} | 2 +- .../main/java/io/openaev/config/AppSecurityConfig.java | 10 +++++----- .../io/openaev/config/security/OpenSamlConfig.java | 6 +++--- .../src/main/java/io/openaev/rest/user/UserApi.java | 8 ++++---- .../SsoRefererAuthenticationFailureHandler.java | 10 +++++----- .../SsoRefererAuthenticationSuccessHandler.java | 10 +++++----- 6 files changed, 23 insertions(+), 23 deletions(-) rename openaev-api/src/main/java/io/openaev/aop/audit_log/{AuditLogger.java => AccessControlAuditLogger.java} (98%) diff --git a/openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java similarity index 98% rename from openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java rename to openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java index 340817d0bdc..a4748401801 100644 --- a/openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java +++ b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java @@ -28,7 +28,7 @@ @ConditionalOnProperty(name = "openaev.audit-logs.service.enabled", havingValue = "true") @RequiredArgsConstructor @Slf4j -public class AuditLogger { +public class AccessControlAuditLogger { private final AuditRequestValidator auditRequestValidator; diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index 23463b9f710..e1aa89c85e9 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -5,7 +5,7 @@ import static org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; import com.fasterxml.jackson.databind.ObjectMapper; -import io.openaev.aop.audit_log.AuditLogger; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.config.security.OpenSamlConfig; import io.openaev.config.security.SecurityService; import io.openaev.database.model.User; @@ -67,7 +67,7 @@ public class AppSecurityConfig { private final UserEventService userEventService; private final UserMappingService userMappingService; - @Autowired @Lazy private AuditLogger auditLogger; + @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; @Resource protected ObjectMapper mapper; @@ -141,7 +141,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { e); } - auditLogger.logAuthEventWithRequestContext( + accessControlAuditLogger.logAuthEventWithRequestContext( rcd, "logout", "success", null, null, null); }) .invalidateHttpSession(true) @@ -158,10 +158,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { auth.authorizationRequestResolver( authorizationRequestResolver( http.getSharedObject(ClientRegistrationRepository.class)))) - .successHandler(new SsoRefererAuthenticationSuccessHandler(this.auditLogger)) + .successHandler(new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger)) .failureHandler( new SsoRefererAuthenticationFailureHandler( - this.userEventService, this.auditLogger))); + this.userEventService, this.accessControlAuditLogger))); } if (openAEVConfig.isAuthSaml2Enable()) { diff --git a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java index 78b76478745..8ebfe791c1e 100644 --- a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java @@ -5,7 +5,7 @@ import static io.openaev.database.model.User.ROLE_USER; import static org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter; -import io.openaev.aop.audit_log.AuditLogger; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.config.OpenAEVSaml2User; import io.openaev.database.model.User; import io.openaev.security.SsoRefererAuthenticationSuccessHandler; @@ -51,7 +51,7 @@ public class OpenSamlConfig { private final UserEventService userEventService; - @Autowired @Lazy private AuditLogger auditLogger; + @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception { if (this.relyingPartyRegistrationRepository == null) { @@ -70,7 +70,7 @@ public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception saml2Login -> saml2Login .authenticationManager(new ProviderManager(authenticationProvider)) - .successHandler(new SsoRefererAuthenticationSuccessHandler(this.auditLogger))); + .successHandler(new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger))); } // -- PRIVATE -- diff --git a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java index 16e7d8b7977..d03dd1bbde8 100644 --- a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java +++ b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java @@ -2,7 +2,7 @@ import io.openaev.aop.AccessControl; import io.openaev.aop.UserRoleDescription; -import io.openaev.aop.audit_log.AuditLogger; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.config.SessionManager; import io.openaev.database.model.Action; import io.openaev.database.model.ResourceType; @@ -52,7 +52,7 @@ public class UserApi extends RestBehavior { private final UserRepository userRepository; private final UserService userService; private final UserEventService userEventService; - private final AuditLogger auditLogger; + private final AccessControlAuditLogger accessControlAuditLogger; @Operation(description = "Endpoint to login", summary = "Endpoint to login") @ApiResponses( @@ -72,13 +72,13 @@ public User login(@Valid @RequestBody LoginUserInput input) { if (userService.isUserPasswordValid(user, input.getPassword())) { userService.createUserSession(user); userEventService.createLoginSuccessEvent(user); - auditLogger.logAuthEvent("login", "success", "local", null, null); + accessControlAuditLogger.logAuthEvent("login", "success", "local", null, null); return user; } } userEventService.createLoginFailedEvent( "local login", BadCredentialsException.class.getSimpleName()); - auditLogger.logAuthEvent( + accessControlAuditLogger.logAuthEvent( "login", "error", "local", BadCredentialsException.class.getSimpleName(), null); throw new BadCredentialsException("Invalid credential."); } diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java index de7bf31d867..15509da1b7f 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java @@ -2,7 +2,7 @@ import static org.springframework.http.HttpHeaders.REFERER; -import io.openaev.aop.audit_log.AuditLogger; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import io.openaev.service.user_events.UserEventService; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -19,12 +19,12 @@ public class SsoRefererAuthenticationFailureHandler extends SimpleUrlAuthenticat private RequestCache requestCache = new HttpSessionRequestCache(); private final UserEventService userEventService; - private final AuditLogger auditLogger; + private final AccessControlAuditLogger accessControlAuditLogger; public SsoRefererAuthenticationFailureHandler( - UserEventService userEventService, AuditLogger auditLogger) { + UserEventService userEventService, AccessControlAuditLogger accessControlAuditLogger) { this.userEventService = userEventService; - this.auditLogger = auditLogger; + this.accessControlAuditLogger = accessControlAuditLogger; } @Override @@ -33,7 +33,7 @@ public void onAuthenticationFailure( throws ServletException, IOException { userEventService.createLoginFailedEvent( request.getRequestURI(), exception.getClass().getSimpleName()); - auditLogger.logAuthEvent( + accessControlAuditLogger.logAuthEvent( "login", "error", request.getRequestURI(), exception.getClass().getSimpleName(), null); this.saveException(request, exception); diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java index 672b02da4e5..e493df0f851 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java @@ -2,7 +2,7 @@ import static org.springframework.http.HttpHeaders.REFERER; -import io.openaev.aop.audit_log.AuditLogger; +import io.openaev.aop.audit_log.AccessControlAuditLogger; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -18,10 +18,10 @@ public class SsoRefererAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final RequestCache requestCache = new HttpSessionRequestCache(); - private final AuditLogger auditLogger; + private final AccessControlAuditLogger accessControlAuditLogger; - public SsoRefererAuthenticationSuccessHandler(AuditLogger auditLogger) { - this.auditLogger = auditLogger; + public SsoRefererAuthenticationSuccessHandler(AccessControlAuditLogger accessControlAuditLogger) { + this.accessControlAuditLogger = accessControlAuditLogger; } @Override @@ -40,7 +40,7 @@ public void onAuthenticationSuccess( // Never block the login flow } - auditLogger.logAuthEvent("login", "success", provider, null, null); + accessControlAuditLogger.logAuthEvent("login", "success", provider, null, null); SavedRequest savedRequest = this.requestCache.getRequest(request, response); From e68b44aef639ca5e76dbd13588fa912476566780 Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 11:45:39 +0100 Subject: [PATCH 08/11] [backend] feat(audit-log): rename AccessControlAuditLogger again to AuditLogger bc this is a generic class not related only with accessControl annotations (#5483) --- .../aop/audit_log/AccessControlAuditLogAspect.java | 10 +++++----- ...{AccessControlAuditLogger.java => AuditLogger.java} | 2 +- .../main/java/io/openaev/config/AppSecurityConfig.java | 10 +++++----- .../io/openaev/config/security/OpenSamlConfig.java | 6 +++--- .../src/main/java/io/openaev/rest/user/UserApi.java | 8 ++++---- .../SsoRefererAuthenticationFailureHandler.java | 10 +++++----- .../SsoRefererAuthenticationSuccessHandler.java | 10 +++++----- 7 files changed, 28 insertions(+), 28 deletions(-) rename openaev-api/src/main/java/io/openaev/aop/audit_log/{AccessControlAuditLogger.java => AuditLogger.java} (98%) diff --git a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java index 2eac5333880..64b64ef3266 100644 --- a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java +++ b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java @@ -43,7 +43,7 @@ @Slf4j public class AccessControlAuditLogAspect { - private final AccessControlAuditLogger accessControlAuditLogger; + private final AuditLogger auditLogger; private final ObjectMapper objectMapper; private final ExpressionParser parser = new SpelExpressionParser(); @@ -58,8 +58,8 @@ public Object auditAround(ProceedingJoinPoint joinPoint, AccessControl accessCon try { action = accessControl.actionPerformed(); isActive = - accessControlAuditLogger.isAuditLoggingEnabled() - && accessControlAuditLogger.isAuditLoggingValid(action); + auditLogger.isAuditLoggingEnabled() + && auditLogger.isAuditLoggingValid(action); } catch (Exception ex) { log.warn("Error during audit logging", ex); } @@ -113,7 +113,7 @@ public Object auditAround(ProceedingJoinPoint joinPoint, AccessControl accessCon JsonNode resultNode = getOutputNode(result); JsonNode errorNode = buildErrorNode(resultNode, ex); - accessControlAuditLogger + auditLogger .logAccessControlEvent( eventScope, "error", @@ -134,7 +134,7 @@ public Object auditAround(ProceedingJoinPoint joinPoint, AccessControl accessCon try { JsonNode resultNode = getOutputNode(result); - accessControlAuditLogger + auditLogger .logAccessControlEvent( eventScope, "success", diff --git a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java b/openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java similarity index 98% rename from openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java rename to openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java index a4748401801..340817d0bdc 100644 --- a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogger.java +++ b/openaev-api/src/main/java/io/openaev/aop/audit_log/AuditLogger.java @@ -28,7 +28,7 @@ @ConditionalOnProperty(name = "openaev.audit-logs.service.enabled", havingValue = "true") @RequiredArgsConstructor @Slf4j -public class AccessControlAuditLogger { +public class AuditLogger { private final AuditRequestValidator auditRequestValidator; diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index e1aa89c85e9..23463b9f710 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -5,7 +5,7 @@ import static org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; import com.fasterxml.jackson.databind.ObjectMapper; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.config.security.OpenSamlConfig; import io.openaev.config.security.SecurityService; import io.openaev.database.model.User; @@ -67,7 +67,7 @@ public class AppSecurityConfig { private final UserEventService userEventService; private final UserMappingService userMappingService; - @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; + @Autowired @Lazy private AuditLogger auditLogger; @Resource protected ObjectMapper mapper; @@ -141,7 +141,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { e); } - accessControlAuditLogger.logAuthEventWithRequestContext( + auditLogger.logAuthEventWithRequestContext( rcd, "logout", "success", null, null, null); }) .invalidateHttpSession(true) @@ -158,10 +158,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { auth.authorizationRequestResolver( authorizationRequestResolver( http.getSharedObject(ClientRegistrationRepository.class)))) - .successHandler(new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger)) + .successHandler(new SsoRefererAuthenticationSuccessHandler(this.auditLogger)) .failureHandler( new SsoRefererAuthenticationFailureHandler( - this.userEventService, this.accessControlAuditLogger))); + this.userEventService, this.auditLogger))); } if (openAEVConfig.isAuthSaml2Enable()) { diff --git a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java index 8ebfe791c1e..78b76478745 100644 --- a/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/security/OpenSamlConfig.java @@ -5,7 +5,7 @@ import static io.openaev.database.model.User.ROLE_USER; import static org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.config.OpenAEVSaml2User; import io.openaev.database.model.User; import io.openaev.security.SsoRefererAuthenticationSuccessHandler; @@ -51,7 +51,7 @@ public class OpenSamlConfig { private final UserEventService userEventService; - @Autowired @Lazy private AccessControlAuditLogger accessControlAuditLogger; + @Autowired @Lazy private AuditLogger auditLogger; public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception { if (this.relyingPartyRegistrationRepository == null) { @@ -70,7 +70,7 @@ public void addOpenSamlConfig(@NotNull final HttpSecurity http) throws Exception saml2Login -> saml2Login .authenticationManager(new ProviderManager(authenticationProvider)) - .successHandler(new SsoRefererAuthenticationSuccessHandler(this.accessControlAuditLogger))); + .successHandler(new SsoRefererAuthenticationSuccessHandler(this.auditLogger))); } // -- PRIVATE -- diff --git a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java index d03dd1bbde8..16e7d8b7977 100644 --- a/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java +++ b/openaev-api/src/main/java/io/openaev/rest/user/UserApi.java @@ -2,7 +2,7 @@ import io.openaev.aop.AccessControl; import io.openaev.aop.UserRoleDescription; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.config.SessionManager; import io.openaev.database.model.Action; import io.openaev.database.model.ResourceType; @@ -52,7 +52,7 @@ public class UserApi extends RestBehavior { private final UserRepository userRepository; private final UserService userService; private final UserEventService userEventService; - private final AccessControlAuditLogger accessControlAuditLogger; + private final AuditLogger auditLogger; @Operation(description = "Endpoint to login", summary = "Endpoint to login") @ApiResponses( @@ -72,13 +72,13 @@ public User login(@Valid @RequestBody LoginUserInput input) { if (userService.isUserPasswordValid(user, input.getPassword())) { userService.createUserSession(user); userEventService.createLoginSuccessEvent(user); - accessControlAuditLogger.logAuthEvent("login", "success", "local", null, null); + auditLogger.logAuthEvent("login", "success", "local", null, null); return user; } } userEventService.createLoginFailedEvent( "local login", BadCredentialsException.class.getSimpleName()); - accessControlAuditLogger.logAuthEvent( + auditLogger.logAuthEvent( "login", "error", "local", BadCredentialsException.class.getSimpleName(), null); throw new BadCredentialsException("Invalid credential."); } diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java index 15509da1b7f..de7bf31d867 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationFailureHandler.java @@ -2,7 +2,7 @@ import static org.springframework.http.HttpHeaders.REFERER; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import io.openaev.service.user_events.UserEventService; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -19,12 +19,12 @@ public class SsoRefererAuthenticationFailureHandler extends SimpleUrlAuthenticat private RequestCache requestCache = new HttpSessionRequestCache(); private final UserEventService userEventService; - private final AccessControlAuditLogger accessControlAuditLogger; + private final AuditLogger auditLogger; public SsoRefererAuthenticationFailureHandler( - UserEventService userEventService, AccessControlAuditLogger accessControlAuditLogger) { + UserEventService userEventService, AuditLogger auditLogger) { this.userEventService = userEventService; - this.accessControlAuditLogger = accessControlAuditLogger; + this.auditLogger = auditLogger; } @Override @@ -33,7 +33,7 @@ public void onAuthenticationFailure( throws ServletException, IOException { userEventService.createLoginFailedEvent( request.getRequestURI(), exception.getClass().getSimpleName()); - accessControlAuditLogger.logAuthEvent( + auditLogger.logAuthEvent( "login", "error", request.getRequestURI(), exception.getClass().getSimpleName(), null); this.saveException(request, exception); diff --git a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java index e493df0f851..672b02da4e5 100644 --- a/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java +++ b/openaev-api/src/main/java/io/openaev/security/SsoRefererAuthenticationSuccessHandler.java @@ -2,7 +2,7 @@ import static org.springframework.http.HttpHeaders.REFERER; -import io.openaev.aop.audit_log.AccessControlAuditLogger; +import io.openaev.aop.audit_log.AuditLogger; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -18,10 +18,10 @@ public class SsoRefererAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final RequestCache requestCache = new HttpSessionRequestCache(); - private final AccessControlAuditLogger accessControlAuditLogger; + private final AuditLogger auditLogger; - public SsoRefererAuthenticationSuccessHandler(AccessControlAuditLogger accessControlAuditLogger) { - this.accessControlAuditLogger = accessControlAuditLogger; + public SsoRefererAuthenticationSuccessHandler(AuditLogger auditLogger) { + this.auditLogger = auditLogger; } @Override @@ -40,7 +40,7 @@ public void onAuthenticationSuccess( // Never block the login flow } - accessControlAuditLogger.logAuthEvent("login", "success", provider, null, null); + auditLogger.logAuthEvent("login", "success", provider, null, null); SavedRequest savedRequest = this.requestCache.getRequest(request, response); From e4597b1393092618972f5e366c191d0a49df1039 Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 11:46:06 +0100 Subject: [PATCH 09/11] [backend] feat(audit-log): lint code (#5483) --- .../io/openaev/aop/audit_log/AccessControlAuditLogAspect.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java index 64b64ef3266..0cbb49767ff 100644 --- a/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java +++ b/openaev-api/src/main/java/io/openaev/aop/audit_log/AccessControlAuditLogAspect.java @@ -57,9 +57,7 @@ public Object auditAround(ProceedingJoinPoint joinPoint, AccessControl accessCon try { action = accessControl.actionPerformed(); - isActive = - auditLogger.isAuditLoggingEnabled() - && auditLogger.isAuditLoggingValid(action); + isActive = auditLogger.isAuditLoggingEnabled() && auditLogger.isAuditLoggingValid(action); } catch (Exception ex) { log.warn("Error during audit logging", ex); } From 9cdeaa7e8999317f493d97dcca183d2adcf613a2 Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 11:51:08 +0100 Subject: [PATCH 10/11] [backend] feat(audit-log): change something so CI tools run (#5483) --- .../src/main/java/io/openaev/config/AppSecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index 23463b9f710..5988d7eec91 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -136,7 +136,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { } catch (Exception e) { // Never block the logout flow log.error( - "Failed to prepare request context on logout event: {}", + "Failed to prepare request context on logout handler: {}", e.getMessage(), e); } From 23abdf92e4b81924f1df216c819e2364729a236e Mon Sep 17 00:00:00 2001 From: JP - Joao Pinto Date: Tue, 26 May 2026 11:57:28 +0100 Subject: [PATCH 11/11] [backend] feat(audit-log): change something so CI tools run, since it didn't work the before (#5483) --- .../src/main/java/io/openaev/config/AppSecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java index 5988d7eec91..be36db6b75b 100644 --- a/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java +++ b/openaev-api/src/main/java/io/openaev/config/AppSecurityConfig.java @@ -136,7 +136,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { } catch (Exception e) { // Never block the logout flow log.error( - "Failed to prepare request context on logout handler: {}", + "Failed to prepare request context on the logout callback handler: {}", e.getMessage(), e); }