diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java index 072c81c71b..a4660cbc8d 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java @@ -30,9 +30,25 @@ import org.springframework.util.ClassUtils; * Default implementation of {@link AbstractAuthenticationAuditListener}. * * @author Dave Syer + * @author Vedran Pavic */ public class AuthenticationAuditListener extends AbstractAuthenticationAuditListener { + /** + * Authentication success event type. + */ + public static final String AUTHENTICATION_SUCCESS = "AUTHENTICATION_SUCCESS"; + + /** + * Authentication failure event type. + */ + public static final String AUTHENTICATION_FAILURE = "AUTHENTICATION_FAILURE"; + + /** + * Authentication switch event type. + */ + public static final String AUTHENTICATION_SWITCH = "AUTHENTICATION_SWITCH"; + private static final String WEB_LISTENER_CHECK_CLASS = "org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent"; private WebAuditListener webListener = maybeCreateWebListener(); @@ -65,7 +81,7 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList data.put("details", event.getAuthentication().getDetails()); } publish(new AuditEvent(event.getAuthentication().getName(), - "AUTHENTICATION_FAILURE", data)); + AUTHENTICATION_FAILURE, data)); } private void onAuthenticationSuccessEvent(AuthenticationSuccessEvent event) { @@ -74,7 +90,7 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList data.put("details", event.getAuthentication().getDetails()); } publish(new AuditEvent(event.getAuthentication().getName(), - "AUTHENTICATION_SUCCESS", data)); + AUTHENTICATION_SUCCESS, data)); } private static class WebAuditListener { @@ -89,7 +105,7 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList } data.put("target", event.getTargetUser().getUsername()); listener.publish(new AuditEvent(event.getAuthentication().getName(), - "AUTHENTICATION_SWITCH", data)); + AUTHENTICATION_SWITCH, data)); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthorizationAuditListener.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthorizationAuditListener.java index 06e6c189bc..387cf3c42f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthorizationAuditListener.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthorizationAuditListener.java @@ -28,9 +28,15 @@ import org.springframework.security.access.event.AuthorizationFailureEvent; * Default implementation of {@link AbstractAuthorizationAuditListener}. * * @author Dave Syer + * @author Vedran Pavic */ public class AuthorizationAuditListener extends AbstractAuthorizationAuditListener { + /** + * Authorization failure event type. + */ + public static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; + @Override public void onApplicationEvent(AbstractAuthorizationEvent event) { if (event instanceof AuthenticationCredentialsNotFoundEvent) { @@ -47,7 +53,8 @@ public class AuthorizationAuditListener extends AbstractAuthorizationAuditListen Map data = new HashMap(); data.put("type", event.getCredentialsNotFoundException().getClass().getName()); data.put("message", event.getCredentialsNotFoundException().getMessage()); - publish(new AuditEvent("", "AUTHENTICATION_FAILURE", data)); + publish(new AuditEvent("", + AuthenticationAuditListener.AUTHENTICATION_FAILURE, data)); } private void onAuthorizationFailureEvent(AuthorizationFailureEvent event) { @@ -58,7 +65,7 @@ public class AuthorizationAuditListener extends AbstractAuthorizationAuditListen data.put("details", event.getAuthentication().getDetails()); } publish(new AuditEvent(event.getAuthentication().getName(), - "AUTHORIZATION_FAILURE", data)); + AUTHORIZATION_FAILURE, data)); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java index 4c77b85ce4..580477399f 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java @@ -25,6 +25,7 @@ import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.event.AbstractAuthenticationEvent; import org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; @@ -55,9 +56,11 @@ public class AuthenticationAuditListenerTests { @Test public void testAuthenticationSuccess() { - this.listener.onApplicationEvent(new AuthenticationSuccessEvent( - new UsernamePasswordAuthenticationToken("user", "password"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + AuditApplicationEvent event = handleAuthenticationEvent( + new AuthenticationSuccessEvent( + new UsernamePasswordAuthenticationToken("user", "password"))); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SUCCESS); } @Test @@ -70,19 +73,23 @@ public class AuthenticationAuditListenerTests { @Test public void testAuthenticationFailed() { - this.listener.onApplicationEvent(new AuthenticationFailureExpiredEvent( - new UsernamePasswordAuthenticationToken("user", "password"), - new BadCredentialsException("Bad user"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + AuditApplicationEvent event = handleAuthenticationEvent( + new AuthenticationFailureExpiredEvent( + new UsernamePasswordAuthenticationToken("user", "password"), + new BadCredentialsException("Bad user"))); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE); } @Test public void testAuthenticationSwitch() { - this.listener.onApplicationEvent(new AuthenticationSwitchUserEvent( - new UsernamePasswordAuthenticationToken("user", "password"), - new User("user", "password", - AuthorityUtils.commaSeparatedStringToAuthorityList("USER")))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + AuditApplicationEvent event = handleAuthenticationEvent( + new AuthenticationSwitchUserEvent( + new UsernamePasswordAuthenticationToken("user", "password"), + new User("user", "password", + AuthorityUtils.commaSeparatedStringToAuthorityList("USER")))); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SWITCH); } @Test @@ -91,13 +98,21 @@ public class AuthenticationAuditListenerTests { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( "user", "password"); authentication.setDetails(details); - this.listener.onApplicationEvent(new AuthenticationFailureExpiredEvent( + AuditApplicationEvent event = handleAuthenticationEvent(new AuthenticationFailureExpiredEvent( authentication, new BadCredentialsException("Bad user"))); - ArgumentCaptor auditApplicationEvent = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(auditApplicationEvent.capture()); - assertThat(auditApplicationEvent.getValue().getAuditEvent().getData()) + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE); + assertThat(event.getAuditEvent().getData()) .containsEntry("details", details); } + private AuditApplicationEvent handleAuthenticationEvent( + AbstractAuthenticationEvent event) { + ArgumentCaptor eventCaptor = ArgumentCaptor + .forClass(AuditApplicationEvent.class); + this.listener.onApplicationEvent(event); + verify(this.publisher).publishEvent(eventCaptor.capture()); + return eventCaptor.getValue(); + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthorizationAuditListenerTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthorizationAuditListenerTests.java index 632ad65f35..7785202a52 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthorizationAuditListenerTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthorizationAuditListenerTests.java @@ -16,25 +16,24 @@ package org.springframework.boot.actuate.security; -import java.util.Arrays; +import java.util.Collections; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.springframework.boot.actuate.audit.listener.AuditApplicationEvent; -import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; +import org.springframework.security.access.event.AbstractAuthorizationEvent; import org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent; import org.springframework.security.access.event.AuthorizationFailureEvent; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -55,19 +54,23 @@ public class AuthorizationAuditListenerTests { @Test public void testAuthenticationCredentialsNotFound() { - this.listener.onApplicationEvent(new AuthenticationCredentialsNotFoundEvent(this, - Arrays.asList(new SecurityConfig("USER")), - new AuthenticationCredentialsNotFoundException("Bad user"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + AuditApplicationEvent event = handleAuthorizationEvent( + new AuthenticationCredentialsNotFoundEvent(this, + Collections.singletonList(new SecurityConfig("USER")), + new AuthenticationCredentialsNotFoundException("Bad user"))); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE); } @Test public void testAuthorizationFailure() { - this.listener.onApplicationEvent(new AuthorizationFailureEvent(this, - Arrays.asList(new SecurityConfig("USER")), - new UsernamePasswordAuthenticationToken("user", "password"), - new AccessDeniedException("Bad user"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + AuditApplicationEvent event = handleAuthorizationEvent( + new AuthorizationFailureEvent(this, + Collections.singletonList(new SecurityConfig("USER")), + new UsernamePasswordAuthenticationToken("user", "password"), + new AccessDeniedException("Bad user"))); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE); } @Test @@ -76,14 +79,22 @@ public class AuthorizationAuditListenerTests { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( "user", "password"); authentication.setDetails(details); - this.listener.onApplicationEvent(new AuthorizationFailureEvent(this, - Arrays.asList(new SecurityConfig("USER")), - authentication, new AccessDeniedException("Bad user"))); - ArgumentCaptor auditApplicationEvent = ArgumentCaptor + AuditApplicationEvent event = handleAuthorizationEvent( + new AuthorizationFailureEvent(this, + Collections.singletonList(new SecurityConfig("USER")), + authentication, new AccessDeniedException("Bad user"))); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE); + assertThat(event.getAuditEvent().getData()).containsEntry("details", details); + } + + private AuditApplicationEvent handleAuthorizationEvent( + AbstractAuthorizationEvent event) { + ArgumentCaptor eventCaptor = ArgumentCaptor .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(auditApplicationEvent.capture()); - assertThat(auditApplicationEvent.getValue().getAuditEvent().getData()) - .containsEntry("details", details); + this.listener.onApplicationEvent(event); + verify(this.publisher).publishEvent(eventCaptor.capture()); + return eventCaptor.getValue(); } }