I use Spring Security 3.1.4 to secure a Spring MVC 3.2.4 application deployed to Tomcat. I have the following Spring Security configuration:
<http auto-config="true" use-expressions="true">
<http-basic />
<logout ... />
<form-login ... />
<intercept-url pattern="/" access="isAnonymous() or hasRole('ROLE_USER')" />
<intercept-url pattern="/about" access="isAnonymous() or hasRole('ROLE_USER')" />
<intercept-url pattern="/login" access="isAnonymous() or hasRole('ROLE_USER')" />
<intercept-url pattern="/under-construction" access="isAnonymous() or hasRole('ROLE_USER')" />
<intercept-url pattern="/admin-task*" access="hasRole('ROLE_USER') and hasRole('ROLE_ADMINISTRATOR')" />
<intercept-url pattern="/resources/**" access="isAnonymous() or hasRole('ROLE_USER')" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
</http>
I noticed that URL patterns without a trailing slash (e.g., /about
) do not match URLs with a trailing slash (e.g., /about/
) and vice-versa. In other words, a URL with a slash and an identical URL without a slash are treated as two different URLs by Spring Security. The problem could be fixed by using two security rules:
<intercept-url pattern="/about" access="isAnonymous() or hasRole('ROLE_USER')" />
<intercept-url pattern="/about/" access="isAnonymous() or hasRole('ROLE_USER')" />
Is there a better solution?
I know that path-type="regex"
allows to define URL patterns with regular expressions, but I would like to avoid any unnecessary complexity if it's possible.
Update
As Adam Gent noted, there is an additional problem that involves URLs with a dot: /about.foo
and /about
are treated as the same URL by Spring MVC. However, Spring Security treats them as two different URLs. So, one more security rule may be necessary:
<intercept-url pattern="/about.*" .../>
Spring Security has now added a new matcher which is aware of your Spring MVC URL matching configuration. This tells Spring Security to match paths based on the same rules that Spring MVC uses, eliminating the possibility of a URL being valid, but unsecured.
First you need to replace any old matchers with the new MVC matcher. Spring Security is now in sync with however you have configured Spring MVC so you are free to add or remove any path matching configuration. I recommend sticking with the defaults where possible.
If you were using antMatchers
, you now should use mvcMatchers
:
protected configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/about").hasRole("USER");
}
You need to add the attribute request-matcher
to your http
tag:
<http request-matcher="mvc">
<intercept-url pattern="/about" access="hasRole('USER')"/>
</http>
Full Reference
Please note that you also should no longer be prefixing your roles with "ROLE_" as Spring Security does this for you automatically.
I've not been able to find a way to handle both trailing slash and path suffixes in Spring Security. Obviously it is possible to write a regexp to handle these cases but this seems to make the security rules overly complex and prone to error. I want to be as confident as possible that I'm not exposing resources accidentally.
Therefore, my approach is to disable this behaviour in Spring by configuring the path matcher to be strict about both trailing slashes and suffixes.
@Configuration
public class ServletConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(final PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
configurer.setUseTrailingSlashMatch(false);
}
}
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false" trailing-slash="false" />
</mvc:annotation-driven>
<intercept-url pattern="/about/**"...
also works for me in Spring Security 3.1.4.
This secures /about
, /about/
, and /about/anything_else
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With