From 899f7aa8f05f6aac90ce430c056c4b563797e969 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Thu, 8 Sep 2016 14:36:55 +0200 Subject: [PATCH 1/2] Add constants for supported audit event types See gh-6582 --- .../security/AuthenticationAuditListener.java | 22 ++++++++++++--- .../security/AuthorizationAuditListener.java | 11 ++++++-- .../AuthenticationAuditListenerTests.java | 27 ++++++++++++++----- .../AuthorizationAuditListenerTests.java | 24 +++++++++++------ 4 files changed, 65 insertions(+), 19 deletions(-) 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..727e0b578e 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 @@ -57,7 +57,11 @@ public class AuthenticationAuditListenerTests { public void testAuthenticationSuccess() { this.listener.onApplicationEvent(new AuthenticationSuccessEvent( new UsernamePasswordAuthenticationToken("user", "password"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + ArgumentCaptor argumentCaptor = ArgumentCaptor + .forClass(AuditApplicationEvent.class); + verify(this.publisher).publishEvent(argumentCaptor.capture()); + assertThat(argumentCaptor.getValue().getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SUCCESS); } @Test @@ -73,7 +77,11 @@ public class AuthenticationAuditListenerTests { this.listener.onApplicationEvent(new AuthenticationFailureExpiredEvent( new UsernamePasswordAuthenticationToken("user", "password"), new BadCredentialsException("Bad user"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + ArgumentCaptor argumentCaptor = ArgumentCaptor + .forClass(AuditApplicationEvent.class); + verify(this.publisher).publishEvent(argumentCaptor.capture()); + assertThat(argumentCaptor.getValue().getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE); } @Test @@ -82,7 +90,11 @@ public class AuthenticationAuditListenerTests { new UsernamePasswordAuthenticationToken("user", "password"), new User("user", "password", AuthorityUtils.commaSeparatedStringToAuthorityList("USER")))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + ArgumentCaptor argumentCaptor = ArgumentCaptor + .forClass(AuditApplicationEvent.class); + verify(this.publisher).publishEvent(argumentCaptor.capture()); + assertThat(argumentCaptor.getValue().getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SWITCH); } @Test @@ -93,10 +105,13 @@ public class AuthenticationAuditListenerTests { authentication.setDetails(details); this.listener.onApplicationEvent(new AuthenticationFailureExpiredEvent( authentication, new BadCredentialsException("Bad user"))); - ArgumentCaptor auditApplicationEvent = ArgumentCaptor + ArgumentCaptor argumentCaptor = ArgumentCaptor .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(auditApplicationEvent.capture()); - assertThat(auditApplicationEvent.getValue().getAuditEvent().getData()) + verify(this.publisher).publishEvent(argumentCaptor.capture()); + AuditApplicationEvent event = argumentCaptor.getValue(); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE); + assertThat(event.getAuditEvent().getData()) .containsEntry("details", details); } 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..d428d331ac 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 @@ -23,7 +23,6 @@ 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; @@ -34,7 +33,6 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF 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; @@ -58,7 +56,11 @@ public class AuthorizationAuditListenerTests { this.listener.onApplicationEvent(new AuthenticationCredentialsNotFoundEvent(this, Arrays.asList(new SecurityConfig("USER")), new AuthenticationCredentialsNotFoundException("Bad user"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + ArgumentCaptor eventArgumentCaptor = ArgumentCaptor + .forClass(AuditApplicationEvent.class); + verify(this.publisher).publishEvent(eventArgumentCaptor.capture()); + assertThat(eventArgumentCaptor.getValue().getAuditEvent().getType()) + .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE); } @Test @@ -67,7 +69,11 @@ public class AuthorizationAuditListenerTests { Arrays.asList(new SecurityConfig("USER")), new UsernamePasswordAuthenticationToken("user", "password"), new AccessDeniedException("Bad user"))); - verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); + ArgumentCaptor eventArgumentCaptor = ArgumentCaptor + .forClass(AuditApplicationEvent.class); + verify(this.publisher).publishEvent(eventArgumentCaptor.capture()); + assertThat(eventArgumentCaptor.getValue().getAuditEvent().getType()) + .isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE); } @Test @@ -79,11 +85,13 @@ public class AuthorizationAuditListenerTests { this.listener.onApplicationEvent(new AuthorizationFailureEvent(this, Arrays.asList(new SecurityConfig("USER")), authentication, new AccessDeniedException("Bad user"))); - ArgumentCaptor auditApplicationEvent = ArgumentCaptor + ArgumentCaptor eventArgumentCaptor = ArgumentCaptor .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(auditApplicationEvent.capture()); - assertThat(auditApplicationEvent.getValue().getAuditEvent().getData()) - .containsEntry("details", details); + verify(this.publisher).publishEvent(eventArgumentCaptor.capture()); + AuditApplicationEvent event = eventArgumentCaptor.getValue(); + assertThat(event.getAuditEvent().getType()) + .isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE); + assertThat(event.getAuditEvent().getData()).containsEntry("details", details); } } From 684be0f048b5ca7c32b87f8d309dabfd422ad931 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 16 Dec 2016 14:19:20 +0100 Subject: [PATCH 2/2] Polish contribution Closes gh-6852 --- .../AuthenticationAuditListenerTests.java | 52 +++++++++---------- .../AuthorizationAuditListenerTests.java | 49 +++++++++-------- 2 files changed, 52 insertions(+), 49 deletions(-) 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 727e0b578e..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,12 +56,10 @@ public class AuthenticationAuditListenerTests { @Test public void testAuthenticationSuccess() { - this.listener.onApplicationEvent(new AuthenticationSuccessEvent( - new UsernamePasswordAuthenticationToken("user", "password"))); - ArgumentCaptor argumentCaptor = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(argumentCaptor.capture()); - assertThat(argumentCaptor.getValue().getAuditEvent().getType()) + AuditApplicationEvent event = handleAuthenticationEvent( + new AuthenticationSuccessEvent( + new UsernamePasswordAuthenticationToken("user", "password"))); + assertThat(event.getAuditEvent().getType()) .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SUCCESS); } @@ -74,26 +73,22 @@ public class AuthenticationAuditListenerTests { @Test public void testAuthenticationFailed() { - this.listener.onApplicationEvent(new AuthenticationFailureExpiredEvent( - new UsernamePasswordAuthenticationToken("user", "password"), - new BadCredentialsException("Bad user"))); - ArgumentCaptor argumentCaptor = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(argumentCaptor.capture()); - assertThat(argumentCaptor.getValue().getAuditEvent().getType()) + 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")))); - ArgumentCaptor argumentCaptor = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(argumentCaptor.capture()); - assertThat(argumentCaptor.getValue().getAuditEvent().getType()) + AuditApplicationEvent event = handleAuthenticationEvent( + new AuthenticationSwitchUserEvent( + new UsernamePasswordAuthenticationToken("user", "password"), + new User("user", "password", + AuthorityUtils.commaSeparatedStringToAuthorityList("USER")))); + assertThat(event.getAuditEvent().getType()) .isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SWITCH); } @@ -103,16 +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 argumentCaptor = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(argumentCaptor.capture()); - AuditApplicationEvent event = argumentCaptor.getValue(); 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 d428d331ac..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,7 +16,7 @@ package org.springframework.boot.actuate.security; -import java.util.Arrays; +import java.util.Collections; import org.junit.Before; import org.junit.Test; @@ -27,6 +27,7 @@ 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; @@ -53,26 +54,22 @@ public class AuthorizationAuditListenerTests { @Test public void testAuthenticationCredentialsNotFound() { - this.listener.onApplicationEvent(new AuthenticationCredentialsNotFoundEvent(this, - Arrays.asList(new SecurityConfig("USER")), - new AuthenticationCredentialsNotFoundException("Bad user"))); - ArgumentCaptor eventArgumentCaptor = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(eventArgumentCaptor.capture()); - assertThat(eventArgumentCaptor.getValue().getAuditEvent().getType()) + 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"))); - ArgumentCaptor eventArgumentCaptor = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(eventArgumentCaptor.capture()); - assertThat(eventArgumentCaptor.getValue().getAuditEvent().getType()) + 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); } @@ -82,16 +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 eventArgumentCaptor = ArgumentCaptor - .forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(eventArgumentCaptor.capture()); - AuditApplicationEvent event = eventArgumentCaptor.getValue(); + 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); + this.listener.onApplicationEvent(event); + verify(this.publisher).publishEvent(eventCaptor.capture()); + return eventCaptor.getValue(); + } + }