1

So after adding Spring Security (not sure if it is the cause) it appears not only are the default Static Content resolution path null and void, but also any subsequent attempts to map URLs to static content

For example, a vanilla Spring Boot Application without a WebSecurityConfigurerAdapter would map /GET localhost:8080/index.html to ResourceHttpRequestHandler with default configured static content locations such as classpath:META-INF/resources and classpath:static/

Thus index.html located in one of these classpath locations are automatically served.

With a WebSecurityConfigurerAdapter however, I get 405s ... and no matter what I do ... it appears the handler registry will not contain a mapping to the aforementioned ResourceHttpRequestHandler locations

For example

Attempt to Add mapping explicitly

Use ResourceHandlerRegistry

@Configuration
public class ServletConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/index.html").addResourceLocations("classpath:statc/index.html");
        super.addResourceHandlers(registry);
    }
}

Here are the TRACE logs

2017-07-17 12:12:21.742 DEBUG 23566 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/]
2017-07-17 12:12:21.755 DEBUG 23566 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /
2017-07-17 12:12:21.760 DEBUG 23566 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
2017-07-17 12:12:21.768 DEBUG 23566 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Invoking @ExceptionHandler method: public final org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest)

Is this a known and frequently encountered issue when dealing with Spring Security?

Or maybe this is not expected and unrelated to Spring Security? I've gotten the entire setup to work many times before, the only thing new is Spring Security

Here is the SecurityConfiguration

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private UserDetailService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        final DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(new StandardPasswordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        /*
        it is important to set the default userDetailsService on AuthenticationManagerBuilder
         */
        auth.authenticationProvider(daoAuthenticationProvider).userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        org.springframework.security.web.authentication.AuthenticationSuccessHandler authenticationSuccessHandler = new AuthenticationSuccessHandler();
        http
                .csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
                .and()
                .authorizeRequests()
                .antMatchers("/index.html").permitAll()
                .antMatchers("/api/security/**")
                .hasAuthority("ADMIN")
                .antMatchers("/api/portfolios/**", "/api/trades/**", "/api/user/**", "/api/init")
                .authenticated()
                .and()
                .formLogin()
                .successHandler(authenticationSuccessHandler)
                .failureHandler(new SimpleUrlAuthenticationFailureHandler())
                .and()
                .rememberMe()
                .and()
                .logout()
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK));
    }
}

Note that the start-up logs show both the default static content handler mapping and my explicit mapping to be both present and configured ... they are just not there when the actual request is made:

2017-07-17 12:25:57.088 DEBUG 23702 --- [           main] o.s.w.s.resource.ResourceUrlProvider     : Found resource handler mapping: URL pattern="/**/favicon.ico", locations=[ServletContext resource [/], class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], class path resource []], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@23707d5d]
2017-07-17 12:25:57.089 DEBUG 23702 --- [           main] o.s.w.s.resource.ResourceUrlProvider     : Found resource handler mapping: URL pattern="/index.html", locations=[class path resource [statc/index.html]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@5fa49615]
2017-07-17 12:25:57.089 DEBUG 23702 --- [           main] o.s.w.s.resource.ResourceUrlProvider     : Found resource handler mapping: URL pattern="/webjars/**", locations=[class path resource [META-INF/resources/webjars/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@7921eb37]
2017-07-17 12:25:57.089 DEBUG 23702 --- [           main] o.s.w.s.resource.ResourceUrlProvider     : Found resource handler mapping: URL pattern="/**", locations=[ServletContext resource [/], class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@3fdb9c55]

EDIT Digging Deeper

It appears there is a PartialMatchHelper in RequestMappingInfoHandlerMapping.java:195 on URL:[], method: PUT which will match every single request!

echen
  • 2,002
  • 1
  • 24
  • 38
  • 1
  • yes ... the issue as I am iterating through `DispatcherServlet` line-by-line is that `RequestMappingHandlerMapping` is short circuiting the entire `HandlerExecutionChain` by prematuring throwing a 405 ... so if one look at `DispatcherServlet.java:1154` we see that the framework is trying to find a handler for a given request by seeing who among `this.handlerMappings` is willing to take the request .... I can see my custom configured handler `SimpleUrlHandlerMapping` and even the SpringBoot default mapping inside `this.handlerMappings` the for loop short circuits before reaching it – echen Jul 17 '17 at 16:52
  • Ah, now *that* can be a problem, and I've run into it in relation to Spring Data REST. I don't think that's the issue *here* though; it looks like a typo in your mapping. – chrylis -cautiouslyoptimistic- Jul 17 '17 at 16:54
  • @chrylis sorry I may have missed the typo ... where is the typo? – echen Jul 17 '17 at 16:56
  • Ok I figured it out ... really random mistake on my part in a somewhat unrelated part of the App ... I am going to put out an self-answer – echen Jul 17 '17 at 17:04

1 Answers1

1

Kind of small mistake on my part - but has huge implications (after learning how Spring MVC framework works internally)

I had accidentally added a controller like this

@RestController("registration")
public class RegistrationController { ... }

When I meant

@RestController
@RequestMapping("registration")
public class RegistrationController {...}

so my registration REST end point would not have worked ... clearly BUT ... the former configuration also unwitting affected static content resolution by placing an empty URL:[], METHOD: PUT/POST or whatever into RequestMappingHandlerMapping which is one of the handler mappings that can take precedence over static Resource mappings

So the moral of the story is:

debug DispatcherServlet.java to see which handler mapping is truly being used

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
echen
  • 2,002
  • 1
  • 24
  • 38