diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java index f35bd905935a..5199d3f94242 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java @@ -24,6 +24,7 @@ import org.springframework.security.authentication.event.AbstractAuthenticationEvent; import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.authentication.event.LogoutSuccessEvent; import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent; import org.springframework.util.ClassUtils; @@ -51,6 +52,8 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList */ public static final String AUTHENTICATION_SWITCH = "AUTHENTICATION_SWITCH"; + public static final String LOGOUT_SUCCESS = "LOGOUT_SUCCESS"; + private static final String WEB_LISTENER_CHECK_CLASS = "org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent"; private final WebAuditListener webListener = maybeCreateWebListener(); @@ -73,6 +76,9 @@ else if (this.webListener != null && this.webListener.accepts(event)) { else if (event instanceof AuthenticationSuccessEvent successEvent) { onAuthenticationSuccessEvent(successEvent); } + else if(event instanceof LogoutSuccessEvent logoutSuccessEvent) { + onLogoutSuccessEvent(logoutSuccessEvent); + } } private void onAuthenticationFailureEvent(AbstractAuthenticationFailureEvent event) { @@ -93,6 +99,18 @@ private void onAuthenticationSuccessEvent(AuthenticationSuccessEvent event) { publish(new AuditEvent(event.getAuthentication().getName(), AUTHENTICATION_SUCCESS, data)); } + private void onLogoutSuccessEvent(LogoutSuccessEvent event) { + Map data = new LinkedHashMap<>(); + if(event.getAuthentication() != null) { + if(event.getAuthentication().getDetails() != null) { + data.put("details", event.getAuthentication().getDetails()); + } + data.put("username", event.getAuthentication().getName()); + } + publish(new AuditEvent(event.getAuthentication().getName(), LOGOUT_SUCCESS, data)); + + } + private static final class WebAuditListener { void process(AuthenticationAuditListener listener, AbstractAuthenticationEvent input) { diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java index 77f973c65649..04d22ab9ad51 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java @@ -29,6 +29,7 @@ import org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; +import org.springframework.security.authentication.event.LogoutSuccessEvent; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent; @@ -60,6 +61,13 @@ void testAuthenticationSuccess() { assertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SUCCESS); } + @Test + void testLogoutSucess() { + AuditApplicationEvent event = handleAuthenticationEvent( + new LogoutSuccessEvent(new UsernamePasswordAuthenticationToken("user", "password"))); + assertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.LOGOUT_SUCCESS); + } + @Test void testOtherAuthenticationSuccess() { this.listener.onApplicationEvent(new InteractiveAuthenticationSuccessEvent(