Last updated by burtbeckwith 4 years ago
Spring Security fires application events after various security-related actions, such as successful login, unsuccessful login, etc. There are two hierarchies of events, AbstractAuthenticationEvent and AbstractAuthorizationEvent.

There are two main ways of being notified of these events when using the Spring Security plugin:

  • register an event listener, ignoring events that you're not interested in (Spring doesn't allow selective event subscription - you get called for every application event)
  • register one or more callback closures in grails-app/conf/SecurityConfig.groovy that take advantage of SecurityEventListener which does the filtering for you
The first approach involves creating either a Groovy or Java class, e.g.
package com.foo.bar
class MySecurityEventListener implements ApplicationListener {
   /**
    * {@inheritDoc}
    * @see org.springframework.context.ApplicationListener#onApplicationEvent(
    *     org.springframework.context.ApplicationEvent)
    */
   void onApplicationEvent(final ApplicationEvent e) {
      if (e instanceof AbstractAuthenticationEvent) {
         if (e instanceof InteractiveAuthenticationSuccessEvent) {
            // handle InteractiveAuthenticationSuccessEvent
         }
         else if (e instanceof AbstractAuthenticationFailureEvent) {
            // handle AbstractAuthenticationFailureEvent
         }
         else if (e instanceof AuthenticationSuccessEvent) {
            // handle AuthenticationSuccessEvent
         }
         else if (e instanceof AuthenticationSwitchUserEvent) {
            // handle AuthenticationSwitchUserEvent
         }
         else {
            // handle other authentication event
         }
      }
      else if (e instanceof AbstractAuthorizationEvent) {
         // handle authorization event
      }
   }
}
and to use this just register it in resources.groovy:
mySecurityEventListener(com.foo.bar.MySecurityEventListener) {}
Alternatively, you can just register one or more callback closure(s) in grails-app/conf/SecurityConfig.groovy and let SecurityEventListener do all of the work for you, and you can just handle any event you like, e.g.:
security {

active = true

useSecurityEventListener = true

onInteractiveAuthenticationSuccessEvent = { e, appCtx -> // handle InteractiveAuthenticationSuccessEvent } onAbstractAuthenticationFailureEvent = { e, appCtx -> // handle AbstractAuthenticationFailureEvent } onAuthenticationSuccessEvent = { e, appCtx -> // handle AuthenticationSuccessEvent } onAuthenticationSwitchUserEvent = { e, appCtx -> // handle AuthenticationSwitchUserEvent } onAuthorizationEvent = { e, appCtx -> // handle AuthorizationEvent } }

None of these closures are required; if none are configured, nothing will be called. Just implement the event handlers that you need, e.g.:
security {

active = true

useSecurityEventListener = true

onInteractiveAuthenticationSuccessEvent = { e, appCtx -> // handle AuthenticationSuccessEvent } }

A quick note about usage: when a user authenticates, Spring Security initially fires an AuthenticationSuccessEvent but this happens before the Authentication (typically a GrailsUserImpl) is registered in the SecurityContextHolder. This means that the authenticateService methods that access the logged-in user won't work. Later in the processing a second event is fired, an InteractiveAuthenticationSuccessEvent, and when this happens the SecurityContextHolder will have the Authentication. So depending on your needs you can choose to implement a callback for either or both events.

Note that your event callback(s) will be ignored unless you set the 'useSecurityEventListener' property to true. This allows you to temporarily disable/enable them or enable them per-environment.