Search code examples
springfilterspring-securityrolespre-authentication

Spring security with multiple custom filters and roles


I am using Spring security with two filters: - One filter for x.509 authentication for client certificates. All his filter does is extracts the username from certificate into principle. - One filter to do header based authentication. The header should have username and roles. In this filter I check to make sure that there is a principal already present in the security context. If present I make sure that it matches whats in the headers. Then I extract the roles from the header and set the granted authorities. I have a url pattern that I want to be made accessible to roles - 'ROLE_USER'

Now here is the problem. The request only hits the first filter(X.509), the role is missing in this header obviously and access is denied by spring security.

I cannot switch the order of the filters because if I do then X.509 filter provided by spring simply sees that principal is already present and does nothing making it useless.

Is there any way for the role check to be deferred until all filters are processed? Or any other way to achieve what I am trying to do.

Here is my spring security config:

<security:http auto-config="true" entry-point-ref="customEntryPoint">
    <security:intercept-url pattern="/user/**"  access="ROLE_USER"/>
    <security:custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="x509Filter"  />
    <security:custom-filter after="FILTER_SECURITY_INTERCEPTOR" ref="headerFilter"/>
</security:http>    

where the x509Filter is standard spring security filter configured as:

<beans:bean id="x509PrincipalExtractor" class="org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor">
    <beans:property name="subjectDnRegex" value="CN=(.*?),"/>
</beans:bean>

I can provide scrubbed up customHeaderFilter if needed but at this point the control never reaches the filter so it is inconsequential as to what happens in it.

Any help/guidance would be greatly appreciated.


Solution

  • Thanks to the pointer from @Maksym, the problem was resolved by changing 'after' to 'before' in the customHeaderFilter as follows:

    <security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="headerFilter"/>
    

    FilterSecurityInterceptor is responsible for handling security of HTTP resources, including applying role checks. In my case X509Filter would fire setting principal but would not set any authorities. This would cause the interceptor to deny access to the resource and the headerFilter would not even come into the picture.

    By setting the position of the headerFilter to before the interceptor allowed the principal and authentication object in the security context to be set up correctly with the given authorities, leading to the expected behavior.