Duplicate registration for springSecurityFilterChain when deploying on tomcat outside of eclipse

18,109

Solution 1

It looks like you have two instances of the springSecurityFilterChain defined: Once in SecurityConfig.java, and once in spring-security.xml. You only need one of those files.

The filter line in web.xml tells the servlet engine (Tomcat) to load that filter, but the instance of that filter is configured in the Spring context. The problem is the Spring context can't start, because you have two configurations for the springSecurityFilterChain. Take one out, and you will be making progress.

Your configuration in the XML file seems more comprehensive and fine-grained, but I would recommend moving that configuration to the Java file and eliminating the XML file.

Once you remove your duplicate configuration, you may still have errors, but you should be able to find a solution to those on this site, or feel free to post a separate question!

Note: It is also possible to get Spring to automatically register the filter chain for you, so you don't need to define it in web.xml. See here for how to do that:

http://www.mkyong.com/spring-security/spring-security-hello-world-annotation-example/

However, I would recommend getting the current config working first, before throwing that in the mix.

Solution 2

if you have this class

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
   //do nothing
}

The above class is equivalent to the following web.xml code

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy
            </filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Just remove the one you do not want.

Solution 3

I think there is no exact answer to this. Posting it anyway may be it would help someone. Two steps for xml approach -

  1. get rid of SpringSecurityInitializer class because u are using xml and have mapping in web.xml
  2. In AppConfig file remove @Import({ SecurityConfig.class })

If you want to keep them both, then do the reverse i.e. remove mapping from web.xml file and get rid of xml.

Share:
18,109
farnett
Author by

farnett

Updated on July 25, 2022

Comments

  • farnett
    farnett almost 2 years

    I am a little new to spring and still confused by all the configurations. I went by several different tutorials and it seems like everyone does things differently. I have a spring application which runs fine through Eclipse using the tomcat plugin. However when exporting a war file to tomcat itself tomcat doesn't start and throws

    SEVERE: ContainerBase.addChild: start org.apache.catalina.LifecycleException: Failed to start component

    Caused by: java.lang.IllegalStateException: Duplicate Filter registration for 'springSecuirtyFilterChain'. Check to insure the Filter is only configured once!

    See picture for full stack trace.

    After commenting out springSecurityFilterChain in web.xml, whether dataSource is autowired or not gives one or two errors.

    • If dataSource is autowired then I just get an error saying creating bean securityConfig failed and that there is no bean found for dependency.

    • If I leave dataSource not autowired (like the code I have which works in Eclipse) then I get an IllegalArgumentException: Property 'dataSource' is required.

    Also in order to not get a multiple ContextLoader definition error I have to comment out the ContextLoaderListener in web xml.

    From what I've seen the problem lies in using xml and java for configurations but I can't pinpoint exactly what is wrong.

    I found a similar question but was unable to solve my problem. Where do I define `springSecurityFilterChain` bean? Adding a bean class pointing to my securityConfig put in spring-security.xml didn't help.

    Thanks!

    picture of full stack trace

    Below is the code which works totally fine when running in Eclipse.

    web.xml

    <web-app id="WebApp_ID" version="2.4"
        xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
    
            <!-- Spring MVC -->
        <servlet>
            <servlet-name>mvc-dispatcher</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
          <servlet>
        <servlet-name>InitServlet</servlet-name>
        <servlet-class>servlet.InitServlet</servlet-class>
        <init-param>
          <param-name>configfile</param-name>
        </init-param>
        <load-on-startup>2</load-on-startup>
      </servlet>
    
      <servlet>
        <servlet-name>AdminServlet</servlet-name>
        <servlet-class>servlet.admin.AdminServlet</servlet-class>
        <load-on-startup>3</load-on-startup>
      </servlet>
    
      <servlet>
        <servlet-name>UserServlet</servlet-name>
        <servlet-class>servlet.user.UserServlet</servlet-class>
        <load-on-startup>4</load-on-startup>
      </servlet>
    
      <servlet>
        <servlet-name>SignupUserServlet</servlet-name>
        <servlet-class>servlet.user.SignupUserServlet</servlet-class>
        <load-on-startup>5</load-on-startup>
      </servlet>
    
      <servlet>
       <servlet-name>ReceiveFile</servlet-name>
        <servlet-class>servlet.user.ReceiveFile</servlet-class>
        <load-on-startup>6</load-on-startup>
      </servlet>
    
      <servlet-mapping>
            <servlet-name>mvc-dispatcher</servlet-name>
            <url-pattern>/pages/*</url-pattern>
        </servlet-mapping>
    
      <servlet-mapping>
       <servlet-name>AdminServlet</servlet-name>
       <url-pattern>/AdminServlet</url-pattern>
      </servlet-mapping>
    
      <servlet-mapping>
       <servlet-name>UserServlet</servlet-name>
       <url-pattern>/UserServlet</url-pattern>
      </servlet-mapping>
    
      <servlet-mapping>
       <servlet-name>SignupUserServlet</servlet-name>
       <url-pattern>/SignupUserServlet</url-pattern>
      </servlet-mapping>
    
      <servlet-mapping>
       <servlet-name>ReceiveFile</servlet-name>
       <url-pattern>/ReceiveFile</url-pattern>
      </servlet-mapping>
    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/spring-security.xml,
                /WEB-INF/spring-database.xml
            </param-value>
        </context-param>
    
        <!-- Spring Security -->
        <!-- This is to allow enctype="multipart/form-data" to upload and not throw an access denied page. 
        See bottom of http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html  for more info.-->
        <filter>
        <filter-name>MultipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
      </filter>
    
      <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter> 
    
     <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <filter-mapping>
        <filter-name>MultipartFilter</filter-name>
        <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    </web-app>
    

    SecuirtyConfig.java

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
      DataSource dataSource;
    
    /*    @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        //    auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
        } */
    
        @Autowired
        public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
    
            auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery("select username,password, enabled from test_users where username=?")
                .authoritiesByUsernameQuery("select username, role from test_user_roles where username=?");
        }   
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                .authorizeRequests()
                  .antMatchers("/res/**").permitAll()
                  .anyRequest().authenticated()
                  .and()
                .formLogin()
                  .loginPage("/loginDatabase.html")
                  .permitAll();
        }
    }
    

    AppConfig.java

    @EnableWebMvc
    @Configuration
    @ComponentScan({"security.spring"})
    @Import({ SecurityConfig.class })
    public class AppConfig {
    
        @Bean(name = "dataSource")
        public DriverManagerDataSource dataSource() {
            DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
            driverManagerDataSource.setUrl("****");
            driverManagerDataSource.setUsername("**");
            driverManagerDataSource.setPassword("**");
            return driverManagerDataSource;
        }
    
        @Bean
        public InternalResourceViewResolver viewResolver() {
            InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
            viewResolver.setViewClass(JstlView.class);
            viewResolver.setPrefix("/WEB-INF/pages/");
            viewResolver.setSuffix(".jsp");
            return viewResolver;
        }
    
    }
    

    spring-security.xml

    <beans:beans xmlns="http://www.springframework.org/schema/security"
      xmlns:context="http://www.springframework.org/schema/context"  
        xmlns:beans="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/context 
      http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
        <context:component-scan base-package="spring.*" />
        <!-- enable use-expressions -->
        <http auto-config="true" use-expressions="true">
            <!-- login page must be available to all. The order matters, if this is after something which secures the page this will fail. -->
    <!--        <intercept-url pattern="/SignupUserServlet" access="permitAll"/> -->
    <!--        <intercept-url pattern="/pages/ReceiveFile" access="permitAll()"/> 
            <intercept-url pattern="/pages/fileUpdate2" access="permitAll()"/>
        <intercept-url pattern="/pages/login" access="permitAll()" />  -->
            <intercept-url pattern="/pages/admin/**" access="hasRole('_admin')" />
            <intercept-url pattern="/pages/trade/**" access="hasRole('_trader')" />
            <intercept-url pattern="/pages/discover/**" access="hasRole('_users')" />       
            <!-- access denied page -->
            <access-denied-handler error-page="/pages/403" />
            <form-login 
                login-page="/pages/login" 
                default-target-url="/pages/common/redirectportal" 
                authentication-failure-url="/pages/login?error" 
                username-parameter="username"
                password-parameter="password" />
            <logout logout-url="/pages/logout" logout-success-url="/pages/login?logout" />
            <!-- enable csrf protection -->
            <!-- currently off for testing... <csrf/> -->
        </http>
    
        <!-- Select users and user_roles from database -->
        <authentication-manager>
            <authentication-provider ref="customAuthenticationProvider"/>
            <!--<jdbc-user-service data-source-ref="dataSource"
                    users-by-username-query=
                        "select email,pwhash, enabled from users where email=?"
                    authorities-by-username-query=
                        "select email, groupname from usergroups where email =?  " /> 
            </authentication-provider> -->
        </authentication-manager>
    
    </beans:beans>