Closed spring-projects-issues closed 9 years ago
Michael Osipov said:
Forgot to mention:
My security filter is configured like this:
<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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Rob Winch said:
Why would you map the springSecurityFilterChain to the ERROR dispatcher if you only want it to be invoked once? By adding an observeOncePerRequest option it is effectively the same thing as removing
Michael Osipov said:
Removing ERROR is not the same as invoking once. As I have mentioned before, I want to maintain the security context on all pages whether they are protected or not. E.g., on a 403 page: the user is logged in but simply does not have the appropriate role.
I do not intend to modify the BasicAuthFilter, I think this can be done globally in the FilterChainProxy just as in the FilterSecurityInterceptor. I have found few discussions in the spring forums and stackoverlow with a resembling problem.
Rob Winch said:
Only processing the REQUEST is effectively the same as stating that the springSecurityFilterChain should be invoked once when filtering on every URL. When the HTTP request is made, the FilterChainProxy will be invoked as normal. On the second invocation of the FilterChainProxy, the invocation of FilterChainProxy will be skipped (thus effectively removing it from the FilterChain). The SecurityContext will not be populated because, as a delegate of FilterChainProxy, the SecurityContextPersistenceFilter will not be invoked.
The attached sample application demonstrates that this is the case.
The reason you are not seeing a response written out is because when the BasicAuthenticationFilter is attempting to authenticate the second time it performs response.sendError a second time. Invoking sendError twice is not allowed and to prevent infinite recursion the container avoids processing the second invocation. You can fix this by:
You will find that the response body is written out when failing to authenticate. When the user authenticates and an error occurs the user is properly displayed.
As demonstrated above, adding observeOncePerRequest to FilterChainProxy will not fix the issue. The actual issue, the response not being written out, is not a bug since Spring Security does what it is being configured to do. At best this is an enhancement request. Anyone wanting a once per request filter can easily create a filter similar to the OncePerRequestDelegatingFilter in the sample application. Alternatively, the LoginUrlAuthenticationEntryPoint can be used which will allow the controller tier to write to the response without using the sendError that is causing this issue.
Rob Winch said:
Updated to new feature per discussion on the JIRA
Michael Osipov said:
I am sorry, I wasn't able to respond anytime sooner.
Though I am not an expert in configuring a Spring app, are you sure that this isn't a typo in the web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>onceSpringSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
Both refer to the same class.
Are you sure that you have configured the application correctly? The security chain does not issue a WWW-Authenticate Basic because the 403EntryPoint does not do that.
The reason you are not seeing a response written out is because when the BasicAuthenticationFilter is attempting to authenticate the second time it performs response.sendError a second time. Invoking sendError twice is not allowed and to prevent infinite recursion the container avoids processing the second invocation.
Exactly, this is what I have observed. In this case, the second auth is just unnecessary.
I am fully satistified with a wrapper which will guarantee that my filter won't run several times without losing the security context. Since I am using a custom filter in my final app, I would wrap it. What I would appreciate is that the default auth filters would have appropriate out-of-the-box support for this with a mere xml attribute. This would save a lot of grief.
Again, brilliant analysis. Though, I still do not fully understand how the FilterChainProxy really works compared to the FilterSecurityInterceptor or how both interact. Deducing from this, it is still not completely clear to me why this cannot be added to the FilterChainProxy directly. I guess I am missing the big picture which I did not find in the Spring Security manual.
Rob Winch said:
In reply to comment #6:
First of all, the project cannot be build. I guess, I am missing some spring repo
Everything (including org.slf4j:slf4j-api:jar:1.5.10) is available in maven central, so unless you have modified your settings.xml or you are behind a proxy it should not require any additional repositories. I confirmed that it builds for me with an empty maven repository and executing mvn clean package
successfully.
Though I am not an expert in configuring a Spring app, are you sure that this isn't a typo in the web.xml:
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter> <filter-name>onceSpringSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter>
Both refer to the same class.
This is not a typo. DelegatingFilterProxy looks up a Spring bean by the name of the Filter and delegates all the work to it. So by changing the filter name we are pointing to a different object in the Spring configuration. You can find additional information on DelegatingFilterProxy in the Spring Security reference.
Though, I still do not fully understand how the FilterChainProxy really works compared to the FilterSecurityInterceptor or how both interact. Deducing from this, it is still not completely clear to me why this cannot be added to the FilterChainProxy directly. I guess I am missing the big picture which I did not find in the Spring Security manual.
I'm sorry you are still uncertain of how things work. If you haven't already read it, you might read the Security Filter Chain section of the reference which describes how it behaves. You can also sign up for the Spring Security Fundamentals webinar where I will talk about how the FilterChainProxy works in detail. Of course if you miss it, the webinar will be available on the SpringSourceDev YouTube channel.
Michael Osipov said:
In reply to comment #6:
First of all, the project cannot be build. I guess, I am missing some spring repo
Everything (including org.slf4j:slf4j-api:jar:1.5.10) is available in maven central, so unless you have modified your settings.xml or you are behind a proxy it should not require any additional repositories. I confirmed that it builds for me with an empty maven repository and executing mvn clean package successfully.
I have already changed the my comment. This was some network problem with my local Nexus instance.
Everything (including org.slf4j:slf4j-api:jar:1.5.10) is available in maven central, so unless you have modified your settings.xml or you are behind a proxy it should not require any additional repositories. I confirmed that it builds for me with an empty maven repository and executing mvn clean package successfully.
Though I am not an expert in configuring a Spring app, are you sure that this isn't a typo in the web.xml:
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter> <filter-name>onceSpringSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter>
Both refer to the same class.
This is not a typo. DelegatingFilterProxy looks up a Spring bean by the name of the Filter and delegates all the work to it. So by changing the filter name we are pointing to a different object in the Spring configuration. You can find additional information on DelegatingFilterProxy in the Spring Security reference.
There is too much voodoo happening inside the framework. That's why I did not understand the wiring in the security.xml. It did not look complete to me.
I'm sorry you are still uncertain of how things work. If you haven't already read it, you might read the Security Filter Chain section of the reference which describes how it behaves.
I have read this part twice. I got it but I still have the feeling that a state chart would help tremendously help to understand the complete wiring behind the scenes. I am in for the webinar too.
So, how can we continue to improve the Spring experience in this case?
Michael Osipov said:
Rob, can wie reuse the org.springframework.web.filter.OncePerRequestFilter
somehow?
Rob Winch said:
No because it clears out the attribute after it executes (i.e. it would still occur twice). The call stack would look something like this:
Container start process request
FilterChainProxy
FilterChainProxy
This is different for FORWARD, INCLUDE, etc which is more like:
Container start process request
FilterChainProxy
FilterChainProxy
As you can see the clearing of the attribute would occur before the second invocation when processing an error and after invocation of a FORWARD, INCLUDE, etc. This means that it only prevents execution on FORWARD, INCLUDE, etc.
Michael Osipov said:
OK, some custom wrapper or built-in support is necessary.
Rob Winch said:
Thinking about this more, I really think it should be resolved in Spring Web. See SPR-9895
Michael Osipov said:
Rob, issue SPR-9895 has been closed and there is method now. How does one now connect this with the DelegatingFilterProxy?
Rob Winch said:
Spring Security 3.2 will be compiled against the new class and override that method.
Michael Osipov said:
I guess this will include/patch INCLUDE, FORWARD, etc too?
Rob Winch said:
Correct
Michael Osipov said:
Great, looking forward too. You did change the summary to BasicAuthFiter. This should apply to every header-based filter, shouldn't it??
Rob Winch said:
I will likely do some more evaluation at the time I address this issue. For now the scope is for the immediate problem, but again will likely change. The main point to updating the text was that it wasn't going to be a generic wrapper anymore
Rob Winch said:
Pushing to 4.0 partially due to time lines and partially due to passivity concerns
Rob Winch said:
This is now resolved in master. I decided to focus on this specific problem at hand since we did not have concrete use cases for other Filter's and dispatches.
Michael Osipov said:
Thanks for the fix. Does it really suffice to extend from OncePerRequestFilter
and it is guaranteed to be executed only once? Is it still valid to have this configuration though you responded this earlier?
Rob Winch said:
Since SPR-9895 has been resolved, yes it is suffice to extend OncePerRequestFilter. Please go ahead and give the latest snapshot a try. You will need to ensure to update your dependencies to use Spring 4.1.2.RELEASE and Spring Security 4.0.0.CI-SNAPSHOT. You can resolve SNAPSHOTs with maven using the following maven repository:
<repositories>
<repository>
<id>snapshot</id>
<url>http://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
NOTE: You may notice that the commit contains a test to ensure this works. I also have ran this through a simple integration test to ensure the unit test is properly setup.
Michael Osipov said:
Thanks a lot Rob, I will add this repo to our local Nexus instance and will give it a try next week. I will update the issue with the outcome of the test soon.
This issue depends on https://jira.spring.io/browse/SPR-9895
This issue depends on https://jira.spring.io/browse/SPR-9895
This issue depends on https://jira.spring.io/browse/SPR-9895
This issue depends on https://jira.spring.io/browse/SPR-9895
Michael Osipov (Migrated from SEC-2054) said:
I have configured the following security element:
I have set up custom error pages in my web.xml:
If for example an authentication fails the 401 page should be displayed.
Now, if a client sends an invalid Basic value the filter chain finds that and calls the 401 page through Tomcat. Unfortunately, the filter chain proxy does not know that this is one request with an error forward only.
It fires the entire auth chain again:
Now the FilterSecurityInterceptor maintains an observeOncePerRequest property which tells him to observe checks only once. The FilterChainProxy does not have such a property which treats a subrequest a whole new request. The response gets reset twice and no output it written to the client.
I could set the error pages to security="none" but I want to maintain the security context on all pages whether they are protected or not.