Showing posts with label Custom securityMetadataSource. Show all posts
Showing posts with label Custom securityMetadataSource. Show all posts

Sunday, January 3, 2010

Spring Security – Part 2 – Custom securityMetadataSource

Now let us look into filterSecurityInterceptor. This filter authorizes web requests based on URL patterns. Instead of having the URLs configured in application context, we will have URLs in the properties file. We can even have these URLs configured in database or LDAP server. Here let us have properties file having URLs and the corresponding roles. The properties file looks like –

/admin/**=ROLE_ADMIN,ROLE_MANAGER
/admin/userPreference/**=ROLE_MANAGER
/admin/userPreference/updatePreference.action=ROLE_USER,ROLE_ASSOCIATE
/admin/userPreference/deletePreference.action=ROLE_USER

Here ROLE_ADMIN, ROLE_MANAGER are given complete access to all admin URLs, ROLE_MANAGER is given access to all URLs having /admin/userPreference/ and ROLE_USER, ROLE_ASSOCIATE are given page / action level access.

Now let us define filterSecurityInterceptor.

<bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource" ref="mySecureResourceFilter"/>
</bean>

We have already configured authenticationManager in the previous part. Let us now define accessDecisionManager.

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</property>
</bean>

We will look into it in more detail in next part.

Now let us write custom securityMetadataSource – mySecureResourceFilter

Let us define the bean first -


<bean id="mySecureResourceFilter" class="com.test.common.MySecureResourceFilter">
<property name="urlProperties">
<util:properties location="classpath:urls.properties" />
</property>
</bean>

Given the requested URL, we have to find all the roles authorized to access it. Like if requested URL is /admin/changePreference/deletePreference.action, we will get the roles from the properties file which can access the following URLs –

/admin/changePreference/deletePreference.action
/admin/changePreference/**
/admin/**

All this is implemented in getAttributes (..) method defined below which returns the name of the Authorities (or Roles) that are allowed to access requested URL.

import java.util.Collection;
import java.util.Properties;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;

import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

public class MySecureResourceFilter implements
FilterInvocationSecurityMetadataSource {

private Properties urlProperties;

public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}

public Collection<ConfigAttribute> getAttributes(Object filter)
throws IllegalArgumentException {
FilterInvocation filterInvocation = (FilterInvocation) filter;
String url = filterInvocation.getRequestUrl();

//get the roles for requested page from the property file
String urlPropsValue = urlProperties.getProperty(url);
StringBuilder rolesStringBuilder = new StringBuilder();
if(urlPropsValue != null) {
rolesStringBuilder.append(urlPropsValue).append(",");
}

if(!url.endsWith("/")) {
int lastSlashIndex = url.lastIndexOf("/");
url = url.substring(0, lastSlashIndex + 1);
}


String [] urlParts = url.split("/");

StringBuilder urlBuilder = new StringBuilder();
for (String urlPart : urlParts) {
if(urlPart.trim().length() == 0) {
continue;
}
urlBuilder.append("/").append(urlPart);
urlPropsValue = urlProperties.getProperty(urlBuilder.toString() + "/**");

if(urlPropsValue != null) {
rolesStringBuilder.append(urlPropsValue).append(",");
}
}

if(rolesStringBuilder.toString().endsWith(",")) {
rolesStringBuilder.deleteCharAt(rolesStringBuilder.length()-1);
}


if(rolesStringBuilder.length() == 0) {
return null;
}

return SecurityConfig.createListFromCommaDelimitedString(rolesStringBuilder.toString());
}

public boolean supports(Class<?> arg0) {
return true;
}

public void setUrlProperties(Properties urlProperties) {
this.urlProperties = urlProperties;
}

public Properties getUrlProperties() {
return urlProperties;
}

}

That’s it. In next part we will look into role based Method Invocation.