2

I setup a fairly simple secure application using spring boot, but I keep getting this exception from the server after I successfully log in:

javax.servlet.ServletException: Filter execution threw an exception
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:116)
org.springframework.boot.context.web.ErrorPageFilter.access$000(ErrorPageFilter.java:60)
org.springframework.boot.context.web.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:91)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:109)

root cause

java.lang.AbstractMethodError
    javax.servlet.http.HttpServletRequestWrapper.changeSessionId(HttpServletRequestWrapper.java:290)
    javax.servlet.http.HttpServletRequestWrapper.changeSessionId(HttpServletRequestWrapper.java:290)
    sun.reflect.GeneratedMethodAccessor295.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:203)
    org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:188)
    org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy.applySessionFixation(ChangeSessionIdAuthenticationStrategy.java:48)
    org.springframework.security.web.authentication.session.AbstractSessionFixationProtectionStrategy.onAuthentication(AbstractSessionFixationProtectionStrategy.java:82)
    org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy.onAuthentication(ChangeSessionIdAuthenticationStrategy.java:32)
    org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy.onAuthentication(CompositeSessionAuthenticationStrategy.java:83)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:216)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:105)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:116)
    org.springframework.boot.context.web.ErrorPageFilter.access$000(ErrorPageFilter.java:60)
    org.springframework.boot.context.web.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:91)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:109)

Here is my initializer class:

@EnableAutoConfiguration
@SpringBootApplication
public class RecruitingDashboardApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(RecruitingDashboardApplication.class);
    }

       public static void main(String[] args) throws Exception {
        SpringApplication.run(RecruitingDashboardApplication.class, args);
       }


}

And my viewResolver configuration class:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Bean 
    public ViewResolver viewResolver() {
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setPrefix("templates/");
        templateResolver.setSuffix(".html");

        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver);

        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(engine);
        return viewResolver;
    }


    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("dashboard");
        registry.addViewController("/login").setViewName("login");
    }

}

And finally my security configuration class:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.headers()
                .frameOptions()
                .disable()
            .authorizeRequests()
                .antMatchers("/css/**", "/img/**", "/fonts/**").permitAll()
                .anyRequest()
                .authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("username").password("password").roles("USER");
    }

}

These are the pom dependencies I'm using:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>net.sourceforge.nekohtml</groupId>
        <artifactId>nekohtml</artifactId>
        <version>1.9.22</version>
    </dependency>

</dependencies>

Any help is appreciated. I've spend three days on this problem and I've searched everywhere on the web, but I could not find a solution.

UPDATE

It seems I don't get the exception when deploying to Tomcat 8. I only get it on Tomcat 7.

UPDATE 2

I've updated my pom file to include the spring-boot-starter-tomcat dependency with a providedscope. I've also excluded that same transient dependency from spring-boot-starter-web, as described in this question. However, the problem still persists.

Community
  • 1
  • 1
Pedro Hoehl Carvalho
  • 2,183
  • 2
  • 19
  • 25
  • Looks like wrong dependency version. `changeSessionId` method is defined in Servlet API 3.1 and you probably have 3.0.1 in you classpath. – tsachev Aug 21 '15 at 14:49
  • Sounds right. But how do I change it, if all the spring boot starter dependencies are all bundled up? – Pedro Hoehl Carvalho Aug 21 '15 at 15:48
  • Also, isn't version 3.1 only available on Tomcat 8? I'm have `7.0.63` on my properties and I thought that would take care of getting the right dependencies. – Pedro Hoehl Carvalho Aug 21 '15 at 16:03

1 Answers1

0

You are deploying a war-based artifact. spring-boot-starter-web provides an embedded web container (Tomcat by default) and the servlet-api goes with it obviously. The container on which you deploy the war uses another version of the API.

You need to flag spring-boot-starter-tomcat with the provided scope so that your war does not bring that extra dependency along. The Spring Boot maven plugin is able to detect that and places such provided dependencies in a separate location of the fat war so that you can still run it from the command line (java -jar yourapp.war). You are free not to use that and just build a regular war file. Don't use the Spring Boot maven plugin in such scenario.

This is explained in the documentation

Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89
  • Thank you for your answer. I've made the changes you proposed, (see update to question) but the problem still persists. – Pedro Hoehl Carvalho Aug 21 '15 at 15:49
  • What can I say? it's essentially the same problem, `servlet-api` is provider by another dependency of your project. Run `mvn dependency:tree` to look who is the culprit. You can also look at `WEB-INF/lib` quickly and make sure no servlet related jars are in there. – Stephane Nicoll Aug 22 '15 at 06:49
  • After looking at a comment on [this question](http://stackoverflow.com/questions/26642493/spring-security-java-lang-abstractmethoderror) I deleted `servlet-api` from my `tomcat/lib` folder. I believe the answer in this case was a combination of the changes you recommended to the `pom.xml` file and cleaning the `tomcat/lib` folder. – Pedro Hoehl Carvalho Aug 26 '15 at 12:54
  • not at all! You shouldn't mess with your `tomcat/lib` since this is the original jar that the server must be using. Like I said, you must have servlet-api (either shaded or with a different name maybe) in your war. That's what is causing the issue. – Stephane Nicoll Aug 26 '15 at 13:45
  • I have checked my war file and there is no `servlet-api` in `WEB-INF/lib`. I also ran `mvn dependency:tree`, which revealed nothing. If its under a different name, I don't know how else I could possibly figure out where it is. – Pedro Hoehl Carvalho Aug 26 '15 at 14:55