Skip to content

Commit

Permalink
HTM-1161: Add authentication event logging (#976)
Browse files Browse the repository at this point in the history
* Add authentication event logging

* Improve auth logging
  • Loading branch information
matthijsln authored Oct 10, 2024
1 parent 1b3b630 commit d2148ac
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,26 @@
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.Cookie;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
Expand All @@ -37,6 +42,8 @@
import org.tailormap.api.persistence.Group;
import org.tailormap.api.repository.GroupRepository;
import org.tailormap.api.repository.OIDCConfigurationRepository;
import org.tailormap.api.security.events.DefaultAuthenticationFailureEvent;
import org.tailormap.api.security.events.OAuth2AuthenticationFailureEvent;

@Configuration
@EnableWebSecurity
Expand Down Expand Up @@ -69,6 +76,22 @@ public CookieCsrfTokenRepository csrfTokenRepository() {
return csrfTokenRepository;
}

@Bean
public AuthenticationEventPublisher authenticationEventPublisher(
ApplicationEventPublisher applicationEventPublisher) {
DefaultAuthenticationEventPublisher authenticationEventPublisher =
new DefaultAuthenticationEventPublisher(applicationEventPublisher);

authenticationEventPublisher.setAdditionalExceptionMappings(
Collections.singletonMap(
OAuth2AuthenticationException.class, OAuth2AuthenticationFailureEvent.class));

authenticationEventPublisher.setDefaultAuthenticationFailureEvent(
DefaultAuthenticationFailureEvent.class);

return authenticationEventPublisher;
}

@Bean
public SecurityFilterChain apiFilterChain(
HttpSecurity http, CookieCsrfTokenRepository csrfTokenRepository) throws Exception {
Expand Down
86 changes: 86 additions & 0 deletions src/main/java/org/tailormap/api/security/AuthenticationEvents.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2024 B3Partners B.V.
*
* SPDX-License-Identifier: MIT
*/

package org.tailormap.api.security;

import java.lang.invoke.MethodHandles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;
import org.tailormap.api.security.events.DefaultAuthenticationFailureEvent;
import org.tailormap.api.security.events.OAuth2AuthenticationFailureEvent;

@Component
public class AuthenticationEvents {
private static final Logger logger =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

private static String getExtraInfo(AbstractAuthenticationEvent event) {
String extraInfo = "";
if (logger.isTraceEnabled()
&& event.getAuthentication().getDetails() instanceof WebAuthenticationDetails details) {
extraInfo = String.format(" (IP: %s)", details.getRemoteAddress());
}
return extraInfo;
}

@EventListener
public void onSuccess(AuthenticationSuccessEvent success) {
String authInfo = "";
if (success.getSource() instanceof OAuth2LoginAuthenticationToken token) {
String userClaims = "";
if (token.getPrincipal() instanceof DefaultOidcUser oidcUser) {
userClaims = ", user claims: " + oidcUser.getUserInfo().getClaims();
}
authInfo =
String.format(
"via OIDC registration \"%s\" with client ID %s%s",
token.getClientRegistration().getClientName(),
token.getClientRegistration().getClientId(),
userClaims);
}
if (success.getSource() instanceof UsernamePasswordAuthenticationToken) {
authInfo = "using username/password";
}
logger.info(
"Authentication successful for user \"{}\"{}, granted authorities: {}, {}",
success.getAuthentication().getName(),
getExtraInfo(success),
success.getAuthentication().getAuthorities().toString(),
authInfo);
}

@EventListener
public void onFailure(AbstractAuthenticationFailureEvent failure) {
String userInfo = "";
if (failure.getAuthentication().getPrincipal() != null) {
userInfo = String.format(" for user \"%s\"", failure.getAuthentication().getPrincipal());
}
logger.info(
"Authentication failure: {} {}{}",
failure.getException().getMessage(),
userInfo,
getExtraInfo(failure));
}

@EventListener
public void onOAuth2AuthenticationFailureEvent(OAuth2AuthenticationFailureEvent event) {
logger.info("OAuth2 authentication failure: {}, {}", event.getException().getMessage(), event);
}

@EventListener
public void onDefaultAuthenticationFailureEvent(DefaultAuthenticationFailureEvent event) {
logger.info("Default authentication failure", event.getException());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 B3Partners B.V.
*
* SPDX-License-Identifier: MIT
*/

package org.tailormap.api.security.events;

import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public class DefaultAuthenticationFailureEvent extends AbstractAuthenticationFailureEvent {

public DefaultAuthenticationFailureEvent(
Authentication authentication, AuthenticationException exception) {
super(authentication, exception);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 B3Partners B.V.
*
* SPDX-License-Identifier: MIT
*/

package org.tailormap.api.security.events;

import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public class OAuth2AuthenticationFailureEvent extends AbstractAuthenticationFailureEvent {

public OAuth2AuthenticationFailureEvent(
Authentication authentication, AuthenticationException exception) {
super(authentication, exception);
}
}
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,4 @@ logging.include-application-name=false

logging.group.tailormap=org.tailormap
logging.group.geotools=org.geotools
logging.group.auth=org.tailormap.api.security.AuthenticationEvents

0 comments on commit d2148ac

Please sign in to comment.