1. Overview

In this article, We will learn Spring Security Oauth2 Success or Failed event listener. Auth2.0 authentication protocol is nowadays very popular for token-based authentication. OAuth workflow is consist of mainly two components one is authentication server and another is resource server.

In this article, We will learn how we can trace event while the user tries to get authentication token, the user may get success or failure and sometimes it’s important for the application to maintain that audit related to auth2 authentication success and failure. So here we try to explain how we can audit success or failure event to OAuth2 tokens.

Using @EventListener we can achieve authentication success and failure events. Register AuthenticationSuccessEvent and AbstractAuthenticationFailureEvent to track authentication success and failed as like:

For fauiler event, we can to check specific reason like Bad credencial or user locked using instanceof AbstractAuthenticationFailureEvent or we can also register specific event like AuthenticationFailureBadCredentialsEventAuthenticationFailureLockedEvent ect.

   @EventListener
   public void authSuccessEventListener(AuthenticationSuccessEvent authorizedEvent){
       // write custom code here for login success audit
       System.out.println("User Oauth2 login success");
       System.out.println("This is success event : "+authorizedEvent.getAuthentication().getPrincipal());
   }

   @EventListener
   public void authFailedEventListener(AbstractAuthenticationFailureEvent oAuth2AuthenticationFailureEvent){
       // write custom code here login failed audit.
       System.out.println("User Oauth2 login Failed");
       System.out.println(oAuth2AuthenticationFailureEvent.getAuthentication().getPrincipal());
   }

2. Example

Spring Security OAuth2 success or failed event listener

Spring Security OAuth2 success or failed event listener

2.1 pom.xml

spring-boot-starter-security for spring security

spring-security-oauth2 for auth2.0 authentication

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>spring-boot-example</groupId>
    <artifactId>Spring-boot-Oauth2-JDBC-token-store-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <description>Spring Security OAuth2 success or failed event listener example</description>
    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>  <!--starter require for spring boot spring security-->
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
    </dependencies>

    <!-- Package as an executable jar -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.2 SecurityOAuth2Configuration

Here we have implemented, @EventListener for AuthenticationSuccessEvent and AbstractAuthenticationFailureEvent (for all type of login failed like the wrong password, user locked)

package com.javadeveloperzone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;


/**
 * Created by JavaDeveloperZone on 04-08-2017.
 */
@Configuration
@EnableAuthorizationServer
public class SecurityOAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()")
                   .checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
               .withClient("javadeveloperzone")
               .secret("secret")
               .accessTokenValiditySeconds(2000)        // expire time for access token
               .refreshTokenValiditySeconds(-1)         // expire time for refresh token
               .scopes("read", "write")                         // scope related to resource server
               .authorizedGrantTypes("password", "refresh_token");      // grant type

    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @EventListener
    public void authSuccessEventListener(AuthenticationSuccessEvent authorizedEvent){
        // write custom code here for login success audit
        System.out.println("User Oauth2 login success");
        System.out.println("This is success event : "+authorizedEvent.getAuthentication().getPrincipal());
    }

    @EventListener
    public void authFailedEventListener(AbstractAuthenticationFailureEvent oAuth2AuthenticationFailureEvent){
        // write custom code here login failed audit.
        System.out.println("User Oauth2 login Failed");
        System.out.println(oAuth2AuthenticationFailureEvent.getAuthentication().getPrincipal());
    }
}

2.3 SecurityConfiguration

Here is spring security-related configuration like in memory users.

package com.javadeveloperzone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * Created by JavaDeveloperZone on 09-12-2017.
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/", "/login**")
                .permitAll()
                .anyRequest()
                .authenticated();
    }

    @Autowired      // here is configuration related to spring boot basic authentication
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()                                               // static users
            .withUser("zone1").password("mypassword").roles("USER")
            .and()
            .withUser("zone2").password("mypassword").roles("USER")
            .and()
            .withUser("zone3").password("mypassword").roles("USER")
            .and()
            .withUser("zone4").password("mypassword").roles("USER")
            .and()
            .withUser("zone5").password("mypassword").roles("USER");
    }
}

2.4 SpringBootApplication

package com.javadeveloperzone;

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

/**
 * Created by JavaDeveloperZone on 19-07-2017.
 */

@org.springframework.boot.autoconfigure.SpringBootApplication
@ComponentScan({"com.javadeveloperzone"})

// Using a root package also allows the @ComponentScan annotation to be used without needing to specify a basePackage attribute
public class SpringBootApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringBootApplication.class, args);            // it wil start application
    }
}

2.5 Output

Let’s Build and run the application:

mvn spring-boot:run
 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.4.RELEASE)
2018-04-14 11:02:44.319  INFO 143192 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-04-14 11:02:44.391  INFO 143192 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-04-14 11:02:44.396  INFO 143192 --- [           main] c.j.SpringBootApplication                : Started SpringBootApplication in 6.96 seconds (JVM running for 7.867)

2.5 Success Event

Let’s try to get access token so we can check LOG for authentication token succeeds.

Spring Security OAuth2 success event

Spring Security OAuth2 success event

here is the output of authSuccessEventListener

User Oauth2 login success
This is success event : [email protected]: Username: zone1; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER

2.6 Failed Event

Here, We have entered the wrong password so we can check failed event listener.

Spring Security OAuth2 failed event

Spring Security OAuth2 failed event

here is the output of authFailedEventListener

User Oauth2 login Failed
zone1
2018-04-14 10:02:42.967  INFO 73396 --- [nio-8080-exec-2] o.s.s.o.provider.endpoint.TokenEndpoint  : Handling error: InvalidGrantException, Bad credentials

3. Conclusion

In this article, we have seen that how we can track OAuth2 authentication success and failed using @EventListener. Spring Security automatically trigger respective listener while authentication gets success or failure.

4. References

5. Source Code

Spring Security OAuth2 success or failed event listener Example (45 KB)

Was this post helpful?
Let us know, if you liked the post. Only in this way, we can improve us.
Yes
No

Leave a Reply

Your email address will not be published. Required fields are marked *