'How to configure Spring-Security AntPathRequestMatcher to case insensitive in XML configuration

We recently upgraded Spring-Security from 3.X to 5.6. Most of the issues we could iron out however one thing proves difficult. The problem was caused by a change in the default behavior (3.1 vs. 5.6) of the AntPathRequestMatcher (happened in Spring 4.2?).

So now we have interceptors and filters which are not triggered anymore when a different case is used.

Please note: In the old version everything spring related is configured in XML and for now it has to stay like this. In future we'll change this to annotations but not for now, since it is an immense task due to the size of the application.

Current config:

<bean class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
        id="filterSecurityInterceptor">
        <property name="securityMetadataSource">
            
            <security:filter-security-metadata-source>
                <security:intercept-url 
                    access="hasRole('ROLE_User')" pattern="/servlet/**"/>
                <security:intercept-url
                    access="hasRole('ROLE_User')" pattern="/mobile.html" />
                <security:intercept-url
                    access="hasAnyRole('ROLE_User', 'ROLE_OtherUser', 'ROLE_Guest')"
                pattern="/offlineAssets/*" />
                ...

In the configuration for filter-security-metadata-source one can configure different matchers using request-matcher="ant" however I did not find a way to use an case-insensitive AntMatcher like it was before. There was a ticket discussing to introduce an ciAnt matcher but it was obviously not done since it is not available in the current spring-security version.

One possibility could be to define a request-matcher-ref on the level of intercept-url however then I would have to define one matcher bean for each rule (and there are a lot of those). This would bloat the whole file and readability would suffer. Also converting everything to ciRegex is unfortunately not an option. There must be simpler way to do this.

There is a similar case with the configured filter-chains however there we could solve the problem by implementing our own SecurityFilterChain class which creates a case-insensitive Matcher and can be configured in the XML configuration. However this is not possible for the intercept-urls (we failed constructing the Map<RequestMatcher, Collection<ConfigAttribute>> requestMap)

So any idea how an case insensitive AntPathRequestMatcher can be configured?



Solution 1:[1]

As suggested in my original post the only way I could think of is to define our own matcher-beans. This now means adding a high two-digit number of new bean definitions bloating our XML configuration:

<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher" id="antmatcherServlet">
    <constructor-arg value="/servlet/**" index="0"/>
    <constructor-arg index="1"><null/></constructor-arg>
    <constructor-arg value="false" index="2"/>
</bean>
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher" id="antmatcherMobile">
    <constructor-arg value="/mobile.html" index="0"/>
    <constructor-arg index="1"><null/></constructor-arg>
    <constructor-arg value="false" index="2"/>
</bean>
...

And the reference is done like this:

        <security:filter-security-metadata-source>
            <security:intercept-url 
                access="hasRole('ROLE_User')" request-matcher-ref="antmatcherServlet"/>
            <security:intercept-url
                access="hasRole('ROLE_User')" request-matcher-ref="antmatcherMobile"/>
            <security:intercept-url
                access="hasAnyRole('ROLE_User', 'ROLE_OtherUser', 'ROLE_Guest')"
            request-matcher-ref= "..." />
            ...

A solution like this would have been really great and also not breaking backwards compatibility:

3.X:

<security:filter-security-metadata-source request-matcher="ant">

4.X, 5.X

<security:filter-security-metadata-source request-matcher="ciAnt">

Solution 2:[2]

I am wondering why you are arguing against some more verbosity inside your XML beans configuration, because it was the way the things are working with Spring since the 1.x version until Java Config has raised up in the ecosystem. I understand you are managing a big application and adding some stuff will complicate your config maintenability.

One way to go (and your best bet I think so) is to add the request-matcher-ref with an extended bean which is an insensitive version of the Spring antMatcher.

One another way could be these one : Maybe you can implement a custom security filter within your request stack and check inside it if a customized insensitive antMatcher is matching or not. These way you can simplify a lot your configuration tasks.

Some tips, not directly related but usefull for managing big config Spring Beans XML files :

1/ You can split your XML configuration in modules dedicated files to make things better to maintain, and import them inside a main XML file which is bounded to your webapplication Spring context.

2/ You can add some Java Config step by step to simplify your daily maintenance work.

3/ You can externalize all the beans fields init values inside Properties files, and get their values with custom Spring profiles using @Profile annotation (dev, qa, prod are usual profiles during development process) and @Value annotations to get values inside your POJOs. => Beans initialization will be put outside of XML configuration, which will be lighter and lighter as much as your are advancing on it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Lonzak
Solution 2 BendaThierry.com