Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine what roles are required to access a URL with Spring Security?

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.

like image 734
Hilton Campbell Avatar asked Jan 17 '09 20:01

Hilton Campbell


People also ask

Which method defines the URL path that has to be secured?

The SecurityFilterChain bean defines which URL paths should be secured and which should not. Specifically, the / and /home paths are configured to not require any authentication.

How do you validate a role in Spring boot?

The first way to check for user roles in Java is to use the @PreAuthorize annotation provided by Spring Security. This annotation can be applied to a class or method, and it accepts a single string value that represents a SpEL expression. Before we can use this annotation, we must first enable global method security.


2 Answers

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.

like image 183
Shaun the Sheep Avatar answered Oct 06 '22 01:10

Shaun the Sheep


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.

like image 39
Andrzej Doyle Avatar answered Oct 06 '22 00:10

Andrzej Doyle