views:

950

answers:

2

I'm using Spring Security to secure a webapp. The URLs are secured like this:

<security:http entry-point-ref="authenticationEntryPoint">
  <security:intercept-url pattern="/" access="ROLE_ANONYMOUS" />
  <security:intercept-url pattern="/assets/**/*" access="ROLE_ANONYMOUS" />
  ...
  <security:intercept-url pattern="/**" access="ROLE_USER" />
  <security:anonymous granted-authority="ROLE_ANONYMOUS" />
</security:http>

I have a filter that needs to redirect the user to a special page under certain circumstances. However, that page requires images and CSS files in the assets directory which will unfortunately also be redirected to that special page. I don't want the filter to manually check against each URL pattern because my actual URL configuration is much longer, and I also want to allow other pages.

Is there a way to determine from the filter for a given page what roles are required? I could then choose not to redirect if ROLE_ANONYMOUS is not required.

+1  A: 

Don't forget that what actually happens when deciding whether to allow access is that the URL and existing authentication is passed through a series of AccessDecisionVoters, one of the default of which is the RoleVoter. This voter checks the configuration for the requested resource, and if a specific role is required, will deny the request if the existing authentication doesn't have that role.

So to the solution - you can add other voters that kick in before the role voter. Each voter must return GRANT, DENY or ABSTAIN, and processing only continues to later voters if ABSTAIN is returned. Thus you can write your own custom voter (or reuse an existing one if this would work), have it fire before the role voter, and unconditionally grant access to any requests to the resources you're referring to.

I have done something like this in a current project, where certain transient application-specific attributes can let someone access resources that ordinarily they would not be able to, and it works well as an approach.

Andrzej Doyle
That's a good idea, but it doesn't quite get me there. The problem is that, regardless of whether the user has access, the filter kicks in and redirects to the special page. I need some way for the filter to know when it should not redirect, and knowing the required roles for a URL would do that.
Hilton Campbell
A: 

Assuming you're using Spring Security 3, the source of that information (which attributes/roles are configured for a particular path) is the FilterInvocationSecurityMetadataSource that is injected into the FilterSecurityInterceptor. So if you have a particular URL, then you can query the configured attributes by passing a FilterInvocation (created from the request and response) to the getAttributes() method of FilterInvocationSecurityMetadataSource.

Getting a reference to inner beans created by the namespace can be a bit tricky. Assuming you have your own bean (or beans) that you want to make the call from, you can inject it into them by adding a BeanPostProcessor to your application context, which is implemented something like this:

public class FilterSecurityMDSExtractor implements BeanPostProcessor, BeanFactoryAware {
    private ConfigurableListableBeanFactory bf;

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof FilterInvocationSecurityMetadataSource) {
            // Get your own bean from the BeanFactory here and inject the SecurityMetadataSource into it
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }    

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.bf = (ConfigurableListableBeanFactory)beanFactory;
    }   
}

Note that Spring Security automatically registers a WebInvocationPrivilegeEvaluator in the context which can be used to check whether a user has the ability to invoke a particular URL without actually invoking it. This is similar, in that it queries the SecurityMetadataSource, but not quite what you're after here.

Munkymisheen