Spring Boot Actuator предоставляет возможности аудита для публикации и прослушивания связанных с безопасностью событий в приложении Spring Boot с включенной Spring Security. События по умолчанию — это успешная аутентификация, неудачная аутентификация и отказ в доступе, но они могут быть расширены с помощью пользовательских событий.
Убедитесь, что в вашем проекте включены Spring Boot Security и Actuator
1
2
3
4
5
6
7
8
|
< dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-security</ artifactId > </ dependency > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-actuator</ artifactId > </ dependency > |
/auditevents
точка Actuator /auditevents
По умолчанию /auditevents
точка /auditevents
включена, поэтому после запуска приложения (и входа в систему с именем user
и паролем, указанным в журнале приложения) вы можете видеть текущие события безопасности:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
{ "events" : [ { "timestamp" : "2017-03-14T22:59:58+0000" , "principal" : "user" , "type" : "AUTHENTICATION_FAILURE" , "data" : { "details" : { "remoteAddress" : "0:0:0:0:0:0:0:1" , "sessionId" : null }, "type" : "org.springframework.security.authentication.BadCredentialsException" , "message" : "Bad credentials" } }, { "timestamp" : "2017-03-14T23:00:07+0000" , "principal" : "user" , "type" : "AUTHENTICATION_SUCCESS" , "data" : { "details" : { "remoteAddress" : "0:0:0:0:0:0:0:1" , "sessionId" : null } } } ] } |
/auditevents
точка /auditevents
принимает необязательные параметры запроса:
-
pricipal
— главное имя -
after
— дата после события произошла в следующем формате:yyyy-MM-dd'T'HH:mm:ssZ
-
type
—type
события (например, AUTHORIZATION_FAILURE, AUTHENTICATION_SUCCESS, AUTHENTICATION_FAILURE, AUTHENTICATION_SWITCH)
Пример запроса:
Реализация конечной точки использует org.springframework.boot.actuate.audit.AuditEventRepository
для возврата всех зарегистрированных событий аудита.
- Настроить
/auditevents
конечную точку
Вы можете настроить конечную точку с помощью свойств endpoints.auditevents.*
. Например, чтобы изменить путь конечной точки событий аудита, просто используйте свойство endpoints.auditevents.path
.
Прослушивание событий аудита безопасности с @EventListener
События безопасности представлены org.springframework.boot.actuate.audit.AuditEvent
значения org.springframework.boot.actuate.audit.AuditEvent
в приводе. Этот объект содержит метку времени, имя пользователя, тип события и данные события.
Самый простой способ получить уведомление о событиях аудита — подписаться на события org.springframework.boot.actuate.audit.listener.AuditApplicationEvent
помощью Spring org.springframework.context.event.EventListener
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
@Component public class AuditApplicationEventListener { private static final Logger LOG = LoggerFactory.getLogger(AuditApplicationEventListener. class ); @EventListener public void onAuditEvent(AuditApplicationEvent event) { AuditEvent actualAuditEvent = event.getAuditEvent(); LOG.info( "On audit application event: timestamp: {}, principal: {}, type: {}, data: {}" , actualAuditEvent.getTimestamp(), actualAuditEvent.getPrincipal(), actualAuditEvent.getType(), actualAuditEvent.getData() ); } } |
Пример вывода:
1
|
2017 - 03 - 15 00 : 44 : 12.921 INFO 13316 --- [nio- 8080 -exec- 1 ] p.c.d.s.s.AuditApplicationEventListener : On audit event: timestamp: Wed Mar 15 00 : 44 : 12 CET 2017 , principal: user, type: AUTHENTICATION_SUCCESS, data: {details=org.springframework.security.web.authentication.WebAuthenticationDetails @b364 : RemoteIpAddress: 0 : 0 : 0 : 0 : 0 : 0 : 0 : 1 ; SessionId: null } |
Асинхронные события
@EventListener
является синхронным, но если требуется асинхронное поведение, вы можете аннотировать метод прослушивателя событий с помощью @Async
и убедиться, что асинхронность включена (например, через @EnableAsync
):
01
02
03
04
05
06
07
08
09
10
11
|
@Component public class AuditApplicationEventListener { private static final Logger LOG = LoggerFactory.getLogger(AuditApplicationEventListener. class ); @EventListener @Async public void onAuditEvent(AuditApplicationEvent event) { } } |
И конфигурация:
1
2
3
4
5
6
7
8
|
@SpringBootApplication @EnableAsync public class Application { public static void main(String[] args) { SpringApplication.run(Application. class ); } } |
Прослушивание событий аудита безопасности с AbstractAuditListener
Кроме того, вы можете расширить org.springframework.boot.actuate.audit.listener.AbstractAuditListener
и переопределить его org.springframework.boot.actuate.audit.listener.AbstractAuditListener#onAuditEvent
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
@Component public class AuditEventListener extends AbstractAuditListener { private static final Logger LOG = LoggerFactory.getLogger(AuditEventListener. class ); @Override protected void onAuditEvent(AuditEvent event) { LOG.info( "On audit event: timestamp: {}, principal: {}, type: {}, data: {}" , event.getTimestamp(), event.getPrincipal(), event.getType(), event.getData() ); } } |
Примечание. Никакие события не будут храниться в репозитории событий, поэтому /auditevents
точка /auditevents
всегда будет возвращать пустой массив. Чтобы это исправить, вы можете внедрить хранилище аудита или расширить его непосредственно из org.springframework.boot.actuate.audit.listener.AuditListener
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
@Component public class AuditEventListener extends AbstractAuditListener { private static final Logger LOG = LoggerFactory.getLogger(AuditEventListener. class ); @Autowired private AuditEventRepository auditEventRepository; @Override protected void onAuditEvent(AuditEvent event) { LOG.info( "On audit event: timestamp: {}, principal: {}, type: {}, data: {}" , event.getTimestamp(), event.getPrincipal(), event.getType(), event.getData() ); auditEventRepository.add(event); } } |
Публикация собственных аудиторских событий с издателем событий
В приведенном ниже примере издатель событий приложения ( org.springframework.context.ApplicationEventPublisher
) используется для публикации настраиваемого события аудита с типом CUSTOM_AUDIT_EVENT
. Новый метод слушателя прослушивает только эти новые события, тогда как предыдущий метод игнорирует их (обратите внимание, что это только пример). Как и любые другие события, пользовательские будут храниться с использованием репозитория событий аудита.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@Component public class AuditApplicationEventListener { private static final Logger LOG = LoggerFactory.getLogger(AuditApplicationEventListener. class ); @Autowired private ApplicationEventPublisher applicationEventPublisher; @EventListener (condition = "#event.auditEvent.type != 'CUSTOM_AUDIT_EVENT'" ) @Async public void onAuditEvent(AuditApplicationEvent event) { AuditEvent actualAuditEvent = event.getAuditEvent(); LOG.info( "On audit application event: timestamp: {}, principal: {}, type: {}, data: {}" , actualAuditEvent.getTimestamp(), actualAuditEvent.getPrincipal(), actualAuditEvent.getType(), actualAuditEvent.getData() ); applicationEventPublisher.publishEvent( new AuditApplicationEvent( new AuditEvent(actualAuditEvent.getPrincipal(), "CUSTOM_AUDIT_EVENT" ) ) ); } @EventListener (condition = "#event.auditEvent.type == 'CUSTOM_AUDIT_EVENT'" ) public void onCustomAuditEvent(AuditApplicationEvent event) { LOG.info( "Handling custom audit event ..." ); } } |
Обратите внимание на пример кода
Пример кода для этой статьи можно найти в репозитории spring-boot-thymeleaf . По умолчанию безопасность отключена в обоих профилях. Включите его, изменив свойство security.basic.enabled
в application.properties
.
Ссылка: | Весенняя загрузка и события безопасности с Actuator от нашего партнера JCG Рафаля Боровца в блоге Codeleak.pl . |