Search code examples
springspring-security

AbstractSecurityWebApplicationInitializer is not working


I was trying to load webapp in java config way. In RAFTWebAppInitializer , I first registered the config classes along with home grown framework. But spring security filter chain is throwing error.

    public class RAFTWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer  {
        public static final String SPRING_DISPATCHER_SERVLET_NAME = "raft";
        public static final String URL_PATTERN = "/";
        private static final String SPRING_FILTER_CHAIN_NAME = "springSecurityFilterChain";
        private static final String UNABLE_TO_REGISTER_FILTER_CHAIN = "Unable to register filter chain";
        
        
        private Logger logger = LogManager.getLogger(RAFTWebAppInitializer.class);
        @Override
        protected WebApplicationContext createRootApplicationContext() {
            //initialize and register context
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            logger.info("Entering in root context to register chassis library");
/*Home grown framework */
            ABCInitializer abcInitializer = new ABCInitializer();
            abcInitializer .initialize(rootAppContext);
            logger.info("Exiting after registering chassis library");
            
            rootAppContext.register(getRootConfigClasses());       
            logger.info("Exiting after registering App config classes");        
            //registerSpringFilterChain(rootAppContext.getServletContext(), URL_PATTERN + "*");
           
            return rootAppContext;
        }
        
        @Override
        protected Class<?>[] getRootConfigClasses() {
            logger.debug("Calling getRootConfigClasses...");
            
            return new Class[]{AppConfig.class,WebAppSecurityConfig.class};
        }   
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            logger.debug("Calling getServletConfigClasses...");
            
            return new Class[]{DispatcherConfiguration.class};
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[]{URL_PATTERN};
        }
        
        @Override
        protected String getServletName() {
            return SPRING_DISPATCHER_SERVLET_NAME;
        }
    }
    
    @Configuration
    @EnableWebSecurity
    @ComponentScan(basePackages = { "com.capitalone.raft" })
    @Order(2)
    public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
        private Logger logger = LogManager.getLogger(this.getClass());
    // Own implementation of different configs
    }
    
    public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
        
        
        @Override
        protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
            logger.info("Before spring security");
            
            
            // super.beforeSpringSecurityFilterChain(servletContext);
        }
        
        @Override
        protected void afterSpringSecurityFilterChain(ServletContext servletContext) {
            logger.info("After spring security");
            // super.afterSpringSecurityFilterChain(servletContext);
        }
        
        
    
        private Logger logger = LogManager.getLogger(this.getClass());  
        private static final String FILTER_ENCODING_TYPE = "UTF-8";
        
        
    /*  @Override
        protected void afterSpringSecurityFilterChain(ServletContext servletContext) {
            logger.info("afterSpringSecurityFilterChain gets called to register other filter");
            //super.afterSpringSecurityFilterChain(servletContext);
            servletContext.addFilter("HttpMethodFilter", HiddenHttpMethodFilter.class);
            CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(FILTER_ENCODING_TYPE, true);
            servletContext.addFilter("CharacterEncodingFilter", characterEncodingFilter);
            logger.info("afterSpringSecurityFilterChain completed to register other filters");      
        }*/
        
    }   

Other than these we have the configuration class for servlet DispatcherConfiguration.class. But I am always getting the error as below:

2016-04-01 14:05:37,237 INFO  [localhost-startStop-1] context.ContextLoader (ContextLoader.java:347) - Root WebApplicationContext: initialization completed in 0 ms
2016-04-01 14:05:37,237 DEBUG [localhost-startStop-1] filter.GenericFilterBean (GenericFilterBean.java:177) - Initializing filter 'springSecurityFilterChain'
01-Apr-2016 14:05:37.252 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal One or more Filters failed to start. Full details will be found in the appropriate container log file
2016-04-01 14:05:37,252 INFO  [localhost-startStop-1] support.AbstractApplicationContext (AbstractApplicationContext.java:957) - Closing Root WebApplicationContext: startup date [Fri Apr 01 14:05:35 EDT 2016]; root of context hierarchy

And in container log:

01-Apr-2016 12:06:17.359 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'chassisConfig': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.capitalone.raft.refapps.api.mvc.config.ChassisConfig$$EnhancerBySpringCGLIB$$7e8af6fb]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.capitalone.raft.refapps.api.mvc.config.ChassisConfig$$EnhancerBySpringCGLIB$$7e8af6fb.<init>()
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1105)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1050)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)

Not able to understans, because when I go debugging the server initialization, actually these two methods are called:

@Override
public final void onStartup(ServletContext servletContext)
        throws ServletException {
    if(enableHttpSessionEventPublisher()) {
        servletContext.addListener(HttpSessionEventPublisher.class);
    }
    insertSpringSecurityFilterChain(servletContext);
    afterSpringSecurityFilterChain(servletContext);
}
then

private void insertSpringSecurityFilterChain(ServletContext servletContext) {
    String filterName = "springSecurityFilterChain";
    DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(filterName);
    String contextAttribute = getWebApplicationContextAttribute();
    if(contextAttribute != null) {
        springSecurityFilterChain.setContextAttribute(contextAttribute);
    }
    registerFilter(servletContext, true, filterName, springSecurityFilterChain);
}

Solution

  • Since, I have bootstrapped the context class with our homegrown framework, I had to refresh the context manually. Once refreshed all issue got resolved. But one thing needs to remember that while using component scan and try to set it at root level. But, we may need to understand the consequence. Sometime while doing scanning on root package, it may try to register some additional (or unrelated to a given context) classes which may cause conflict(s). Updated code:

        public class RAFTWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer  {
        public static final String SPRING_DISPATCHER_SERVLET_NAME = "raft";
        public static final String URL_PATTERN = "/";
        private static final String SPRING_FILTER_CHAIN_NAME = "springSecurityFilterChain";
        private static final String UNABLE_TO_REGISTER_FILTER_CHAIN = "Unable to register filter chain";
    
    
        private Logger logger = LogManager.getLogger(RAFTWebAppInitializer.class);
        @Override
        protected WebApplicationContext createRootApplicationContext() {
            //initialize and register context
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            logger.info("Entering in root context to register abc library");
            /*Home grown framework */
            ABCInitializer abcInitializer = new ABCInitializer();
            abcInitializer .initialize(rootAppContext);
            logger.info("Exiting after registering chassis library");
    
            rootAppContext.register(getRootConfigClasses());       
            logger.info("Exiting after registering App config classes");        
            rootAppContext.refresh();
    
            return rootAppContext;
           }