Secure your web application with Spring Security

Spring Security is great framework to secure web application. It’s easy to configure and it doesn’t need to make special changes or deploy libraries to your Servlet or EJB container.

Spring security keeps your application objects free of security code, unless you specifically choose to interact with the security context.

   

Photo credit: V.Áron

This article explains how to secure a JEE application with Spring Security by a sample project. This project is implemented with JSF, Spring (version 3.0) and Hibernate.

The source code of the project is available on github here.

Basic configuration

In this part we will add dependencies and basic configuration to integrate Spring security to the web application.

  • Add Spring Security dependencies to the maven pom.xml file.
     <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>org.springframework.security.web</artifactId>
            <version>3.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>org.springframework.security.config</artifactId>
            <version>3.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>org.springframework.security.taglibs</artifactId>
            <version>3.0.5.RELEASE</version>
        </dependency>
    

– Update web.xml file.
Inside web.xml, insert the following block of code. It should be inserted right after the /context-param end-tag.

<filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>

– Add applicationContext-security.xml file
This file contains the basic Spring Security config. There is no user access control for any path. Users are defined in the Spring application context file.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
 
 <http use-expressions="true">
        <intercept-url pattern="/**" filters="none" />
        <form-login />
        <logout />
    </http>

	<authentication-manager>
	    <authentication-provider>
	      <user-service>
	        <user name="user1" password="password1" authorities="ROLE_USER, ROLE_ADMIN" />
	        <user name="user2" password="password2" authorities="ROLE_USER" />
	      </user-service>
	    </authentication-provider>
  </authentication-manager>
</beans>

After the basic configuration is done, you should have your web application running and you should access all pages.

Security Configuration

1 – Authentication

Authentication is the process of determining whether someone or something is, in fact, who or what it is declared to be. [2]

Spring security supports LDAP, database, XML and Properties file to authenticate users. In this article, we use database authentication. The database schema is created by hibernate and it is populated by DbUnit framework.

We create two persistent classes to save users and their authorities.


– Create a login.xhtml page as shown in the code bellow

<html xmlns:jsp="http://java.sun.com/JSP/Page"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core" 
>
<head></head>
<body>

<c:if test="${param.state=='failure'}">
		<c:set var="username" value="#{sessionScope.SPRING_SECURITY_LAST_USERNAME}"/>
		<div class="ERROR">
			Your login attempt was not successful, try again.<br />
			Reason: #{sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
		</div>
</c:if>
	<form  action="#{request.contextPath}/j_spring_security_check" method="post">
		<h:panelGrid columns="2" title="Customer">
			<f:facet name="header"> 
				<h:outputText value="Login form" />
			</f:facet>
			<h:outputText value="User:" />
			<h:inputText id="j_username" value="#{username}"  />
			<h:outputText value="Password:" />
			<h:inputSecret id="j_password" />
			<f:facet name="footer"> 
				<h:commandButton  value="Login" type="submit"  />
			</f:facet>
		</h:panelGrid>
	</form>
</body>
</html>

To add JDBC Spring security some changes nead to be done to the applicationContext-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	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">

	<http use-expressions="true" access-denied-page="/pages/static/accessDenied.jsf">
		<intercept-url pattern="/login.jsf" filters="none"/>
		<intercept-url pattern="/pages/**" access="isAuthenticated()" />
		<form-login login-page="/login.jsf" default-target-url="/pages/static/welcome.jsf" authentication-failure-url="/login.jsf?state=failure"/>
		<logout logout-success-url="/login.jsf?state=logout"  />
	</http>

	<authentication-manager alias="authenticationManager">
		<authentication-provider>
			<password-encoder hash="md5" />
			<jdbc-user-service data-source-ref="dataSource"
				users-by-username-query="SELECT U.login AS username, U.password as password, U.enabled as enabled FROM user U where U.login=?"
				authorities-by-username-query="SELECT U.login as username, A.authority_name as authority FROM user U, authority A WHERE U.user_id=A.user_id and U.login=?"
				role-prefix="ROLE_" />
		</authentication-provider>
	</authentication-manager>

</beans:beans>

To maximize password security we made a choice to use md5 password encoding.

2 – Authorization

Authorization is the function of specifying access rights to resources, which is related to information security and computer security in general and to access control in particular. More formally, “to authorize” is to define access policy. [1]

With spring security we can manage pages, screen components and methods execution rights policies.

– Path access control

Then implement access rules for URLs by adding <intercept-url> children directly under the <http> element.

	
	<http use-expressions="true" access-denied-page="/pages/static/accessDenied.jsf">
		<intercept-url pattern="/login.jsf" filters="none" />
		<intercept-url pattern="/pages/static/**" access="isAuthenticated()" />
		<intercept-url pattern="/pages/customer/**" access="hasAnyRole('ROLE_ADMIN','ROLE_CUSTOMER')" />
		<intercept-url pattern="/pages/order/**" access="hasAnyRole('ROLE_ADMIN','ROLE_ORDER')" />
		<intercept-url pattern="/pages/admin/**" access="hasRole('ROLE_ADMIN')" />
		<form-login login-page="/login.jsf" default-target-url="/pages/static/welcome.jsf"
			authentication-failure-url="/login.jsf?state=failure" />
		<logout logout-success-url="/login.jsf?state=logout" />
	</http>

-Taglib Spring Security

Sometimes, it is better to hide some unauthorized links rather than letting them available and showing the access denied page when they are requested.

Spring Security has its own taglib which provides basic support for accessing security information and applying security constraints in JSPs. [3]

To use Spring security taglib in JSP pages, you need to add the taglib declaration to your project as shown in the source code bellow:

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<sec:authorize ifAllGranted="ROLE_USER">
  Utilisateur : <sec:authentication property="principal.username"/>
</sec:authorize>

To use Spring security Taglib in a facelets pages is a little bit more complicated.

  • We need to add XML namespaces declaration for Spring security taglib into facelet page as highlighted in this source code.
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:rich="http://richfaces.org/rich"
    xmlns:sec="http://www.springframework.org/security/tags">
  • Create springsecurity.taglib.xml file into the WEB-INF file and a param declaration to reference this file in the web.xml file.
	<context-param>
		<param-name>facelets.LIBRARIES</param-name>
		<param-value>/WEB-INF/springsecurity.taglib.xml</param-value>
	</context-param>

This is the source code of springsecurity.taglib.xml I used in this prototype project. But this file has to be changed if you are using JSF 2.0. For more detail, read the spring documentation in this link.

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
	<namespace>http://www.springframework.org/security/tags</namespace>
	<tag>
		<tag-name>authorize</tag-name>
		<handler-class>org.springframework.faces.security.Jsf12FaceletsAuthorizeTagHandler</handler-class>
	</tag>
	<function>
		<function-name>areAllGranted</function-name>
		<function-class>org.springframework.faces.security.Jsf12FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean areAllGranted(java.lang.String)</function-signature>
	</function>
	<function>
		<function-name>areAnyGranted</function-name>
		<function-class>org.springframework.faces.security.Jsf12FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean areAnyGranted(java.lang.String)</function-signature>
	</function>
	<function>
		<function-name>areNotGranted</function-name>
		<function-class>org.springframework.faces.security.Jsf12FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean areNotGranted(java.lang.String)</function-signature>
	</function>
	<function>
		<function-name>isAllowed</function-name>
		<function-class>org.springframework.faces.security.Jsf12FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean isAllowed(java.lang.String, java.lang.String)</function-signature>
	</function>
</facelet-taglib>

  • Add this dependency to the pom.xml file
		<dependency>
			<groupId>org.springframework.webflow</groupId>
			<artifactId>spring-faces</artifactId>
			<version>2.2.1.RELEASE</version>
		</dependency>

Usually, the admin menu panel is visible only for users having the admin role. To implement this behavior, the panel source code is nested into the spring security authorize tag.

<sec:authorize access="hasAnyRole('ROLE_ADMIN')" >
	<rich:panelMenuGroup label="Admin">
		<rich:panelMenuItem >
				 <h:outputLink value="../admin/admin.jsf" >Users</h:outputLink>
		</rich:panelMenuItem> 
	</rich:panelMenuGroup>
</sec:authorize>

-Method authorization

Spring security allows method execution authorization management. It provides annotations which can contain expression attributes which are applied before and after the method invocation. To enable support for them, the attribute global-method-security has to be assigned the value enabled:

<global-method-security pre-post-annotations="enabled"/>

The source code above is added to application-context-security.xml file.

In this example we made a choice to allow only users having ROLE_CUSTOMER role to add customers.

import com.mycompany.dao.ICustomerDao;
import com.mycompany.entity.Customer;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.security.access.prepost.PreAuthorize;

public class CustomerDao extends HibernateDaoSupport implements ICustomerDao{

    @PreAuthorize("hasRole('ROLE_CUSTOMER')")
    public void save(Customer customer) {
        getHibernateTemplate().save(customer);
    }

// Other methods ....

}

To test Spring method execution authorization, we created a user “orderManager” which doesn’t have the role ROLE_CUSTOMER. When this user tries to save a customer, the application display the caught error message “Access is denied”.

Application example (Access is denied message)


Spring Security is a powerful framework to secure JEE applications. It has many other features to manage authentication and access-control services for java/JEE applications. I had used Spring Security since the project had a name Acegi. I think that the framewok has made a lot of progress and I recommend it for Securing web applications.

Reference:
[1] en.wikipedia.org
[2] searchsecurity.techtarget.com
[3] www.springsource.org

Advertisements