Merge pull request #41278 from Chu3laMan

* pr/41278:
  Polish "Publish an AuditEvent on logout"
  Publish an AuditEvent on logout

Closes gh-41278
This commit is contained in:
Moritz Halbritter 2024-07-03 10:41:44 +02:00
commit edafc78375
2 changed files with 27 additions and 0 deletions

View File

@ -24,6 +24,7 @@ import org.springframework.boot.actuate.audit.AuditEvent;
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,13 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList
*/
public static final String AUTHENTICATION_SWITCH = "AUTHENTICATION_SWITCH";
/**
* Logout success event type.
*
* @since 3.4.0
*/
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 +81,9 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList
else if (event instanceof AuthenticationSuccessEvent successEvent) {
onAuthenticationSuccessEvent(successEvent);
}
else if (event instanceof LogoutSuccessEvent logoutSuccessEvent) {
onLogoutSuccessEvent(logoutSuccessEvent);
}
}
private void onAuthenticationFailureEvent(AbstractAuthenticationFailureEvent event) {
@ -93,6 +104,14 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList
publish(new AuditEvent(event.getAuthentication().getName(), AUTHENTICATION_SUCCESS, data));
}
private void onLogoutSuccessEvent(LogoutSuccessEvent event) {
Map<String, Object> data = new LinkedHashMap<>();
if (event.getAuthentication().getDetails() != null) {
data.put("details", event.getAuthentication().getDetails());
}
publish(new AuditEvent(event.getAuthentication().getName(), LOGOUT_SUCCESS, data));
}
private static final class WebAuditListener {
void process(AuthenticationAuditListener listener, AbstractAuthenticationEvent input) {

View File

@ -29,6 +29,7 @@ import org.springframework.security.authentication.event.AbstractAuthenticationE
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 @@ class AuthenticationAuditListenerTests {
assertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SUCCESS);
}
@Test
void testLogoutSuccess() {
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(