Hello,
We are encountering an issue with the sec:authorize expression in JSPX files after upgrading to Spring Security 6.
We've created a simple Spring Boot application to reproduce the exception:
jsp-demo.zip
- In
example.jspx, thesec:authorizeexpression is used. - When accessing the URL
http://localhost:8080/jsp-demo/, the following exception is thrown:
java.lang.NullPointerException: Cannot invoke "jakarta.servlet.ServletRegistration.getClassName()" because "registration" is null
at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry$DispatcherServletRequestMatcher.matches(AbstractRequestMatcherRegistry.java:514) ~[spring-security-config-6.3.1.jar:6.3.1]
at org.springframework.security.web.util.matcher.OrRequestMatcher.matches(OrRequestMatcher.java:58) ~[spring-security-web-6.3.1.jar:6.3.1]
Is there something missing in our configuration, or is this a bug?
Comment From: kse-music
Related to #13849
based on your code,you can use MvcRequestMatcher as temporary solution like so:
@Bean
public WebSecurityCustomizer webSecurityCustomizer(HandlerMappingIntrospector introspector) {
return (web) -> web.ignoring()
.requestMatchers(new MvcRequestMatcher(introspector,"/"))
// .requestMatchers("/")
;
}
Comment From: zverde
Hi,
thank you for your response. We were able to avoid the issue by using antMatchers in our security configuration instead.
Comment From: jzheaux
@zverde, thanks for the report and for the extra detail.
First regarding your workaround:
- Please avoid
web.ignoringinWebSecurityCustomizerin favor of.requestMatchers(...).permitAll()inHttpSecurity - Please use
MvcRequestMatcherinstead ofAntPathRequestMatcher, since/is an MVC endpoint in your application
It will look similar to this in the end:
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(mvc.pattern("/")).permitAll()
// ...
.anyMatcher().authenticated()
)
// ...
return http.build();
}
Note that #13562 has been filed to simplify the construction of MvcRequestMatcher.Builder.
Regarding what is going on:
When an application has DispatcherServlet and non-DispatcherServlets in its deployment, Spring Security must know which servlet a given request is destined for to compute the correct request matcher. In many cases, it can determine this on its own by inspecting the HttpServletRequest instance.
In the case of <sec:authorize url="/somepath">, though, there is only a mock request, so the container cannot provide the needed servlet information. Because of this and other factors, it is often necessary for a JSP-based application to use requestMatchers(RequestMatcher) instead of requestMatchers(String) to create your authorization rules.
When you do, you should determine whether the described endpoint is an MVC endpoint or not. If it is, you should use MvcRequestMatcher instead of AntPathRequestMatcher.
Steps Forward:
I believe for this ticket, we should improve the error message. Spring Security should be able to detect a mock request and then provide a more informative error message accordingly.