Suporte para auditoria de autenticação de inicialização Spring
1. Visão geral
Neste breve artigo, exploraremos o módulo Spring Boot Actuator e o suporte para publicar eventos de autenticação e autorização em conjunto com Spring Security.
2. Dependências do Maven
Primeiro, precisamos adicionarspring-boot-starter-actuator ao nossopom.xml:
org.springframework.boot
spring-boot-starter-actuator
2.1.7.RELEASE
A versão mais recente está disponível no repositórioMaven Central.
3. Ouvindo eventos de autenticação e autorização
Para registrar todas as tentativas de autenticação e autorização em um aplicativo Spring Boot, podemos apenas definir um bean com um método listener:
@Component
public class LoginAttemptsLogger {
@EventListener
public void auditEventHappened(
AuditApplicationEvent auditApplicationEvent) {
AuditEvent auditEvent = auditApplicationEvent.getAuditEvent();
System.out.println("Principal " + auditEvent.getPrincipal()
+ " - " + auditEvent.getType());
WebAuthenticationDetails details =
(WebAuthenticationDetails) auditEvent.getData().get("details");
System.out.println("Remote IP address: "
+ details.getRemoteAddress());
System.out.println(" Session Id: " + details.getSessionId());
}
}
Observe que estamos apenas gerando algumas das coisas que estão disponíveis emAuditApplicationEvent para mostrar quais informações estão disponíveis. Em um aplicativo real, convém armazenar essas informações em um repositório ou cache para processá-las ainda mais.
Observe que qualquer bean Spring funcionará; os princípios básicos do novo suporte a eventos da Primavera são bastante simples:
-
anote o método com@EventListener
-
adicioneAuditApplicationEvent como o único argumento do método
A saída da execução do aplicativo será parecida com esta:
Principal anonymousUser - AUTHORIZATION_FAILURE Remote IP address: 0:0:0:0:0:0:0:1 Session Id: null Principal user - AUTHENTICATION_FAILURE Remote IP address: 0:0:0:0:0:0:0:1 Session Id: BD41692232875A5A65C5E35E63D784F6 Principal user - AUTHENTICATION_SUCCESS Remote IP address: 0:0:0:0:0:0:0:1 Session Id: BD41692232875A5A65C5E35E63D784F6
Neste exemplo, trêsAuditApplicationEvents foram recebidos pelo ouvinte:
-
Sem fazer logon, o acesso foi solicitado a uma página restrita
-
Uma senha incorreta foi usada durante o logon
-
Uma senha correta foi usada na segunda vez
4. Um ouvinte de auditoria de autenticação
Se a informação exposta porAuthorizationAuditListener do Spring Boot não for suficiente, você podecreate your own bean to expose more information.
Vejamos um exemplo, onde também expomos o URL de solicitação que foi acessado quando a autorização falhou:
@Component
public class ExposeAttemptedPathAuthorizationAuditListener
extends AbstractAuthorizationAuditListener {
public static final String AUTHORIZATION_FAILURE
= "AUTHORIZATION_FAILURE";
@Override
public void onApplicationEvent(AbstractAuthorizationEvent event) {
if (event instanceof AuthorizationFailureEvent) {
onAuthorizationFailureEvent((AuthorizationFailureEvent) event);
}
}
private void onAuthorizationFailureEvent(
AuthorizationFailureEvent event) {
Map data = new HashMap<>();
data.put(
"type", event.getAccessDeniedException().getClass().getName());
data.put("message", event.getAccessDeniedException().getMessage());
data.put(
"requestUrl", ((FilterInvocation)event.getSource()).getRequestUrl() );
if (event.getAuthentication().getDetails() != null) {
data.put("details",
event.getAuthentication().getDetails());
}
publish(new AuditEvent(event.getAuthentication().getName(),
AUTHORIZATION_FAILURE, data));
}
}
Agora podemos registrar o URL da solicitação em nosso ouvinte:
@Component
public class LoginAttemptsLogger {
@EventListener
public void auditEventHappened(
AuditApplicationEvent auditApplicationEvent) {
AuditEvent auditEvent = auditApplicationEvent.getAuditEvent();
System.out.println("Principal " + auditEvent.getPrincipal()
+ " - " + auditEvent.getType());
WebAuthenticationDetails details
= (WebAuthenticationDetails) auditEvent.getData().get("details");
System.out.println(" Remote IP address: "
+ details.getRemoteAddress());
System.out.println(" Session Id: " + details.getSessionId());
System.out.println(" Request URL: "
+ auditEvent.getData().get("requestUrl"));
}
}
Como resultado, a saída agora contém o URL solicitado:
Principal anonymousUser - AUTHORIZATION_FAILURE Remote IP address: 0:0:0:0:0:0:0:1 Session Id: null Request URL: /hello
Observe que estendemos a partir doAbstractAuthorizationAuditListener abstrato neste exemplo, então podemos usar o métodopublish dessa classe base em nossa implementação.
Se você quiser testá-lo, verifique o código-fonte e execute:
mvn clean spring-boot:run
Depois disso, você pode apontar seu navegador parahttp://localhost:8080/
.
5. Armazenamento de eventos de auditoria
Por padrão, o Spring Boot armazena os eventos de auditoria em umAuditEventRepository. Se você não criar um bean com uma implementação própria, umInMemoryAuditEventRepository será instalado para você.
OInMemoryAuditEventRepository é um tipo de buffer circular que armazena os últimos 4000 eventos de auditoria na memória. Esses eventos podem ser acessados por meio do endpoint de gerenciamentohttp://localhost:8080/auditevents
.
Isso retorna uma representação JSON dos eventos de auditoria:
{
"events": [
{
"timestamp": "2017-03-09T19:21:59+0000",
"principal": "anonymousUser",
"type": "AUTHORIZATION_FAILURE",
"data": {
"requestUrl": "/auditevents",
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": null
},
"type": "org.springframework.security.access.AccessDeniedException",
"message": "Access is denied"
}
},
{
"timestamp": "2017-03-09T19:22:00+0000",
"principal": "anonymousUser",
"type": "AUTHORIZATION_FAILURE",
"data": {
"requestUrl": "/favicon.ico",
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "18FA15865F80760521BBB736D3036901"
},
"type": "org.springframework.security.access.AccessDeniedException",
"message": "Access is denied"
}
},
{
"timestamp": "2017-03-09T19:22:03+0000",
"principal": "user",
"type": "AUTHENTICATION_SUCCESS",
"data": {
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "18FA15865F80760521BBB736D3036901"
}
}
}
]
}
6. Conclusão
Com o suporte do atuador no Spring Boot, torna-se trivial registrar as tentativas de autenticação e autorização dos usuários. O leitor também é referido aproduction ready auditing para algumas informações adicionais.
O código deste artigo pode ser encontradoover on GitHub.