Saturday, March 20, 2010

Spring ACL for RESTful web services

I had mentioned before that the easiest way to provision permissions for URIs using Spring Security is by adding intercept-urls and corresponding expressions in security metadata for a filter in a web application. It is also possible to define security metadata in file/database for these URIs so that permission could be changed dynamically after the webapp is deployed. Here is a sample using a property file named url.properties (credits: custom security metadata)for more details.

1:  <bean id="filterInvocationInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">  
2:      <property name="authenticationManager" ref="authenticationManager"/>  
3:      <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>  
4:      <property name="securityMetadataSource" ref="cspaceMetadataSource"/>  
5:    </bean>  
6:    <bean id="cspaceMetadataSource" class="org.collectionspace.services.authorization.spring.CSpaceSecurityMetadataSource">  
7:      <property name="urlProperties">  
8:        <util:properties location="classpath:urls.properties" />  
9:      </property>  
10:    </bean>  

The url.properties includes a list of permissions. It might look something like following.

1:  /accounts/**=ROLE_ADMINISTRATOR  

And the CSpaceSecurityMetadataResource looks as follows:


1:  import java.util.Collection;  
2:  import java.util.Properties;  
3:  import org.springframework.security.access.ConfigAttribute;  
4:  import org.springframework.security.access.SecurityConfig;  
5:  import org.springframework.security.web.FilterInvocation;  
6:  import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
7:  public class CSpaceSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {  
8:    private Properties urlProperties;  
9:    public Collection<ConfigAttribute> getAllConfigAttributes() {  
10:      return null;  
11:    }  
12:    public Collection<ConfigAttribute> getAttributes(Object filter)  
13:        throws IllegalArgumentException {  
14:      FilterInvocation filterInvocation = (FilterInvocation) filter;  
15:      String url = filterInvocation.getRequestUrl();  
16:      String method = filterInvocation.getHttpRequest().getMethod();  
17:      //get the roles for requested page from the property file  
18:      String urlPropsValue = urlProperties.getProperty(url);  
19:      StringBuilder rolesStringBuilder = new StringBuilder();  
20:      //fetch roles from property file that could invoke the given http method on given url
21:      return SecurityConfig.createListFromCommaDelimitedString(rolesStringBuilder.toString());  
22:    }  
23:    public boolean supports(Class<?> arg0) {  
24:      return true;  
25:    }  
26:    public void setUrlProperties(Properties urlProperties) {  
27:      this.urlProperties = urlProperties;  
28:    }  
29:    public Properties getUrlProperties() {  
30:      return urlProperties;  
31:    }  
32:  }  

Limitations :


Http Method

Unlike a web application, for the RESTful web service, it is important to know the http method (e.g. POST is used for creating representation for a resource) in addition to the URI (e.g. /accounts/) from the invocation context. Using this two part information, you should retrieve a list of roles (comma separated) that are allowed to invoke the given HTTP method on the given URI. Note that for this reason the example url.properties file shown earlier is not enough as it does not include any HTTP methods in permission definition.

Sub-resources and permission inheritance

According to the HATEOS principle, it is very common to expect that a representation received from a resource could include additional URIs to retrieve representations of related resources. For example, to retrieve the user profile associated with an account, one could invoke a GET request on URI /accounts/{accountid}/users/{userid}. Security administrator may want to inherit permissions for the users resource from the accounts resource. Using a flat permission model such as shown above in the url.properties, it is not possible to define inheritance.

Therefore, I am exploring if a URI could be considered a domain object and Spring ACL could be used to define permissions. Will keep you posted ...

No comments:

Post a Comment