I've been trying to update one Spring Boot project today from 2.5.8 to 2.6.2. However the introduction of ErrorPageSecurityFilter
causes me quite some headache. I've read a few other issues that say it's fixed now, but I cannot find a way to make my use case work:
We have a client that tries to authenticate with the Spring Boot server. Before the update, it would just sent 401 and a message containing the reason for the failure. When no message is returned (like now) the client assumes some sort of Internal Server Error. The way this is implemented is that we have an AuthenticationFailureHandler
that handles AuthenticationException
during the authentication process and then essentially calls response.sendError(HttpServletResponse.SC_UNAUTHORIZED, exception.message)
.
Now the suggestion with the new filter as far as I understood is to permit access to "/error" to explicitly allow this behavior. However that will never work as the WebInvocationPrivilegeEvaluator
when isAllowed()
is called, checks if (authentication == null) return false;
and I don't have an authentication since it just failed to authenticate. Even if I try to set one, it gets removed.
I would be completely fine with just disabling the new filter entirely, but this seems to be extremely difficult?
I've tried setting the property server.error.include-message=always
, but as far as I can see that changes nothing. Creating my own FilterRegistrationBean<ErrorPageSecurityFilter>
and setting setEnabled(false)
doesn't work. I can't simply exclude the ErrorPageSecurityFilterConfiguration
since it's not an AutoConfiguration and/or package private. I've tried wrapping the DefaultWebInvocationPrivilegeEvaluator
to always allow /error
, but that is getting nowhere because in the WebSecurityConfigurerAdapter
the constructor argument FilterSecurityInterceptor
has no public getter and it apparently gets passed by some complicated mechanism.
So obviously, if the default configuration had been like this from the start, we would have never designed the flow like this; but I feel like the current behavior should be easier to opt-out of.
Comment From: wilkinsona
Thanks for the report, @xcq1.
There have been some improvements in this area in Spring Security. The details are in https://github.com/spring-projects/spring-security/issues/10554, the changes for which have been backported to the yet-to-be-released 5.6.2 and 5.5.5. The gist is that things should now work better with multiple security filter chains and when a URL is covered by ignoring(), i.e. when there's no Authentication
.
Could you please give your app a try with Spring Security 5.6.2-SNAPSHOT available from https://repo.spring.io/snapshot and let us know how you get on? If it doesn't help, could you please share a small sample application that reproduces the problem that you're facing? You can share it with us by zipping it up and attaching it to this issue or pushing it to a separate repository in GitHub. In the meantime, you may also be interested in this workaround which should work equally well in main code. It'll remove the filter entirely.
Comment From: xcq1
Thanks @wilkinsona, those are excellent news. I can confirm that building with Spring Security 5.6.2-SNAPSHOT fixes my problem. The filter is called, but isAllowed returns true as expected. The workaround that you mentioned works as well, so I can bump to Boot 2.6.2 for now, and I guess this will do until the proper patch drops in the coming months.
Comment From: wilkinsona
Thanks very much for trying the security snapshot, @xcq1. It's great to hear that it fixes your problem. I'll close this one as a duplicate of the security issues. We'll pick up the Security maintenance releases in due course.