DuyHai's Java Blog

Spring Security part IV : ExceptionTranslationFilter & FilterSecurityInterceptor

Advertisements

In this post we’ll examine in depth the ExceptionTranslationFilter and FilterSecurityInterceptor filters

VII ExceptionTranslationFilter


<!-- Filter to redirect to login page -->
<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
        <property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</bean>
    
<bean id="authenticationEntryPoint"  class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
	  <property name="loginFormUrl" value="/pages/Security/login.html"/>
	  <property name="forceHttps" value="false"/>
</bean>
    
<bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
	<property name="errorPage" value="/pages/Security/accessDenied.html"/>
</bean>

1) ExceptionTranslationFilter

The ExceptionTranslationFilter purpose is to redirect the user to the login page if he’s not yet authenticated and to a default error page if he tries to access an unauthorized resources.

The authenticationEntryPoint defines a loginFormUrl pointing to the default login page. Optionally you can force usage of HTTPS by setting forceHttps to true.

Your login page should resemble:


<form action="myApplication/j_myApplication_security_check" method="post">
	<fieldset>
		<legend>Login form</legend>
		<label for="j_username">Login</label>
		<input type="text" id="j_username" size="20"/>

		<label for="j_password">Password</label>
		<input type="password" id="j_password" size="20"/>
			
		<button type="submit">Submit</button>
		<button type="reset">Reset</button>
	</fieldset>		
</form>

Remember about the filterProcessesUrl parameter we mentionned in the previous post ? It is used here as default action for the login form.

For Spring Security to retrieve the login & password values in the HTTP request attributes, we should set their ids to “j_username” & “j_password” respectively. This is the default convention.

Again it is possible to change these defaults by setting the “usernameParameter” & “passwordParameter” for the authenticationProcessingFilter.


<bean id="authenticationProcessingFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
	<property name="authenticationManager" ref="authenticationManager"/>
	<property name="usernameParameter" value="j_myUserNameId"/>
	<property name="passwordParameter" value="j_myPasswordId"/>
	<property name="filterProcessesUrl" value="/j_myApplication_security_check"/>
	...
</bean>

 

2) AccessDeniedHandler

This handler simply forwards the user to the error page defined by the “errorPage” parameter if he is not authorized to access the requested resources, quite straightforward.

 

VIII FilterSecurityInterceptor

The core of access management is done by this filter.
First, the namespace for Spring security should be set in order to use the shorthand “sec“.


<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xmlns:sec="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">

1) <sec:filter-security-metadata-source>


<!-- Filter for role checking -->
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
	<property name="authenticationManager" ref="authenticationManager"/>
	<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
	<property name="securityMetadataSource">
		<sec:filter-security-metadata-source lowercase-comparisons="true" request-matcher="ant" use-expressions="true">
			<sec:intercept-url pattern="/pages/Security/**" access="permitAll"/>
			<sec:intercept-url pattern="/resources/**" access="permitAll"/>
			<sec:intercept-url pattern="/pages/Settings/**" access="hasRole('SETTINGS')"/>
			<sec:intercept-url pattern="/pages/Home/*" access="hasRole('HOME')"/>              
			<sec:intercept-url pattern="/pages/Admin/**" access="hasRole('ADMINISTRATOR')"/>
			<sec:intercept-url pattern="/servlet/Download" access="hasAnyRole('DOWNLOAD','PREMIUM_ACCOUNT')"/>
                
			<sec:intercept-url pattern="/**" access="isAuthenticated()"/>
		</sec:filter-security-metadata-source>
	</property>
</bean>

Lots of interesting points to mention here.

We define inside the <filter-security-metadata-source> tag a list of resource URLs and the corresponding roles to access them. This tag exposes the following attributes:

At line 8, we allow un-authenticated access to theme resources (css, images, javascripts) by setting access=”permitAll”. Similarly, all pages in “/pages/Security” folder, including login form, are granted the permitAll access (otherwise the user can never reach the login form).

At line 9, accessing all pages in “/pages/Settings” subfolder requires the role SETTINGS. The role definition relies on the hasRole(String) expression. A comprehensive list of all available expressions for access control is documented here Expression-Based Access Control

At line 12 we have an example of access control base on a list of roles using the hasAnyRole() expression.

Finally, at line 14, we restrict the access to all of our application resources (path = “/**”) by requiring that the user should be authenticated (not anonymous).

There is an important gotcha with the above access control definition. Spring will apply access control rules in their declaration order. Consequently it is important to declare first all un-secured resources and finish with the most restricted resources.

For example, if we had declared <sec:intercept-url pattern=”/**” access=”isAuthenticated()”/> before <sec:intercept-url pattern=”/pages/Security/**” access=”permitAll”/>, the application will never be accessible since on entering the login form, the user is rejected because not authenticated.

 

2) AccessDecisionManager

Above we just define access control rules for incoming URLs. Still we need a manager to enforce these rules and there comes the AccessDecisionManager into play.


<bean id="httpRequestAccessDecisionManager" 
	class="org.springframework.security.access.vote.AffirmativeBased">
	<property name="allowIfAllAbstainDecisions" value="false"/>
	<property name="decisionVoters">
		<list>
			<ref bean="webExpressionVoter"/>
			<ref bean="authenticatedVoter"/>
		</list>
	</property>
</bean>
    
<bean id="webExpressionVoter" 
	class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
<bean id="authenticatedVoter" 
	class="org.springframework.security.access.vote.AuthenticatedVoter" />

First we use the org.springframework.security.access.vote.AffirmativeBased provided by Spring to control access rules. This default implementation of the AccessDecisionManager interface simply grants access if any injected decisionVoters returns an affirmative response.

Two other implementations of the AccessDecisionManager interface are available:

The allowIfAllAbstainDecisions property on the is set to false so that at least one affirmative response is required from decision voters to grant access.

Next we inject two decision voters into this AccessDecisionManager:

There are some other implementations of the AccessDecisionVoter interface provided by Spring, we just mention them for information:

Advertisements