/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* Copyright 2006 - 2015 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.platform.engine.security.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.LoggerListener;
import org.springframework.security.core.Authentication;
/**
* org.pentaho.platform.engine.security.event.PentahoLoggerListener wraps org.springframework.security.authentication.event.LoggerListener
* and safeguards onApplicationEvent() calls
* <p/>
* This is because on the later spring security, LoggerListener has changed its method signature from
* <p/>
* void onApplicationEvent( ApplicationEvent event )
* <p/>
* to
* <p/>
* void onApplicationEvent(AbstractAuthenticationEvent event)
* <p/>
* @see https://github.com/spring-projects/spring-security/blob/4.1.3.RELEASE/core/src/main/java/org/springframework/security/authentication/event/LoggerListener.java#L46
* <p/>
* But when the OrderedApplicationEventMulticaster multicasts a ApplicationEvent to all listeners
* ( read: ApplicationListener interface ), it does so without checking if that particular ApplicationListener instance
* does in fact support the ApplicationEvent instance
* <p/>
* listener.onApplicationEvent( event )
* <p/>
* and in cases such as a 'PublicInvocationEvent' or a 'ContextRefreshedEvent' are sent, the LoggerListener ended up
* throwing a ClassCastException: event <instance> cannot be cast to AbstractAuthenticationEvent and actually halting
* the operation at hand
* <p/>
* <p/>
* We are instantiating org.springframework.security.authentication.event.LoggerListener internally in the constructor
* and not via spring IoC ( as desired ) because spring.framework does a last-safeguard check on all beans
* ( including inner beans ) where IF bean is instanceof ApplicationListener AND is a singleton-scoped bean, then
* add if on-the-fly to the listeners list ( which would wound up bringing us back to the issue above )
* @see https://github.com/spring-projects/spring-framework/blob/v4.1.5.RELEASE/spring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.java#L349-L355
*/
public class PentahoLoggerListener implements ApplicationListener {
LoggerListener loggerListener;
public PentahoLoggerListener() {
this.loggerListener = new LoggerListener();
}
public PentahoLoggerListener( LoggerListener loggerListener ) {
this.loggerListener = loggerListener;
}
@Override public void onApplicationEvent( ApplicationEvent event ) {
if ( event != null && event.getClass().isAssignableFrom( AbstractAuthenticationEvent.class ) ) {
loggerListener.onApplicationEvent( new WrappedAuthenticationEvent( (Authentication) event.getSource() ) );
}
}
public boolean isLogInteractiveAuthenticationSuccessEvents() {
return loggerListener.isLogInteractiveAuthenticationSuccessEvents();
}
public void setLogInteractiveAuthenticationSuccessEvents( boolean logInteractiveAuthenticationSuccessEvents ) {
loggerListener.setLogInteractiveAuthenticationSuccessEvents( logInteractiveAuthenticationSuccessEvents );
}
private class WrappedAuthenticationEvent extends AbstractAuthenticationEvent {
public WrappedAuthenticationEvent( Authentication authentication ) {
super( authentication );
}
}
}