3

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?

Lonzak
  • 9,334
  • 5
  • 57
  • 88
  • I am not sure if it would work but, have you tried configuring your `http` `request-matcher` attribute as `mvc`? As you can see in the [documentation](https://docs.spring.io/spring-security/reference/5.6.4/servlet/appendix/namespace/http.html#nsa-http-request-matcher), is a supported configuration option and will instruct Spring Security to use [Spring MVC pattern matching](https://stackoverflow.com/questions/50536292/difference-between-antmatcher-and-mvcmatcher). I think path matching is case sensitive as well, but at least it will be coherent with your Spring MVC definitions. – jccampanero May 02 '22 at 21:42
  • But our Spring definitions are based on the ant matcher - so we'll have to rewrite those, too. And it wouldn't help since it is case sensitive... – Lonzak May 03 '22 at 08:22
  • Thank you very much for the feedback @Lonzak. Yes, although I think most of the pattern definitions will be the same for both approaches but you are right, MVC pattern matching is case sensitive as well. In any way, I think it is worth giving it a try and see.. – jccampanero May 03 '22 at 16:46
  • I'm not sure if I understand the question correct, but in the old Spring docs I found the attribute `path-type="regex"` on the element `security:filter-security-metadata-source`: (second example on https://docs.spring.io/spring-security/site/docs/3.0.x/reference/core-web-filters.html#filter-security-interceptor) - if you can modify your paths to case insensitive regular expressions, this might help. – cyberbrain May 07 '22 at 22:48

2 Answers2

0

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.

BendaThierry.com
  • 2,080
  • 1
  • 15
  • 17
  • The request matcher I did already mention as a solution. For your 2nd possible solution I am not quite sure that I follow - could you elaborate on that approach some more? Regarding your 3rd suggestion - so you mean that I can annotate my beans with `@value` or e.g. `@Bean` and then reference them in my XML configuration? – Lonzak May 10 '22 at 14:32
  • The third way is just here to handle maintenability a lot easier if you have a lot of big XML files. It simplifies a lot my daily work too ;) – BendaThierry.com May 10 '22 at 21:06
  • The second solution is to implement a custom security filter, and process each request to get the request uri with the stack of antMatchers extracted from your Spring security config. It could be easier to implement with a request interceptor, as you want. – BendaThierry.com May 10 '22 at 21:09
0

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">
Lonzak
  • 9,334
  • 5
  • 57
  • 88