I have a web application that uses spring security. It uses <intercept-url ../>
elements to describe the access filters for different urls. By default, this does not take request parameters of urls into account. I needed to set custom security rules of an url based on the request parameters. So I've done the following:
1) I created a bean post-processor class that will enable request parameters option for the spring security mechanisms:
<beans:beans>
. . .
<beans:bean class="MySecurityBeanPostProcessor">
<beans:property name="stripQueryStringFromUrls" value="false" />
</beans:bean>
. . .
</beans:beans>
And the code:
public class MySecurityBeanPostProcessor implements BeanPostProcessor {
private Boolean stripQueryStringFromUrls = null;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DefaultFilterInvocationSecurityMetadataSource && stripQueryStringFromUrls != null) {
((DefaultFilterInvocationSecurityMetadataSource) bean)
.setStripQueryStringFromUrls(stripQueryStringFromUrls.booleanValue());
}
return bean;
}
// code stripped for clarity
}
This should set the spring security metadata source to take into account the request parameters. I have debugged the above code and the stripQueryStringFromUrls
property is being set.
2) In my security context xml I have the following definitions:
<intercept-url pattern="/myUrl?param=value" access="!isAuthenticated() or hasRole('ROLE_GUEST')" />
<intercept-url pattern="/myUrl" filters="none" />
...
<intercept-url pattern="/**" access="isAuthenticated()" />
As you can see, I need to access the url with the params specified only if the user is not authenticated, or uses a guest account. Also, I have added a rule for the same url, but without any params, which has no filters.
As far as I know, spring security should be configured providing the more-specific url BEFORE the less-specific, because otherwise the chain will detect the more-general rule first and will not continue to the more-specific. That is why I expect the url with params to be more-specific, therefore to be denied access of authenticated non-guest users. Instead, the defined below more general rule applies. Here is the output:
INFO [STDOUT] 186879 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - Candidate is: '/myUrl'; pattern is /myUrl; matched=true
INFO [STDOUT] 186879 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - /myUrl?param=value has an empty filter list
I also tried to remove the rule for the url wit no params. Then, instead of getting my rule for the url with params to work, the filter chooses the /**
pattern and requires the users to log-in.
The output for that is:
INFO [STDOUT] 73066 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - Candidate is: '/myUrl'; pattern is /**; matched=true
INFO [STDOUT] 73068 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - /myUrl?param=value at position 1 of 8 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
The application is written in Java 1.6, uses Spring v3.0 and is deployed on JBoss v5.1.0-GA, on a linux machine. I have no clues why the filters behave in the way I described. Your help and advices will be greatly appreciated.
Edit:
As a conclusion, what I observed is that the /myUrl?param=value
filter is never applied - as if the entry in the security-context.xml was ignored. This fits the behavior I have observed up to now. I have also tried replacing filters="none"
with access="permitAll"
, switched to regex (and changes patterns accordingly - for example /myUrl?param=value
becomes \A/myUrl\?param=value\Z
) and in all variations the behavior I get is the same.
Edit 2:
The issue described here is actually invalid. The reasons for this is the following matter: the project where the problem is present has excluded some spring packages due to internal library clashes and incompatibility, while the whole setup somehow worked. I was never made aware of that and actually this unpure configuration renders the whole question obsolete. The concrete reason is that the implementations of isAuthenticated() and isAnonymous() methods were not working as expected, therefore any advice provided here was not working.