From 3724db9eccc24383c47647c6b92caa50d5b367a2 Mon Sep 17 00:00:00 2001 From: mkwaczynski Date: Wed, 20 Jan 2016 10:08:27 +0100 Subject: [PATCH 1/2] Include details in AuditEvent data in AuthenticationAuditListener Closes gh-4976 --- .../security/AuthenticationAuditListener.java | 3 ++ .../AuthenticationAuditListenerTests.java | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+) 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 87ff5f6fb0d..4f85b867013 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 @@ -61,6 +61,9 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList Map data = new HashMap(); data.put("type", event.getException().getClass().getName()); data.put("message", event.getException().getMessage()); + if (event.getAuthentication().getDetails() != null) { + data.put("details", event.getAuthentication().getDetails()); + } publish(new AuditEvent(event.getAuthentication().getName(), "AUTHENTICATION_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 aca33b18031..59823e51a3b 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 @@ -16,9 +16,13 @@ package org.springframework.boot.actuate.security; +import java.util.Map; + 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.authentication.BadCredentialsException; @@ -30,6 +34,8 @@ import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent; +import static org.hamcrest.Matchers.hasEntry; +import static org.junit.Assert.assertThat; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -82,4 +88,32 @@ public class AuthenticationAuditListenerTests { verify(this.publisher).publishEvent((ApplicationEvent) anyObject()); } + @Test + public void shouldPassDetailsToAuditEventOnAuthenticationFailureEvent() + throws Exception { + // given + final Object details = new Object(); + final AuthenticationFailureExpiredEvent event = + createAuthenticationFailureEvent(details); + + // when + this.listener.onApplicationEvent(event); + + // then + final ArgumentCaptor applicationEventArgumentCaptor = + ArgumentCaptor.forClass(AuditApplicationEvent.class); + verify(this.publisher).publishEvent(applicationEventArgumentCaptor.capture()); + final Map eventData = + applicationEventArgumentCaptor.getValue().getAuditEvent().getData(); + assertThat(eventData, hasEntry("details", details)); + } + + private AuthenticationFailureExpiredEvent createAuthenticationFailureEvent( + final Object details) { + final UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken("user", "password"); + authentication.setDetails(details); + final BadCredentialsException exception = new BadCredentialsException("Bad user"); + return new AuthenticationFailureExpiredEvent(authentication, exception); + } } From 2f24c1862a040e08cb6d7887adab817db6e57dc8 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 20 Jan 2016 10:13:11 +0000 Subject: [PATCH 2/2] Polish contribution --- .../security/AuthenticationAuditListener.java | 2 +- .../AuthenticationAuditListenerTests.java | 40 ++++++------------- 2 files changed, 13 insertions(+), 29 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 4f85b867013..072c81c71b5 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. 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 59823e51a3b..216b06fbd9b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,6 @@ package org.springframework.boot.actuate.security; -import java.util.Map; - import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -89,31 +87,17 @@ public class AuthenticationAuditListenerTests { } @Test - public void shouldPassDetailsToAuditEventOnAuthenticationFailureEvent() - throws Exception { - // given - final Object details = new Object(); - final AuthenticationFailureExpiredEvent event = - createAuthenticationFailureEvent(details); - - // when - this.listener.onApplicationEvent(event); - - // then - final ArgumentCaptor applicationEventArgumentCaptor = - ArgumentCaptor.forClass(AuditApplicationEvent.class); - verify(this.publisher).publishEvent(applicationEventArgumentCaptor.capture()); - final Map eventData = - applicationEventArgumentCaptor.getValue().getAuditEvent().getData(); - assertThat(eventData, hasEntry("details", details)); - } - - private AuthenticationFailureExpiredEvent createAuthenticationFailureEvent( - final Object details) { - final UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken("user", "password"); + public void testDetailsAreIncludedInAuditEvent() throws Exception { + Object details = new Object(); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "user", "password"); authentication.setDetails(details); - final BadCredentialsException exception = new BadCredentialsException("Bad user"); - return new AuthenticationFailureExpiredEvent(authentication, exception); + this.listener.onApplicationEvent(new AuthenticationFailureExpiredEvent( + authentication, new BadCredentialsException("Bad user"))); + ArgumentCaptor auditApplicationEvent = ArgumentCaptor + .forClass(AuditApplicationEvent.class); + verify(this.publisher).publishEvent(auditApplicationEvent.capture()); + assertThat(auditApplicationEvent.getValue().getAuditEvent().getData(), + hasEntry("details", details)); } }